diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index 013ec2ad5..c51b4cb74 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -14,7 +14,7 @@ jobs: - name: 📥 Set up Java uses: actions/setup-java@v4 with: - java-version: 17 + java-version: 21 distribution: 'temurin' - name: 📥 Setup Gradle @@ -87,7 +87,7 @@ jobs: - name: 📥 Set up Java uses: actions/setup-java@v4 with: - java-version: 17 + java-version: 21 distribution: 'temurin' - name: 📥 Setup Gradle diff --git a/.github/workflows/make-doc.yml b/.github/workflows/make-doc.yml index 4da2a788a..12929cb7d 100644 --- a/.github/workflows/make-doc.yml +++ b/.github/workflows/make-doc.yml @@ -18,7 +18,7 @@ jobs: - name: Set up Java uses: actions/setup-java@v4 with: - java-version: 17 + java-version: 21 distribution: 'temurin' - name: Setup Gradle diff --git a/buildSrc/src/main/kotlin/cc-tweaked.java-convention.gradle.kts b/buildSrc/src/main/kotlin/cc-tweaked.java-convention.gradle.kts index 2e6308d20..e6a5ce9ae 100644 --- a/buildSrc/src/main/kotlin/cc-tweaked.java-convention.gradle.kts +++ b/buildSrc/src/main/kotlin/cc-tweaked.java-convention.gradle.kts @@ -78,8 +78,16 @@ dependencies { // Configure default JavaCompile tasks with our arguments. sourceSets.all { tasks.named(compileJavaTaskName, JavaCompile::class.java) { - // Processing just gives us "No processor claimed any of these annotations", so skip that! - options.compilerArgs.addAll(listOf("-Xlint", "-Xlint:-processing")) + + options.compilerArgs.addAll( + listOf( + "-Xlint", + // Processing just gives us "No processor claimed any of these annotations", so skip that! + "-Xlint:-processing", + // We violate this pattern too often for it to be a helpful warning. Something to improve one day! + "-Xlint:-this-escape", + ), + ) options.errorprone { check("InvalidBlockTag", CheckSeverity.OFF) // Broken by @cc.xyz @@ -148,7 +156,7 @@ tasks.javadoc { options { val stdOptions = this as StandardJavadocDocletOptions stdOptions.addBooleanOption("Xdoclint:all,-missing", true) - stdOptions.links("https://docs.oracle.com/en/java/javase/17/docs/api/") + stdOptions.links("https://docs.oracle.com/en/java/javase/21/docs/api/") } } diff --git a/buildSrc/src/main/kotlin/cc/tweaked/gradle/CCTweakedExtension.kt b/buildSrc/src/main/kotlin/cc/tweaked/gradle/CCTweakedExtension.kt index c254d55b6..802ea5c23 100644 --- a/buildSrc/src/main/kotlin/cc/tweaked/gradle/CCTweakedExtension.kt +++ b/buildSrc/src/main/kotlin/cc/tweaked/gradle/CCTweakedExtension.kt @@ -35,7 +35,6 @@ import java.io.File import java.io.IOException import java.net.URI -import java.net.URL import java.util.regex.Pattern abstract class CCTweakedExtension( @@ -226,12 +225,12 @@ fun jacoco(task: NamedDomainObjectProvider) where T : Task, T : JavaForkO * where possible. */ fun downloadFile(label: String, url: String): File { - val url = URL(url) + val url = URI(url) val path = File(url.path) project.repositories.ivy { name = label - setUrl(URI(url.protocol, url.userInfo, url.host, url.port, path.parent, null, null)) + setUrl(URI(url.scheme, url.userInfo, url.host, url.port, path.parent, null, null)) patternLayout { artifact("[artifact].[ext]") } diff --git a/buildSrc/src/main/kotlin/cc/tweaked/gradle/CCTweakedPlugin.kt b/buildSrc/src/main/kotlin/cc/tweaked/gradle/CCTweakedPlugin.kt index 5a5e27eb6..1c0bc1d38 100644 --- a/buildSrc/src/main/kotlin/cc/tweaked/gradle/CCTweakedPlugin.kt +++ b/buildSrc/src/main/kotlin/cc/tweaked/gradle/CCTweakedPlugin.kt @@ -42,6 +42,6 @@ private fun extendIdea(project: Project) { } companion object { - val JAVA_VERSION = JavaLanguageVersion.of(17) + val JAVA_VERSION = JavaLanguageVersion.of(21) } } diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml index 434436e7a..c7e7bf71d 100644 --- a/config/checkstyle/suppressions.xml +++ b/config/checkstyle/suppressions.xml @@ -22,4 +22,7 @@ SPDX-License-Identifier: MPL-2.0 + + + diff --git a/gradle.properties b/gradle.properties index 59600d400..105fcaa53 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,4 +13,4 @@ isUnstable=true modVersion=1.110.2 # Minecraft properties: We want to configure this here so we can read it in settings.gradle -mcVersion=1.20.4 +mcVersion=1.20.5 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7642546ed..16a88ad5b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,26 +7,26 @@ # Minecraft # MC version is specified in gradle.properties, as we need that in settings.gradle. # Remember to update corresponding versions in fabric.mod.json/mods.toml -fabric-api = "0.93.1+1.20.4" -fabric-loader = "0.15.3" -neoForge = "20.4.210" +fabric-api = "0.97.6+1.20.5" +fabric-loader = "0.15.10" +neoForge = "20.5.0-beta" neoForgeSpi = "8.0.1" mixin = "0.8.5" -parchment = "2023.12.31" -parchmentMc = "1.20.3" -yarn = "1.20.4+build.3" +parchment = "2024.04.14" +parchmentMc = "1.20.4" +yarn = "1.20.5+build.1" # Core dependencies (these versions are tied to the version Minecraft uses) fastutil = "8.5.12" guava = "32.1.2-jre" netty = "4.1.97.Final" -slf4j = "2.0.7" +slf4j = "2.0.9" # Core dependencies (independent of Minecraft) asm = "9.6" autoService = "1.1.1" checkerFramework = "3.42.0" -cobalt = "0.9.3" +cobalt = { strictly = "0.9.3" } commonsCli = "1.6.0" jetbrainsAnnotations = "24.1.0" jsr305 = "3.0.2" @@ -46,6 +46,7 @@ oculus = "1.2.5" rei = "14.0.688" rubidium = "0.6.1" sodium = "mc1.20-0.4.10" +mixinExtra = "0.3.5" # Testing hamcrest = "2.2" @@ -66,7 +67,7 @@ ideaExt = "1.1.7" illuaminate = "0.1.0-71-g378d86e" lwjgl = "3.3.3" minotaur = "2.8.7" -neoGradle = "7.0.100" +neoGradle = "7.0.107" nullAway = "0.10.25" spotless = "6.23.3" taskTree = "2.1.1" @@ -109,6 +110,7 @@ jei-api = { module = "mezz.jei:jei-1.20.4-common-api", version.ref = "jei" } jei-fabric = { module = "mezz.jei:jei-1.20.4-fabric", version.ref = "jei" } jei-forge = { module = "mezz.jei:jei-1.20.4-forge", version.ref = "jei" } mixin = { module = "org.spongepowered:mixin", version.ref = "mixin" } +mixinExtra = { module = "io.github.llamalad7:mixinextras-common", version.ref = "mixinExtra" } modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu" } moreRed = { module = "commoble.morered:morered-1.20.1", version.ref = "moreRed" } oculus = { module = "maven.modrinth:oculus", version.ref = "oculus" } @@ -179,7 +181,7 @@ externalMods-common = ["jei-api", "nightConfig-core", "nightConfig-toml"] externalMods-forge-compile = ["moreRed", "oculus", "jei-api"] externalMods-forge-runtime = [] externalMods-fabric-compile = ["fabricPermissions", "iris", "jei-api", "rei-api", "rei-builtin"] -externalMods-fabric-runtime = ["jei-fabric", "modmenu"] +externalMods-fabric-runtime = [] # ["jei-fabric", "modmenu"] # Testing test = ["junit-jupiter-api", "junit-jupiter-params", "hamcrest", "jqwik-api"] 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 ae1b8a8c0..1e52e7971 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 @@ -9,7 +9,7 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; import net.minecraft.client.resources.model.UnbakedModel; -import net.minecraft.nbt.CompoundTag; +import net.minecraft.core.component.DataComponentPatch; import net.minecraft.resources.ResourceLocation; import javax.annotation.Nullable; @@ -38,7 +38,7 @@ public interface TurtleUpgradeModeller { * @param data Upgrade data instance for current turtle side. * @return The model that you wish to be used to render your upgrade. */ - TransformedModel getModel(T upgrade, @Nullable ITurtleAccess turtle, TurtleSide side, CompoundTag data); + TransformedModel getModel(T upgrade, @Nullable ITurtleAccess turtle, TurtleSide side, DataComponentPatch data); /** * Get a list of models that this turtle modeller depends on. @@ -55,7 +55,7 @@ default Collection getDependencies() { } /** - * A basic {@link TurtleUpgradeModeller} which renders using the upgrade's {@linkplain ITurtleUpgrade#getUpgradeItem(CompoundTag)} + * A basic {@link TurtleUpgradeModeller} which renders using the upgrade's {@linkplain ITurtleUpgrade#getUpgradeItem(DataComponentPatch)} * upgrade item}. *

* This uses appropriate transformations for "flat" items, namely those extending the {@literal minecraft:item/generated} @@ -80,7 +80,7 @@ static TurtleUpgradeModeller flatItem() { static TurtleUpgradeModeller sided(ResourceLocation left, ResourceLocation right) { return new TurtleUpgradeModeller<>() { @Override - public TransformedModel getModel(T upgrade, @Nullable ITurtleAccess turtle, TurtleSide side, CompoundTag data) { + public TransformedModel getModel(T upgrade, @Nullable ITurtleAccess turtle, TurtleSide side, DataComponentPatch data) { return TransformedModel.of(side == TurtleSide.LEFT ? left : right); } 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 5493cae27..644c0a65a 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 @@ -11,7 +11,7 @@ import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.impl.client.ClientPlatformHelper; import net.minecraft.client.Minecraft; -import net.minecraft.nbt.CompoundTag; +import net.minecraft.core.component.DataComponentPatch; import org.joml.Matrix4f; import javax.annotation.Nullable; @@ -36,7 +36,7 @@ private static Transformation getMatrixFor(float offset) { private static final class UpgradeItemModeller implements TurtleUpgradeModeller { @Override - public TransformedModel getModel(ITurtleUpgrade upgrade, @Nullable ITurtleAccess turtle, TurtleSide side, CompoundTag data) { + public TransformedModel getModel(ITurtleUpgrade upgrade, @Nullable ITurtleAccess turtle, TurtleSide side, DataComponentPatch data) { var stack = upgrade.getUpgradeItem(data); 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/ComputerCraftTags.java b/projects/common-api/src/main/java/dan200/computercraft/api/ComputerCraftTags.java index 54f741f75..469e12407 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/ComputerCraftTags.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/ComputerCraftTags.java @@ -6,10 +6,12 @@ import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.ItemTags; import net.minecraft.tags.TagKey; import net.minecraft.world.InteractionHand; 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.level.Level; import net.minecraft.world.level.block.Block; @@ -35,6 +37,14 @@ public static class Items { */ public static final TagKey TURTLE_CAN_PLACE = make("turtle_can_place"); + /** + * Items which can be dyed. + *

+ * This is similar to {@link ItemTags#DYEABLE}, but allows cleaning the item with a sponge, rather than in a + * cauldron. + */ + public static final TagKey DYEABLE = make("dyeable"); + private static TagKey make(String name) { return TagKey.create(Registries.ITEM, new ResourceLocation(ComputerCraftAPI.MOD_ID, name)); } @@ -75,8 +85,8 @@ public static class Blocks { public static final TagKey TURTLE_HOE_BREAKABLE = make("turtle_hoe_harvestable"); /** - * Block which can be {@linkplain BlockState#use(Level, Player, InteractionHand, BlockHitResult) used} when - * calling {@code turtle.place()}. + * Block which can be {@linkplain BlockState#useItemOn(ItemStack, Level, Player, InteractionHand, BlockHitResult) used} + * when calling {@code turtle.place()}. */ public static final TagKey TURTLE_CAN_USE = make("turtle_can_use"); 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 5f5627a1c..013f62a28 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 @@ -5,7 +5,7 @@ package dan200.computercraft.api.pocket; import dan200.computercraft.api.upgrades.UpgradeBase; -import net.minecraft.nbt.CompoundTag; +import net.minecraft.core.component.DataComponentPatch; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.ItemStack; @@ -67,18 +67,19 @@ public interface IPocketAccess { * This is persisted between computer reboots and chunk loads. * * @return The upgrade's NBT. - * @see #updateUpgradeNBTData() - * @see UpgradeBase#getUpgradeItem(CompoundTag) + * @see #setUpgradeData(DataComponentPatch) + * @see UpgradeBase#getUpgradeItem(DataComponentPatch) * @see UpgradeBase#getUpgradeData(ItemStack) */ - CompoundTag getUpgradeNBTData(); + DataComponentPatch getUpgradeData(); /** - * Mark the upgrade-specific NBT as dirty. + * Update the upgrade-specific data. * - * @see #getUpgradeNBTData() + * @param data The new upgrade data. + * @see #getUpgradeData() */ - void updateUpgradeNBTData(); + void setUpgradeData(DataComponentPatch data); /** * Remove the current peripheral and create a new one. 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 9565a6e2d..c726dfc3e 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 @@ -12,7 +12,7 @@ import dan200.computercraft.api.upgrades.UpgradeData; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; +import net.minecraft.core.component.DataComponentPatch; import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; @@ -229,37 +229,22 @@ public interface ITurtleAccess { * @param side The side to get the upgrade from. * @return The upgrade on the specified side of the turtle, if there is one. * @see #getUpgradeWithData(TurtleSide) - * @see #setUpgradeWithData(TurtleSide, UpgradeData) + * @see #setUpgrade(TurtleSide, UpgradeData) */ @Nullable ITurtleUpgrade getUpgrade(TurtleSide side); /** - * Returns the upgrade on the specified side of the turtle, along with its {@linkplain #getUpgradeNBTData(TurtleSide) + * Returns the upgrade on the specified side of the turtle, along with its {@linkplain #getUpgradeData(TurtleSide) * update data}. * * @param side The side to get the upgrade from. * @return The upgrade on the specified side of the turtle, along with its upgrade data, if there is one. * @see #getUpgradeWithData(TurtleSide) - * @see #setUpgradeWithData(TurtleSide, UpgradeData) + * @see #setUpgrade(TurtleSide, UpgradeData) */ - default @Nullable UpgradeData getUpgradeWithData(TurtleSide side) { - var upgrade = getUpgrade(side); - return upgrade == null ? null : UpgradeData.of(upgrade, getUpgradeNBTData(side)); - } - - /** - * Set the upgrade for a given side, resetting peripherals and clearing upgrade specific data. - * - * @param side The side to set the upgrade on. - * @param upgrade The upgrade to set, may be {@code null} to clear. - * @see #getUpgrade(TurtleSide) - * @deprecated Use {@link #setUpgradeWithData(TurtleSide, UpgradeData)} - */ - @Deprecated - default void setUpgrade(TurtleSide side, @Nullable ITurtleUpgrade upgrade) { - setUpgradeWithData(side, upgrade == null ? null : UpgradeData.ofDefault(upgrade)); - } + @Nullable + UpgradeData getUpgradeWithData(TurtleSide side); /** * Set the upgrade for a given side and its upgrade data. @@ -268,7 +253,7 @@ default void setUpgrade(TurtleSide side, @Nullable ITurtleUpgrade upgrade) { * @param upgrade The upgrade to set, may be {@code null} to clear. * @see #getUpgradeWithData(TurtleSide) */ - void setUpgradeWithData(TurtleSide side, @Nullable UpgradeData upgrade); + void setUpgrade(TurtleSide side, @Nullable UpgradeData upgrade); /** * Returns the peripheral created by the upgrade on the specified side of the turtle, if there is one. @@ -282,23 +267,23 @@ default void setUpgrade(TurtleSide side, @Nullable ITurtleUpgrade upgrade) { /** * Get an upgrade-specific NBT compound, which can be used to store arbitrary data. *

- * This will be persisted across turtle restarts and chunk loads, as well as being synced to the client. You must - * call {@link #updateUpgradeNBTData(TurtleSide)} after modifying it. + * This will be persisted across turtle restarts and chunk loads, as well as being synced to the client. You can + * call {@link #setUpgrade(TurtleSide, UpgradeData)} to modify it. * * @param side The side to get the upgrade data for. * @return The upgrade-specific data. - * @see #updateUpgradeNBTData(TurtleSide) - * @see UpgradeBase#getUpgradeItem(CompoundTag) + * @see #setUpgradeData(TurtleSide, DataComponentPatch) + * @see UpgradeBase#getUpgradeItem(DataComponentPatch) * @see UpgradeBase#getUpgradeData(ItemStack) */ - CompoundTag getUpgradeNBTData(TurtleSide side); + DataComponentPatch getUpgradeData(TurtleSide side); /** - * Mark the upgrade-specific data as dirty on a specific side. This is required for the data to be synced to the - * client and persisted. + * Update the upgrade-specific data. * - * @param side The side to mark dirty. - * @see #updateUpgradeNBTData(TurtleSide) + * @param side The side to set the upgrade data for. + * @param data The new upgrade data. + * @see #getUpgradeData(TurtleSide) */ - void updateUpgradeNBTData(TurtleSide side); + void setUpgradeData(TurtleSide side, DataComponentPatch data); } diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java b/projects/common-api/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java index c3f7c471f..9dbf8ab0c 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java @@ -10,7 +10,7 @@ import dan200.computercraft.impl.ComputerCraftAPIService; import net.minecraft.core.Direction; import net.minecraft.core.Registry; -import net.minecraft.nbt.CompoundTag; +import net.minecraft.core.component.DataComponentPatch; import net.minecraft.resources.ResourceKey; import javax.annotation.Nullable; @@ -133,7 +133,7 @@ default void update(ITurtleAccess turtle, TurtleSide side) { * @param upgradeData Data that currently stored for this upgrade * @return Filtered version of this data. */ - default CompoundTag getPersistedData(CompoundTag upgradeData) { + default DataComponentPatch getPersistedData(DataComponentPatch upgradeData) { return upgradeData; } } diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/turtle/TurtleToolDurability.java b/projects/common-api/src/main/java/dan200/computercraft/api/turtle/TurtleToolDurability.java index 85e60b919..543f98731 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/turtle/TurtleToolDurability.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/turtle/TurtleToolDurability.java @@ -4,8 +4,8 @@ package dan200.computercraft.api.turtle; +import net.minecraft.core.component.DataComponents; import net.minecraft.util.StringRepresentable; -import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.item.ItemStack; /** @@ -21,7 +21,7 @@ public enum TurtleToolDurability implements StringRepresentable { /** * The equipped tool consumes durability if it is {@linkplain ItemStack#isEnchanted() enchanted} or has - * {@linkplain ItemStack#getAttributeModifiers(EquipmentSlot) custom attribute modifiers}. + * {@linkplain DataComponents#ATTRIBUTE_MODIFIERS custom attribute modifiers}. */ WHEN_ENCHANTED("when_enchanted"), diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeDataProvider.java b/projects/common-api/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeDataProvider.java index 02019f0ca..2b11a1fde 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeDataProvider.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeDataProvider.java @@ -9,12 +9,12 @@ import dan200.computercraft.api.upgrades.UpgradeDataProvider; import dan200.computercraft.api.upgrades.UpgradeSerialiser; import dan200.computercraft.impl.RegistryHelper; +import net.minecraft.core.component.DataComponents; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.data.DataGenerator; import net.minecraft.data.PackOutput; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; -import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -111,7 +111,7 @@ public ToolBuilder damageMultiplier(float damageMultiplier) { /** * Indicate that this upgrade allows items which have been {@linkplain ItemStack#isEnchanted() enchanted} or have - * {@linkplain ItemStack#getAttributeModifiers(EquipmentSlot) custom attribute modifiers}. + * {@linkplain DataComponents#ATTRIBUTE_MODIFIERS custom attribute modifiers}. * * @return The tool builder, for further use. */ 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 603e1c7ae..2850fea15 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 @@ -10,12 +10,10 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; import net.minecraft.Util; -import net.minecraft.nbt.CompoundTag; +import net.minecraft.core.component.DataComponentPatch; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; -import java.util.Objects; - /** * Common functionality between {@link ITurtleUpgrade} and {@link IPocketUpgrade}. */ @@ -56,8 +54,8 @@ public interface UpgradeBase { /** * Returns the item stack representing a currently equipped turtle upgrade. *

- * While upgrades can store upgrade data ({@link ITurtleAccess#getUpgradeNBTData(TurtleSide)} and - * {@link IPocketAccess#getUpgradeNBTData()}}, by default this data is discarded when an upgrade is unequipped, + * While upgrades can store upgrade data ({@link ITurtleAccess#getUpgradeData(TurtleSide)} and + * {@link IPocketAccess#getUpgradeData()}}, by default this data is discarded when an upgrade is unequipped, * and the original item stack is returned. *

* By overriding this method, you can create a new {@link ItemStack} which contains enough data to @@ -69,24 +67,24 @@ public interface UpgradeBase { * @param upgradeData The current upgrade data. This should NOT be mutated. * @return The item stack returned when unequipping. */ - default ItemStack getUpgradeItem(CompoundTag upgradeData) { + default ItemStack getUpgradeItem(DataComponentPatch upgradeData) { return getCraftingItem(); } /** * Extract upgrade data from an {@link ItemStack}. *

- * This upgrade data will be available with {@link ITurtleAccess#getUpgradeNBTData(TurtleSide)} or - * {@link IPocketAccess#getUpgradeNBTData()}. + * This upgrade data will be available with {@link ITurtleAccess#getUpgradeData(TurtleSide)} or + * {@link IPocketAccess#getUpgradeData()}. *

- * This should be an inverse to {@link #getUpgradeItem(CompoundTag)}. + * This should be an inverse to {@link #getUpgradeItem(DataComponentPatch)}. * * @param stack The stack that was equipped by the turtle or pocket computer. This will have the same item as * {@link #getCraftingItem()}. * @return The upgrade data that should be set on the turtle or pocket computer. */ - default CompoundTag getUpgradeData(ItemStack stack) { - return new CompoundTag(); + default DataComponentPatch getUpgradeData(ItemStack stack) { + return DataComponentPatch.EMPTY; } /** @@ -96,26 +94,15 @@ default CompoundTag getUpgradeData(ItemStack stack) { * the original stack. In order to prevent people losing items with enchantments (or * repairing items with non-0 damage), we impose additional checks on the item. *

- * The default check requires that any non-capability NBT is exactly the same as the - * crafting item, but this may be relaxed for your upgrade. - *

- * This is based on {@code net.neoforged.common.crafting.StrictNBTIngredient}'s check. + * The default check requires that any NBT is exactly the same as the crafting item, + * but this may be relaxed for your upgrade. * * @param stack The stack to check. This is guaranteed to be non-empty and have the same item as * {@link #getCraftingItem()}. * @return If this stack may be used to equip this upgrade. */ default boolean isItemSuitable(ItemStack stack) { - var crafting = getCraftingItem(); - - // A more expanded form of ItemStack.areShareTagsEqual, but allowing an empty tag to be equal to a - // null one. - var tag = stack.getTag(); - var craftingTag = crafting.getTag(); - if (tag == craftingTag) return true; - if (tag == null) return Objects.requireNonNull(craftingTag).isEmpty(); - if (craftingTag == null) return tag.isEmpty(); - return tag.equals(craftingTag); + return ItemStack.isSameItemSameComponents(getCraftingItem(), stack); } /** 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 27dd914f2..e82c4643d 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 @@ -6,23 +6,17 @@ import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.turtle.ITurtleUpgrade; -import net.minecraft.nbt.CompoundTag; +import net.minecraft.core.component.DataComponentPatch; import net.minecraft.world.item.ItemStack; -import org.jetbrains.annotations.Contract; - -import javax.annotation.Nullable; /** * 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}. */ -public record UpgradeData(T upgrade, CompoundTag data) { +public record UpgradeData(T upgrade, DataComponentPatch data) { /** * A utility method to construct a new {@link UpgradeData} instance. * @@ -31,7 +25,7 @@ public record UpgradeData(T upgrade, CompoundTag data) { * @param The type of upgrade. * @return The new {@link UpgradeData} instance. */ - public static UpgradeData of(T upgrade, CompoundTag data) { + public static UpgradeData of(T upgrade, DataComponentPatch data) { return new UpgradeData<>(upgrade, data); } @@ -47,19 +41,7 @@ public static UpgradeData ofDefault(T upgrade) { } /** - * Take a copy of a (possibly {@code null}) {@link UpgradeData} instance. - * - * @param upgrade The copied upgrade data. - * @param The type of upgrade. - * @return The newly created upgrade data. - */ - @Contract("!null -> !null; null -> null") - public static @Nullable UpgradeData copyOf(@Nullable UpgradeData upgrade) { - return upgrade == null ? null : upgrade.copy(); - } - - /** - * Get the {@linkplain UpgradeBase#getUpgradeItem(CompoundTag) upgrade item} for this upgrade. + * Get the {@linkplain UpgradeBase#getUpgradeItem(DataComponentPatch) 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}. @@ -69,14 +51,4 @@ public static UpgradeData ofDefault(T upgrade) { public ItemStack getUpgradeItem() { return upgrade.getUpgradeItem(data).copy(); } - - /** - * Take a copy of this {@link UpgradeData}. This returns a new instance with the same upgrade and a fresh copy of - * the upgrade data. - * - * @return A copy of the current instance. - */ - public UpgradeData copy() { - return new UpgradeData<>(upgrade(), data().copy()); - } } diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeSerialiser.java b/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeSerialiser.java index 65be99127..0b5aef824 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeSerialiser.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeSerialiser.java @@ -12,7 +12,7 @@ import dan200.computercraft.impl.upgrades.SerialiserWithCraftingItem; import dan200.computercraft.impl.upgrades.SimpleSerialiser; import net.minecraft.core.Registry; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.RecipeSerializer; @@ -58,7 +58,7 @@ public interface UpgradeSerialiser { * @param buffer The buffer object to read this upgrade from. * @return The constructed upgrade, with a {@link UpgradeBase#getUpgradeID()} equal to {@code id}. */ - T fromNetwork(ResourceLocation id, FriendlyByteBuf buffer); + T fromNetwork(ResourceLocation id, RegistryFriendlyByteBuf buffer); /** * Write this upgrade to a network packet, to be sent to the client. @@ -66,7 +66,7 @@ public interface UpgradeSerialiser { * @param buffer The buffer object to write this upgrade to * @param upgrade The upgrade to write. */ - void toNetwork(FriendlyByteBuf buffer, T upgrade); + void toNetwork(RegistryFriendlyByteBuf buffer, T upgrade); /** * Create an upgrade serialiser for a simple upgrade. This is similar to a {@link SimpleCraftingRecipeSerializer}, diff --git a/projects/common-api/src/main/java/dan200/computercraft/impl/upgrades/SerialiserWithCraftingItem.java b/projects/common-api/src/main/java/dan200/computercraft/impl/upgrades/SerialiserWithCraftingItem.java index 49dc31729..a78008936 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/impl/upgrades/SerialiserWithCraftingItem.java +++ b/projects/common-api/src/main/java/dan200/computercraft/impl/upgrades/SerialiserWithCraftingItem.java @@ -7,7 +7,7 @@ import com.google.gson.JsonObject; import dan200.computercraft.api.upgrades.UpgradeBase; import dan200.computercraft.api.upgrades.UpgradeSerialiser; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.GsonHelper; import net.minecraft.world.item.ItemStack; @@ -37,13 +37,13 @@ public T fromJson(ResourceLocation id, JsonObject object) { } @Override - public T fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) { - var item = buffer.readItem(); + public T fromNetwork(ResourceLocation id, RegistryFriendlyByteBuf buffer) { + var item = ItemStack.STREAM_CODEC.decode(buffer); return factory.apply(id, item); } @Override - public void toNetwork(FriendlyByteBuf buffer, T upgrade) { - buffer.writeItem(upgrade.getCraftingItem()); + public void toNetwork(RegistryFriendlyByteBuf buffer, T upgrade) { + ItemStack.STREAM_CODEC.encode(buffer, upgrade.getCraftingItem()); } } diff --git a/projects/common-api/src/main/java/dan200/computercraft/impl/upgrades/SimpleSerialiser.java b/projects/common-api/src/main/java/dan200/computercraft/impl/upgrades/SimpleSerialiser.java index ffc6e49fe..fb01bc435 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/impl/upgrades/SimpleSerialiser.java +++ b/projects/common-api/src/main/java/dan200/computercraft/impl/upgrades/SimpleSerialiser.java @@ -7,7 +7,7 @@ import com.google.gson.JsonObject; import dan200.computercraft.api.upgrades.UpgradeBase; import dan200.computercraft.api.upgrades.UpgradeSerialiser; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.ApiStatus; @@ -34,11 +34,11 @@ public T fromJson(ResourceLocation id, JsonObject object) { } @Override - public T fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) { + public T fromNetwork(ResourceLocation id, RegistryFriendlyByteBuf buffer) { return constructor.apply(id); } @Override - public void toNetwork(FriendlyByteBuf buffer, T upgrade) { + public void toNetwork(RegistryFriendlyByteBuf buffer, T upgrade) { } } diff --git a/projects/common/build.gradle.kts b/projects/common/build.gradle.kts index 46120488f..c95818fae 100644 --- a/projects/common/build.gradle.kts +++ b/projects/common/build.gradle.kts @@ -23,7 +23,7 @@ configurations { } repositories { - maven("https://maven.minecraftforge.net/") { + maven("https://maven.neoforged.net/") { content { includeModule("org.spongepowered", "mixin") } @@ -37,6 +37,7 @@ dependencies { clientImplementation(clientClasses(project(":common-api"))) compileOnly(libs.mixin) + compileOnly(libs.mixinExtra) compileOnly(libs.bundles.externalMods.common) clientCompileOnly(variantOf(libs.emi) { classifier("api") }) 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 508e5b3b4..09ba31986 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/ClientRegistry.java +++ b/projects/common/src/client/java/dan200/computercraft/client/ClientRegistry.java @@ -21,13 +21,11 @@ import dan200.computercraft.core.util.Colour; import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.command.CommandComputerCraft; -import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerContext; import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu; import dan200.computercraft.shared.computer.inventory.ViewComputerMenu; import dan200.computercraft.shared.media.items.DiskItem; -import dan200.computercraft.shared.media.items.TreasureDiskItem; import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.color.item.ItemColor; @@ -44,11 +42,13 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.PreparableReloadListener; import net.minecraft.server.packs.resources.ResourceProvider; +import net.minecraft.util.FastColor; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.DyedItemColor; import net.minecraft.world.level.ItemLike; import javax.annotation.Nullable; @@ -94,7 +94,7 @@ public static void registerMainThread(RegisterItemProperty itemProperties) { ModRegistry.Items.POCKET_COMPUTER_NORMAL, ModRegistry.Items.POCKET_COMPUTER_ADVANCED ); registerItemProperty(itemProperties, "coloured", - (stack, world, player, random) -> IColouredItem.getColourBasic(stack) != -1 ? 1 : 0, + (stack, world, player, random) -> DyedItemColor.getOrDefault(stack, -1) != -1 ? 1 : 0, ModRegistry.Items.POCKET_COMPUTER_NORMAL, ModRegistry.Items.POCKET_COMPUTER_ADVANCED ); } @@ -162,12 +162,12 @@ public static void registerExtraModels(Consumer register) { public static void registerItemColours(BiConsumer register) { register.accept( - (stack, layer) -> layer == 1 ? ((DiskItem) stack.getItem()).getColour(stack) : 0xFFFFFF, + (stack, layer) -> layer == 1 ? DiskItem.getColour(stack) : -1, ModRegistry.Items.DISK.get() ); register.accept( - (stack, layer) -> layer == 1 ? TreasureDiskItem.getColour(stack) : 0xFFFFFF, + (stack, layer) -> layer == 1 ? DyedItemColor.getOrDefault(stack, Colour.BLUE.getARGB()) : -1, ModRegistry.Items.TREASURE_DISK.get() ); @@ -180,17 +180,17 @@ public static void registerItemColours(BiConsumer register) private static int getPocketColour(ItemStack stack, int layer) { return switch (layer) { - default -> 0xFFFFFF; - case 1 -> IColouredItem.getColourBasic(stack); // Frame colour + default -> -1; + case 1 -> DyedItemColor.getOrDefault(stack, -1); // Frame colour case 2 -> { // Light colour var computer = ClientPocketComputers.get(stack); - yield computer == null || computer.getLightState() == -1 ? Colour.BLACK.getHex() : computer.getLightState(); + yield computer == null || computer.getLightState() == -1 ? Colour.BLACK.getARGB() : FastColor.ARGB32.opaque(computer.getLightState()); } }; } private static int getTurtleColour(ItemStack stack, int layer) { - return layer == 0 ? ((IColouredItem) stack.getItem()).getColour(stack) : 0xFFFFFF; + return layer == 0 ? DyedItemColor.getOrDefault(stack, -1) : -1; } public static void registerShaders(ResourceProvider resources, BiConsumer> load) throws IOException { diff --git a/projects/common/src/client/java/dan200/computercraft/client/ClientTableFormatter.java b/projects/common/src/client/java/dan200/computercraft/client/ClientTableFormatter.java index fe6263b51..d9f02178e 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/ClientTableFormatter.java +++ b/projects/common/src/client/java/dan200/computercraft/client/ClientTableFormatter.java @@ -75,7 +75,7 @@ public void display(TableBuilder table) { var tag = createTag(table.getId()); if (chat.allMessages.removeIf(guiMessage -> guiMessage.tag() != null && Objects.equals(guiMessage.tag().logTag(), tag.logTag()))) { - chat.refreshTrimmedMessage(); + chat.rescaleChat(); } TableFormatter.super.display(table); diff --git a/projects/common/src/client/java/dan200/computercraft/client/gui/PrintoutScreen.java b/projects/common/src/client/java/dan200/computercraft/client/gui/PrintoutScreen.java index e3c087284..fa1add725 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/gui/PrintoutScreen.java +++ b/projects/common/src/client/java/dan200/computercraft/client/gui/PrintoutScreen.java @@ -6,7 +6,9 @@ import com.mojang.blaze3d.vertex.Tesselator; import dan200.computercraft.core.terminal.TextBuffer; +import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.common.HeldItemMenu; +import dan200.computercraft.shared.media.items.PrintoutData; import dan200.computercraft.shared.media.items.PrintoutItem; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; @@ -35,16 +37,17 @@ public PrintoutScreen(HeldItemMenu container, Inventory player, Component title) imageHeight = Y_SIZE; - var text = PrintoutItem.getText(container.getStack()); - this.text = new TextBuffer[text.length]; - for (var i = 0; i < this.text.length; i++) this.text[i] = new TextBuffer(text[i]); - - var colours = PrintoutItem.getColours(container.getStack()); - this.colours = new TextBuffer[colours.length]; - for (var i = 0; i < this.colours.length; i++) this.colours[i] = new TextBuffer(colours[i]); + var printout = container.getStack().getOrDefault(ModRegistry.DataComponents.PRINTOUT.get(), PrintoutData.EMPTY); + this.text = new TextBuffer[printout.lines().size()]; + this.colours = new TextBuffer[printout.lines().size()]; + for (var i = 0; i < this.text.length; i++) { + var line = printout.lines().get(i); + this.text[i] = new TextBuffer(line.text()); + this.colours[i] = new TextBuffer(line.foreground()); + } page = 0; - pages = Math.max(this.text.length / PrintoutItem.LINES_PER_PAGE, 1); + pages = Math.max(this.text.length / PrintoutData.LINES_PER_PAGE, 1); book = ((PrintoutItem) container.getStack().getItem()).getType() == PrintoutItem.Type.BOOK; } @@ -89,7 +92,7 @@ protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, in var renderer = MultiBufferSource.immediate(Tesselator.getInstance().getBuilder()); drawBorder(graphics.pose(), renderer, leftPos, topPos, 0, page, pages, book, FULL_BRIGHT_LIGHTMAP); - drawText(graphics.pose(), renderer, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, PrintoutItem.LINES_PER_PAGE * page, FULL_BRIGHT_LIGHTMAP, text, colours); + drawText(graphics.pose(), renderer, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, PrintoutData.LINES_PER_PAGE * page, FULL_BRIGHT_LIGHTMAP, text, colours); renderer.endBatch(); graphics.pose().popPose(); diff --git a/projects/common/src/client/java/dan200/computercraft/client/integration/emi/EMIComputerCraft.java b/projects/common/src/client/java/dan200/computercraft/client/integration/emi/EMIComputerCraft.java index 2a64f68ad..f6e19ebef 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/integration/emi/EMIComputerCraft.java +++ b/projects/common/src/client/java/dan200/computercraft/client/integration/emi/EMIComputerCraft.java @@ -27,13 +27,11 @@ public void register(EmiRegistry registry) { registry.setDefaultComparison(ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get(), pocketComparison); } - private static final Comparison turtleComparison = compareStacks((left, right) -> - left.getItem() instanceof TurtleItem turtle - && turtle.getUpgrade(left, TurtleSide.LEFT) == turtle.getUpgrade(right, TurtleSide.LEFT) - && turtle.getUpgrade(left, TurtleSide.RIGHT) == turtle.getUpgrade(right, TurtleSide.RIGHT)); + private static final Comparison turtleComparison = compareStacks((left, right) + -> TurtleItem.getUpgrade(left, TurtleSide.LEFT) == TurtleItem.getUpgrade(right, TurtleSide.LEFT) + && TurtleItem.getUpgrade(left, TurtleSide.RIGHT) == TurtleItem.getUpgrade(right, TurtleSide.RIGHT)); - private static final Comparison pocketComparison = compareStacks((left, right) -> - left.getItem() instanceof PocketComputerItem && PocketComputerItem.getUpgrade(left) == PocketComputerItem.getUpgrade(right)); + private static final Comparison pocketComparison = compareStacks((left, right) -> PocketComputerItem.getUpgrade(left) == PocketComputerItem.getUpgrade(right)); private static Comparison compareStacks(BiPredicate test) { return Comparison.of((left, right) -> { 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 fec6d4d7d..f8da518c8 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 @@ -15,9 +15,11 @@ import dan200.computercraft.client.render.TurtleBlockEntityRenderer; import dan200.computercraft.client.turtle.TurtleUpgradeModellers; import dan200.computercraft.shared.turtle.items.TurtleItem; +import dan200.computercraft.shared.util.DataComponentUtil; import dan200.computercraft.shared.util.Holiday; import net.minecraft.client.Minecraft; import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.component.DataComponents; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; @@ -54,13 +56,6 @@ private record Combination( boolean christmas, boolean flip ) { - Combination copy() { - if (leftUpgrade == null && rightUpgrade == null) return this; - return new Combination( - colour, UpgradeData.copyOf(leftUpgrade), UpgradeData.copyOf(rightUpgrade), - overlay, christmas, flip - ); - } } private final BakedModel familyModel; @@ -96,31 +91,18 @@ public TurtleModelParts(BakedModel familyModel, BakedModel colourModel, ModelTra public T getModel(ItemStack stack) { var combination = getCombination(stack); - var existing = modelCache.get(combination); - if (existing != null) return existing; - - // Take a defensive copy of the upgrade data, and add it to the cache. - var newCombination = combination.copy(); - var newModel = buildModel.apply(newCombination); - modelCache.put(newCombination, newModel); - return newModel; + return modelCache.computeIfAbsent(combination, buildModel); } private Combination getCombination(ItemStack stack) { var christmas = Holiday.getCurrent() == Holiday.CHRISTMAS; - - if (!(stack.getItem() instanceof TurtleItem turtle)) { - return new Combination(false, null, null, null, christmas, false); - } - - var colour = turtle.getColour(stack); - var leftUpgrade = turtle.getUpgradeWithData(stack, TurtleSide.LEFT); - var rightUpgrade = turtle.getUpgradeWithData(stack, TurtleSide.RIGHT); - var overlay = turtle.getOverlay(stack); - var label = turtle.getLabel(stack); + var leftUpgrade = TurtleItem.getUpgradeWithData(stack, TurtleSide.LEFT); + var rightUpgrade = TurtleItem.getUpgradeWithData(stack, TurtleSide.RIGHT); + var overlay = TurtleItem.getOverlay(stack); + var label = DataComponentUtil.getCustomName(stack); var flip = label != null && (label.equals("Dinnerbone") || label.equals("Grumm")); - return new Combination(colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip); + return new Combination(stack.has(DataComponents.DYED_COLOR), leftUpgrade, rightUpgrade, overlay, christmas, flip); } private List buildModel(Combination combo) { diff --git a/projects/common/src/client/java/dan200/computercraft/client/network/ClientNetworking.java b/projects/common/src/client/java/dan200/computercraft/client/network/ClientNetworking.java index 8f9b6de9d..6525db269 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/network/ClientNetworking.java +++ b/projects/common/src/client/java/dan200/computercraft/client/network/ClientNetworking.java @@ -4,10 +4,10 @@ package dan200.computercraft.client.network; -import dan200.computercraft.client.platform.ClientPlatformHelper; import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.server.ServerNetworkContext; import net.minecraft.client.Minecraft; +import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket; /** * Methods for sending packets from clients to the server. @@ -23,6 +23,6 @@ private ClientNetworking() { */ public static void sendToServer(NetworkMessage message) { var connection = Minecraft.getInstance().getConnection(); - if (connection != null) connection.send(ClientPlatformHelper.get().createPacket(message)); + if (connection != null) connection.send(new ServerboundCustomPayloadPacket(message)); } } diff --git a/projects/common/src/client/java/dan200/computercraft/client/platform/ClientPlatformHelper.java b/projects/common/src/client/java/dan200/computercraft/client/platform/ClientPlatformHelper.java index 3a489fee2..63d956756 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/platform/ClientPlatformHelper.java +++ b/projects/common/src/client/java/dan200/computercraft/client/platform/ClientPlatformHelper.java @@ -5,13 +5,9 @@ package dan200.computercraft.client.platform; import com.mojang.blaze3d.vertex.PoseStack; -import dan200.computercraft.shared.network.NetworkMessage; -import dan200.computercraft.shared.network.server.ServerNetworkContext; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.core.BlockPos; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.common.ServerCommonPacketListener; import net.minecraft.sounds.SoundEvent; import javax.annotation.Nullable; @@ -21,14 +17,6 @@ static ClientPlatformHelper get() { return (ClientPlatformHelper) dan200.computercraft.impl.client.ClientPlatformHelper.get(); } - /** - * Convert a serverbound {@link NetworkMessage} to a Minecraft {@link Packet}. - * - * @param message The messsge to convert. - * @return The converted message. - */ - Packet createPacket(NetworkMessage message); - /** * Render a {@link BakedModel}, using any loader-specific hooks. * diff --git a/projects/common/src/client/java/dan200/computercraft/client/pocket/ClientPocketComputers.java b/projects/common/src/client/java/dan200/computercraft/client/pocket/ClientPocketComputers.java index 2d4eef3c7..c8cde6d79 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/pocket/ClientPocketComputers.java +++ b/projects/common/src/client/java/dan200/computercraft/client/pocket/ClientPocketComputers.java @@ -4,11 +4,11 @@ package dan200.computercraft.client.pocket; +import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.terminal.TerminalState; import dan200.computercraft.shared.network.client.PocketComputerDataMessage; -import dan200.computercraft.shared.pocket.items.PocketComputerItem; import net.minecraft.world.item.ItemStack; import javax.annotation.Nullable; @@ -53,7 +53,7 @@ public static void setState(UUID instanceId, ComputerState state, int lightColou } public static @Nullable PocketComputerData get(ItemStack stack) { - var id = PocketComputerItem.getInstanceID(stack); - return id == null ? null : instances.get(id); + var id = stack.get(ModRegistry.DataComponents.COMPUTER.get()); + return id == null ? null : instances.get(id.instance()); } } diff --git a/projects/common/src/client/java/dan200/computercraft/client/render/CableHighlightRenderer.java b/projects/common/src/client/java/dan200/computercraft/client/render/CableHighlightRenderer.java index 6e8166df2..e0a629403 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/render/CableHighlightRenderer.java +++ b/projects/common/src/client/java/dan200/computercraft/client/render/CableHighlightRenderer.java @@ -51,7 +51,6 @@ public static boolean drawHighlight(PoseStack transform, MultiBufferSource buffe var buffer = bufferSource.getBuffer(RenderType.lines()); var matrix4f = transform.last().pose(); - var normal = transform.last().normal(); // TODO: Can we just accesstransformer out LevelRenderer.renderShape? shape.forAllEdges((x1, y1, z1, x2, y2, z2) -> { var xDelta = (float) (x2 - x1); @@ -65,12 +64,12 @@ public static boolean drawHighlight(PoseStack transform, MultiBufferSource buffe buffer .vertex(matrix4f, (float) (x1 + xOffset), (float) (y1 + yOffset), (float) (z1 + zOffset)) .color(0, 0, 0, 0.4f) - .normal(normal, xDelta, yDelta, zDelta) + .normal(transform.last(), xDelta, yDelta, zDelta) .endVertex(); buffer .vertex(matrix4f, (float) (x2 + xOffset), (float) (y2 + yOffset), (float) (z2 + zOffset)) .color(0, 0, 0, 0.4f) - .normal(normal, xDelta, yDelta, zDelta) + .normal(transform.last(), xDelta, yDelta, zDelta) .endVertex(); }); diff --git a/projects/common/src/client/java/dan200/computercraft/client/render/PocketItemRenderer.java b/projects/common/src/client/java/dan200/computercraft/client/render/PocketItemRenderer.java index 676f13556..9a22513c7 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/render/PocketItemRenderer.java +++ b/projects/common/src/client/java/dan200/computercraft/client/render/PocketItemRenderer.java @@ -15,6 +15,7 @@ import dan200.computercraft.shared.pocket.items.PocketComputerItem; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.DyedItemColor; import org.joml.Matrix4f; import static dan200.computercraft.client.render.ComputerBorderRenderer.*; @@ -61,7 +62,7 @@ protected void renderItem(PoseStack transform, MultiBufferSource bufferSource, I // Render the main frame var item = (PocketComputerItem) stack.getItem(); var family = item.getFamily(); - var frameColour = item.getColour(stack); + var frameColour = DyedItemColor.getOrDefault(stack, -1); var matrix = transform.last().pose(); renderFrame(matrix, bufferSource, family, frameColour, light, width, height); diff --git a/projects/common/src/client/java/dan200/computercraft/client/render/PrintoutItemRenderer.java b/projects/common/src/client/java/dan200/computercraft/client/render/PrintoutItemRenderer.java index d0aa02470..1a4fa829b 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/render/PrintoutItemRenderer.java +++ b/projects/common/src/client/java/dan200/computercraft/client/render/PrintoutItemRenderer.java @@ -6,6 +6,8 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; +import dan200.computercraft.shared.ModRegistry; +import dan200.computercraft.shared.media.items.PrintoutData; import dan200.computercraft.shared.media.items.PrintoutItem; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.world.entity.EntityType; @@ -15,8 +17,8 @@ import static dan200.computercraft.client.render.PrintoutRenderer.*; import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT; import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH; -import static dan200.computercraft.shared.media.items.PrintoutItem.LINES_PER_PAGE; -import static dan200.computercraft.shared.media.items.PrintoutItem.LINE_MAX_LENGTH; +import static dan200.computercraft.shared.media.items.PrintoutData.LINES_PER_PAGE; +import static dan200.computercraft.shared.media.items.PrintoutData.LINE_LENGTH; /** * Emulates map and item-frame rendering for printouts. @@ -37,8 +39,6 @@ protected void renderItem(PoseStack transform, MultiBufferSource render, ItemSta } public static void onRenderInFrame(PoseStack transform, MultiBufferSource render, ItemFrame frame, ItemStack stack, int packedLight) { - if (!(stack.getItem() instanceof PrintoutItem)) return; - // Move a little bit forward to ensure we're not clipping with the frame transform.translate(0.0f, 0.0f, -0.001f); transform.mulPose(Axis.ZP.rotationDegrees(180f)); @@ -50,10 +50,12 @@ public static void onRenderInFrame(PoseStack transform, MultiBufferSource render } private static void drawPrintout(PoseStack transform, MultiBufferSource render, ItemStack stack, int light) { - var pages = PrintoutItem.getPageCount(stack); + var pageData = stack.getOrDefault(ModRegistry.DataComponents.PRINTOUT.get(), PrintoutData.EMPTY); + + var pages = pageData.pages(); var book = ((PrintoutItem) stack.getItem()).getType() == PrintoutItem.Type.BOOK; - double width = LINE_MAX_LENGTH * FONT_WIDTH + X_TEXT_MARGIN * 2; + double width = LINE_LENGTH * FONT_WIDTH + X_TEXT_MARGIN * 2; double height = LINES_PER_PAGE * FONT_HEIGHT + Y_TEXT_MARGIN * 2; // Non-books will be left aligned @@ -75,9 +77,6 @@ private static void drawPrintout(PoseStack transform, MultiBufferSource render, transform.translate((max - width) / 2.0, (max - height) / 2.0, 0.0); drawBorder(transform, render, 0, 0, -0.01f, 0, pages, book, light); - drawText( - transform, render, X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, light, - PrintoutItem.getText(stack), PrintoutItem.getColours(stack) - ); + drawText(transform, render, X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, light, pageData.lines()); } } diff --git a/projects/common/src/client/java/dan200/computercraft/client/render/PrintoutRenderer.java b/projects/common/src/client/java/dan200/computercraft/client/render/PrintoutRenderer.java index e4aa3a1b9..f8eec2b96 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/render/PrintoutRenderer.java +++ b/projects/common/src/client/java/dan200/computercraft/client/render/PrintoutRenderer.java @@ -9,11 +9,14 @@ import dan200.computercraft.client.render.text.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Palette; import dan200.computercraft.core.terminal.TextBuffer; +import dan200.computercraft.shared.media.items.PrintoutData; import net.minecraft.client.renderer.MultiBufferSource; import org.joml.Matrix4f; +import java.util.List; + import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT; -import static dan200.computercraft.shared.media.items.PrintoutItem.LINES_PER_PAGE; +import static dan200.computercraft.shared.media.items.PrintoutData.LINES_PER_PAGE; /** * Renders printed pages or books, either for a GUI ({@link dan200.computercraft.client.gui.PrintoutScreen}) or @@ -69,13 +72,14 @@ public static void drawText(PoseStack transform, MultiBufferSource bufferSource, } } - public static void drawText(PoseStack transform, MultiBufferSource bufferSource, int x, int y, int start, int light, String[] text, String[] colours) { + public static void drawText(PoseStack transform, MultiBufferSource bufferSource, int x, int y, int start, int light, List lines) { var buffer = bufferSource.getBuffer(RenderTypes.PRINTOUT_TEXT); var emitter = FixedWidthFontRenderer.toVertexConsumer(transform, buffer); - for (var line = 0; line < LINES_PER_PAGE && line < text.length; line++) { + for (var line = 0; line < LINES_PER_PAGE && line < lines.size(); line++) { + var lineContents = lines.get(start + line); FixedWidthFontRenderer.drawString(emitter, x, y + line * FONT_HEIGHT, - new TextBuffer(text[start + line]), new TextBuffer(colours[start + line]), + new TextBuffer(lineContents.text()), new TextBuffer(lineContents.foreground()), Palette.DEFAULT, light ); } diff --git a/projects/common/src/client/java/dan200/computercraft/client/render/monitor/MonitorBlockEntityRenderer.java b/projects/common/src/client/java/dan200/computercraft/client/render/monitor/MonitorBlockEntityRenderer.java index 055f6d68b..0813318c3 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/render/monitor/MonitorBlockEntityRenderer.java +++ b/projects/common/src/client/java/dan200/computercraft/client/render/monitor/MonitorBlockEntityRenderer.java @@ -191,17 +191,23 @@ private static void renderTerminal( }); } - // Our VBO doesn't transform its vertices with the provided pose stack, which means that the inverse view - // rotation matrix gives entirely wrong numbers for fog distances. We just set it to the identity which - // gives a good enough approximation. - var oldInverseRotation = RenderSystem.getInverseViewRotationMatrix(); - RenderSystem.setInverseViewRotationMatrix(IDENTITY_NORMAL); + // Our VBO renders coordinates in monitor-space rather than world space. A full sized monitor (8x6) will + // use positions from (0, 0) to (164*FONT_WIDTH, 81*FONT_HEIGHT) = (984, 729). This is far outside the + // normal render distance (~200), and the edges of the monitor fade out due to fog. + // There's not really a good way around this, at least without using a custom render type (which the VBO + // renderer is trying to avoid!). Instead, we just disable fog entirely by setting the fog start to an + // absurdly high value. + var oldFogStart = RenderSystem.getShaderFogStart(); + RenderSystem.setShaderFogStart(1e4f); RenderTypes.TERMINAL.setupRenderState(); + // Compose the existing model view matrix with our transformation matrix. + var modelView = new Matrix4f(RenderSystem.getModelViewMatrix()).mul(matrix); + // Render background geometry backgroundBuffer.bind(); - backgroundBuffer.drawWithShader(matrix, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader()); + backgroundBuffer.drawWithShader(modelView, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader()); // Render foreground geometry with glPolygonOffset enabled. RenderSystem.polygonOffset(-1.0f, -10.0f); @@ -209,7 +215,7 @@ private static void renderTerminal( foregroundBuffer.bind(); foregroundBuffer.drawWithShader( - matrix, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader(), + modelView, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader(), // As mentioned in the above comment, render the extra cursor quad if it is visible this frame. Each // // quad has an index count of 6. FixedWidthFontRenderer.isCursorVisible(terminal) && FrameInfo.getGlobalCursorBlink() @@ -222,7 +228,7 @@ private static void renderTerminal( RenderTypes.TERMINAL.clearRenderState(); VertexBuffer.unbind(); - RenderSystem.setInverseViewRotationMatrix(oldInverseRotation); + RenderSystem.setShaderFogStart(oldFogStart); } case BEST -> throw new IllegalStateException("Impossible: Should never use BEST renderer"); } diff --git a/projects/common/src/client/java/dan200/computercraft/client/render/monitor/MonitorHighlightRenderer.java b/projects/common/src/client/java/dan200/computercraft/client/render/monitor/MonitorHighlightRenderer.java index c93224332..a9d303797 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/render/monitor/MonitorHighlightRenderer.java +++ b/projects/common/src/client/java/dan200/computercraft/client/render/monitor/MonitorHighlightRenderer.java @@ -12,7 +12,6 @@ import net.minecraft.client.renderer.RenderType; import net.minecraft.core.Direction; import net.minecraft.world.phys.BlockHitResult; -import org.joml.Matrix3f; import org.joml.Matrix4f; import java.util.EnumSet; @@ -53,7 +52,7 @@ public static boolean drawHighlight(PoseStack transformStack, MultiBufferSource // I wish I could think of a better way to do this var buffer = bufferSource.getBuffer(RenderType.lines()); var transform = transformStack.last().pose(); - var normal = transformStack.last().normal(); + var normal = transformStack.last(); if (faces.contains(NORTH) || faces.contains(WEST)) line(buffer, transform, normal, 0, 0, 0, UP); if (faces.contains(SOUTH) || faces.contains(WEST)) line(buffer, transform, normal, 0, 0, 1, UP); if (faces.contains(NORTH) || faces.contains(EAST)) line(buffer, transform, normal, 1, 0, 0, UP); @@ -71,7 +70,7 @@ public static boolean drawHighlight(PoseStack transformStack, MultiBufferSource return true; } - private static void line(VertexConsumer buffer, Matrix4f transform, Matrix3f normal, float x, float y, float z, Direction direction) { + private static void line(VertexConsumer buffer, Matrix4f transform, PoseStack.Pose normal, float x, float y, float z, Direction direction) { buffer .vertex(transform, x, y, z) .color(0, 0, 0, 0.4f) 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 5e04d6cc2..bc5302685 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 @@ -9,8 +9,9 @@ import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; +import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.turtle.upgrades.TurtleModem; -import net.minecraft.nbt.CompoundTag; +import net.minecraft.core.component.DataComponentPatch; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.Nullable; @@ -41,12 +42,9 @@ public TurtleModemModeller(boolean advanced) { } @Override - public TransformedModel getModel(TurtleModem upgrade, @Nullable ITurtleAccess turtle, TurtleSide side, CompoundTag data) { - var active = false; - if (turtle != null) { - var turtleNBT = turtle.getUpgradeNBTData(side); - active = turtleNBT.contains("active") && turtleNBT.getBoolean("active"); - } + public TransformedModel getModel(TurtleModem upgrade, @Nullable ITurtleAccess turtle, TurtleSide side, DataComponentPatch data) { + var component = data.get(ModRegistry.DataComponents.ON.get()); + var active = component != null && component.isPresent() && component.get(); return side == TurtleSide.LEFT ? TransformedModel.of(active ? leftOnModel : leftOffModel) 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 b27b32277..988d5134d 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 @@ -15,7 +15,7 @@ import dan200.computercraft.impl.TurtleUpgrades; import dan200.computercraft.impl.UpgradeManager; import net.minecraft.client.Minecraft; -import net.minecraft.nbt.CompoundTag; +import net.minecraft.core.component.DataComponentPatch; import net.minecraft.resources.ResourceLocation; import java.util.Map; @@ -60,10 +60,10 @@ public static void register(UpgradeSerialiser seri public static TransformedModel getModel(ITurtleUpgrade upgrade, ITurtleAccess access, TurtleSide side) { @SuppressWarnings("unchecked") var modeller = (TurtleUpgradeModeller) modelCache.computeIfAbsent(upgrade, TurtleUpgradeModellers::getModeller); - return modeller.getModel(upgrade, access, side, access.getUpgradeNBTData(side)); + return modeller.getModel(upgrade, access, side, access.getUpgradeData(side)); } - public static TransformedModel getModel(ITurtleUpgrade upgrade, CompoundTag data, TurtleSide side) { + public static TransformedModel getModel(ITurtleUpgrade upgrade, DataComponentPatch data, TurtleSide side) { @SuppressWarnings("unchecked") var modeller = (TurtleUpgradeModeller) modelCache.computeIfAbsent(upgrade, TurtleUpgradeModellers::getModeller); return modeller.getModel(upgrade, null, side, data); diff --git a/projects/common/src/main/java/dan200/computercraft/data/DataProviders.java b/projects/common/src/main/java/dan200/computercraft/data/DataProviders.java index c5f8aa661..56158bfe6 100644 --- a/projects/common/src/main/java/dan200/computercraft/data/DataProviders.java +++ b/projects/common/src/main/java/dan200/computercraft/data/DataProviders.java @@ -5,6 +5,7 @@ package dan200.computercraft.data; import com.mojang.serialization.Codec; +import net.minecraft.core.HolderLookup; import net.minecraft.data.DataProvider; import net.minecraft.data.PackOutput; import net.minecraft.data.loot.LootTableProvider.SubProviderEntry; @@ -17,7 +18,9 @@ import net.minecraft.world.level.block.Block; import java.util.List; +import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; +import java.util.function.BiFunction; import java.util.function.Consumer; /** @@ -31,7 +34,7 @@ private DataProviders() { public static void add(GeneratorSink generator) { var turtleUpgrades = generator.add(TurtleUpgradeProvider::new); var pocketUpgrades = generator.add(PocketUpgradeProvider::new); - generator.add(out -> new RecipeProvider(out, turtleUpgrades, pocketUpgrades)); + generator.add((out, registries) -> new RecipeProvider(out, registries, turtleUpgrades, pocketUpgrades)); var blockTags = generator.blockTags(TagProvider::blockTags); generator.itemTags(TagProvider::itemTags, blockTags); @@ -55,6 +58,8 @@ public static void add(GeneratorSink generator) { public interface GeneratorSink { T add(DataProvider.Factory factory); + T add(BiFunction, T> factory); + void addFromCodec(String name, PackType type, String directory, Codec codec, Consumer> output); void lootTable(List tables); diff --git a/projects/common/src/main/java/dan200/computercraft/data/LootTableProvider.java b/projects/common/src/main/java/dan200/computercraft/data/LootTableProvider.java index 33c9d239b..90fc2733b 100644 --- a/projects/common/src/main/java/dan200/computercraft/data/LootTableProvider.java +++ b/projects/common/src/main/java/dan200/computercraft/data/LootTableProvider.java @@ -4,7 +4,6 @@ package dan200.computercraft.data; -import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.shared.CommonHooks; import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.data.BlockNamedEntityLootCondition; @@ -13,14 +12,15 @@ import dan200.computercraft.shared.peripheral.modem.wired.CableBlock; import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant; import net.minecraft.advancements.critereon.StatePropertiesPredicate; +import net.minecraft.core.HolderLookup; import net.minecraft.data.loot.LootTableProvider.SubProviderEntry; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.ResourceKey; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.storage.loot.LootPool; import net.minecraft.world.level.storage.loot.LootTable; -import net.minecraft.world.level.storage.loot.entries.DynamicLoot; import net.minecraft.world.level.storage.loot.entries.LootItem; import net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainer; +import net.minecraft.world.level.storage.loot.functions.CopyComponentsFunction; import net.minecraft.world.level.storage.loot.functions.CopyNameFunction; import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; import net.minecraft.world.level.storage.loot.predicates.AnyOfCondition; @@ -41,7 +41,7 @@ public static List getTables() { ); } - private static void registerBlocks(BiConsumer add) { + private static void registerBlocks(HolderLookup.Provider registries, BiConsumer, LootTable.Builder> add) { namedBlockDrop(add, ModRegistry.Blocks.DISK_DRIVE); selfDrop(add, ModRegistry.Blocks.MONITOR_NORMAL); selfDrop(add, ModRegistry.Blocks.MONITOR_ADVANCED); @@ -78,15 +78,15 @@ private static void registerBlocks(BiConsumer add) { + private static void registerGeneric(HolderLookup.Provider registries, BiConsumer, LootTable.Builder> add) { add.accept(CommonHooks.TREASURE_DISK_LOOT, LootTable.lootTable()); } - private static void selfDrop(BiConsumer add, Supplier wrapper) { + private static void selfDrop(BiConsumer, LootTable.Builder> add, Supplier wrapper) { blockDrop(add, wrapper, LootItem.lootTableItem(wrapper.get()), ExplosionCondition.survivesExplosion()); } - private static void namedBlockDrop(BiConsumer add, Supplier wrapper) { + private static void namedBlockDrop(BiConsumer, LootTable.Builder> add, Supplier wrapper) { blockDrop( add, wrapper, LootItem.lootTableItem(wrapper.get()).apply(CopyNameFunction.copyName(CopyNameFunction.NameSource.BLOCK_ENTITY)), @@ -94,10 +94,10 @@ private static void namedBlockDrop(BiConsumer add, Supplier block) { + private static void computerDrop(BiConsumer, LootTable.Builder> add, Supplier block) { blockDrop( add, block, - DynamicLoot.dynamicEntry(new ResourceLocation(ComputerCraftAPI.MOD_ID, "computer")), + LootItem.lootTableItem(block.get()).apply(CopyComponentsFunction.copyComponents(CopyComponentsFunction.Source.BLOCK_ENTITY)), AnyOfCondition.anyOf( BlockNamedEntityLootCondition.BUILDER, HasComputerIdLootCondition.BUILDER, @@ -107,7 +107,7 @@ private static void computerDrop(BiConsumer } private static void blockDrop( - BiConsumer add, Supplier wrapper, + BiConsumer, LootTable.Builder> add, Supplier wrapper, LootPoolEntryContainer.Builder drop, LootItemCondition.Builder condition ) { diff --git a/projects/common/src/main/java/dan200/computercraft/data/RecipeProvider.java b/projects/common/src/main/java/dan200/computercraft/data/RecipeProvider.java index 5c4d09612..b67ecb1b5 100644 --- a/projects/common/src/main/java/dan200/computercraft/data/RecipeProvider.java +++ b/projects/common/src/main/java/dan200/computercraft/data/RecipeProvider.java @@ -5,7 +5,6 @@ package dan200.computercraft.data; import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; import com.mojang.serialization.JsonOps; import dan200.computercraft.api.ComputerCraftAPI; @@ -19,26 +18,25 @@ import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.common.ClearColourRecipe; import dan200.computercraft.shared.common.ColourableRecipe; -import dan200.computercraft.shared.computer.recipe.ComputerUpgradeRecipe; -import dan200.computercraft.shared.media.items.DiskItem; +import dan200.computercraft.shared.computer.recipe.ComputerConvertRecipe; import dan200.computercraft.shared.media.recipes.DiskRecipe; import dan200.computercraft.shared.media.recipes.PrintoutRecipe; import dan200.computercraft.shared.platform.PlatformHelper; import dan200.computercraft.shared.platform.RecipeIngredients; import dan200.computercraft.shared.pocket.items.PocketComputerItem; import dan200.computercraft.shared.pocket.recipes.PocketComputerUpgradeRecipe; -import dan200.computercraft.shared.recipe.CustomShapelessRecipe; import dan200.computercraft.shared.recipe.ImpostorShapedRecipe; import dan200.computercraft.shared.recipe.ImpostorShapelessRecipe; import dan200.computercraft.shared.turtle.items.TurtleItem; import dan200.computercraft.shared.turtle.recipes.TurtleOverlayRecipe; -import dan200.computercraft.shared.turtle.recipes.TurtleRecipe; import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe; import dan200.computercraft.shared.util.ColourUtils; -import net.minecraft.Util; +import dan200.computercraft.shared.util.DataComponentUtil; import net.minecraft.advancements.Criterion; import net.minecraft.advancements.critereon.InventoryChangeTrigger; import net.minecraft.advancements.critereon.ItemPredicate; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.component.DataComponents; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.data.PackOutput; @@ -46,12 +44,13 @@ import net.minecraft.data.recipes.RecipeOutput; import net.minecraft.data.recipes.ShapedRecipeBuilder; import net.minecraft.data.recipes.ShapelessRecipeBuilder; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtUtils; import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.ItemTags; import net.minecraft.tags.TagKey; import net.minecraft.util.GsonHelper; import net.minecraft.world.item.*; +import net.minecraft.world.item.component.DyedItemColor; +import net.minecraft.world.item.component.ResolvableProfile; import net.minecraft.world.item.crafting.CraftingBookCategory; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.Recipe; @@ -60,6 +59,7 @@ import java.util.List; import java.util.UUID; +import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; import static dan200.computercraft.api.ComputerCraftTags.Items.COMPUTER; @@ -70,8 +70,8 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider { private final TurtleUpgradeDataProvider turtleUpgrades; private final PocketUpgradeDataProvider pocketUpgrades; - RecipeProvider(PackOutput output, TurtleUpgradeDataProvider turtleUpgrades, PocketUpgradeDataProvider pocketUpgrades) { - super(output); + RecipeProvider(PackOutput output, CompletableFuture registries, TurtleUpgradeDataProvider turtleUpgrades, PocketUpgradeDataProvider pocketUpgrades) { + super(output, registries); this.turtleUpgrades = turtleUpgrades; this.pocketUpgrades = pocketUpgrades; } @@ -100,7 +100,7 @@ public void buildRecipes(RecipeOutput add) { private void diskColours(RecipeOutput output) { for (var colour : Colour.VALUES) { ShapelessSpecBuilder - .shapeless(RecipeCategory.REDSTONE, DiskItem.createFromIDAndColour(-1, null, colour.getHex())) + .shapeless(RecipeCategory.REDSTONE, DataComponentUtil.createStack(ModRegistry.Items.DISK.get(), DataComponents.DYED_COLOR, new DyedItemColor(colour.getHex(), false))) .requires(ingredients.redstone()) .requires(Items.PAPER) .requires(DyeItem.byColor(ofColour(colour))) @@ -122,17 +122,16 @@ private static List turtleItems() { */ private void turtleUpgrades(RecipeOutput add) { for (var turtleItem : turtleItems()) { - var base = turtleItem.create(-1, null, -1, null, null, 0, null); var name = RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, turtleItem); for (var upgrade : turtleUpgrades.getGeneratedUpgrades()) { ShapedSpecBuilder - .shaped(RecipeCategory.REDSTONE, turtleItem.create(-1, null, -1, null, UpgradeData.ofDefault(upgrade), -1, null)) + .shaped(RecipeCategory.REDSTONE, DataComponentUtil.createStack(turtleItem, ModRegistry.DataComponents.RIGHT_TURTLE_UPGRADE.get(), UpgradeData.ofDefault(upgrade))) .group(name.toString()) .pattern("#T") - .define('T', base.getItem()) + .define('T', turtleItem) .define('#', upgrade.getCraftingItem().getItem()) - .unlockedBy("has_items", inventoryChange(base.getItem(), upgrade.getCraftingItem().getItem())) + .unlockedBy("has_items", inventoryChange(turtleItem, upgrade.getCraftingItem().getItem())) .build(ImpostorShapedRecipe::new) .save( add, @@ -153,18 +152,17 @@ private static List pocketComputerItems() { */ private void pocketUpgrades(RecipeOutput add) { for (var pocket : pocketComputerItems()) { - var base = pocket.create(-1, null, -1, null); var name = RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, pocket).withPath(x -> x.replace("pocket_computer_", "pocket_")); for (var upgrade : pocketUpgrades.getGeneratedUpgrades()) { ShapedSpecBuilder - .shaped(RecipeCategory.REDSTONE, pocket.create(-1, null, -1, UpgradeData.ofDefault(upgrade))) + .shaped(RecipeCategory.REDSTONE, DataComponentUtil.createStack(pocket, ModRegistry.DataComponents.POCKET_UPGRADE.get(), UpgradeData.ofDefault(upgrade))) .group(name.toString()) .pattern("#") .pattern("P") - .define('P', base.getItem()) + .define('P', pocket) .define('#', upgrade.getCraftingItem().getItem()) - .unlockedBy("has_items", inventoryChange(base.getItem(), upgrade.getCraftingItem().getItem())) + .unlockedBy("has_items", inventoryChange(pocket, upgrade.getCraftingItem().getItem())) .build(ImpostorShapedRecipe::new) .save( add, @@ -197,15 +195,14 @@ private void turtleOverlays(RecipeOutput add) { private void turtleOverlay(RecipeOutput add, String overlay, Consumer build) { for (var turtleItem : turtleItems()) { - var base = turtleItem.create(-1, null, -1, null, null, 0, null); var name = RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, turtleItem); - var builder = ShapelessSpecBuilder.shapeless(RecipeCategory.REDSTONE, base) + var builder = ShapelessSpecBuilder.shapeless(RecipeCategory.REDSTONE, new ItemStack(turtleItem)) .group(name.withSuffix("_overlay").toString()) - .unlockedBy("has_turtle", inventoryChange(base.getItem())); + .unlockedBy("has_turtle", inventoryChange(turtleItem)); build.accept(builder); builder - .requires(base.getItem()) + .requires(turtleItem) .build(s -> new TurtleOverlayRecipe(s, new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/" + overlay))) .save(add, name.withSuffix("_overlays/" + overlay)); } @@ -254,7 +251,7 @@ private void basicRecipes(RecipeOutput add) { .define('#', ingredients.goldIngot()) .define('C', ModRegistry.Items.COMPUTER_NORMAL.get()) .unlockedBy("has_components", inventoryChange(itemPredicate(ModRegistry.Items.COMPUTER_NORMAL.get()), itemPredicate(ingredients.goldIngot()))) - .build(ComputerUpgradeRecipe::new) + .build(ComputerConvertRecipe::new) .save(add, new ResourceLocation(ComputerCraftAPI.MOD_ID, "computer_advanced_upgrade")); ShapedRecipeBuilder @@ -277,7 +274,7 @@ private void basicRecipes(RecipeOutput add) { .define('C', ModRegistry.Items.COMPUTER_NORMAL.get()) .define('I', ingredients.woodenChest()) .unlockedBy("has_computer", inventoryChange(ModRegistry.Items.COMPUTER_NORMAL.get())) - .buildOrThrow(TurtleRecipe::of) + .build(ComputerConvertRecipe::new) .save(add); ShapedSpecBuilder @@ -289,7 +286,7 @@ private void basicRecipes(RecipeOutput add) { .define('C', ModRegistry.Items.COMPUTER_ADVANCED.get()) .define('I', ingredients.woodenChest()) .unlockedBy("has_computer", inventoryChange(ModRegistry.Items.COMPUTER_NORMAL.get())) - .buildOrThrow(TurtleRecipe::of) + .build(ComputerConvertRecipe::new) .save(add); ShapedSpecBuilder @@ -301,7 +298,7 @@ private void basicRecipes(RecipeOutput add) { .define('C', ModRegistry.Items.TURTLE_NORMAL.get()) .define('B', ingredients.goldBlock()) .unlockedBy("has_components", inventoryChange(itemPredicate(ModRegistry.Items.TURTLE_NORMAL.get()), itemPredicate(ingredients.goldIngot()))) - .build(ComputerUpgradeRecipe::new) + .build(ComputerConvertRecipe::new) .save(add, new ResourceLocation(ComputerCraftAPI.MOD_ID, "turtle_advanced_upgrade")); ShapedRecipeBuilder @@ -366,7 +363,7 @@ private void basicRecipes(RecipeOutput add) { .define('#', ingredients.goldIngot()) .define('C', ModRegistry.Items.POCKET_COMPUTER_NORMAL.get()) .unlockedBy("has_components", inventoryChange(itemPredicate(ModRegistry.Items.POCKET_COMPUTER_NORMAL.get()), itemPredicate(ingredients.goldIngot()))) - .build(ComputerUpgradeRecipe::new) + .build(ComputerConvertRecipe::new) .save(add, new ResourceLocation(ComputerCraftAPI.MOD_ID, "pocket_computer_advanced_upgrade")); ShapedRecipeBuilder @@ -436,18 +433,18 @@ private void basicRecipes(RecipeOutput add) { ShapelessSpecBuilder .shapeless(RecipeCategory.DECORATIONS, playerHead("Cloudhunter", "6d074736-b1e9-4378-a99b-bd8777821c9c")) - .requires(ingredients.head()) + .requires(ItemTags.SKULLS) .requires(ModRegistry.Items.MONITOR_NORMAL.get()) .unlockedBy("has_monitor", inventoryChange(ModRegistry.Items.MONITOR_NORMAL.get())) - .build(CustomShapelessRecipe::new) + .build() .save(add, new ResourceLocation(ComputerCraftAPI.MOD_ID, "skull_cloudy")); ShapelessSpecBuilder .shapeless(RecipeCategory.DECORATIONS, playerHead("dan200", "f3c8d69b-0776-4512-8434-d1b2165909eb")) - .requires(ingredients.head()) + .requires(ItemTags.SKULLS) .requires(ModRegistry.Items.COMPUTER_ADVANCED.get()) .unlockedBy("has_computer", inventoryChange(ModRegistry.Items.COMPUTER_ADVANCED.get())) - .build(CustomShapelessRecipe::new) + .build() .save(add, new ResourceLocation(ComputerCraftAPI.MOD_ID, "skull_dan200")); ShapelessSpecBuilder @@ -493,11 +490,11 @@ private static ItemPredicate itemPredicate(TagKey item) { } private static ItemPredicate itemPredicate(Ingredient ingredient) { - var json = Util.getOrThrow(Ingredient.CODEC_NONEMPTY.encodeStart(JsonOps.INSTANCE, ingredient), JsonParseException::new); + var json = Ingredient.CODEC_NONEMPTY.encodeStart(JsonOps.INSTANCE, ingredient).getOrThrow(); if (!(json instanceof JsonObject object)) throw new IllegalStateException("Unknown ingredient " + json); if (object.has("item")) { - var item = Util.getOrThrow(ItemStack.ITEM_WITH_COUNT_CODEC.parse(JsonOps.INSTANCE, object), JsonParseException::new); + var item = ItemStack.SIMPLE_ITEM_CODEC.parse(JsonOps.INSTANCE, object).getOrThrow(); return itemPredicate(item.getItem()); } else if (object.has("tag")) { return itemPredicate(TagKey.create(Registries.ITEM, new ResourceLocation(GsonHelper.getAsString(object, "tag")))); @@ -507,10 +504,7 @@ private static ItemPredicate itemPredicate(Ingredient ingredient) { } private static ItemStack playerHead(String name, String uuid) { - var item = new ItemStack(Items.PLAYER_HEAD); - var owner = NbtUtils.writeGameProfile(new CompoundTag(), new GameProfile(UUID.fromString(uuid), name)); - item.getOrCreateTag().put(PlayerHeadItem.TAG_SKULL_OWNER, owner); - return item; + return DataComponentUtil.createStack(Items.PLAYER_HEAD, DataComponents.PROFILE, new ResolvableProfile(new GameProfile(UUID.fromString(uuid), name))); } private static void addSpecial(RecipeOutput add, Recipe recipe) { diff --git a/projects/common/src/main/java/dan200/computercraft/data/TagProvider.java b/projects/common/src/main/java/dan200/computercraft/data/TagProvider.java index 7f8d0421c..dce38ac3c 100644 --- a/projects/common/src/main/java/dan200/computercraft/data/TagProvider.java +++ b/projects/common/src/main/java/dan200/computercraft/data/TagProvider.java @@ -7,8 +7,8 @@ import dan200.computercraft.api.ComputerCraftTags; import dan200.computercraft.impl.RegistryHelper; import dan200.computercraft.shared.ModRegistry; -import net.minecraft.core.Registry; import dan200.computercraft.shared.integration.ExternalModTags; +import net.minecraft.core.Registry; import net.minecraft.data.tags.ItemTagsProvider; import net.minecraft.data.tags.TagsProvider; import net.minecraft.tags.BlockTags; @@ -97,6 +97,10 @@ public static void itemTags(ItemTagConsumer tags) { tags.tag(ComputerCraftTags.Items.WIRED_MODEM).add(ModRegistry.Items.WIRED_MODEM.get(), ModRegistry.Items.WIRED_MODEM_FULL.get()); tags.copy(ComputerCraftTags.Blocks.MONITOR, ComputerCraftTags.Items.MONITOR); + tags.tag(ComputerCraftTags.Items.DYEABLE) + .addTag(ComputerCraftTags.Items.TURTLE) + .add(ModRegistry.Items.DISK.get(), ModRegistry.Items.POCKET_COMPUTER_NORMAL.get(), ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get()); + tags.tag(ItemTags.PIGLIN_LOVED).add( ModRegistry.Items.COMPUTER_ADVANCED.get(), ModRegistry.Items.TURTLE_ADVANCED.get(), ModRegistry.Items.WIRELESS_MODEM_ADVANCED.get(), ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get(), diff --git a/projects/common/src/main/java/dan200/computercraft/data/recipe/AbstractRecipeBuilder.java b/projects/common/src/main/java/dan200/computercraft/data/recipe/AbstractRecipeBuilder.java index fb9492df3..3b1e55590 100644 --- a/projects/common/src/main/java/dan200/computercraft/data/recipe/AbstractRecipeBuilder.java +++ b/projects/common/src/main/java/dan200/computercraft/data/recipe/AbstractRecipeBuilder.java @@ -6,7 +6,6 @@ import com.mojang.serialization.DataResult; import dan200.computercraft.shared.recipe.RecipeProperties; -import net.minecraft.Util; import net.minecraft.advancements.AdvancementRequirements; import net.minecraft.advancements.AdvancementRewards; import net.minecraft.advancements.Criterion; @@ -90,7 +89,7 @@ public final FinishedRecipe build(Function> factory) { * @return The "built" recipe. */ public final FinishedRecipe buildOrThrow(Function>> factory) { - return build(s -> Util.getOrThrow(factory.apply(s), IllegalStateException::new)); + return build(s -> factory.apply(s).getOrThrow()); } @SuppressWarnings("unchecked") diff --git a/projects/common/src/main/java/dan200/computercraft/data/recipe/ShapelessSpecBuilder.java b/projects/common/src/main/java/dan200/computercraft/data/recipe/ShapelessSpecBuilder.java index ae103e9dd..29f49e221 100644 --- a/projects/common/src/main/java/dan200/computercraft/data/recipe/ShapelessSpecBuilder.java +++ b/projects/common/src/main/java/dan200/computercraft/data/recipe/ShapelessSpecBuilder.java @@ -13,6 +13,7 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.ShapelessRecipe; import net.minecraft.world.level.ItemLike; /** @@ -58,4 +59,8 @@ public ShapelessSpecBuilder requires(TagKey item) { protected ShapelessRecipeSpec build(RecipeProperties properties) { return new ShapelessRecipeSpec(properties, ingredients, result); } + + public FinishedRecipe build() { + return build(spec -> new ShapelessRecipe(spec.properties().group(), spec.properties().category(), spec.result(), spec.ingredients())); + } } 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 2a6561bb6..d60b44ce3 100644 --- a/projects/common/src/main/java/dan200/computercraft/impl/UpgradeManager.java +++ b/projects/common/src/main/java/dan200/computercraft/impl/UpgradeManager.java @@ -5,12 +5,19 @@ package dan200.computercraft.impl; import com.google.gson.*; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.codecs.RecordCodecBuilder; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.upgrades.UpgradeBase; import dan200.computercraft.api.upgrades.UpgradeData; import dan200.computercraft.api.upgrades.UpgradeSerialiser; import dan200.computercraft.shared.platform.PlatformHelper; +import io.netty.buffer.ByteBuf; import net.minecraft.core.Registry; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; @@ -40,16 +47,46 @@ public class UpgradeManager extends SimpleJsonResourceRel private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); public record UpgradeWrapper( - String id, T upgrade, UpgradeSerialiser serialiser, String modId + ResourceLocation id, T upgrade, UpgradeSerialiser serialiser, String modId ) { } private final String kind; private final ResourceKey>> registry; - private Map> current = Map.of(); + private Map> current = Map.of(); private Map> currentWrappers = Map.of(); + private final Codec upgradeCodec = ResourceLocation.CODEC.flatXmap( + x -> { + var upgrade = get(x); + return upgrade == null ? DataResult.error(() -> "Unknown upgrade " + x) : DataResult.success(upgrade); + }, + x -> DataResult.success(x.getUpgradeID()) + ); + + private final Codec> fullCodec = RecordCodecBuilder.create(i -> i.group( + upgradeCodec.fieldOf("id").forGetter(UpgradeData::upgrade), + DataComponentPatch.CODEC.optionalFieldOf("components", DataComponentPatch.EMPTY).forGetter(UpgradeData::data) + ).apply(i, UpgradeData::new)); + + private final Codec> codec = Codec.withAlternative(fullCodec, upgradeCodec, UpgradeData::ofDefault); + + private final StreamCodec upgradeStreamCodec = ResourceLocation.STREAM_CODEC.map( + x -> { + var upgrade = get(x); + if (upgrade == null) throw new IllegalStateException("Unknown upgrade " + x); + return upgrade; + }, + UpgradeBase::getUpgradeID + ); + + private final StreamCodec> streamCodec = StreamCodec.composite( + upgradeStreamCodec, UpgradeData::upgrade, + DataComponentPatch.STREAM_CODEC, UpgradeData::data, + UpgradeData::new + ); + public UpgradeManager(String kind, String path, ResourceKey>> registry) { super(GSON, path); this.kind = kind; @@ -57,7 +94,7 @@ public UpgradeManager(String kind, String path, ResourceKey getUpgrades() { return currentWrappers.keySet(); } - public Map> getUpgradeWrappers() { + public Map> getUpgradeWrappers() { return current; } + public Codec> codec() { + return codec; + } + + public StreamCodec> streamCodec() { + return streamCodec; + } + @Override protected void apply(Map upgrades, ResourceManager manager, ProfilerFiller profiler) { var registry = RegistryHelper.getRegistry(this.registry); - Map> newUpgrades = new HashMap<>(); + Map> newUpgrades = new HashMap<>(); for (var element : upgrades.entrySet()) { try { loadUpgrade(registry, newUpgrades, element.getKey(), element.getValue()); @@ -112,7 +157,7 @@ protected void apply(Map upgrades, ResourceManage LOG.info("Loaded {} {}s", current.size(), kind); } - private void loadUpgrade(Registry> registry, Map> current, ResourceLocation id, JsonElement json) { + private void loadUpgrade(Registry> registry, Map> current, ResourceLocation id, JsonElement json) { var root = GsonHelper.convertToJsonObject(json, "top element"); if (!PlatformHelper.get().shouldLoadResource(root)) return; @@ -130,11 +175,11 @@ private void loadUpgrade(Registry> registry, Map< throw new IllegalArgumentException("Upgrade " + id + " from " + serialiser + " was incorrectly given id " + upgrade.getUpgradeID()); } - var result = new UpgradeWrapper(id.toString(), upgrade, serialiser, modId); + var result = new UpgradeWrapper(id, upgrade, serialiser, modId); current.put(result.id(), result); } - public void loadFromNetwork(Map> newUpgrades) { + public void loadFromNetwork(Map> newUpgrades) { current = Collections.unmodifiableMap(newUpgrades); currentWrappers = newUpgrades.values().stream().collect(Collectors.toUnmodifiableMap(UpgradeWrapper::upgrade, x -> x)); } diff --git a/projects/common/src/main/java/dan200/computercraft/mixin/ItemStackComponentizationFixMixin.java b/projects/common/src/main/java/dan200/computercraft/mixin/ItemStackComponentizationFixMixin.java new file mode 100644 index 000000000..16984f6cf --- /dev/null +++ b/projects/common/src/main/java/dan200/computercraft/mixin/ItemStackComponentizationFixMixin.java @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.mixin; + +import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import com.mojang.datafixers.DataFix; +import com.mojang.datafixers.TypeRewriteRule; +import com.mojang.datafixers.schemas.Schema; +import com.mojang.serialization.Dynamic; +import dan200.computercraft.shared.util.ComponentizationFixers; +import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix; +import net.minecraft.util.datafix.fixes.References; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** + * Migrates CC's item NBT to use components. + * + * @see V3818_3Mixin + * @see ComponentizationFixers + */ +@Mixin(ItemStackComponentizationFix.class) +abstract class ItemStackComponentizationFixMixin extends DataFix { + @SuppressWarnings("UnusedMethod") + private ItemStackComponentizationFixMixin(Schema outputSchema, boolean changesType) { + super(outputSchema, changesType); + } + + @Inject(method = "fixItemStack", at = @At("TAIL")) + @SuppressWarnings("UnusedMethod") + private static void fixItemStack(ItemStackComponentizationFix.ItemStackData data, Dynamic ops, CallbackInfo ci) { + ComponentizationFixers.fixItemComponents(data, ops); + } + + @ModifyReturnValue(method = "makeRule", at = @At("RETURN"), remap = false) + @SuppressWarnings("UnusedMethod") + private TypeRewriteRule wrapMakeRule(TypeRewriteRule existing) { + return TypeRewriteRule.seq(existing, fixTypeEverywhereTyped( + "Turtle upgrade componentization", + getInputSchema().getType(References.BLOCK_ENTITY), + getOutputSchema().getType(References.BLOCK_ENTITY), + ComponentizationFixers.makeBlockEntityRewrites(getInputSchema(), getOutputSchema()) + )); + } +} 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 282b552d7..5a5f57af9 100644 --- a/projects/common/src/main/java/dan200/computercraft/mixin/V1460Mixin.java +++ b/projects/common/src/main/java/dan200/computercraft/mixin/V1460Mixin.java @@ -7,16 +7,17 @@ import com.mojang.datafixers.DSL; import com.mojang.datafixers.schemas.Schema; import com.mojang.datafixers.types.templates.TypeTemplate; -import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveBlockEntity; import dan200.computercraft.shared.peripheral.printer.PrinterBlockEntity; import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity; import net.minecraft.util.datafix.fixes.References; +import net.minecraft.util.datafix.schemas.NamespacedSchema; import net.minecraft.util.datafix.schemas.V1460; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.util.Map; @@ -37,16 +38,34 @@ private void registerBlockEntities(Schema schema, CallbackInfoReturnable DSL.optionalFields( + schema.register(map, "computercraft:disk_drive", () -> DSL.optionalFields( "Item", References.ITEM_STACK.in(schema) )); } + 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("components", References.DATA_COMPONENTS.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)) + )); + } + @Shadow protected static void registerInventory(Schema schema, Map> map, String name) { } diff --git a/projects/common/src/main/java/dan200/computercraft/mixin/V3818_3Mixin.java b/projects/common/src/main/java/dan200/computercraft/mixin/V3818_3Mixin.java new file mode 100644 index 000000000..8156a3b6f --- /dev/null +++ b/projects/common/src/main/java/dan200/computercraft/mixin/V3818_3Mixin.java @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.mixin; + +import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import com.mojang.datafixers.DSL; +import com.mojang.datafixers.schemas.Schema; +import com.mojang.datafixers.types.templates.TypeTemplate; +import com.mojang.datafixers.util.Pair; +import dan200.computercraft.impl.UpgradeManager; +import dan200.computercraft.shared.ModRegistry.DataComponents; +import net.minecraft.util.datafix.fixes.References; +import net.minecraft.util.datafix.schemas.V3818_3; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import java.util.Arrays; +import java.util.stream.Stream; + +/** + * Add our custom data components to the datafixer system. + * + * @see UpgradeManager#codec() + * @see DataComponents#POCKET_UPGRADE + * @see DataComponents#LEFT_TURTLE_UPGRADE + * @see DataComponents#RIGHT_TURTLE_UPGRADE + * @see ItemStackComponentizationFixMixin + */ +@Mixin(V3818_3.class) +class V3818_3Mixin { + @ModifyReturnValue( + method = "method_57277", + at = @At("TAIL") + ) + @SuppressWarnings("UnusedMethod") + private static TypeTemplate addExtraTypes(TypeTemplate type, Schema schema) { + // Create a codec for UpgradeData + var upgradeData = DSL.optionalFields("components", References.DATA_COMPONENTS.in(schema)); + + return extraOptionalFields(type, + Pair.of("computercraft:pocket_upgrade", upgradeData), + Pair.of("computercraft:left_turtle_upgrade", upgradeData), + Pair.of("computercraft:right_turtle_upgrade", upgradeData) + ); + } + + @SafeVarargs + @SuppressWarnings("varargs") + private static TypeTemplate extraOptionalFields(TypeTemplate base, Pair... fields) { + return DSL.and(Stream.concat( + Arrays.stream(fields).map(entry -> DSL.optional(DSL.field(entry.getFirst(), entry.getSecond()))), + Stream.of(base) + ).toList()); + } +} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/CommonHooks.java b/projects/common/src/main/java/dan200/computercraft/shared/CommonHooks.java index 5350075f1..0a7d8b708 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/CommonHooks.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/CommonHooks.java @@ -14,6 +14,7 @@ import dan200.computercraft.shared.peripheral.monitor.MonitorWatcher; import dan200.computercraft.shared.util.DropConsumer; import dan200.computercraft.shared.util.TickScheduler; +import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; @@ -28,7 +29,8 @@ import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.storage.loot.BuiltInLootTables; import net.minecraft.world.level.storage.loot.LootPool; -import net.minecraft.world.level.storage.loot.entries.LootTableReference; +import net.minecraft.world.level.storage.loot.LootTable; +import net.minecraft.world.level.storage.loot.entries.NestedLootTable; import net.minecraft.world.level.storage.loot.providers.number.ConstantValue; import javax.annotation.Nullable; @@ -92,9 +94,9 @@ public static void onChunkTicketLevelChanged(ServerLevel level, long chunkPos, i TickScheduler.onChunkTicketChanged(level, chunkPos, oldLevel, newLevel); } - public static final ResourceLocation TREASURE_DISK_LOOT = new ResourceLocation(ComputerCraftAPI.MOD_ID, "treasure_disk"); + public static final ResourceKey TREASURE_DISK_LOOT = ResourceKey.create(Registries.LOOT_TABLE, new ResourceLocation(ComputerCraftAPI.MOD_ID, "treasure_disk")); - private static final Set TREASURE_DISK_LOOT_TABLES = Set.of( + private static final Set> TREASURE_DISK_LOOT_TABLES = Set.of( BuiltInLootTables.SIMPLE_DUNGEON, BuiltInLootTables.ABANDONED_MINESHAFT, BuiltInLootTables.STRONGHOLD_CORRIDOR, @@ -107,13 +109,13 @@ public static void onChunkTicketLevelChanged(ServerLevel level, long chunkPos, i BuiltInLootTables.VILLAGE_CARTOGRAPHER ); - public static @Nullable LootPool.Builder getExtraLootPool(ResourceLocation lootTable) { - if (!lootTable.getNamespace().equals("minecraft") || !TREASURE_DISK_LOOT_TABLES.contains(lootTable)) { + public static @Nullable LootPool.Builder getExtraLootPool(ResourceKey lootTable) { + if (!TREASURE_DISK_LOOT_TABLES.contains(lootTable)) { return null; } return LootPool.lootPool() - .add(LootTableReference.lootTableReference(TREASURE_DISK_LOOT)) + .add(NestedLootTable.lootTableReference(TREASURE_DISK_LOOT)) .setRolls(ConstantValue.exactly(1)); } 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 22a109d61..0a99662d4 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/ModRegistry.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/ModRegistry.java @@ -6,6 +6,7 @@ import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.detail.DetailProvider; import dan200.computercraft.api.detail.VanillaDetailRegistries; @@ -32,9 +33,11 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory; import dan200.computercraft.shared.computer.inventory.ViewComputerMenu; +import dan200.computercraft.shared.computer.items.AbstractComputerItem; import dan200.computercraft.shared.computer.items.CommandComputerItem; import dan200.computercraft.shared.computer.items.ComputerItem; -import dan200.computercraft.shared.computer.recipe.ComputerUpgradeRecipe; +import dan200.computercraft.shared.computer.items.ServerComputerReference; +import dan200.computercraft.shared.computer.recipe.ComputerConvertRecipe; import dan200.computercraft.shared.config.Config; import dan200.computercraft.shared.data.BlockNamedEntityLootCondition; import dan200.computercraft.shared.data.HasComputerIdLootCondition; @@ -42,10 +45,7 @@ import dan200.computercraft.shared.details.BlockDetails; import dan200.computercraft.shared.details.ItemDetails; import dan200.computercraft.shared.integration.PermissionRegistry; -import dan200.computercraft.shared.media.items.DiskItem; -import dan200.computercraft.shared.media.items.PrintoutItem; -import dan200.computercraft.shared.media.items.RecordMedia; -import dan200.computercraft.shared.media.items.TreasureDiskItem; +import dan200.computercraft.shared.media.items.*; import dan200.computercraft.shared.media.recipes.DiskRecipe; import dan200.computercraft.shared.media.recipes.PrintoutRecipe; import dan200.computercraft.shared.network.container.ComputerContainerData; @@ -81,19 +81,23 @@ import dan200.computercraft.shared.turtle.inventory.TurtleMenu; import dan200.computercraft.shared.turtle.items.TurtleItem; import dan200.computercraft.shared.turtle.recipes.TurtleOverlayRecipe; -import dan200.computercraft.shared.turtle.recipes.TurtleRecipe; import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe; import dan200.computercraft.shared.turtle.upgrades.*; +import dan200.computercraft.shared.util.DataComponentUtil; +import dan200.computercraft.shared.util.NonNegativeId; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.synchronization.ArgumentTypeInfo; import net.minecraft.commands.synchronization.SingletonArgumentInfo; -import net.minecraft.core.BlockPos; import net.minecraft.core.cauldron.CauldronInteraction; +import net.minecraft.core.component.DataComponentType; import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.flag.FeatureFlags; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.*; +import net.minecraft.world.item.component.DyedItemColor; import net.minecraft.world.item.crafting.CustomRecipe; import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.SimpleCraftingRecipeSerializer; @@ -101,12 +105,12 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.MapColor; import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType; import java.util.function.BiFunction; import java.util.function.Predicate; +import java.util.function.UnaryOperator; /** * Registers ComputerCraft's registry entries and additional objects, such as {@link CauldronInteraction}s and @@ -174,8 +178,8 @@ private static BlockBehaviour.Properties modemProperties() { public static class BlockEntities { static final RegistrationHelper> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registries.BLOCK_ENTITY_TYPE); - private static RegistryEntry> ofBlock(RegistryEntry block, BiFunction factory) { - return REGISTRY.register(block.id().getPath(), () -> PlatformHelper.get().createBlockEntityType(factory, block.get())); + private static RegistryEntry> ofBlock(RegistryEntry block, BlockEntityType.BlockEntitySupplier factory) { + return REGISTRY.register(block.id().getPath(), () -> BlockEntityType.Builder.of(factory, block.get()).build(null)); } public static final RegistryEntry> MONITOR_NORMAL = @@ -262,6 +266,114 @@ private static RegistryEntry ofBlock(Regist () -> new CableBlockItem.WiredModem(Blocks.CABLE.get(), properties())); } + public static final class DataComponents { + static final RegistrationHelper> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registries.DATA_COMPONENT_TYPE); + + private static RegistryEntry> register(String name, UnaryOperator> unaryOperator) { + return REGISTRY.register(name, () -> unaryOperator.apply(DataComponentType.builder()).build()); + } + + /** + * The id of a computer. + * + * @see AbstractComputerItem + * @see PocketComputerItem + */ + public static final RegistryEntry> COMPUTER_ID = register("computer_id", b -> b + .persistent(NonNegativeId.CODEC).networkSynchronized(NonNegativeId.STREAM_CODEC) + ); + + /** + * The left upgrade of a turtle. + * + * @see TurtleItem + */ + public static final RegistryEntry>> LEFT_TURTLE_UPGRADE = register("left_turtle_upgrade", b -> b + .persistent(TurtleUpgrades.instance().codec()).networkSynchronized(TurtleUpgrades.instance().streamCodec()) + ); + + /** + * The right upgrade of a turtle. + * + * @see TurtleItem + */ + public static final RegistryEntry>> RIGHT_TURTLE_UPGRADE = register("right_turtle_upgrade", b -> b + .persistent(TurtleUpgrades.instance().codec()).networkSynchronized(TurtleUpgrades.instance().streamCodec()) + ); + + /** + * The fuel level of a turtle. + */ + public static final RegistryEntry> FUEL = register("fuel", b -> b + .persistent(Codec.INT).networkSynchronized(ByteBufCodecs.VAR_INT) + ); + + /** + * The overlay on a turtle. + */ + public static final RegistryEntry> OVERLAY = register("overlay", b -> b + .persistent(ResourceLocation.CODEC).networkSynchronized(ResourceLocation.STREAM_CODEC) + ); + + /** + * The back upgrade of a pocket computer. + * + * @see PocketComputerItem + */ + public static final RegistryEntry>> POCKET_UPGRADE = register("pocket_upgrade", b -> b + .persistent(PocketUpgrades.instance().codec()).networkSynchronized(PocketUpgrades.instance().streamCodec()) + ); + + /** + * A reference to the currently running {@link dan200.computercraft.shared.computer.core.ServerComputer}. + * + * @see ServerComputerReference + * @see PocketComputerItem + */ + public static final RegistryEntry> COMPUTER = register("computer", b -> b + .persistent(ServerComputerReference.CODEC).networkSynchronized(ServerComputerReference.STREAM_CODEC) + ); + + /** + * Whether this item is currently on. + * + * @see PocketComputerItem + * @see TurtleModem + */ + public static final RegistryEntry> ON = register("on", b -> b + .persistent(Codec.BOOL).networkSynchronized(ByteBufCodecs.BOOL) + ); + + /** + * Information about a treasure disk's mount. + * + * @see TreasureDiskItem + * @see TreasureDisk + */ + public static final RegistryEntry> TREASURE_DISK = register("treasure_disk", b -> b + .persistent(TreasureDisk.CODEC).networkSynchronized(TreasureDisk.STREAM_CODEC) + ); + + /** + * The id of a disk. + * + * @see DiskItem + */ + public static final RegistryEntry> DISK_ID = register("disk_id", b -> b + .persistent(NonNegativeId.CODEC).networkSynchronized(NonNegativeId.STREAM_CODEC) + ); + + /** + * The contents of a printed page/printed pages. + * + * @see PrintoutItem + * @see PrintoutData + */ + public static final RegistryEntry> PRINTOUT = register("printout", b -> b + .persistent(PrintoutData.CODEC).networkSynchronized(PrintoutData.STREAM_CODEC) + ); + } + public static class TurtleSerialisers { static final RegistrationHelper> REGISTRY = PlatformHelper.get().createRegistrationHelper(ITurtleUpgrade.serialiserRegistryKey()); @@ -292,16 +404,16 @@ public static class Menus { static final RegistrationHelper> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registries.MENU); public static final RegistryEntry> COMPUTER = REGISTRY.register("computer", - () -> ContainerData.toType(ComputerContainerData::new, (id, inv, data) -> new ComputerMenuWithoutInventory(Menus.COMPUTER.get(), id, inv, data))); + () -> ContainerData.toType(ComputerContainerData.STREAM_CODEC, (id, inv, data) -> new ComputerMenuWithoutInventory(Menus.COMPUTER.get(), id, inv, data))); public static final RegistryEntry> POCKET_COMPUTER = REGISTRY.register("pocket_computer", - () -> ContainerData.toType(ComputerContainerData::new, (id, inv, data) -> new ComputerMenuWithoutInventory(Menus.POCKET_COMPUTER.get(), id, inv, data))); + () -> ContainerData.toType(ComputerContainerData.STREAM_CODEC, (id, inv, data) -> new ComputerMenuWithoutInventory(Menus.POCKET_COMPUTER.get(), id, inv, data))); public static final RegistryEntry> POCKET_COMPUTER_NO_TERM = REGISTRY.register("pocket_computer_no_term", - () -> ContainerData.toType(ComputerContainerData::new, (id, inv, data) -> new ComputerMenuWithoutInventory(Menus.POCKET_COMPUTER_NO_TERM.get(), id, inv, data))); + () -> ContainerData.toType(ComputerContainerData.STREAM_CODEC, (id, inv, data) -> new ComputerMenuWithoutInventory(Menus.POCKET_COMPUTER_NO_TERM.get(), id, inv, data))); public static final RegistryEntry> TURTLE = REGISTRY.register("turtle", - () -> ContainerData.toType(ComputerContainerData::new, TurtleMenu::ofMenuData)); + () -> ContainerData.toType(ComputerContainerData.STREAM_CODEC, TurtleMenu::ofMenuData)); public static final RegistryEntry> DISK_DRIVE = REGISTRY.register("disk_drive", () -> new MenuType<>(DiskDriveMenu::new, FeatureFlags.VANILLA_SET)); @@ -311,12 +423,12 @@ public static class Menus { public static final RegistryEntry> PRINTOUT = REGISTRY.register("printout", () -> ContainerData.toType( - HeldItemContainerData::new, - (id, inventory, data) -> new HeldItemMenu(Menus.PRINTOUT.get(), id, inventory.player, data.getHand()) + HeldItemContainerData.STREAM_CODEC, + (id, inventory, data) -> new HeldItemMenu(Menus.PRINTOUT.get(), id, inventory.player, data.hand()) )); public static final RegistryEntry> VIEW_COMPUTER = REGISTRY.register("view_computer", - () -> ContainerData.toType(ComputerContainerData::new, ViewComputerMenu::new)); + () -> ContainerData.toType(ComputerContainerData.STREAM_CODEC, ViewComputerMenu::new)); } static class ArgumentTypes { @@ -346,13 +458,13 @@ public static class LootItemConditionTypes { static final RegistrationHelper REGISTRY = PlatformHelper.get().createRegistrationHelper(Registries.LOOT_CONDITION_TYPE); public static final RegistryEntry BLOCK_NAMED = REGISTRY.register("block_named", - () -> new LootItemConditionType(Codec.unit(BlockNamedEntityLootCondition.INSTANCE))); + () -> new LootItemConditionType(MapCodec.unit(BlockNamedEntityLootCondition.INSTANCE))); public static final RegistryEntry PLAYER_CREATIVE = REGISTRY.register("player_creative", - () -> new LootItemConditionType(Codec.unit(PlayerCreativeLootCondition.INSTANCE))); + () -> new LootItemConditionType(MapCodec.unit(PlayerCreativeLootCondition.INSTANCE))); public static final RegistryEntry HAS_ID = REGISTRY.register("has_id", - () -> new LootItemConditionType(Codec.unit(HasComputerIdLootCondition.INSTANCE))); + () -> new LootItemConditionType(MapCodec.unit(HasComputerIdLootCondition.INSTANCE))); } public static class RecipeSerializers { @@ -362,21 +474,17 @@ private static RegistryEntry new SimpleCraftingRecipeSerializer<>(factory)); } - public static final RegistryEntry> SHAPED = REGISTRY.register("shaped", () -> CustomShapedRecipe.serialiser(CustomShapedRecipe::new)); - public static final RegistryEntry> SHAPELESS = REGISTRY.register("shapeless", () -> CustomShapelessRecipe.serialiser(CustomShapelessRecipe::new)); - public static final RegistryEntry> IMPOSTOR_SHAPED = REGISTRY.register("impostor_shaped", () -> CustomShapedRecipe.serialiser(ImpostorShapedRecipe::new)); public static final RegistryEntry> IMPOSTOR_SHAPELESS = REGISTRY.register("impostor_shapeless", () -> CustomShapelessRecipe.serialiser(ImpostorShapelessRecipe::new)); public static final RegistryEntry> DYEABLE_ITEM = simple("colour", ColourableRecipe::new); public static final RegistryEntry> DYEABLE_ITEM_CLEAR = simple("clear_colour", ClearColourRecipe::new); - public static final RegistryEntry> TURTLE = REGISTRY.register("turtle", () -> TurtleRecipe.validatingSerialiser(TurtleRecipe::of)); public static final RegistryEntry> TURTLE_UPGRADE = simple("turtle_upgrade", TurtleUpgradeRecipe::new); - public static final RegistryEntry> TURTLE_OVERLAY = REGISTRY.register("turtle_overlay", TurtleOverlayRecipe.Serialiser::new); + public static final RegistryEntry> TURTLE_OVERLAY = REGISTRY.register("turtle_overlay", TurtleOverlayRecipe::serialiser); public static final RegistryEntry> POCKET_COMPUTER_UPGRADE = simple("pocket_computer_upgrade", PocketComputerUpgradeRecipe::new); public static final RegistryEntry> PRINTOUT = simple("printout", PrintoutRecipe::new); public static final RegistryEntry> DISK = simple("disk", DiskRecipe::new); - public static final RegistryEntry> COMPUTER_UPGRADE = REGISTRY.register("computer_upgrade", () -> CustomShapedRecipe.validatingSerialiser(ComputerUpgradeRecipe::of)); + public static final RegistryEntry> COMPUTER_CONVERT = REGISTRY.register("computer_convert", () -> CustomShapedRecipe.serialiser(ComputerConvertRecipe::new)); } public static class Permissions { @@ -425,7 +533,7 @@ static class CreativeTabs { out.accept(Items.DISK_DRIVE.get()); for (var colour = 0; colour < 16; colour++) { - out.accept(DiskItem.createFromIDAndColour(-1, null, Colour.VALUES[colour].getHex())); + out.accept(DataComponentUtil.createStack(Items.DISK.get(), net.minecraft.core.component.DataComponents.DYED_COLOR, new DyedItemColor(Colour.VALUES[colour].getHex(), false))); } }) .build()); @@ -438,6 +546,7 @@ public static void register() { Blocks.REGISTRY.register(); BlockEntities.REGISTRY.register(); Items.REGISTRY.register(); + DataComponents.REGISTRY.register(); TurtleSerialisers.REGISTRY.register(); PocketUpgradeSerialisers.REGISTRY.register(); Menus.REGISTRY.register(); @@ -470,14 +579,14 @@ public static void registerMainThread() { } private static void addTurtle(CreativeModeTab.Output out, TurtleItem turtle) { - out.accept(turtle.create(-1, null, -1, null, null, 0, null)); + out.accept(new ItemStack(turtle)); TurtleUpgrades.getVanillaUpgrades() - .map(x -> turtle.create(-1, null, -1, null, UpgradeData.ofDefault(x), 0, null)) + .map(x -> DataComponentUtil.createStack(turtle, DataComponents.RIGHT_TURTLE_UPGRADE.get(), UpgradeData.ofDefault(x))) .forEach(out::accept); } private static void addPocket(CreativeModeTab.Output out, PocketComputerItem pocket) { - out.accept(pocket.create(-1, null, -1, null)); - PocketUpgrades.getVanillaUpgrades().map(x -> pocket.create(-1, null, -1, UpgradeData.ofDefault(x))).forEach(out::accept); + out.accept(new ItemStack(pocket)); + PocketUpgrades.getVanillaUpgrades().map(x -> DataComponentUtil.createStack(pocket, DataComponents.POCKET_UPGRADE.get(), UpgradeData.ofDefault(x))).forEach(out::accept); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java b/projects/common/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java index 018237a1b..fc2fbf4b6 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java @@ -260,7 +260,7 @@ private static int queue(Collection computers, List args */ private static int view(CommandSourceStack source, ServerComputer computer) throws CommandSyntaxException { var player = source.getPlayerOrException(); - new ComputerContainerData(computer, ItemStack.EMPTY).open(player, new MenuProvider() { + new ComputerContainerData(computer, new ItemStack(ModRegistry.Items.COMPUTER_NORMAL.get())).open(player, new MenuProvider() { @Override public Component getDisplayName() { return Component.translatable("gui.computercraft.view_computer"); diff --git a/projects/common/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentUtils.java b/projects/common/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentUtils.java index 5eb7ca110..25a8a6068 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentUtils.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentUtils.java @@ -14,8 +14,6 @@ import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; -import java.util.Objects; - /** * Utilities for working with arguments. * @@ -45,13 +43,12 @@ public static > void serializeToNetwork(FriendlyByteBu @SuppressWarnings("unchecked") private static , T extends ArgumentTypeInfo.Template> void serializeToNetwork(FriendlyByteBuf buffer, ArgumentTypeInfo type, ArgumentTypeInfo.Template template) { - buffer.writeId(BuiltInRegistries.COMMAND_ARGUMENT_TYPE, type); + buffer.writeVarInt(BuiltInRegistries.COMMAND_ARGUMENT_TYPE.getIdOrThrow(type)); type.serializeToNetwork((T) template, buffer); } public static ArgumentTypeInfo.Template deserialize(FriendlyByteBuf buffer) { - var type = buffer.readById(BuiltInRegistries.COMMAND_ARGUMENT_TYPE); - Objects.requireNonNull(type, "Unknown argument type"); + var type = BuiltInRegistries.COMMAND_ARGUMENT_TYPE.byIdOrThrow(buffer.readVarInt()); return type.deserializeFromNetwork(buffer); } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java b/projects/common/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java index 51ff6c5fc..d1cdfb0a9 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java @@ -15,8 +15,10 @@ import net.minecraft.commands.CommandBuildContext; import net.minecraft.commands.synchronization.ArgumentTypeInfo; import net.minecraft.commands.synchronization.ArgumentTypeInfos; +import net.minecraft.core.RegistryAccess; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.ComponentSerialization; import java.util.ArrayList; import java.util.Collection; @@ -114,14 +116,14 @@ public static class Info implements ArgumentTypeInfo, T public void serializeToNetwork(RepeatArgumentType.Template arg, FriendlyByteBuf buf) { buf.writeBoolean(arg.flatten); ArgumentUtils.serializeToNetwork(buf, arg.child); - buf.writeComponent(ArgumentUtils.getMessage(arg.some)); + ComponentSerialization.TRUSTED_CONTEXT_FREE_STREAM_CODEC.encode(buf, ArgumentUtils.getMessage(arg.some)); } @Override public RepeatArgumentType.Template deserializeFromNetwork(FriendlyByteBuf buf) { var isList = buf.readBoolean(); var child = ArgumentUtils.deserialize(buf); - var message = buf.readComponent(); + var message = ComponentSerialization.TRUSTED_CONTEXT_FREE_STREAM_CODEC.decode(buf); return new RepeatArgumentType.Template(this, child, isList, new SimpleCommandExceptionType(message)); } @@ -134,7 +136,7 @@ public RepeatArgumentType.Template unpack(RepeatArgumentType argumentType) public void serializeToJson(RepeatArgumentType.Template arg, JsonObject json) { json.addProperty("flatten", arg.flatten); json.add("child", ArgumentUtils.serializeToJson(arg.child)); - json.addProperty("error", Component.Serializer.toJson(ArgumentUtils.getMessage(arg.some))); + json.addProperty("error", Component.Serializer.toJson(ArgumentUtils.getMessage(arg.some), RegistryAccess.EMPTY)); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/common/AbstractContainerBlockEntity.java b/projects/common/src/main/java/dan200/computercraft/shared/common/AbstractContainerBlockEntity.java index d4aca0a79..ba17489da 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/common/AbstractContainerBlockEntity.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/common/AbstractContainerBlockEntity.java @@ -4,11 +4,8 @@ package dan200.computercraft.shared.common; -import dan200.computercraft.shared.container.BasicContainer; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.world.Container; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.entity.BaseContainerBlockEntity; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; @@ -17,7 +14,7 @@ /** * A {@link BlockEntity} which exposes an inventory. */ -public abstract class AbstractContainerBlockEntity extends BaseContainerBlockEntity implements BasicContainer { +public abstract class AbstractContainerBlockEntity extends BaseContainerBlockEntity { protected AbstractContainerBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { super(type, pos, state); } @@ -26,9 +23,4 @@ protected AbstractContainerBlockEntity(BlockEntityType type, BlockPos pos, Bl protected final Component getDefaultName() { return Component.translatable(getBlockState().getBlock().getDescriptionId()); } - - @Override - public boolean stillValid(Player player) { - return Container.stillValidBlockEntity(this, player); - } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/common/ClearColourRecipe.java b/projects/common/src/main/java/dan200/computercraft/shared/common/ClearColourRecipe.java index 956c409c4..05a53a87a 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/common/ClearColourRecipe.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/common/ClearColourRecipe.java @@ -4,9 +4,12 @@ package dan200.computercraft.shared.common; +import dan200.computercraft.api.ComputerCraftTags; import dan200.computercraft.shared.ModRegistry; +import dan200.computercraft.shared.util.DataComponentUtil; +import net.minecraft.core.HolderLookup; import net.minecraft.core.NonNullList; -import net.minecraft.core.RegistryAccess; +import net.minecraft.core.component.DataComponents; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; @@ -16,7 +19,7 @@ import net.minecraft.world.level.Level; /** - * Craft a wet sponge with a {@linkplain IColouredItem dyable item} to remove its dye. + * Craft a wet sponge with a {@linkplain ComputerCraftTags.Items#DYEABLE dyable item} to remove its dye. */ public final class ClearColourRecipe extends CustomRecipe { public ClearColourRecipe(CraftingBookCategory category) { @@ -31,9 +34,9 @@ public boolean matches(CraftingContainer inv, Level world) { var stack = inv.getItem(i); if (stack.isEmpty()) continue; - if (stack.getItem() instanceof IColouredItem colourable) { + if (stack.is(ComputerCraftTags.Items.DYEABLE)) { if (hasColourable) return false; - if (colourable.getColour(stack) == -1) return false; + if (!stack.has(DataComponents.DYED_COLOR)) return false; hasColourable = true; } else if (stack.getItem() == Items.WET_SPONGE) { if (hasSponge) return false; @@ -47,19 +50,17 @@ public boolean matches(CraftingContainer inv, Level world) { } @Override - public ItemStack assemble(CraftingContainer inv, RegistryAccess registryAccess) { + public ItemStack assemble(CraftingContainer inv, HolderLookup.Provider registryAccess) { var colourable = ItemStack.EMPTY; for (var i = 0; i < inv.getContainerSize(); i++) { var stack = inv.getItem(i); - if (stack.getItem() instanceof IColouredItem) colourable = stack; + if (stack.is(ComputerCraftTags.Items.DYEABLE)) colourable = stack; } if (colourable.isEmpty()) return ItemStack.EMPTY; - var stack = ((IColouredItem) colourable.getItem()).withColour(colourable, -1); - stack.setCount(1); - return stack; + return DataComponentUtil.createResult(colourable, DataComponents.DYED_COLOR, null); } @Override diff --git a/projects/common/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java b/projects/common/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java index ab8d9f1f7..dda9564f3 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java @@ -4,12 +4,16 @@ package dan200.computercraft.shared.common; +import dan200.computercraft.api.ComputerCraftTags; import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.util.ColourTracker; import dan200.computercraft.shared.util.ColourUtils; -import net.minecraft.core.RegistryAccess; +import dan200.computercraft.shared.util.DataComponentUtil; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.component.DataComponents; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.DyedItemColor; import net.minecraft.world.item.crafting.CraftingBookCategory; import net.minecraft.world.item.crafting.CustomRecipe; import net.minecraft.world.item.crafting.RecipeSerializer; @@ -28,7 +32,7 @@ public boolean matches(CraftingContainer inv, Level world) { var stack = inv.getItem(i); if (stack.isEmpty()) continue; - if (stack.getItem() instanceof IColouredItem) { + if (stack.is(ComputerCraftTags.Items.DYEABLE)) { if (hasColourable) return false; hasColourable = true; } else if (ColourUtils.getStackColour(stack) != null) { @@ -42,7 +46,7 @@ public boolean matches(CraftingContainer inv, Level world) { } @Override - public ItemStack assemble(CraftingContainer inv, RegistryAccess registryAccess) { + public ItemStack assemble(CraftingContainer inv, HolderLookup.Provider registryAccess) { var colourable = ItemStack.EMPTY; var tracker = new ColourTracker(); @@ -52,7 +56,7 @@ public ItemStack assemble(CraftingContainer inv, RegistryAccess registryAccess) if (stack.isEmpty()) continue; - if (stack.getItem() instanceof IColouredItem) { + if (stack.is(ComputerCraftTags.Items.DYEABLE)) { colourable = stack; } else { var dye = ColourUtils.getStackColour(stack); @@ -60,11 +64,10 @@ public ItemStack assemble(CraftingContainer inv, RegistryAccess registryAccess) } } - if (colourable.isEmpty()) return ItemStack.EMPTY; + return colourable.isEmpty() + ? ItemStack.EMPTY + : DataComponentUtil.createResult(colourable, DataComponents.DYED_COLOR, new DyedItemColor(tracker.getColour(), false)); - var stack = ((IColouredItem) colourable.getItem()).withColour(colourable, tracker.getColour()); - stack.setCount(1); - return stack; } @Override diff --git a/projects/common/src/main/java/dan200/computercraft/shared/common/HorizontalContainerBlock.java b/projects/common/src/main/java/dan200/computercraft/shared/common/HorizontalContainerBlock.java index ab8b4965b..d9392c962 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/common/HorizontalContainerBlock.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/common/HorizontalContainerBlock.java @@ -6,12 +6,9 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.Containers; -import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.BaseEntityBlock; @@ -24,7 +21,6 @@ import net.minecraft.world.level.block.state.properties.DirectionProperty; import net.minecraft.world.phys.BlockHitResult; -import javax.annotation.Nullable; /** * A block which has a container and can be placed in a horizontal direction. @@ -44,20 +40,17 @@ public final BlockState getStateForPlacement(BlockPlaceContext placement) { } @Override - @Deprecated - public final BlockState mirror(BlockState state, Mirror mirrorIn) { + protected final BlockState mirror(BlockState state, Mirror mirrorIn) { return state.rotate(mirrorIn.getRotation(state.getValue(FACING))); } @Override - @Deprecated - public final BlockState rotate(BlockState state, Rotation rot) { + protected final BlockState rotate(BlockState state, Rotation rot) { return state.setValue(FACING, rot.rotate(state.getValue(FACING))); } @Override - @Deprecated - public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { + protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) { if (level.isClientSide) return InteractionResult.SUCCESS; if (level.getBlockEntity(pos) instanceof BaseContainerBlockEntity container) { @@ -68,8 +61,7 @@ public InteractionResult use(BlockState state, Level level, BlockPos pos, Player } @Override - @Deprecated - public final void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) { + protected final void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) { if (state.is(newState.getBlock())) return; if (level.getBlockEntity(pos) instanceof BaseContainerBlockEntity container) { @@ -81,27 +73,17 @@ public final void onRemove(BlockState state, Level level, BlockPos pos, BlockSta } @Override - public final void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) { - if (stack.hasCustomHoverName() && world.getBlockEntity(pos) instanceof BaseContainerBlockEntity container) { - container.setCustomName(stack.getHoverName()); - } - } - - @Override - @Deprecated - public final boolean hasAnalogOutputSignal(BlockState pState) { + protected final boolean hasAnalogOutputSignal(BlockState pState) { return true; } @Override - @Deprecated - public final int getAnalogOutputSignal(BlockState pBlockState, Level pLevel, BlockPos pPos) { + protected final int getAnalogOutputSignal(BlockState pBlockState, Level pLevel, BlockPos pPos) { return AbstractContainerMenu.getRedstoneSignalFromBlockEntity(pLevel.getBlockEntity(pPos)); } @Override - @Deprecated - public RenderShape getRenderShape(BlockState state) { + protected RenderShape getRenderShape(BlockState state) { return RenderShape.MODEL; } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/common/IColouredItem.java b/projects/common/src/main/java/dan200/computercraft/shared/common/IColouredItem.java deleted file mode 100644 index 7357530e0..000000000 --- a/projects/common/src/main/java/dan200/computercraft/shared/common/IColouredItem.java +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-FileCopyrightText: 2017 The CC: Tweaked Developers -// -// SPDX-License-Identifier: MPL-2.0 - -package dan200.computercraft.shared.common; - -import net.minecraft.world.item.ItemStack; - -public interface IColouredItem { - String NBT_COLOUR = "Color"; - - default int getColour(ItemStack stack) { - return getColourBasic(stack); - } - - default ItemStack withColour(ItemStack stack, int colour) { - var copy = stack.copy(); - setColourBasic(copy, colour); - return copy; - } - - static int getColourBasic(ItemStack stack) { - var tag = stack.getTag(); - return tag != null && tag.contains(NBT_COLOUR) ? tag.getInt(NBT_COLOUR) : -1; - } - - static void setColourBasic(ItemStack stack, int colour) { - if (colour == -1) { - var tag = stack.getTag(); - if (tag != null) tag.remove(NBT_COLOUR); - } else { - stack.getOrCreateTag().putInt(NBT_COLOUR, colour); - } - } -} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java index 5baab1df5..0c0bd0fe6 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java @@ -78,7 +78,7 @@ private static final class CommandState { var table = VanillaDetailRegistries.BLOCK_IN_WORLD.getDetails(block); var tile = block.blockEntity(); - if (tile != null) table.put("nbt", NBTUtil.toLua(tile.saveWithFullMetadata())); + if (tile != null) table.put("nbt", NBTUtil.toLua(tile.saveWithFullMetadata(world.registryAccess()))); return table; } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/AbstractComputerBlock.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/AbstractComputerBlock.java index 4c1beb0e3..b91b8d73f 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/AbstractComputerBlock.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/AbstractComputerBlock.java @@ -7,19 +7,14 @@ import dan200.computercraft.annotations.ForgeOverride; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.shared.common.IBundledRedstoneBlock; -import dan200.computercraft.shared.computer.items.IComputerItem; import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.platform.RegistryEntry; import dan200.computercraft.shared.util.BlockEntityHelpers; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.stats.Stats; -import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.MenuProvider; -import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.BlockGetter; @@ -27,16 +22,14 @@ import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.HorizontalDirectionalBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityTicker; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.storage.loot.LootParams; -import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; import javax.annotation.Nullable; @@ -52,8 +45,7 @@ protected AbstractComputerBlock(Properties settings, RegistryEntry out.accept(getItem(computer))); - for (var item : state.getDrops(context)) { - popResource(world, pos, item); - } - - state.spawnAfterBreak(serverWorld, pos, player.getMainHandItem(), true); - } - - return result; + return super.playerWillDestroy(world, pos, state, player); } @Override - public void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) { - super.setPlacedBy(world, pos, state, placer, stack); - - var tile = world.getBlockEntity(pos); - if (!world.isClientSide && tile instanceof IComputerBlockEntity computer && stack.getItem() instanceof IComputerItem item) { - - var id = item.getComputerID(stack); - if (id != -1) computer.setComputerID(id); - - var label = item.getLabel(stack); - if (label != null) computer.setLabel(label); - } - } - - @Override - @Deprecated - public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { + protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) { if (!player.isCrouching() && level.getBlockEntity(pos) instanceof AbstractComputerBlockEntity computer) { // Regular right click to activate computer if (!level.isClientSide && computer.isUsable(player)) { @@ -173,12 +131,11 @@ public InteractionResult use(BlockState state, Level level, BlockPos pos, Player return InteractionResult.sidedSuccess(level.isClientSide); } - return super.use(state, level, pos, player, hand, hit); + return super.useWithoutItem(state, level, pos, player, hit); } @Override - @Deprecated - public final void neighborChanged(BlockState state, Level world, BlockPos pos, Block neighbourBlock, BlockPos neighbourPos, boolean isMoving) { + protected final void neighborChanged(BlockState state, Level world, BlockPos pos, Block neighbourBlock, BlockPos neighbourPos, boolean isMoving) { var be = world.getBlockEntity(pos); if (be instanceof AbstractComputerBlockEntity computer) computer.neighborChanged(neighbourPos); } @@ -190,8 +147,7 @@ public final void onNeighborChange(BlockState state, LevelReader world, BlockPos } @Override - @Deprecated - public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) { + protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) { var be = level.getBlockEntity(pos); if (be instanceof AbstractComputerBlockEntity computer) computer.neighbourShapeChanged(direction); @@ -200,8 +156,7 @@ public BlockState updateShape(BlockState state, Direction direction, BlockState @Nullable @Override - @Deprecated - public MenuProvider getMenuProvider(BlockState state, Level level, BlockPos pos) { + protected MenuProvider getMenuProvider(BlockState state, Level level, BlockPos pos) { return level.getBlockEntity(pos) instanceof AbstractComputerBlockEntity computer ? computer : null; } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/AbstractComputerBlockEntity.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/AbstractComputerBlockEntity.java index 1486505cc..5716ffcc8 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/AbstractComputerBlockEntity.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/AbstractComputerBlockEntity.java @@ -9,18 +9,19 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.impl.BundledRedstone; +import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.core.ServerContext; import dan200.computercraft.shared.platform.ComponentAccess; import dan200.computercraft.shared.platform.PlatformHelper; -import dan200.computercraft.shared.util.BlockEntityHelpers; -import dan200.computercraft.shared.util.DirectionUtil; -import dan200.computercraft.shared.util.IDAssigner; -import dan200.computercraft.shared.util.RedstoneUtil; +import dan200.computercraft.shared.util.*; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.component.DataComponentMap; +import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; @@ -76,8 +77,8 @@ public void setRemoved() { unload(); } - protected int getInteractRange() { - return Container.DEFAULT_DISTANCE_LIMIT; + protected float getInteractRange() { + return Container.DEFAULT_DISTANCE_BUFFER; } public boolean isUsable(Player player) { @@ -137,7 +138,7 @@ protected void serverTick() { protected abstract void updateBlockState(ComputerState newState); @Override - public void saveAdditional(CompoundTag nbt) { + public void saveAdditional(CompoundTag nbt, HolderLookup.Provider registries) { // Save ID, label and power state if (computerID >= 0) nbt.putInt(NBT_ID, computerID); if (label != null) nbt.putString(NBT_LABEL, label); @@ -145,20 +146,20 @@ public void saveAdditional(CompoundTag nbt) { lockCode.addToTag(nbt); - super.saveAdditional(nbt); + super.saveAdditional(nbt, registries); } @Override - public final void load(CompoundTag nbt) { - super.load(nbt); + public final void loadAdditional(CompoundTag nbt, HolderLookup.Provider registries) { + super.loadAdditional(nbt, registries); if (level != null && level.isClientSide) { - loadClient(nbt); + loadClient(nbt, registries); } else { - loadServer(nbt); + loadServer(nbt, registries); } } - protected void loadServer(CompoundTag nbt) { + protected void loadServer(CompoundTag nbt, HolderLookup.Provider registries) { // Load ID, label and power state computerID = nbt.contains(NBT_ID) ? nbt.getInt(NBT_ID) : -1; label = nbt.contains(NBT_LABEL) ? nbt.getString(NBT_LABEL) : null; @@ -167,6 +168,31 @@ protected void loadServer(CompoundTag nbt) { lockCode = LockCode.fromTag(nbt); } + @Override + protected void applyImplicitComponents(DataComponentInput component) { + super.applyImplicitComponents(component); + label = DataComponentUtil.getCustomName(component.get(DataComponents.CUSTOM_NAME)); + computerID = NonNegativeId.getId(component.get(ModRegistry.DataComponents.COMPUTER_ID.get())); + lockCode = component.getOrDefault(DataComponents.LOCK, LockCode.NO_LOCK); + } + + @Override + protected void collectImplicitComponents(DataComponentMap.Builder builder) { + super.collectImplicitComponents(builder); + builder.set(ModRegistry.DataComponents.COMPUTER_ID.get(), NonNegativeId.of(computerID)); + builder.set(DataComponents.CUSTOM_NAME, label == null ? null : Component.literal(label)); + if (lockCode != LockCode.NO_LOCK) builder.set(DataComponents.LOCK, lockCode); + } + + @Override + @Deprecated + public void removeComponentsFromTag(CompoundTag tag) { + super.removeComponentsFromTag(tag); + tag.remove(NBT_ID); + tag.remove(NBT_LABEL); + tag.remove(LockCode.TAG_LOCK); + } + protected boolean isPeripheralBlockedOnSide(ComputerSide localSide) { return false; } @@ -370,15 +396,15 @@ public final ClientboundBlockEntityDataPacket getUpdatePacket() { } @Override - public CompoundTag getUpdateTag() { + public CompoundTag getUpdateTag(HolderLookup.Provider registries) { // We need this for pick block on the client side. - var nbt = super.getUpdateTag(); + var nbt = super.getUpdateTag(registries); if (label != null) nbt.putString(NBT_LABEL, label); if (computerID >= 0) nbt.putInt(NBT_ID, computerID); return nbt; } - protected void loadClient(CompoundTag nbt) { + protected void loadClient(CompoundTag nbt, HolderLookup.Provider registries) { label = nbt.contains(NBT_LABEL) ? nbt.getString(NBT_LABEL) : null; computerID = nbt.contains(NBT_ID) ? nbt.getInt(NBT_ID) : -1; } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerBlock.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerBlock.java index 6d594c6b3..417834708 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerBlock.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerBlock.java @@ -7,11 +7,9 @@ import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import dan200.computercraft.shared.computer.core.ComputerState; -import dan200.computercraft.shared.computer.items.ComputerItem; import dan200.computercraft.shared.platform.RegistryEntry; import dan200.computercraft.shared.util.BlockCodecs; import net.minecraft.core.Direction; -import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntityType; @@ -55,12 +53,4 @@ protected MapCodec> codec() { public BlockState getStateForPlacement(BlockPlaceContext placement) { return defaultBlockState().setValue(FACING, placement.getHorizontalDirection().getOpposite()); } - - @Override - protected ItemStack getItem(AbstractComputerBlockEntity tile) { - if (!(tile instanceof ComputerBlockEntity computer)) return ItemStack.EMPTY; - if (!(asItem() instanceof ComputerItem item)) return ItemStack.EMPTY; - - return item.create(computer.getComputerID(), computer.getLabel()); - } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/items/AbstractComputerItem.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/items/AbstractComputerItem.java index f9499e7dc..73ff33c56 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/items/AbstractComputerItem.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/items/AbstractComputerItem.java @@ -7,30 +7,32 @@ import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.filesystem.Mount; import dan200.computercraft.api.media.IMedia; +import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.computer.blocks.AbstractComputerBlock; import dan200.computercraft.shared.config.Config; +import dan200.computercraft.shared.util.DataComponentUtil; import net.minecraft.ChatFormatting; +import net.minecraft.core.component.DataComponents; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; -import net.minecraft.world.level.Level; import javax.annotation.Nullable; import java.util.List; -public abstract class AbstractComputerItem extends BlockItem implements IComputerItem, IMedia { +public class AbstractComputerItem extends BlockItem implements IMedia { public AbstractComputerItem(AbstractComputerBlock block, Properties settings) { super(block, settings); } @Override - public void appendHoverText(ItemStack stack, @Nullable Level world, List list, TooltipFlag options) { - if (options.isAdvanced() || getLabel(stack) == null) { - var id = getComputerID(stack); - if (id >= 0) { - list.add(Component.translatable("gui.computercraft.tooltip.computer_id", id) + public void appendHoverText(ItemStack stack, TooltipContext context, List list, TooltipFlag options) { + if (options.isAdvanced() || !stack.has(DataComponents.CUSTOM_NAME)) { + var id = stack.get(ModRegistry.DataComponents.COMPUTER_ID.get()); + if (id != null) { + list.add(Component.translatable("gui.computercraft.tooltip.computer_id", id.id()) .withStyle(ChatFormatting.GRAY)); } } @@ -38,22 +40,18 @@ public void appendHoverText(ItemStack stack, @Nullable Level world, List= 0 ? ComputerCraftAPI.createSaveDirMount(level.getServer(), "computer/" + id, Config.computerSpaceLimit) : null; + var id = stack.get(ModRegistry.DataComponents.COMPUTER_ID.get()); + return id != null ? ComputerCraftAPI.createSaveDirMount(level.getServer(), "computer/" + id.id(), Config.computerSpaceLimit) : null; } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/items/ComputerItem.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/items/ComputerItem.java index 56170e454..af637288c 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/items/ComputerItem.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/items/ComputerItem.java @@ -5,28 +5,10 @@ package dan200.computercraft.shared.computer.items; import dan200.computercraft.shared.computer.blocks.ComputerBlock; -import net.minecraft.network.chat.Component; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; - -import javax.annotation.Nullable; public class ComputerItem extends AbstractComputerItem { + // TODO: Do we deprecate this? public ComputerItem(ComputerBlock block, Properties settings) { super(block, settings); } - - public ItemStack create(int id, @Nullable String label) { - var result = new ItemStack(this); - if (id >= 0) result.getOrCreateTag().putInt(NBT_ID, id); - if (label != null) result.setHoverName(Component.literal(label)); - return result; - } - - @Override - public ItemStack changeItem(ItemStack stack, Item newItem) { - return newItem instanceof ComputerItem computer - ? computer.create(getComputerID(stack), getLabel(stack)) - : ItemStack.EMPTY; - } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java deleted file mode 100644 index 03bcb762e..000000000 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. -// -// SPDX-License-Identifier: LicenseRef-CCPL - -package dan200.computercraft.shared.computer.items; - -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; - -import javax.annotation.Nullable; - -public interface IComputerItem { - String NBT_ID = "ComputerId"; - - default int getComputerID(ItemStack stack) { - var nbt = stack.getTag(); - return nbt != null && nbt.contains(NBT_ID) ? nbt.getInt(NBT_ID) : -1; - } - - default @Nullable String getLabel(ItemStack stack) { - return stack.hasCustomHoverName() ? stack.getHoverName().getString() : null; - } - - /** - * Create a new stack, changing the underlying item. - *

- * This should copy the computer's data to a different item of the same type (for instance, converting a normal - * computer to an advanced one). - * - * @param stack The current computer stack. - * @param newItem The new item. - * @return The new stack, possibly {@linkplain ItemStack#EMPTY empty} if {@code newItem} is of the same type. - */ - ItemStack changeItem(ItemStack stack, Item newItem); -} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/items/ServerComputerReference.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/items/ServerComputerReference.java new file mode 100644 index 000000000..250ae30a9 --- /dev/null +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/items/ServerComputerReference.java @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.shared.computer.items; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import dan200.computercraft.shared.ModRegistry; +import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.core.ServerComputerRegistry; +import net.minecraft.core.UUIDUtil; +import net.minecraft.core.component.DataComponentHolder; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; + +import javax.annotation.Nullable; +import java.util.UUID; + +/** + * A reference to a {@link ServerComputer}. + * + * @param session The current {@linkplain ServerComputerRegistry#getSessionID() session id}. + * @param instance The computer's {@linkplain ServerComputer#getInstanceUUID() instance id}. + */ +public record ServerComputerReference(int session, UUID instance) { + public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( + Codec.INT.fieldOf("session").forGetter(ServerComputerReference::session), + UUIDUtil.CODEC.fieldOf("instance").forGetter(ServerComputerReference::instance) + ).apply(i, ServerComputerReference::new)); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.VAR_INT, ServerComputerReference::session, + UUIDUtil.STREAM_CODEC, ServerComputerReference::instance, + ServerComputerReference::new + ); + + public @Nullable ServerComputer get(ServerComputerRegistry registry) { + return registry.get(session, this.instance()); + } + + public static @Nullable ServerComputer get(DataComponentHolder holder, ServerComputerRegistry registry) { + var reference = holder.get(ModRegistry.DataComponents.COMPUTER.get()); + return reference == null ? null : reference.get(registry); + } +} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java index e2cc16aec..15cc56e67 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java @@ -4,43 +4,50 @@ package dan200.computercraft.shared.computer.recipe; -import dan200.computercraft.shared.computer.items.IComputerItem; +import dan200.computercraft.shared.ModRegistry; +import dan200.computercraft.shared.computer.items.AbstractComputerItem; +import dan200.computercraft.shared.pocket.items.PocketComputerItem; import dan200.computercraft.shared.recipe.CustomShapedRecipe; import dan200.computercraft.shared.recipe.ShapedRecipeSpec; -import net.minecraft.core.RegistryAccess; +import net.minecraft.core.HolderLookup; import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; +import net.minecraft.world.item.crafting.RecipeSerializer; /** * A recipe which converts a computer from one form into another. */ -public abstract class ComputerConvertRecipe extends CustomShapedRecipe { +public final class ComputerConvertRecipe extends CustomShapedRecipe { + private final Item result; + public ComputerConvertRecipe(ShapedRecipeSpec recipe) { super(recipe); - } - - protected abstract ItemStack convert(IComputerItem item, ItemStack stack); - - @Override - public boolean matches(CraftingContainer inventory, Level world) { - if (!super.matches(inventory, world)) return false; - - for (var i = 0; i < inventory.getContainerSize(); i++) { - if (inventory.getItem(i).getItem() instanceof IComputerItem) return true; - } - - return false; + this.result = recipe.result().getItem(); } @Override - public ItemStack assemble(CraftingContainer inventory, RegistryAccess registryAccess) { - // Find our computer item and convert it. + public ItemStack assemble(CraftingContainer inventory, HolderLookup.Provider registryAccess) { + // Find our computer item and copy the components across. for (var i = 0; i < inventory.getContainerSize(); i++) { var stack = inventory.getItem(i); - if (stack.getItem() instanceof IComputerItem) return convert((IComputerItem) stack.getItem(), stack); + if (isComputerItem(stack.getItem())) { + var newStack = new ItemStack(result); + newStack.applyComponents(stack.getComponentsPatch()); + return newStack; + } } return ItemStack.EMPTY; } + + @Override + public RecipeSerializer getSerializer() { + return ModRegistry.RecipeSerializers.COMPUTER_CONVERT.get(); + } + + private static boolean isComputerItem(Item item) { + // TODO: Make this a little more general. Either with a tag, or a predicate on the recipe itself? + return item instanceof AbstractComputerItem || item instanceof PocketComputerItem; + } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java deleted file mode 100644 index 4ae1a1f32..000000000 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-FileCopyrightText: 2019 The CC: Tweaked Developers -// -// SPDX-License-Identifier: MPL-2.0 - -package dan200.computercraft.shared.computer.recipe; - -import com.mojang.serialization.DataResult; -import dan200.computercraft.shared.ModRegistry; -import dan200.computercraft.shared.computer.items.IComputerItem; -import dan200.computercraft.shared.recipe.ShapedRecipeSpec; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.RecipeSerializer; - -/** - * A recipe which "upgrades" a {@linkplain IComputerItem computer}, converting to it a new item (for instance a normal - * turtle to an advanced one). - * - * @see IComputerItem#changeItem(ItemStack, Item) - */ -public final class ComputerUpgradeRecipe extends ComputerConvertRecipe { - private final Item result; - - public ComputerUpgradeRecipe(ShapedRecipeSpec recipe) { - super(recipe); - this.result = recipe.result().getItem(); - } - - public static DataResult of(ShapedRecipeSpec recipe) { - if (!(recipe.result().getItem() instanceof IComputerItem)) { - return DataResult.error(() -> recipe.result().getItem() + " is not a computer item"); - } - - return DataResult.success(new ComputerUpgradeRecipe(recipe)); - } - - @Override - protected ItemStack convert(IComputerItem item, ItemStack stack) { - return item.changeItem(stack, result); - } - - @Override - public RecipeSerializer getSerializer() { - return ModRegistry.RecipeSerializers.COMPUTER_UPGRADE.get(); - } -} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/terminal/TerminalState.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/terminal/TerminalState.java index 13d23561b..e397c70e3 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/terminal/TerminalState.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/terminal/TerminalState.java @@ -7,6 +7,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import org.jetbrains.annotations.Contract; import javax.annotation.Nullable; @@ -19,6 +20,8 @@ * states, etc... */ public class TerminalState { + public static final StreamCodec STREAM_CODEC = StreamCodec.ofMember(TerminalState::write, TerminalState::new); + private final boolean colour; private final int width; private final int height; @@ -38,7 +41,7 @@ public TerminalState(NetworkedTerminal terminal) { return terminal == null ? null : new TerminalState(terminal); } - public TerminalState(FriendlyByteBuf buf) { + private TerminalState(FriendlyByteBuf buf) { colour = buf.readBoolean(); width = buf.readVarInt(); height = buf.readVarInt(); @@ -47,7 +50,7 @@ public TerminalState(FriendlyByteBuf buf) { buffer = buf.readBytes(length); } - public void write(FriendlyByteBuf buf) { + private void write(FriendlyByteBuf buf) { buf.writeBoolean(colour); buf.writeVarInt(width); buf.writeVarInt(height); diff --git a/projects/common/src/main/java/dan200/computercraft/shared/container/BasicContainer.java b/projects/common/src/main/java/dan200/computercraft/shared/container/BasicContainer.java index 6680725da..8541329b8 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/container/BasicContainer.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/container/BasicContainer.java @@ -10,19 +10,19 @@ import net.minecraft.world.item.ItemStack; /** - * A basic implementation of {@link Container} which operates on a {@linkplain #getContents() list of stacks}. + * A basic implementation of {@link Container} which operates on a {@linkplain #getItems() list of stacks}. */ public interface BasicContainer extends Container { - NonNullList getContents(); + NonNullList getItems(); @Override default int getContainerSize() { - return getContents().size(); + return getItems().size(); } @Override default boolean isEmpty() { - for (var stack : getContents()) { + for (var stack : getItems()) { if (!stack.isEmpty()) return false; } @@ -31,27 +31,33 @@ default boolean isEmpty() { @Override default ItemStack getItem(int slot) { - var contents = getContents(); + var contents = getItems(); return slot >= 0 && slot < contents.size() ? contents.get(slot) : ItemStack.EMPTY; } @Override default ItemStack removeItemNoUpdate(int slot) { - return ContainerHelper.takeItem(getContents(), slot); + return ContainerHelper.takeItem(getItems(), slot); } @Override default ItemStack removeItem(int slot, int count) { - return ContainerHelper.removeItem(getContents(), slot, count); + return ContainerHelper.removeItem(getItems(), slot, count); } @Override default void setItem(int slot, ItemStack itemStack) { - getContents().set(slot, itemStack); + getItems().set(slot, itemStack); } @Override default void clearContent() { - getContents().clear(); + getItems().clear(); + } + + static void defaultSetItems(NonNullList inventory, NonNullList items) { + var i = 0; + for (; i < items.size(); i++) inventory.set(i, items.get(i)); + for (; i < inventory.size(); i++) inventory.set(i, ItemStack.EMPTY); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/container/BasicWorldlyContainer.java b/projects/common/src/main/java/dan200/computercraft/shared/container/BasicWorldlyContainer.java index b2e92bd79..e3f389913 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/container/BasicWorldlyContainer.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/container/BasicWorldlyContainer.java @@ -11,7 +11,7 @@ import javax.annotation.Nullable; /** - * A basic implementation of {@link WorldlyContainer} which operates on a {@linkplain #getContents() list of stacks}. + * A basic implementation of {@link WorldlyContainer} which operates on a {@linkplain #getItems() list of stacks}. */ public interface BasicWorldlyContainer extends BasicContainer, WorldlyContainer { @Override diff --git a/projects/common/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java b/projects/common/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java index 0601b8485..db8bfc85d 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java @@ -27,7 +27,7 @@ private PlayerCreativeLootCondition() { @Override public boolean test(LootContext lootContext) { var entity = lootContext.getParamOrNull(LootContextParams.THIS_ENTITY); - return entity instanceof Player player && player.getAbilities().instabuild; + return entity instanceof Player player && player.isCreative(); } @Override diff --git a/projects/common/src/main/java/dan200/computercraft/shared/details/ItemDetails.java b/projects/common/src/main/java/dan200/computercraft/shared/details/ItemDetails.java index ca5b1ad2f..7d16804c2 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/details/ItemDetails.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/details/ItemDetails.java @@ -4,20 +4,23 @@ package dan200.computercraft.shared.details; -import com.google.gson.JsonParseException; import dan200.computercraft.shared.util.NBTUtil; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.component.DataComponents; import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; +import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.CreativeModeTabs; -import net.minecraft.world.item.EnchantedBookItem; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.item.enchantment.ItemEnchantments; import javax.annotation.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * Data providers for items. @@ -26,7 +29,9 @@ public class ItemDetails { public static void fillBasic(Map data, ItemStack stack) { data.put("name", DetailHelpers.getId(BuiltInRegistries.ITEM, stack.getItem())); data.put("count", stack.getCount()); - var hash = NBTUtil.getNBTHash(stack.getTag()); + + var components = stack.getComponentsPatch(); + var hash = components.isEmpty() ? null : NBTUtil.getNBTHash(DataComponentPatch.CODEC.encodeStart(NbtOps.INSTANCE, components).result().orElse(null)); if (hash != null) data.put("nbt", hash); } @@ -46,41 +51,14 @@ public static void fill(Map data, ItemStack stack) { data.put("tags", DetailHelpers.getTags(stack.getTags())); data.put("itemGroups", getItemGroups(stack)); - var tag = stack.getTag(); - if (tag != null && tag.contains("display", Tag.TAG_COMPOUND)) { - var displayTag = tag.getCompound("display"); - if (displayTag.contains("Lore", Tag.TAG_LIST)) { - var loreTag = displayTag.getList("Lore", Tag.TAG_STRING); - data.put("lore", loreTag.stream() - .map(ItemDetails::parseTextComponent) - .filter(Objects::nonNull) - .map(Component::getString) - .toList()); - } - } + var lore = stack.get(DataComponents.LORE); + if (lore != null) data.put("lore", lore.lines().stream().map(Component::getString).toList()); - /* - * Used to hide some data from ItemStack tooltip. - * @see https://minecraft.wiki/w/Tutorials/Command_NBT_tags - * @see ItemStack#getTooltip - */ - var hideFlags = tag != null ? tag.getInt("HideFlags") : 0; - - var enchants = getAllEnchants(stack, hideFlags); + var enchants = getAllEnchants(stack); if (!enchants.isEmpty()) data.put("enchantments", enchants); - if (tag != null && tag.getBoolean("Unbreakable") && (hideFlags & 4) == 0) { - data.put("unbreakable", true); - } - } - - @Nullable - private static Component parseTextComponent(Tag x) { - try { - return Component.Serializer.fromJson(x.getAsString()); - } catch (JsonParseException e) { - return null; - } + var unbreakable = stack.get(DataComponents.UNBREAKABLE); + if (unbreakable != null && unbreakable.showInTooltip()) data.put("unbreakable", true); } /** @@ -107,26 +85,13 @@ private static List> getItemGroups(ItemStack stack) { /** * Retrieve all visible enchantments from given stack. Try to follow all tooltip rules : order and visibility. * - * @param stack Stack to analyse - * @param hideFlags An int used as bit field to provide visibility rules. + * @param stack Stack to analyse * @return A filled list that contain all visible enchantments. */ - private static List> getAllEnchants(ItemStack stack, int hideFlags) { + private static List> getAllEnchants(ItemStack stack) { var enchants = new ArrayList>(0); - - if (stack.getItem() instanceof EnchantedBookItem && (hideFlags & 32) == 0) { - addEnchantments(EnchantedBookItem.getEnchantments(stack), enchants); - } - - if (stack.isEnchanted() && (hideFlags & 1) == 0) { - /* - * Mimic the EnchantmentHelper.getEnchantments(ItemStack stack) behavior without special case for Enchanted book. - * I'll do that to have the same data than ones displayed in tooltip. - * @see EnchantmentHelper.getEnchantments(ItemStack stack) - */ - addEnchantments(stack.getEnchantmentTags(), enchants); - } - + addEnchantments(stack.get(DataComponents.STORED_ENCHANTMENTS), enchants); + addEnchantments(stack.get(DataComponents.ENCHANTMENTS), enchants); return enchants; } @@ -138,18 +103,18 @@ private static List> getAllEnchants(ItemStack stack, int hid * @see EnchantmentHelper */ @SuppressWarnings("NonApiType") - private static void addEnchantments(ListTag rawEnchants, ArrayList> enchants) { - if (rawEnchants.isEmpty()) return; + private static void addEnchantments(@Nullable ItemEnchantments rawEnchants, ArrayList> enchants) { + if (rawEnchants == null || rawEnchants.isEmpty()) return; enchants.ensureCapacity(enchants.size() + rawEnchants.size()); - for (var entry : EnchantmentHelper.deserializeEnchantments(rawEnchants).entrySet()) { + for (var entry : rawEnchants.entrySet()) { var enchantment = entry.getKey(); - var level = entry.getValue(); + var level = entry.getIntValue(); var enchant = new HashMap(3); - enchant.put("name", DetailHelpers.getId(BuiltInRegistries.ENCHANTMENT, enchantment)); + enchant.put("name", DetailHelpers.getId(BuiltInRegistries.ENCHANTMENT, enchantment.value())); enchant.put("level", level); - enchant.put("displayName", enchantment.getFullname(level).getString()); + enchant.put("displayName", enchantment.value().getFullname(level).getString()); enchants.add(enchant); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/integration/RecipeModHelpers.java b/projects/common/src/main/java/dan200/computercraft/shared/integration/RecipeModHelpers.java index 44b0c7c3d..ae13e6436 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/integration/RecipeModHelpers.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/integration/RecipeModHelpers.java @@ -11,6 +11,7 @@ import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.pocket.items.PocketComputerItem; import dan200.computercraft.shared.turtle.items.TurtleItem; +import dan200.computercraft.shared.util.DataComponentUtil; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; @@ -54,14 +55,14 @@ public static List getExtraStacks() { for (var turtleSupplier : TURTLES) { var turtle = turtleSupplier.get(); for (var upgrade : TurtleUpgrades.instance().getUpgrades()) { - upgradeItems.add(turtle.create(-1, null, -1, null, UpgradeData.ofDefault(upgrade), 0, null)); + upgradeItems.add(DataComponentUtil.createStack(turtle, ModRegistry.DataComponents.RIGHT_TURTLE_UPGRADE.get(), UpgradeData.ofDefault(upgrade))); } } for (var pocketSupplier : POCKET_COMPUTERS) { var pocket = pocketSupplier.get(); for (var upgrade : PocketUpgrades.instance().getUpgrades()) { - upgradeItems.add(pocket.create(-1, null, -1, UpgradeData.ofDefault(upgrade))); + upgradeItems.add(DataComponentUtil.createStack(pocket, ModRegistry.DataComponents.POCKET_UPGRADE.get(), UpgradeData.ofDefault(upgrade))); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/integration/UpgradeRecipeGenerator.java b/projects/common/src/main/java/dan200/computercraft/shared/integration/UpgradeRecipeGenerator.java index 925e5e344..e4904516c 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/integration/UpgradeRecipeGenerator.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/integration/UpgradeRecipeGenerator.java @@ -11,8 +11,10 @@ import dan200.computercraft.api.upgrades.UpgradeData; import dan200.computercraft.impl.PocketUpgrades; import dan200.computercraft.impl.TurtleUpgrades; +import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.pocket.items.PocketComputerItem; import dan200.computercraft.shared.turtle.items.TurtleItem; +import dan200.computercraft.shared.util.DataComponentUtil; import net.minecraft.core.NonNullList; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -105,10 +107,10 @@ public boolean isUpgrade(ItemStack stack) { public List findRecipesWithInput(ItemStack stack) { setupCache(); - if (stack.getItem() instanceof TurtleItem item) { + if (stack.getItem() instanceof TurtleItem) { // Suggest possible upgrades which can be applied to this turtle - var left = item.getUpgradeWithData(stack, TurtleSide.LEFT); - var right = item.getUpgradeWithData(stack, TurtleSide.RIGHT); + var left = TurtleItem.getUpgradeWithData(stack, TurtleSide.LEFT); + var right = TurtleItem.getUpgradeWithData(stack, TurtleSide.RIGHT); if (left != null && right != null) return List.of(); List recipes = new ArrayList<>(); @@ -176,11 +178,11 @@ public List findRecipesWithInput(ItemStack stack) { */ public List findRecipesWithOutput(ItemStack stack) { // Find which upgrade this item currently has, and so how we could build it. - if (stack.getItem() instanceof TurtleItem item) { + if (stack.getItem() instanceof TurtleItem) { List recipes = new ArrayList<>(0); - var left = item.getUpgradeWithData(stack, TurtleSide.LEFT); - var right = item.getUpgradeWithData(stack, TurtleSide.RIGHT); + var left = TurtleItem.getUpgradeWithData(stack, TurtleSide.LEFT); + var right = TurtleItem.getUpgradeWithData(stack, TurtleSide.RIGHT); // The turtle is facing towards us, so upgrades on the left are actually crafted on the right. if (left != null) { @@ -215,18 +217,16 @@ public List findRecipesWithOutput(ItemStack stack) { } private static ItemStack turtleWith(ItemStack stack, @Nullable UpgradeData left, @Nullable UpgradeData right) { - var item = (TurtleItem) stack.getItem(); - return item.create( - item.getComputerID(stack), item.getLabel(stack), item.getColour(stack), - left, right, item.getFuelLevel(stack), item.getOverlay(stack) - ); + var newStack = stack.copyWithCount(1); + newStack.set(ModRegistry.DataComponents.LEFT_TURTLE_UPGRADE.get(), left); + newStack.set(ModRegistry.DataComponents.RIGHT_TURTLE_UPGRADE.get(), right); + return stack; } private static ItemStack pocketWith(ItemStack stack, @Nullable UpgradeData back) { - var item = (PocketComputerItem) stack.getItem(); - return item.create( - item.getComputerID(stack), item.getLabel(stack), item.getColour(stack), back - ); + var newStack = stack.copyWithCount(1); + newStack.set(ModRegistry.DataComponents.POCKET_UPGRADE.get(), back); + return stack; } private T pocket(Ingredient upgrade, Ingredient pocketComputer, ItemStack result) { @@ -278,8 +278,8 @@ List getRecipes() { var turtleItem = turtleSupplier.get(); recipes.add(turtle( ingredient, // Right upgrade, recipe on left - Ingredient.of(turtleItem.create(-1, null, -1, null, null, 0, null)), - turtleItem.create(-1, null, -1, null, UpgradeData.ofDefault(turtle), 0, null) + Ingredient.of(new ItemStack(turtleItem)), + DataComponentUtil.createStack(turtleItem, ModRegistry.DataComponents.RIGHT_TURTLE_UPGRADE.get(), UpgradeData.ofDefault(turtle)) )); } } @@ -289,8 +289,8 @@ List getRecipes() { var pocketItem = pocketSupplier.get(); recipes.add(pocket( ingredient, - Ingredient.of(pocketItem.create(-1, null, -1, null)), - pocketItem.create(-1, null, -1, UpgradeData.ofDefault(pocket)) + Ingredient.of(pocketItem), + DataComponentUtil.createStack(pocketItem, ModRegistry.DataComponents.POCKET_UPGRADE.get(), UpgradeData.ofDefault(pocket)) )); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java b/projects/common/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java index 3642491a1..825e80bd9 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java @@ -70,14 +70,11 @@ public void onRuntimeAvailable(IJeiRuntime runtime) { * Distinguishes turtles by upgrades and family. */ private static final IIngredientSubtypeInterpreter turtleSubtype = (stack, ctx) -> { - var item = stack.getItem(); - if (!(item instanceof TurtleItem turtle)) return IIngredientSubtypeInterpreter.NONE; - var name = new StringBuilder("turtle:"); // Add left and right upgrades to the identifier - var left = turtle.getUpgrade(stack, TurtleSide.LEFT); - var right = turtle.getUpgrade(stack, TurtleSide.RIGHT); + var left = TurtleItem.getUpgrade(stack, TurtleSide.LEFT); + var right = TurtleItem.getUpgrade(stack, TurtleSide.RIGHT); if (left != null) name.append(left.getUpgradeID()); if (left != null && right != null) name.append('|'); if (right != null) name.append(right.getUpgradeID()); @@ -89,9 +86,6 @@ public void onRuntimeAvailable(IJeiRuntime runtime) { * Distinguishes pocket computers by upgrade and family. */ private static final IIngredientSubtypeInterpreter pocketSubtype = (stack, ctx) -> { - var item = stack.getItem(); - if (!(item instanceof PocketComputerItem)) return IIngredientSubtypeInterpreter.NONE; - var name = new StringBuilder("pocket:"); // Add the upgrade to the identifier @@ -104,11 +98,5 @@ public void onRuntimeAvailable(IJeiRuntime runtime) { /** * Distinguishes disks by colour. */ - private static final IIngredientSubtypeInterpreter diskSubtype = (stack, ctx) -> { - var item = stack.getItem(); - if (!(item instanceof DiskItem disk)) return IIngredientSubtypeInterpreter.NONE; - - var colour = disk.getColour(stack); - return colour == -1 ? IIngredientSubtypeInterpreter.NONE : String.format("%06x", colour); - }; + private static final IIngredientSubtypeInterpreter diskSubtype = (stack, ctx) -> Integer.toString(DiskItem.getColour(stack)); } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/media/items/DiskItem.java b/projects/common/src/main/java/dan200/computercraft/shared/media/items/DiskItem.java index 0b38fa8fe..59fbbbf33 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/media/items/DiskItem.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/media/items/DiskItem.java @@ -10,43 +10,34 @@ import dan200.computercraft.api.media.IMedia; import dan200.computercraft.core.util.Colour; import dan200.computercraft.shared.ModRegistry; -import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.config.Config; +import dan200.computercraft.shared.util.NonNegativeId; import net.minecraft.ChatFormatting; import net.minecraft.core.BlockPos; +import net.minecraft.core.component.DataComponents; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; -import net.minecraft.world.level.Level; +import net.minecraft.world.item.component.DyedItemColor; import net.minecraft.world.level.LevelReader; import javax.annotation.Nullable; import java.util.List; -public class DiskItem extends Item implements IMedia, IColouredItem { - private static final String NBT_ID = "DiskId"; - +public class DiskItem extends Item implements IMedia { public DiskItem(Properties settings) { super(settings); } - public static ItemStack createFromIDAndColour(int id, @Nullable String label, int colour) { - var stack = new ItemStack(ModRegistry.Items.DISK.get()); - setDiskID(stack, id); - ModRegistry.Items.DISK.get().setLabel(stack, label); - IColouredItem.setColourBasic(stack, colour); - return stack; - } - @Override - public void appendHoverText(ItemStack stack, @Nullable Level world, List list, TooltipFlag options) { + public void appendHoverText(ItemStack stack, TooltipContext context, List list, TooltipFlag options) { if (options.isAdvanced()) { - var id = getDiskID(stack); - if (id >= 0) { - list.add(Component.translatable("gui.computercraft.tooltip.disk_id", id) + var id = stack.get(ModRegistry.DataComponents.DISK_ID.get()); + if (id != null) { + list.add(Component.translatable("gui.computercraft.tooltip.disk_id", id.id()) .withStyle(ChatFormatting.GRAY)); } } @@ -59,41 +50,27 @@ public boolean doesSneakBypassUse(ItemStack stack, LevelReader world, BlockPos p @Override public @Nullable String getLabel(ItemStack stack) { - return stack.hasCustomHoverName() ? stack.getHoverName().getString() : null; + var label = stack.get(DataComponents.CUSTOM_NAME); + return label != null ? label.getString() : null; } @Override public boolean setLabel(ItemStack stack, @Nullable String label) { - if (label != null) { - stack.setHoverName(Component.literal(label)); - } else { - stack.resetHoverName(); - } + stack.set(DataComponents.CUSTOM_NAME, label != null ? Component.literal(label) : null); return true; } @Override public @Nullable Mount createDataMount(ItemStack stack, ServerLevel level) { - var diskID = getDiskID(stack); - if (diskID < 0) { - diskID = ComputerCraftAPI.createUniqueNumberedSaveDir(level.getServer(), "disk"); - setDiskID(stack, diskID); - } + var diskID = NonNegativeId.getOrCreate(level.getServer(), stack, ModRegistry.DataComponents.DISK_ID.get(), "disk"); return ComputerCraftAPI.createSaveDirMount(level.getServer(), "disk/" + diskID, Config.floppySpaceLimit); } public static int getDiskID(ItemStack stack) { - var nbt = stack.getTag(); - return nbt != null && nbt.contains(NBT_ID) ? nbt.getInt(NBT_ID) : -1; + return NonNegativeId.getId(stack.get(ModRegistry.DataComponents.DISK_ID.get())); } - private static void setDiskID(ItemStack stack, int id) { - if (id >= 0) stack.getOrCreateTag().putInt(NBT_ID, id); - } - - @Override - public int getColour(ItemStack stack) { - var colour = IColouredItem.getColourBasic(stack); - return colour == -1 ? Colour.WHITE.getHex() : colour; + public static int getColour(ItemStack stack) { + return DyedItemColor.getOrDefault(stack, Colour.WHITE.getARGB()); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/media/items/PrintoutData.java b/projects/common/src/main/java/dan200/computercraft/shared/media/items/PrintoutData.java new file mode 100644 index 000000000..680867810 --- /dev/null +++ b/projects/common/src/main/java/dan200/computercraft/shared/media/items/PrintoutData.java @@ -0,0 +1,104 @@ +// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.shared.media.items; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import dan200.computercraft.core.terminal.Terminal; +import io.netty.buffer.ByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; + +import java.util.Arrays; +import java.util.List; + +/** + * The contents of a printout. + * + * @param title The title of this printout. + * @param lines A list of lines for this printout. + * @see PrintoutItem + * @see dan200.computercraft.shared.ModRegistry.DataComponents#PRINTOUT + */ +public record PrintoutData(String title, List lines) { + public static final int LINE_LENGTH = 25; + public static final int LINES_PER_PAGE = 21; + public static final int MAX_PAGES = 16; + + /** + * An empty printout. This has no title, and is a single page of empty lines. + */ + public static final PrintoutData EMPTY; + + static { + var lines = new Line[LINES_PER_PAGE]; + Arrays.fill(lines, Line.EMPTY); + EMPTY = new PrintoutData("", List.of(lines)); + } + + private static final Codec LINE_TEXT = Codec.STRING.validate(x -> x.length() == LINE_LENGTH + ? DataResult.success(x) + : DataResult.error(() -> "Expected string of length " + LINE_LENGTH)); + + private static final Codec LINE_CODEC = RecordCodecBuilder.create(s -> s.group( + LINE_TEXT.fieldOf("text").forGetter(Line::text), + LINE_TEXT.fieldOf("foreground").forGetter(Line::foreground) + ).apply(s, Line::new)); + + private static final StreamCodec LINE_STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.STRING_UTF8, Line::text, + ByteBufCodecs.STRING_UTF8, Line::foreground, + Line::new + ); + + public static final Codec CODEC = RecordCodecBuilder.create(s -> s.group( + Codec.STRING.optionalFieldOf("title", "").forGetter(PrintoutData::title), + LINE_CODEC.listOf(1, MAX_PAGES * LINES_PER_PAGE) + .validate(PrintoutData::validateLines) + .fieldOf("lines").forGetter(PrintoutData::lines) + ).apply(s, PrintoutData::new)); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.STRING_UTF8, PrintoutData::title, + LINE_STREAM_CODEC.apply(ByteBufCodecs.list(MAX_PAGES * LINES_PER_PAGE)), PrintoutData::lines, + PrintoutData::new + ); + + /** + * A single line on our printed pages. + * + * @param text The text for this line. + * @param foreground The foreground colour of this line, in a format equivalent to {@link Terminal#getTextColourLine(int)}. + */ + public record Line(String text, String foreground) { + public static final Line EMPTY = new Line(" ".repeat(LINE_LENGTH), "f".repeat(LINE_LENGTH)); + + public Line { + if (text.length() != LINE_LENGTH) throw new IllegalArgumentException("text is of wrong length"); + if (foreground.length() != LINE_LENGTH) throw new IllegalArgumentException("foreground is of wrong length"); + } + } + + public PrintoutData { + validateLines(lines).getOrThrow(IllegalArgumentException::new); + } + + private static DataResult> validateLines(List lines) { + if (lines.isEmpty()) return DataResult.error(() -> "Expected non-empty list of lines"); + if ((lines.size() % LINES_PER_PAGE) != 0) return DataResult.error(() -> "Not enough lines for a page"); + if (lines.size() > LINES_PER_PAGE * MAX_PAGES) return DataResult.error(() -> "Too many pages"); + return DataResult.success(lines); + } + + /** + * Get the number of pages in this printout. + * + * @return The number of pages. + */ + public int pages() { + return Math.ceilDiv(lines.size(), LINES_PER_PAGE); + } +} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/media/items/PrintoutItem.java b/projects/common/src/main/java/dan200/computercraft/shared/media/items/PrintoutItem.java index c99f2b756..39af29be0 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/media/items/PrintoutItem.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/media/items/PrintoutItem.java @@ -17,19 +17,9 @@ import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.level.Level; -import javax.annotation.Nullable; import java.util.List; public class PrintoutItem extends Item { - private static final String NBT_TITLE = "Title"; - private static final String NBT_PAGES = "Pages"; - private static final String NBT_LINE_TEXT = "Text"; - private static final String NBT_LINE_COLOUR = "Color"; - - public static final int LINES_PER_PAGE = 21; - public static final int LINE_MAX_LENGTH = 25; - public static final int MAX_PAGES = 16; - public enum Type { PAGE, PAGES, @@ -44,9 +34,9 @@ public PrintoutItem(Properties settings, Type type) { } @Override - public void appendHoverText(ItemStack stack, @Nullable Level world, List list, TooltipFlag options) { + public void appendHoverText(ItemStack stack, TooltipContext context, List list, TooltipFlag options) { var title = getTitle(stack); - if (title != null && !title.isEmpty()) list.add(Component.literal(title)); + if (!title.isEmpty()) list.add(Component.literal(title)); } @Override @@ -58,70 +48,17 @@ public InteractionResultHolder use(Level world, Player player, Intera return new InteractionResultHolder<>(InteractionResult.sidedSuccess(world.isClientSide), player.getItemInHand(hand)); } - private ItemStack createFromTitleAndText(@Nullable String title, @Nullable String[] text, @Nullable String[] colours) { - var stack = new ItemStack(this); - - // Build NBT - if (title != null) stack.getOrCreateTag().putString(NBT_TITLE, title); - if (text != null) { - var tag = stack.getOrCreateTag(); - tag.putInt(NBT_PAGES, text.length / LINES_PER_PAGE); - for (var i = 0; i < text.length; i++) { - if (text[i] != null) tag.putString(NBT_LINE_TEXT + i, text[i]); - } - } - if (colours != null) { - var tag = stack.getOrCreateTag(); - for (var i = 0; i < colours.length; i++) { - if (colours[i] != null) tag.putString(NBT_LINE_COLOUR + i, colours[i]); - } - } - - - return stack; - } - - public static ItemStack createSingleFromTitleAndText(@Nullable String title, @Nullable String[] text, @Nullable String[] colours) { - return ModRegistry.Items.PRINTED_PAGE.get().createFromTitleAndText(title, text, colours); - } - - public static ItemStack createMultipleFromTitleAndText(@Nullable String title, @Nullable String[] text, @Nullable String[] colours) { - return ModRegistry.Items.PRINTED_PAGES.get().createFromTitleAndText(title, text, colours); - } - - public static ItemStack createBookFromTitleAndText(@Nullable String title, @Nullable String[] text, @Nullable String[] colours) { - return ModRegistry.Items.PRINTED_BOOK.get().createFromTitleAndText(title, text, colours); - } - public Type getType() { return type; } public static String getTitle(ItemStack stack) { - var nbt = stack.getTag(); - return nbt != null && nbt.contains(NBT_TITLE) ? nbt.getString(NBT_TITLE) : ""; + var nbt = stack.get(ModRegistry.DataComponents.PRINTOUT.get()); + return nbt == null ? "" : nbt.title(); } public static int getPageCount(ItemStack stack) { - var nbt = stack.getTag(); - return nbt != null && nbt.contains(NBT_PAGES) ? nbt.getInt(NBT_PAGES) : 1; - } - - public static String[] getText(ItemStack stack) { - return getLines(stack, NBT_LINE_TEXT); - } - - public static String[] getColours(ItemStack stack) { - return getLines(stack, NBT_LINE_COLOUR); - } - - private static String[] getLines(ItemStack stack, String prefix) { - var nbt = stack.getTag(); - var numLines = getPageCount(stack) * LINES_PER_PAGE; - var lines = new String[numLines]; - for (var i = 0; i < lines.length; i++) { - lines[i] = nbt != null ? nbt.getString(prefix + i) : ""; - } - return lines; + var nbt = stack.get(ModRegistry.DataComponents.PRINTOUT.get()); + return nbt == null ? 1 : nbt.pages(); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/media/items/TreasureDisk.java b/projects/common/src/main/java/dan200/computercraft/shared/media/items/TreasureDisk.java new file mode 100644 index 000000000..7f91c0f64 --- /dev/null +++ b/projects/common/src/main/java/dan200/computercraft/shared/media/items/TreasureDisk.java @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.shared.media.items; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import dan200.computercraft.shared.ModRegistry; +import net.minecraft.core.component.DataComponentHolder; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; + +/** + * Stores information about a {@linkplain TreasureDiskItem treasure disk's} mount. + * + * @param name The name/title of the disk. + * @param path The subpath to the resource + * @see ModRegistry.DataComponents#TREASURE_DISK + */ +public record TreasureDisk(String name, String path) { + public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( + Codec.STRING.fieldOf("name").forGetter(TreasureDisk::name), + Codec.STRING.fieldOf("path").forGetter(TreasureDisk::path) + ).apply(i, TreasureDisk::new)); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.STRING_UTF8, TreasureDisk::name, + ByteBufCodecs.STRING_UTF8, TreasureDisk::path, + TreasureDisk::new + ); + + public static String getTitle(DataComponentHolder holder) { + var nbt = holder.get(ModRegistry.DataComponents.TREASURE_DISK.get()); + return nbt != null ? nbt.name() : "'missingno' by how did you get this anyway?"; + } +} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/media/items/TreasureDiskItem.java b/projects/common/src/main/java/dan200/computercraft/shared/media/items/TreasureDiskItem.java index f5fab821a..0d768b813 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/media/items/TreasureDiskItem.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/media/items/TreasureDiskItem.java @@ -9,7 +9,6 @@ import dan200.computercraft.api.filesystem.Mount; import dan200.computercraft.api.media.IMedia; import dan200.computercraft.core.filesystem.SubMount; -import dan200.computercraft.core.util.Colour; import dan200.computercraft.shared.ModRegistry; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; @@ -18,7 +17,6 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; -import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelReader; import javax.annotation.Nullable; @@ -26,18 +24,13 @@ import java.util.List; public class TreasureDiskItem extends Item implements IMedia { - private static final String NBT_TITLE = "Title"; - private static final String NBT_COLOUR = "Colour"; - private static final String NBT_SUB_PATH = "SubPath"; - public TreasureDiskItem(Properties settings) { super(settings); } @Override - public void appendHoverText(ItemStack stack, @Nullable Level world, List list, TooltipFlag tooltipOptions) { - var label = getTitle(stack); - if (!label.isEmpty()) list.add(Component.literal(label)); + public void appendHoverText(ItemStack stack, TooltipContext context, List list, TooltipFlag tooltipOptions) { + list.add(Component.literal(TreasureDisk.getTitle(stack))); } @ForgeOverride @@ -47,7 +40,7 @@ public boolean doesSneakBypassUse(ItemStack stack, LevelReader world, BlockPos p @Override public String getLabel(ItemStack stack) { - return getTitle(stack); + return TreasureDisk.getTitle(stack); } @Override @@ -55,7 +48,10 @@ public String getLabel(ItemStack stack) { var rootTreasure = ComputerCraftAPI.createResourceMount(level.getServer(), "computercraft", "lua/treasure"); if (rootTreasure == null) return null; - var subPath = getSubPath(stack); + var treasureDisk = stack.get(ModRegistry.DataComponents.TREASURE_DISK.get()); + if (treasureDisk == null) return null; + + var subPath = treasureDisk.path(); try { if (rootTreasure.exists(subPath)) { return new SubMount(rootTreasure, subPath); @@ -68,37 +64,4 @@ public String getLabel(ItemStack stack) { return null; } } - - public static ItemStack create(String subPath, int colourIndex) { - var result = new ItemStack(ModRegistry.Items.TREASURE_DISK.get()); - var nbt = result.getOrCreateTag(); - nbt.putString(NBT_SUB_PATH, subPath); - - var slash = subPath.indexOf('/'); - if (slash >= 0) { - var author = subPath.substring(0, slash); - var title = subPath.substring(slash + 1); - nbt.putString(NBT_TITLE, "\"" + title + "\" by " + author); - } else { - nbt.putString(NBT_TITLE, "untitled"); - } - nbt.putInt(NBT_COLOUR, Colour.values()[colourIndex].getHex()); - - return result; - } - - private static String getTitle(ItemStack stack) { - var nbt = stack.getTag(); - return nbt != null && nbt.contains(NBT_TITLE) ? nbt.getString(NBT_TITLE) : "'missingno' by how did you get this anyway?"; - } - - private static String getSubPath(ItemStack stack) { - var nbt = stack.getTag(); - return nbt != null && nbt.contains(NBT_SUB_PATH) ? nbt.getString(NBT_SUB_PATH) : "dan200/alongtimeago"; - } - - public static int getColour(ItemStack stack) { - var nbt = stack.getTag(); - return nbt != null && nbt.contains(NBT_COLOUR) ? nbt.getInt(NBT_COLOUR) : Colour.BLUE.getHex(); - } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java b/projects/common/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java index eaf2f5981..5f478cc5e 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java @@ -6,14 +6,16 @@ import dan200.computercraft.core.util.Colour; import dan200.computercraft.shared.ModRegistry; -import dan200.computercraft.shared.media.items.DiskItem; import dan200.computercraft.shared.platform.PlatformHelper; import dan200.computercraft.shared.util.ColourTracker; import dan200.computercraft.shared.util.ColourUtils; -import net.minecraft.core.RegistryAccess; +import dan200.computercraft.shared.util.DataComponentUtil; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.component.DataComponents; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +import net.minecraft.world.item.component.DyedItemColor; import net.minecraft.world.item.crafting.CraftingBookCategory; import net.minecraft.world.item.crafting.CustomRecipe; import net.minecraft.world.item.crafting.Ingredient; @@ -53,7 +55,7 @@ public boolean matches(CraftingContainer inv, Level world) { } @Override - public ItemStack assemble(CraftingContainer inv, RegistryAccess registryAccess) { + public ItemStack assemble(CraftingContainer inv, HolderLookup.Provider registryAccess) { var tracker = new ColourTracker(); for (var i = 0; i < inv.getContainerSize(); i++) { @@ -67,7 +69,7 @@ public ItemStack assemble(CraftingContainer inv, RegistryAccess registryAccess) } } - return DiskItem.createFromIDAndColour(-1, null, tracker.hasColour() ? tracker.getColour() : Colour.BLUE.getHex()); + return DataComponentUtil.createStack(ModRegistry.Items.DISK.get(), DataComponents.DYED_COLOR, new DyedItemColor(tracker.hasColour() ? tracker.getColour() : Colour.BLUE.getHex(), false)); } @Override @@ -76,8 +78,8 @@ public boolean canCraftInDimensions(int x, int y) { } @Override - public ItemStack getResultItem(RegistryAccess registryAccess) { - return DiskItem.createFromIDAndColour(-1, null, Colour.BLUE.getHex()); + public ItemStack getResultItem(HolderLookup.Provider registryAccess) { + return DataComponentUtil.createStack(ModRegistry.Items.DISK.get(), DataComponents.DYED_COLOR, new DyedItemColor(Colour.BLUE.getHex(), false)); } @Override diff --git a/projects/common/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java b/projects/common/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java index 11376cef2..adc5895ea 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java @@ -5,9 +5,11 @@ package dan200.computercraft.shared.media.recipes; import dan200.computercraft.shared.ModRegistry; +import dan200.computercraft.shared.media.items.PrintoutData; import dan200.computercraft.shared.media.items.PrintoutItem; import dan200.computercraft.shared.platform.PlatformHelper; -import net.minecraft.core.RegistryAccess; +import dan200.computercraft.shared.util.DataComponentUtil; +import net.minecraft.core.HolderLookup; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; @@ -17,6 +19,8 @@ import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.level.Level; +import java.util.List; + public final class PrintoutRecipe extends CustomRecipe { private final Ingredient leather; private final Ingredient string; @@ -35,8 +39,8 @@ public boolean canCraftInDimensions(int x, int y) { } @Override - public ItemStack getResultItem(RegistryAccess registryAccess) { - return PrintoutItem.createMultipleFromTitleAndText(null, null, null); + public ItemStack getResultItem(HolderLookup.Provider registryAccess) { + return new ItemStack(ModRegistry.Items.PRINTED_PAGES.get()); } @Override @@ -45,7 +49,7 @@ public boolean matches(CraftingContainer inventory, Level world) { } @Override - public ItemStack assemble(CraftingContainer inventory, RegistryAccess registryAccess) { + public ItemStack assemble(CraftingContainer inventory, HolderLookup.Provider registryAccess) { // See if we match the recipe, and extract the input disk ID and dye colour var numPages = 0; var numPrintouts = 0; @@ -82,43 +86,30 @@ public ItemStack assemble(CraftingContainer inventory, RegistryAccess registryAc } // Build some pages with what was passed in - if (numPages <= PrintoutItem.MAX_PAGES && stringFound && printoutFound && numPrintouts >= (leatherFound ? 1 : 2)) { + if (numPages <= PrintoutData.MAX_PAGES && stringFound && printoutFound && numPrintouts >= (leatherFound ? 1 : 2)) { if (printouts == null) throw new IllegalStateException("Printouts must be non-null"); - var text = new String[numPages * PrintoutItem.LINES_PER_PAGE]; - var colours = new String[numPages * PrintoutItem.LINES_PER_PAGE]; + var lines = new PrintoutData.Line[numPages * PrintoutData.LINES_PER_PAGE]; var line = 0; for (var printout = 0; printout < numPrintouts; printout++) { - var stack = printouts[printout]; - if (stack.getItem() instanceof PrintoutItem) { + var pageText = printouts[printout].get(ModRegistry.DataComponents.PRINTOUT.get()); + if (pageText != null) { // Add a printout - var pageText = PrintoutItem.getText(printouts[printout]); - var pageColours = PrintoutItem.getColours(printouts[printout]); - for (var pageLine = 0; pageLine < pageText.length; pageLine++) { - text[line] = pageText[pageLine]; - colours[line] = pageColours[pageLine]; - line++; - } + for (var pageLine : pageText.lines()) lines[line++] = pageLine; } else { // Add a blank page - for (var pageLine = 0; pageLine < PrintoutItem.LINES_PER_PAGE; pageLine++) { - text[line] = ""; - colours[line] = ""; - line++; + for (var pageLine = 0; pageLine < PrintoutData.LINES_PER_PAGE; pageLine++) { + lines[line++] = PrintoutData.Line.EMPTY; } } } - String title = null; - if (printouts[0].getItem() instanceof PrintoutItem) { - title = PrintoutItem.getTitle(printouts[0]); - } + var title = PrintoutItem.getTitle(printouts[0]); - if (leatherFound) { - return PrintoutItem.createBookFromTitleAndText(title, text, colours); - } else { - return PrintoutItem.createMultipleFromTitleAndText(title, text, colours); - } + return DataComponentUtil.createStack( + leatherFound ? ModRegistry.Items.PRINTED_BOOK.get() : ModRegistry.Items.PRINTED_PAGES.get(), + ModRegistry.DataComponents.PRINTOUT.get(), new PrintoutData(title, List.of(lines)) + ); } return ItemStack.EMPTY; diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/MessageType.java b/projects/common/src/main/java/dan200/computercraft/shared/network/MessageType.java deleted file mode 100644 index 93f673850..000000000 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/MessageType.java +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers -// -// SPDX-License-Identifier: MPL-2.0 - -package dan200.computercraft.shared.network; - -import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -import net.minecraft.resources.ResourceLocation; - -/** - * A type of message to send over the network. - *

- * Much like recipe or argument serialisers, each type of {@link NetworkMessage} should have a unique type associated - * with it. This holds platform-specific information about how the packet should be sent over the network. - * - * @param The type of message to send - * @see NetworkMessages - * @see NetworkMessage#type() - */ -public interface MessageType> { - /** - * Get the id of this message type. This will be used as the custom packet channel name. - * - * @return The id of this message type. - * @see CustomPacketPayload#id() - */ - ResourceLocation id(); -} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java b/projects/common/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java index 6ccfb95e8..b33969e66 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java @@ -6,8 +6,7 @@ import dan200.computercraft.shared.network.client.ClientNetworkContext; import dan200.computercraft.shared.network.server.ServerNetworkContext; -import net.minecraft.network.FriendlyByteBuf; - +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; /** * The base interface for any message which will be sent to the client or server. @@ -16,23 +15,7 @@ * @see ClientNetworkContext * @see ServerNetworkContext */ -public interface NetworkMessage { - /** - * Get the type of this message. - * - * @return The type of this message. - */ - MessageType type(); - - /** - * Write this packet to a buffer. - *

- * This may be called on any thread, so this should be a pure operation. - * - * @param buf The buffer to write data to. - */ - void write(FriendlyByteBuf buf); - +public interface NetworkMessage extends CustomPacketPayload { /** * Handle this {@link NetworkMessage}. * diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/NetworkMessages.java b/projects/common/src/main/java/dan200/computercraft/shared/network/NetworkMessages.java index 75dedc2a3..04d6b0cd8 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/NetworkMessages.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/NetworkMessages.java @@ -8,59 +8,61 @@ import dan200.computercraft.shared.network.client.*; import dan200.computercraft.shared.network.server.*; import dan200.computercraft.shared.platform.PlatformHelper; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceLocation; import java.util.*; /** - * List of all {@link MessageType}s provided by CC: Tweaked. + * List of all {@link CustomPacketPayload.Type}s provided by CC: Tweaked. * * @see PlatformHelper The platform helper is used to send packets. */ public final class NetworkMessages { private static final Set seenChannel = new HashSet<>(); - private static final List>> serverMessages = new ArrayList<>(); - private static final List>> clientMessages = new ArrayList<>(); + private static final List>> serverMessages = new ArrayList<>(); + private static final List>> clientMessages = new ArrayList<>(); - public static final MessageType COMPUTER_ACTION = registerServerbound("computer_action", ComputerActionServerMessage::new); - public static final MessageType QUEUE_EVENT = registerServerbound("queue_event", QueueEventServerMessage::new); - public static final MessageType KEY_EVENT = registerServerbound("key_event", KeyEventServerMessage::new); - public static final MessageType MOUSE_EVENT = registerServerbound("mouse_event", MouseEventServerMessage::new); - public static final MessageType UPLOAD_FILE = registerServerbound("upload_file", UploadFileMessage::new); + public static final CustomPacketPayload.Type COMPUTER_ACTION = registerServerbound("computer_action", ComputerActionServerMessage.STREAM_CODEC); + public static final CustomPacketPayload.Type QUEUE_EVENT = register(serverMessages, "queue_event", QueueEventServerMessage.STREAM_CODEC); + public static final CustomPacketPayload.Type KEY_EVENT = registerServerbound("key_event", KeyEventServerMessage.STREAM_CODEC); + public static final CustomPacketPayload.Type MOUSE_EVENT = registerServerbound("mouse_event", MouseEventServerMessage.STREAM_CODEC); + public static final CustomPacketPayload.Type UPLOAD_FILE = register(serverMessages, "upload_file", UploadFileMessage.STREAM_CODEC); - public static final MessageType CHAT_TABLE = registerClientbound("chat_table", ChatTableClientMessage::new); - public static final MessageType POCKET_COMPUTER_DATA = registerClientbound("pocket_computer_data", PocketComputerDataMessage::new); - public static final MessageType POCKET_COMPUTER_DELETED = registerClientbound("pocket_computer_deleted", PocketComputerDeletedClientMessage::new); - public static final MessageType COMPUTER_TERMINAL = registerClientbound("computer_terminal", ComputerTerminalClientMessage::new); - public static final MessageType PLAY_RECORD = registerClientbound("play_record", PlayRecordClientMessage::new); - public static final MessageType MONITOR_CLIENT = registerClientbound("monitor_client", MonitorClientMessage::new); - public static final MessageType SPEAKER_AUDIO = registerClientbound("speaker_audio", SpeakerAudioClientMessage::new); - public static final MessageType SPEAKER_MOVE = registerClientbound("speaker_move", SpeakerMoveClientMessage::new); - public static final MessageType SPEAKER_PLAY = registerClientbound("speaker_play", SpeakerPlayClientMessage::new); - public static final MessageType SPEAKER_STOP = registerClientbound("speaker_stop", SpeakerStopClientMessage::new); - public static final MessageType UPLOAD_RESULT = registerClientbound("upload_result", UploadResultMessage::new); - public static final MessageType UPGRADES_LOADED = registerClientbound("upgrades_loaded", UpgradesLoadedMessage::new); + public static final CustomPacketPayload.Type CHAT_TABLE = registerClientbound("chat_table", ChatTableClientMessage.STREAM_CODEC); + public static final CustomPacketPayload.Type POCKET_COMPUTER_DATA = registerClientbound("pocket_computer_data", PocketComputerDataMessage.STREAM_CODEC); + public static final CustomPacketPayload.Type POCKET_COMPUTER_DELETED = registerClientbound("pocket_computer_deleted", PocketComputerDeletedClientMessage.STREAM_CODEC); + public static final CustomPacketPayload.Type COMPUTER_TERMINAL = registerClientbound("computer_terminal", ComputerTerminalClientMessage.STREAM_CODEC); + public static final CustomPacketPayload.Type PLAY_RECORD = registerClientbound("play_record", PlayRecordClientMessage.STREAM_CODEC); + public static final CustomPacketPayload.Type MONITOR_CLIENT = registerClientbound("monitor_client", MonitorClientMessage.STREAM_CODEC); + public static final CustomPacketPayload.Type SPEAKER_AUDIO = registerClientbound("speaker_audio", SpeakerAudioClientMessage.STREAM_CODEC); + public static final CustomPacketPayload.Type SPEAKER_MOVE = registerClientbound("speaker_move", SpeakerMoveClientMessage.STREAM_CODEC); + public static final CustomPacketPayload.Type SPEAKER_PLAY = registerClientbound("speaker_play", SpeakerPlayClientMessage.STREAM_CODEC); + public static final CustomPacketPayload.Type SPEAKER_STOP = registerClientbound("speaker_stop", SpeakerStopClientMessage.STREAM_CODEC); + public static final CustomPacketPayload.Type UPLOAD_RESULT = registerClientbound("upload_result", UploadResultMessage.STREAM_CODEC); + public static final CustomPacketPayload.Type UPGRADES_LOADED = registerClientbound("upgrades_loaded", UpgradesLoadedMessage.STREAM_CODEC); private NetworkMessages() { } - private static > MessageType register( - List>> messages, - String channel, FriendlyByteBuf.Reader reader + private static > CustomPacketPayload.Type register( + List>> messages, + String channel, StreamCodec codec ) { if (!seenChannel.add(channel)) throw new IllegalArgumentException("Duplicate channel " + channel); - var type = PlatformHelper.get().createMessageType(new ResourceLocation(ComputerCraftAPI.MOD_ID, channel), reader); - messages.add(type); + var type = new CustomPacketPayload.Type(new ResourceLocation(ComputerCraftAPI.MOD_ID, channel)); + messages.add(new CustomPacketPayload.TypeAndCodec<>(type, codec)); return type; } - private static > MessageType registerServerbound(String id, FriendlyByteBuf.Reader reader) { - return register(serverMessages, id, reader); + private static > CustomPacketPayload.Type registerServerbound(String id, StreamCodec codec) { + return register(serverMessages, id, codec); } - private static > MessageType registerClientbound(String id, FriendlyByteBuf.Reader reader) { - return register(clientMessages, id, reader); + private static > CustomPacketPayload.Type registerClientbound(String id, StreamCodec codec) { + return register(clientMessages, id, codec); } /** @@ -68,7 +70,7 @@ private static > MessageType r * * @return An unmodifiable sequence of all serverbound message types. */ - public static Collection>> getServerbound() { + public static Collection>> getServerbound() { return Collections.unmodifiableCollection(serverMessages); } @@ -77,7 +79,7 @@ public static Collection>> getClientbound() { + public static Collection>> getClientbound() { return Collections.unmodifiableCollection(clientMessages); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java b/projects/common/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java index d5ed9caca..cdaf298f5 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java @@ -5,14 +5,18 @@ package dan200.computercraft.shared.network.client; import dan200.computercraft.shared.command.text.TableBuilder; -import dan200.computercraft.shared.network.MessageType; import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.NetworkMessages; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.ComponentSerialization; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; public class ChatTableClientMessage implements NetworkMessage { + public static final StreamCodec STREAM_CODEC = StreamCodec.ofMember(ChatTableClientMessage::write, ChatTableClientMessage::new); + private static final int MAX_LEN = 16; private final TableBuilder table; @@ -21,13 +25,13 @@ public ChatTableClientMessage(TableBuilder table) { this.table = table; } - public ChatTableClientMessage(FriendlyByteBuf buf) { + private ChatTableClientMessage(RegistryFriendlyByteBuf buf) { var id = buf.readUtf(MAX_LEN); var columns = buf.readVarInt(); TableBuilder table; if (buf.readBoolean()) { var headers = new Component[columns]; - for (var i = 0; i < columns; i++) headers[i] = buf.readComponent(); + for (var i = 0; i < columns; i++) headers[i] = ComponentSerialization.STREAM_CODEC.decode(buf); table = new TableBuilder(id, headers); } else { table = new TableBuilder(id); @@ -36,7 +40,7 @@ public ChatTableClientMessage(FriendlyByteBuf buf) { var rows = buf.readVarInt(); for (var i = 0; i < rows; i++) { var row = new Component[columns]; - for (var j = 0; j < columns; j++) row[j] = buf.readComponent(); + for (var j = 0; j < columns; j++) row[j] = ComponentSerialization.STREAM_CODEC.decode(buf); table.row(row); } @@ -44,18 +48,17 @@ public ChatTableClientMessage(FriendlyByteBuf buf) { this.table = table; } - @Override - public void write(FriendlyByteBuf buf) { + private void write(RegistryFriendlyByteBuf buf) { buf.writeUtf(table.getId(), MAX_LEN); buf.writeVarInt(table.getColumns()); buf.writeBoolean(table.getHeaders() != null); if (table.getHeaders() != null) { - for (var header : table.getHeaders()) buf.writeComponent(header); + for (var header : table.getHeaders()) ComponentSerialization.STREAM_CODEC.encode(buf, header); } buf.writeVarInt(table.getRows().size()); for (var row : table.getRows()) { - for (var column : row) buf.writeComponent(column); + for (var column : row) ComponentSerialization.STREAM_CODEC.encode(buf, column); } buf.writeVarInt(table.getAdditional()); @@ -67,7 +70,7 @@ public void handle(ClientNetworkContext context) { } @Override - public MessageType type() { + public CustomPacketPayload.Type type() { return NetworkMessages.CHAT_TABLE; } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java b/projects/common/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java index e47bbf25c..fff53a1d5 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java @@ -4,32 +4,33 @@ package dan200.computercraft.shared.network.client; +import dan200.computercraft.shared.computer.menu.ComputerMenu; import dan200.computercraft.shared.computer.terminal.TerminalState; -import dan200.computercraft.shared.network.MessageType; import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.NetworkMessages; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.world.inventory.AbstractContainerMenu; - -public class ComputerTerminalClientMessage implements NetworkMessage { - private final int containerId; - private final TerminalState terminal; +/** + * Update the terminal for the currently opened {@link ComputerMenu}. + * + * @param containerId The currently opened container id. + * @param terminal The new terminal data. + */ +public record ComputerTerminalClientMessage( + int containerId, TerminalState terminal +) implements NetworkMessage { + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.VAR_INT, ComputerTerminalClientMessage::containerId, + TerminalState.STREAM_CODEC, ComputerTerminalClientMessage::terminal, + ComputerTerminalClientMessage::new + ); public ComputerTerminalClientMessage(AbstractContainerMenu menu, TerminalState terminal) { - containerId = menu.containerId; - this.terminal = terminal; - } - - public ComputerTerminalClientMessage(FriendlyByteBuf buf) { - containerId = buf.readVarInt(); - terminal = new TerminalState(buf); - } - - @Override - public void write(FriendlyByteBuf buf) { - buf.writeVarInt(containerId); - terminal.write(buf); + this(menu.containerId, terminal); } @Override @@ -38,7 +39,7 @@ public void handle(ClientNetworkContext context) { } @Override - public MessageType type() { + public CustomPacketPayload.Type type() { return NetworkMessages.COMPUTER_TERMINAL; } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java b/projects/common/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java index 97f7c73cd..6081ab46c 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java @@ -5,41 +5,38 @@ package dan200.computercraft.shared.network.client; import dan200.computercraft.shared.computer.terminal.TerminalState; -import dan200.computercraft.shared.network.MessageType; import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.NetworkMessages; import net.minecraft.core.BlockPos; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -import javax.annotation.Nullable; +import java.util.Optional; -public class MonitorClientMessage implements NetworkMessage { - private final BlockPos pos; - private final @Nullable TerminalState state; - - public MonitorClientMessage(BlockPos pos, @Nullable TerminalState state) { - this.pos = pos; - this.state = state; - } - - public MonitorClientMessage(FriendlyByteBuf buf) { - pos = buf.readBlockPos(); - state = buf.readNullable(TerminalState::new); - } - - @Override - public void write(FriendlyByteBuf buf) { - buf.writeBlockPos(pos); - buf.writeNullable(state, (b, t) -> t.write(b)); - } +/** + * Update the terminal contents of a monitor. + * + * @param pos The position of the origin monitor. + * @param terminal The current monitor terminal. + */ +public record MonitorClientMessage( + BlockPos pos, Optional terminal +) implements NetworkMessage { + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + BlockPos.STREAM_CODEC, MonitorClientMessage::pos, + ByteBufCodecs.optional(TerminalState.STREAM_CODEC), MonitorClientMessage::terminal, + MonitorClientMessage::new + ); @Override public void handle(ClientNetworkContext context) { - context.handleMonitorData(pos, state); + context.handleMonitorData(pos, terminal.orElse(null)); } @Override - public MessageType type() { + public CustomPacketPayload.Type type() { return NetworkMessages.MONITOR_CLIENT; } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java b/projects/common/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java index c5580ae48..a40b3b608 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java @@ -4,60 +4,50 @@ package dan200.computercraft.shared.network.client; -import dan200.computercraft.shared.network.MessageType; import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.NetworkMessages; import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveBlockEntity; import net.minecraft.core.BlockPos; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.core.Holder; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.sounds.SoundEvent; -import javax.annotation.Nullable; +import java.util.Optional; /** * Starts or stops a record on the client, depending on if {@link #soundEvent} is {@code null}. *

* Used by disk drives to play record items. * + * @param pos The position of the speaker, where we should play this sound. + * @param soundEvent The sound to play, or {@link Optional#empty()} if we should stop playing. + * @param name The title of the audio to play. * @see DiskDriveBlockEntity */ -public class PlayRecordClientMessage implements NetworkMessage { - private final BlockPos pos; - private final @Nullable String name; - private final @Nullable SoundEvent soundEvent; - - public PlayRecordClientMessage(BlockPos pos, SoundEvent event, @Nullable String name) { - this.pos = pos; - this.name = name; - soundEvent = event; - } +public record PlayRecordClientMessage( + BlockPos pos, Optional> soundEvent, Optional name +) implements NetworkMessage { + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + BlockPos.STREAM_CODEC, PlayRecordClientMessage::pos, + ByteBufCodecs.optional(SoundEvent.STREAM_CODEC), PlayRecordClientMessage::soundEvent, + ByteBufCodecs.optional(ByteBufCodecs.STRING_UTF8), PlayRecordClientMessage::name, + PlayRecordClientMessage::new + ); public PlayRecordClientMessage(BlockPos pos) { - this.pos = pos; - name = null; - soundEvent = null; - } - - public PlayRecordClientMessage(FriendlyByteBuf buf) { - pos = buf.readBlockPos(); - soundEvent = buf.readNullable(SoundEvent::readFromNetwork); - name = buf.readNullable(FriendlyByteBuf::readUtf); - } - - @Override - public void write(FriendlyByteBuf buf) { - buf.writeBlockPos(pos); - buf.writeNullable(soundEvent, (b, e) -> e.writeToNetwork(b)); - buf.writeNullable(name, FriendlyByteBuf::writeUtf); + this(pos, Optional.empty(), Optional.empty()); } @Override public void handle(ClientNetworkContext context) { - context.handlePlayRecord(pos, soundEvent, name); + context.handlePlayRecord(pos, soundEvent.map(Holder::value).orElse(null), name.orElse(null)); } @Override - public MessageType type() { + public CustomPacketPayload.Type type() { return NetworkMessages.PLAY_RECORD; } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/client/PocketComputerDataMessage.java b/projects/common/src/main/java/dan200/computercraft/shared/network/client/PocketComputerDataMessage.java index d9396707d..7ff820ebc 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/client/PocketComputerDataMessage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/client/PocketComputerDataMessage.java @@ -5,54 +5,56 @@ package dan200.computercraft.shared.network.client; import dan200.computercraft.shared.computer.core.ComputerState; +import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.terminal.TerminalState; -import dan200.computercraft.shared.network.MessageType; import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.NetworkMessages; +import dan200.computercraft.shared.network.codec.MoreStreamCodecs; import dan200.computercraft.shared.pocket.core.PocketServerComputer; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.core.UUIDUtil; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -import javax.annotation.Nullable; +import java.util.Optional; import java.util.UUID; /** * Provides additional data about a client computer, such as its ID and current state. + * + * @param id The {@linkplain ServerComputer#getInstanceUUID() instance id} of the pocket computer. + * @param state Whether the computer is on, off, or blinking. + * @param lightState The colour of the light, or {@code -1} if off. + * @param terminal The computer's terminal. This may be absent, in which case the terminal will not be updated on. */ -public class PocketComputerDataMessage implements NetworkMessage { - private final UUID clientId; - private final ComputerState state; - private final int lightState; - private final @Nullable TerminalState terminal; +public record PocketComputerDataMessage( + UUID id, ComputerState state, int lightState, Optional terminal +) implements NetworkMessage { + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + UUIDUtil.STREAM_CODEC, PocketComputerDataMessage::id, + MoreStreamCodecs.ofEnum(ComputerState.class), PocketComputerDataMessage::state, + ByteBufCodecs.VAR_INT, PocketComputerDataMessage::lightState, + ByteBufCodecs.optional(TerminalState.STREAM_CODEC), PocketComputerDataMessage::terminal, + PocketComputerDataMessage::new + ); public PocketComputerDataMessage(PocketServerComputer computer, boolean sendTerminal) { - clientId = computer.getInstanceUUID(); - state = computer.getState(); - lightState = computer.getLight(); - terminal = sendTerminal ? computer.getTerminalState() : null; - } - - public PocketComputerDataMessage(FriendlyByteBuf buf) { - clientId = buf.readUUID(); - state = buf.readEnum(ComputerState.class); - lightState = buf.readVarInt(); - terminal = buf.readNullable(TerminalState::new); - } - - @Override - public void write(FriendlyByteBuf buf) { - buf.writeUUID(clientId); - buf.writeEnum(state); - buf.writeVarInt(lightState); - buf.writeNullable(terminal, (b, t) -> t.write(b)); + this( + computer.getInstanceUUID(), + computer.getState(), + computer.getLight(), + sendTerminal ? Optional.of(computer.getTerminalState()) : Optional.empty() + ); } @Override public void handle(ClientNetworkContext context) { - context.handlePocketComputerData(clientId, state, lightState, terminal); + context.handlePocketComputerData(id, state, lightState, terminal.orElse(null)); } @Override - public MessageType type() { + public CustomPacketPayload.Type type() { return NetworkMessages.POCKET_COMPUTER_DATA; } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/client/PocketComputerDeletedClientMessage.java b/projects/common/src/main/java/dan200/computercraft/shared/network/client/PocketComputerDeletedClientMessage.java index 30340139a..93de6204e 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/client/PocketComputerDeletedClientMessage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/client/PocketComputerDeletedClientMessage.java @@ -4,29 +4,24 @@ package dan200.computercraft.shared.network.client; -import dan200.computercraft.shared.network.MessageType; import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.NetworkMessages; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.core.UUIDUtil; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import java.util.UUID; - -public class PocketComputerDeletedClientMessage implements NetworkMessage { - private final UUID instanceId; - - public PocketComputerDeletedClientMessage(UUID instanceId) { - this.instanceId = instanceId; - } - - public PocketComputerDeletedClientMessage(FriendlyByteBuf buffer) { - instanceId = buffer.readUUID(); - } - - @Override - public void write(FriendlyByteBuf buf) { - buf.writeUUID(instanceId); - } +/** + * Delete any client-side pocket computer state. + * + * @param instanceId The pocket computer's instance id. + */ +public record PocketComputerDeletedClientMessage(UUID instanceId) implements NetworkMessage { + public static final StreamCodec STREAM_CODEC = UUIDUtil.STREAM_CODEC + .map(PocketComputerDeletedClientMessage::new, PocketComputerDeletedClientMessage::instanceId) + .cast(); @Override public void handle(ClientNetworkContext context) { @@ -34,7 +29,7 @@ public void handle(ClientNetworkContext context) { } @Override - public MessageType type() { + public CustomPacketPayload.Type type() { return NetworkMessages.POCKET_COMPUTER_DELETED; } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/client/SpeakerAudioClientMessage.java b/projects/common/src/main/java/dan200/computercraft/shared/network/client/SpeakerAudioClientMessage.java index 283ff91d1..93b28258d 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/client/SpeakerAudioClientMessage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/client/SpeakerAudioClientMessage.java @@ -4,13 +4,17 @@ package dan200.computercraft.shared.network.client; -import dan200.computercraft.shared.network.MessageType; import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.NetworkMessages; import dan200.computercraft.shared.peripheral.speaker.EncodedAudio; import dan200.computercraft.shared.peripheral.speaker.SpeakerBlockEntity; +import dan200.computercraft.shared.peripheral.speaker.SpeakerPeripheral; import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.core.UUIDUtil; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import java.util.UUID; @@ -19,34 +23,28 @@ *

* Used by speakers to play sounds. * + * @param source The {@linkplain SpeakerPeripheral#getSource() id} of the speaker playing audio. + * @param pos The position of the speaker. + * @param content The audio to play. + * @param volume The volume to play the audio at. * @see SpeakerBlockEntity */ -public class SpeakerAudioClientMessage implements NetworkMessage { - private final UUID source; - private final SpeakerPosition.Message pos; - private final EncodedAudio content; - private final float volume; +public record SpeakerAudioClientMessage( + UUID source, + SpeakerPosition.Message pos, + EncodedAudio content, + float volume +) implements NetworkMessage { + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + UUIDUtil.STREAM_CODEC, SpeakerAudioClientMessage::source, + SpeakerPosition.Message.STREAM_CODEC, SpeakerAudioClientMessage::pos, + EncodedAudio.STREAM_CODEC, SpeakerAudioClientMessage::content, + ByteBufCodecs.FLOAT, SpeakerAudioClientMessage::volume, + SpeakerAudioClientMessage::new + ); public SpeakerAudioClientMessage(UUID source, SpeakerPosition pos, float volume, EncodedAudio content) { - this.source = source; - this.pos = pos.asMessage(); - this.content = content; - this.volume = volume; - } - - public SpeakerAudioClientMessage(FriendlyByteBuf buf) { - source = buf.readUUID(); - pos = SpeakerPosition.Message.read(buf); - volume = buf.readFloat(); - content = EncodedAudio.read(buf); - } - - @Override - public void write(FriendlyByteBuf buf) { - buf.writeUUID(source); - pos.write(buf); - buf.writeFloat(volume); - content.write(buf); + this(source, pos.asMessage(), content, volume); } @Override @@ -55,7 +53,7 @@ public void handle(ClientNetworkContext context) { } @Override - public MessageType type() { + public CustomPacketPayload.Type type() { return NetworkMessages.SPEAKER_AUDIO; } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/client/SpeakerMoveClientMessage.java b/projects/common/src/main/java/dan200/computercraft/shared/network/client/SpeakerMoveClientMessage.java index fd7704321..11c267754 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/client/SpeakerMoveClientMessage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/client/SpeakerMoveClientMessage.java @@ -4,12 +4,15 @@ package dan200.computercraft.shared.network.client; -import dan200.computercraft.shared.network.MessageType; import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.NetworkMessages; import dan200.computercraft.shared.peripheral.speaker.SpeakerBlockEntity; +import dan200.computercraft.shared.peripheral.speaker.SpeakerPeripheral; import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.core.UUIDUtil; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import java.util.UUID; @@ -18,26 +21,21 @@ *

* Used by speakers to play sounds. * + * @param source The {@linkplain SpeakerPeripheral#getSource() id} of the speaker playing audio. + * @param pos The new position of the speaker. * @see SpeakerBlockEntity */ -public class SpeakerMoveClientMessage implements NetworkMessage { - private final UUID source; - private final SpeakerPosition.Message pos; +public record SpeakerMoveClientMessage( + UUID source, SpeakerPosition.Message pos +) implements NetworkMessage { + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + UUIDUtil.STREAM_CODEC, SpeakerMoveClientMessage::source, + SpeakerPosition.Message.STREAM_CODEC, SpeakerMoveClientMessage::pos, + SpeakerMoveClientMessage::new + ); public SpeakerMoveClientMessage(UUID source, SpeakerPosition pos) { - this.source = source; - this.pos = pos.asMessage(); - } - - public SpeakerMoveClientMessage(FriendlyByteBuf buf) { - source = buf.readUUID(); - pos = SpeakerPosition.Message.read(buf); - } - - @Override - public void write(FriendlyByteBuf buf) { - buf.writeUUID(source); - pos.write(buf); + this(source, pos.asMessage()); } @Override @@ -46,7 +44,7 @@ public void handle(ClientNetworkContext context) { } @Override - public MessageType type() { + public CustomPacketPayload.Type type() { return NetworkMessages.SPEAKER_MOVE; } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/client/SpeakerPlayClientMessage.java b/projects/common/src/main/java/dan200/computercraft/shared/network/client/SpeakerPlayClientMessage.java index 68eb1e63a..fd83204b0 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/client/SpeakerPlayClientMessage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/client/SpeakerPlayClientMessage.java @@ -4,12 +4,16 @@ package dan200.computercraft.shared.network.client; -import dan200.computercraft.shared.network.MessageType; import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.NetworkMessages; import dan200.computercraft.shared.peripheral.speaker.SpeakerBlockEntity; +import dan200.computercraft.shared.peripheral.speaker.SpeakerPeripheral; import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.core.UUIDUtil; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceLocation; import java.util.UUID; @@ -19,38 +23,31 @@ *

* Used by speakers to play sounds. * + * @param source The {@linkplain SpeakerPeripheral#getSource() id} of the speaker playing audio. + * @param pos The position of the speaker. + * @param sound The sound to play. + * @param volume The volume to play the sound at. + * @param pitch The pitch to play the sound at. * @see SpeakerBlockEntity */ -public class SpeakerPlayClientMessage implements NetworkMessage { - private final UUID source; - private final SpeakerPosition.Message pos; - private final ResourceLocation sound; - private final float volume; - private final float pitch; +public record SpeakerPlayClientMessage( + UUID source, + SpeakerPosition.Message pos, + ResourceLocation sound, + float volume, + float pitch +) implements NetworkMessage { + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + UUIDUtil.STREAM_CODEC, SpeakerPlayClientMessage::source, + SpeakerPosition.Message.STREAM_CODEC, SpeakerPlayClientMessage::pos, + ResourceLocation.STREAM_CODEC, SpeakerPlayClientMessage::sound, + ByteBufCodecs.FLOAT, SpeakerPlayClientMessage::volume, + ByteBufCodecs.FLOAT, SpeakerPlayClientMessage::pitch, + SpeakerPlayClientMessage::new + ); public SpeakerPlayClientMessage(UUID source, SpeakerPosition pos, ResourceLocation sound, float volume, float pitch) { - this.source = source; - this.pos = pos.asMessage(); - this.sound = sound; - this.volume = volume; - this.pitch = pitch; - } - - public SpeakerPlayClientMessage(FriendlyByteBuf buf) { - source = buf.readUUID(); - pos = SpeakerPosition.Message.read(buf); - sound = buf.readResourceLocation(); - volume = buf.readFloat(); - pitch = buf.readFloat(); - } - - @Override - public void write(FriendlyByteBuf buf) { - buf.writeUUID(source); - pos.write(buf); - buf.writeResourceLocation(sound); - buf.writeFloat(volume); - buf.writeFloat(pitch); + this(source, pos.asMessage(), sound, volume, pitch); } @Override @@ -59,7 +56,7 @@ public void handle(ClientNetworkContext context) { } @Override - public MessageType type() { + public CustomPacketPayload.Type type() { return NetworkMessages.SPEAKER_PLAY; } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/client/SpeakerStopClientMessage.java b/projects/common/src/main/java/dan200/computercraft/shared/network/client/SpeakerStopClientMessage.java index ac90d59c3..1e71ead87 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/client/SpeakerStopClientMessage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/client/SpeakerStopClientMessage.java @@ -4,11 +4,14 @@ package dan200.computercraft.shared.network.client; -import dan200.computercraft.shared.network.MessageType; import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.NetworkMessages; import dan200.computercraft.shared.peripheral.speaker.SpeakerBlockEntity; -import net.minecraft.network.FriendlyByteBuf; +import dan200.computercraft.shared.peripheral.speaker.SpeakerPeripheral; +import net.minecraft.core.UUIDUtil; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import java.util.UUID; @@ -17,23 +20,13 @@ *

* Called when a speaker is broken. * + * @param source The {@linkplain SpeakerPeripheral#getSource() id} of the speaker playing audio. * @see SpeakerBlockEntity */ -public class SpeakerStopClientMessage implements NetworkMessage { - private final UUID source; - - public SpeakerStopClientMessage(UUID source) { - this.source = source; - } - - public SpeakerStopClientMessage(FriendlyByteBuf buf) { - source = buf.readUUID(); - } - - @Override - public void write(FriendlyByteBuf buf) { - buf.writeUUID(source); - } +public record SpeakerStopClientMessage(UUID source) implements NetworkMessage { + public static final StreamCodec STREAM_CODEC = UUIDUtil.STREAM_CODEC + .map(SpeakerStopClientMessage::new, SpeakerStopClientMessage::source) + .cast(); @Override public void handle(ClientNetworkContext context) { @@ -41,7 +34,7 @@ public void handle(ClientNetworkContext context) { } @Override - public MessageType type() { + public CustomPacketPayload.Type type() { return NetworkMessages.SPEAKER_STOP; } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/client/UpgradesLoadedMessage.java b/projects/common/src/main/java/dan200/computercraft/shared/network/client/UpgradesLoadedMessage.java index 1b1d414ec..b836f6549 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/client/UpgradesLoadedMessage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/client/UpgradesLoadedMessage.java @@ -12,11 +12,12 @@ import dan200.computercraft.impl.RegistryHelper; import dan200.computercraft.impl.TurtleUpgrades; import dan200.computercraft.impl.UpgradeManager; -import dan200.computercraft.shared.network.MessageType; import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.NetworkMessages; import net.minecraft.core.Registry; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; @@ -27,34 +28,36 @@ * Syncs turtle and pocket upgrades to the client. */ public final class UpgradesLoadedMessage implements NetworkMessage { - private final Map> turtleUpgrades; - private final Map> pocketUpgrades; + public static final StreamCodec STREAM_CODEC = StreamCodec.ofMember(UpgradesLoadedMessage::write, UpgradesLoadedMessage::new); + + private final Map> turtleUpgrades; + private final Map> pocketUpgrades; public UpgradesLoadedMessage() { turtleUpgrades = TurtleUpgrades.instance().getUpgradeWrappers(); pocketUpgrades = PocketUpgrades.instance().getUpgradeWrappers(); } - public UpgradesLoadedMessage(FriendlyByteBuf buf) { + private UpgradesLoadedMessage(RegistryFriendlyByteBuf buf) { turtleUpgrades = fromBytes(buf, ITurtleUpgrade.serialiserRegistryKey()); pocketUpgrades = fromBytes(buf, IPocketUpgrade.serialiserRegistryKey()); } - private Map> fromBytes( - FriendlyByteBuf buf, ResourceKey>> registryKey + private Map> fromBytes( + RegistryFriendlyByteBuf buf, ResourceKey>> registryKey ) { var registry = RegistryHelper.getRegistry(registryKey); var size = buf.readVarInt(); - Map> upgrades = new HashMap<>(size); + Map> upgrades = new HashMap<>(size); for (var i = 0; i < size; i++) { - var id = buf.readUtf(); + var id = buf.readResourceLocation(); var serialiserId = buf.readResourceLocation(); var serialiser = registry.get(serialiserId); if (serialiser == null) throw new IllegalStateException("Unknown serialiser " + serialiserId); - var upgrade = serialiser.fromNetwork(new ResourceLocation(id), buf); + var upgrade = serialiser.fromNetwork(id, buf); var modId = buf.readUtf(); upgrades.put(id, new UpgradeManager.UpgradeWrapper(id, upgrade, serialiser, modId)); @@ -63,20 +66,19 @@ private Map> fr return upgrades; } - @Override - public void write(FriendlyByteBuf buf) { + private void write(RegistryFriendlyByteBuf buf) { toBytes(buf, ITurtleUpgrade.serialiserRegistryKey(), turtleUpgrades); toBytes(buf, IPocketUpgrade.serialiserRegistryKey(), pocketUpgrades); } private void toBytes( - FriendlyByteBuf buf, ResourceKey>> registryKey, Map> upgrades + RegistryFriendlyByteBuf buf, ResourceKey>> registryKey, Map> upgrades ) { var registry = RegistryHelper.getRegistry(registryKey); buf.writeVarInt(upgrades.size()); for (var entry : upgrades.entrySet()) { - buf.writeUtf(entry.getKey()); + buf.writeResourceLocation(entry.getKey()); var serialiser = entry.getValue().serialiser(); @SuppressWarnings("unchecked") @@ -96,7 +98,7 @@ public void handle(ClientNetworkContext context) { } @Override - public MessageType type() { + public CustomPacketPayload.Type type() { return NetworkMessages.UPGRADES_LOADED; } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/client/UploadResultMessage.java b/projects/common/src/main/java/dan200/computercraft/shared/network/client/UploadResultMessage.java index ec2b8e192..66c7ee527 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/client/UploadResultMessage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/client/UploadResultMessage.java @@ -4,60 +4,57 @@ package dan200.computercraft.shared.network.client; -import dan200.computercraft.core.util.Nullability; import dan200.computercraft.shared.computer.upload.UploadResult; -import dan200.computercraft.shared.network.MessageType; import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.NetworkMessages; -import net.minecraft.network.FriendlyByteBuf; +import dan200.computercraft.shared.network.codec.MoreStreamCodecs; +import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.ComponentSerialization; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.world.inventory.AbstractContainerMenu; -import javax.annotation.Nullable; +import java.util.Optional; + +public final class UploadResultMessage implements NetworkMessage { + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.VAR_INT, x -> x.containerId, + MoreStreamCodecs.ofEnum(UploadResult.class), x -> x.result, + ComponentSerialization.OPTIONAL_STREAM_CODEC, x -> x.errorMessage, + UploadResultMessage::new + ); -public class UploadResultMessage implements NetworkMessage { private final int containerId; private final UploadResult result; - private final @Nullable Component errorMessage; + private final Optional errorMessage; - private UploadResultMessage(AbstractContainerMenu container, UploadResult result, @Nullable Component errorMessage) { - containerId = container.containerId; + private UploadResultMessage(int containerId, UploadResult result, Optional errorMessage) { + this.containerId = containerId; this.result = result; this.errorMessage = errorMessage; } public static UploadResultMessage queued(AbstractContainerMenu container) { - return new UploadResultMessage(container, UploadResult.QUEUED, null); + return new UploadResultMessage(container.containerId, UploadResult.QUEUED, Optional.empty()); } public static UploadResultMessage consumed(AbstractContainerMenu container) { - return new UploadResultMessage(container, UploadResult.CONSUMED, null); + return new UploadResultMessage(container.containerId, UploadResult.CONSUMED, Optional.empty()); } public static UploadResultMessage error(AbstractContainerMenu container, Component errorMessage) { - return new UploadResultMessage(container, UploadResult.ERROR, errorMessage); - } - - public UploadResultMessage(FriendlyByteBuf buf) { - containerId = buf.readVarInt(); - result = buf.readEnum(UploadResult.class); - errorMessage = result == UploadResult.ERROR ? buf.readComponent() : null; - } - - @Override - public void write(FriendlyByteBuf buf) { - buf.writeVarInt(containerId); - buf.writeEnum(result); - if (result == UploadResult.ERROR) buf.writeComponent(Nullability.assertNonNull(errorMessage)); + return new UploadResultMessage(container.containerId, UploadResult.ERROR, Optional.of(errorMessage)); } @Override public void handle(ClientNetworkContext context) { - context.handleUploadResult(containerId, result, errorMessage); + context.handleUploadResult(containerId, result, errorMessage.orElse(null)); } @Override - public MessageType type() { + public CustomPacketPayload.Type type() { return NetworkMessages.UPLOAD_RESULT; } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/codec/MoreStreamCodecs.java b/projects/common/src/main/java/dan200/computercraft/shared/network/codec/MoreStreamCodecs.java new file mode 100644 index 000000000..f20f92014 --- /dev/null +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/codec/MoreStreamCodecs.java @@ -0,0 +1,107 @@ +// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.shared.network.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.handler.codec.DecoderException; +import net.minecraft.core.NonNullList; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.VarInt; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.world.phys.Vec3; + +import java.nio.ByteBuffer; +import java.util.OptionalInt; + +/** + * Additional {@link StreamCodec}s. + * + * @see ByteBufCodecs + */ +public class MoreStreamCodecs { + public static > StreamCodec ofEnum(Class klass) { + return new StreamCodec<>() { + @Override + public C decode(B buffer) { + return buffer.readEnum(klass); + } + + @Override + public void encode(B buffer, C value) { + buffer.writeEnum(value); + } + }; + } + + public static StreamCodec> nonNullList(StreamCodec codec, C empty) { + return new StreamCodec<>() { + @Override + public NonNullList decode(B buffer) { + var count = buffer.readVarInt(); + var result = NonNullList.withSize(count, empty); + for (var i = 0; i < result.size(); i++) result.set(i, codec.decode(buffer)); + return result; + } + + @Override + public void encode(B buffer, NonNullList list) { + var count = buffer.writeVarInt(list.size()); + for (var entry : list) codec.encode(buffer, entry); + } + }; + } + + public static final StreamCodec VEC3 = StreamCodec.composite( + ByteBufCodecs.DOUBLE, Vec3::x, + ByteBufCodecs.DOUBLE, Vec3::y, + ByteBufCodecs.DOUBLE, Vec3::z, + Vec3::new + ); + + /** + * A codec for {@link OptionalInt}. This uses the same wire format as {@link ByteBufCodecs#optional(StreamCodec)} + * and {@link ByteBufCodecs#VAR_INT}. + */ + public static final StreamCodec OPTIONAL_INT = new StreamCodec<>() { + @Override + public OptionalInt decode(ByteBuf buf) { + return buf.readBoolean() ? OptionalInt.of(ByteBufCodecs.VAR_INT.decode(buf)) : OptionalInt.empty(); + } + + @Override + public void encode(ByteBuf buf, OptionalInt optional) { + if (optional.isPresent()) { + buf.writeBoolean(true); + ByteBufCodecs.VAR_INT.encode(buf, optional.getAsInt()); + } else { + buf.writeBoolean(false); + } + } + }; + + /** + * Equivalent to {@link ByteBufCodecs#BYTE_ARRAY}, but into an immutable {@link ByteBuffer}. + */ + public static final StreamCodec BYTE_BUFFER = new StreamCodec<>() { + @Override + public ByteBuffer decode(ByteBuf buf) { + var toRead = VarInt.read(buf); + if (toRead > buf.readableBytes()) { + throw new DecoderException("ByteArray with size " + toRead + " is bigger than allowed"); + } + + var bytes = new byte[toRead]; + buf.readBytes(bytes); + return ByteBuffer.wrap(bytes).asReadOnlyBuffer(); + } + + @Override + public void encode(ByteBuf buf, ByteBuffer buffer) { + VarInt.write(buf, buffer.remaining()); + buf.writeBytes(buffer.duplicate()); + } + }; +} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java b/projects/common/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java index 9e658faed..4730728c3 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java @@ -8,55 +8,37 @@ import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.terminal.TerminalState; import dan200.computercraft.shared.config.Config; -import net.minecraft.network.FriendlyByteBuf; +import dan200.computercraft.shared.network.codec.MoreStreamCodecs; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.world.item.ItemStack; -public class ComputerContainerData implements ContainerData { - private final ComputerFamily family; - private final TerminalState terminal; - private final ItemStack displayStack; - private final int uploadMaxSize; +/** + * The data required to open a computer container. + * + * @param family The computer family. + * @param terminal The initial terminal contents. + * @param displayStack The stack associated with this menu. This may be displayed on the client. + * @param uploadMaxSize The maximum size of a file upload. + */ +public record ComputerContainerData( + ComputerFamily family, TerminalState terminal, ItemStack displayStack, int uploadMaxSize +) implements ContainerData { + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + MoreStreamCodecs.ofEnum(ComputerFamily.class), ComputerContainerData::family, + TerminalState.STREAM_CODEC, ComputerContainerData::terminal, + ItemStack.OPTIONAL_STREAM_CODEC, ComputerContainerData::displayStack, + ByteBufCodecs.VAR_INT, ComputerContainerData::uploadMaxSize, + ComputerContainerData::new + ); public ComputerContainerData(ServerComputer computer, ItemStack displayStack) { - family = computer.getFamily(); - terminal = computer.getTerminalState(); - this.displayStack = displayStack; - uploadMaxSize = Config.uploadMaxSize; - } - - public ComputerContainerData(FriendlyByteBuf buf) { - family = buf.readEnum(ComputerFamily.class); - terminal = new TerminalState(buf); - displayStack = buf.readItem(); - uploadMaxSize = buf.readInt(); + this(computer.getFamily(), computer.getTerminalState(), displayStack, Config.uploadMaxSize); } @Override - public void toBytes(FriendlyByteBuf buf) { - buf.writeEnum(family); - terminal.write(buf); - buf.writeItem(displayStack); - buf.writeInt(uploadMaxSize); - } - - public ComputerFamily family() { - return family; - } - - public TerminalState terminal() { - return terminal; - } - - /** - * Get a stack associated with this menu. This may be displayed on the client. - * - * @return The stack associated with this menu. - */ - public ItemStack displayStack() { - return displayStack; - } - - public int uploadMaxSize() { - return uploadMaxSize; + public void toBytes(RegistryFriendlyByteBuf buf) { + STREAM_CODEC.encode(buf, this); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java b/projects/common/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java index 8ad6cd68d..4e8b92965 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java @@ -6,20 +6,19 @@ import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.platform.PlatformHelper; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.world.MenuProvider; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.MenuType; -import java.util.function.Function; - /** * Additional data to send when opening a menu. Like {@link NetworkMessage}, this should be immutable. */ public interface ContainerData { - void toBytes(FriendlyByteBuf buf); + void toBytes(RegistryFriendlyByteBuf buf); /** * Open a menu for a specific player using this data. @@ -31,8 +30,8 @@ default void open(Player player, MenuProvider menu) { PlatformHelper.get().openMenu(player, menu, this); } - static MenuType toType(Function reader, Factory factory) { - return PlatformHelper.get().createMenuType(reader, factory); + static MenuType toType(StreamCodec codec, Factory factory) { + return PlatformHelper.get().createMenuType(codec, factory); } interface Factory { diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java b/projects/common/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java index 8bbb6522b..02c1c061f 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java @@ -6,32 +6,26 @@ import dan200.computercraft.shared.common.HeldItemMenu; import dan200.computercraft.shared.media.items.PrintoutItem; -import net.minecraft.network.FriendlyByteBuf; +import dan200.computercraft.shared.network.codec.MoreStreamCodecs; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.world.InteractionHand; /** * Opens a printout GUI based on the currently held item. * + * @param hand The hand holding this item. * @see HeldItemMenu * @see PrintoutItem */ -public class HeldItemContainerData implements ContainerData { - private final InteractionHand hand; - - public HeldItemContainerData(InteractionHand hand) { - this.hand = hand; - } - - public HeldItemContainerData(FriendlyByteBuf buffer) { - hand = buffer.readEnum(InteractionHand.class); - } +public record HeldItemContainerData(InteractionHand hand) implements ContainerData { + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + MoreStreamCodecs.ofEnum(InteractionHand.class), HeldItemContainerData::hand, + HeldItemContainerData::new + ); @Override - public void toBytes(FriendlyByteBuf buf) { - buf.writeEnum(hand); - } - - public InteractionHand getHand() { - return hand; + public void toBytes(RegistryFriendlyByteBuf buf) { + STREAM_CODEC.encode(buf, this); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java b/projects/common/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java index e4811f8e3..bac0756bc 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java @@ -5,31 +5,35 @@ package dan200.computercraft.shared.network.server; import dan200.computercraft.shared.computer.menu.ComputerMenu; -import dan200.computercraft.shared.network.MessageType; import dan200.computercraft.shared.network.NetworkMessages; -import net.minecraft.network.FriendlyByteBuf; +import dan200.computercraft.shared.network.codec.MoreStreamCodecs; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.world.inventory.AbstractContainerMenu; +/** + * Turn on, shutdown, or reboot the currently open computer. + */ +public final class ComputerActionServerMessage extends ComputerServerMessage { + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.VAR_INT, ComputerActionServerMessage::containerId, + MoreStreamCodecs.ofEnum(Action.class), x -> x.action, + ComputerActionServerMessage::new + ); -public class ComputerActionServerMessage extends ComputerServerMessage { private final Action action; public ComputerActionServerMessage(AbstractContainerMenu menu, Action action) { + this(menu.containerId, action); + } + + private ComputerActionServerMessage(int menu, Action action) { super(menu); this.action = action; } - public ComputerActionServerMessage(FriendlyByteBuf buf) { - super(buf); - action = buf.readEnum(Action.class); - } - - @Override - public void write(FriendlyByteBuf buf) { - super.write(buf); - buf.writeEnum(action); - } - @Override protected void handle(ServerNetworkContext context, ComputerMenu container) { switch (action) { @@ -40,7 +44,7 @@ protected void handle(ServerNetworkContext context, ComputerMenu container) { } @Override - public MessageType type() { + public CustomPacketPayload.Type type() { return NetworkMessages.COMPUTER_ACTION; } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java b/projects/common/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java index c7bfe2d10..6b8c609b2 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java @@ -6,11 +6,7 @@ import dan200.computercraft.shared.computer.menu.ComputerMenu; import dan200.computercraft.shared.network.NetworkMessage; -import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.AbstractContainerMenu; - -import javax.annotation.OverridingMethodsMustInvokeSuper; /** * A packet, which performs an action on the currently open {@link ComputerMenu}. @@ -18,18 +14,12 @@ public abstract class ComputerServerMessage implements NetworkMessage { private final int containerId; - protected ComputerServerMessage(AbstractContainerMenu menu) { - containerId = menu.containerId; + ComputerServerMessage(int id) { + containerId = id; } - public ComputerServerMessage(FriendlyByteBuf buffer) { - containerId = buffer.readVarInt(); - } - - @Override - @OverridingMethodsMustInvokeSuper - public void write(FriendlyByteBuf buf) { - buf.writeVarInt(containerId); + int containerId() { + return containerId; } @Override diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java b/projects/common/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java index 97a17ee3a..9e51d936a 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java @@ -5,47 +5,50 @@ package dan200.computercraft.shared.network.server; import dan200.computercraft.shared.computer.menu.ComputerMenu; -import dan200.computercraft.shared.network.MessageType; import dan200.computercraft.shared.network.NetworkMessages; -import net.minecraft.network.FriendlyByteBuf; +import dan200.computercraft.shared.network.codec.MoreStreamCodecs; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.world.inventory.AbstractContainerMenu; +/** + * Queue a key event on the currently opened computer. + */ +public final class KeyEventServerMessage extends ComputerServerMessage { + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.VAR_INT, KeyEventServerMessage::containerId, + MoreStreamCodecs.ofEnum(Action.class), x -> x.action, + ByteBufCodecs.INT, x -> x.key, + KeyEventServerMessage::new + ); -public class KeyEventServerMessage extends ComputerServerMessage { - private final Action type; + private final Action action; private final int key; - public KeyEventServerMessage(AbstractContainerMenu menu, Action type, int key) { - super(menu); - this.type = type; + public KeyEventServerMessage(AbstractContainerMenu menu, Action action, int key) { + this(menu.containerId, action, key); + } + + private KeyEventServerMessage(int id, Action action, int key) { + super(id); + this.action = action; this.key = key; } - public KeyEventServerMessage(FriendlyByteBuf buf) { - super(buf); - type = buf.readEnum(Action.class); - key = buf.readVarInt(); - } - - @Override - public void write(FriendlyByteBuf buf) { - super.write(buf); - buf.writeEnum(type); - buf.writeVarInt(key); - } - @Override protected void handle(ServerNetworkContext context, ComputerMenu container) { var input = container.getInput(); - if (type == Action.UP) { - input.keyUp(key); - } else { - input.keyDown(key, type == Action.REPEAT); + switch (action) { + case UP -> input.keyUp(key); + case DOWN -> input.keyDown(key, false); + case REPEAT -> input.keyDown(key, true); } } @Override - public MessageType type() { + public CustomPacketPayload.Type type() { return NetworkMessages.KEY_EVENT; } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java b/projects/common/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java index 7a8cddc10..b958c3c7e 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java @@ -5,47 +5,48 @@ package dan200.computercraft.shared.network.server; import dan200.computercraft.shared.computer.menu.ComputerMenu; -import dan200.computercraft.shared.network.MessageType; import dan200.computercraft.shared.network.NetworkMessages; -import net.minecraft.network.FriendlyByteBuf; +import dan200.computercraft.shared.network.codec.MoreStreamCodecs; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.world.inventory.AbstractContainerMenu; +/** + * Queue a mouse event on the currently opened computer. + */ +public final class MouseEventServerMessage extends ComputerServerMessage { + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.VAR_INT, MouseEventServerMessage::containerId, + MoreStreamCodecs.ofEnum(Action.class), x -> x.action, + ByteBufCodecs.VAR_INT, x -> x.arg, + ByteBufCodecs.VAR_INT, x -> x.x, + ByteBufCodecs.VAR_INT, x -> x.y, + MouseEventServerMessage::new + ); -public class MouseEventServerMessage extends ComputerServerMessage { - private final Action type; + private final Action action; + private final int arg; private final int x; private final int y; - private final int arg; - public MouseEventServerMessage(AbstractContainerMenu menu, Action type, int arg, int x, int y) { - super(menu); - this.type = type; - this.arg = arg; + public MouseEventServerMessage(AbstractContainerMenu menu, Action action, int arg, int x, int y) { + this(menu.containerId, action, arg, x, y); + } + + private MouseEventServerMessage(int id, Action action, int arg, int x, int y) { + super(id); + this.action = action; this.x = x; this.y = y; - } - - public MouseEventServerMessage(FriendlyByteBuf buf) { - super(buf); - type = buf.readEnum(Action.class); - arg = buf.readVarInt(); - x = buf.readVarInt(); - y = buf.readVarInt(); - } - - @Override - public void write(FriendlyByteBuf buf) { - super.write(buf); - buf.writeEnum(type); - buf.writeVarInt(arg); - buf.writeVarInt(x); - buf.writeVarInt(y); + this.arg = arg; } @Override protected void handle(ServerNetworkContext context, ComputerMenu container) { var input = container.getInput(); - switch (type) { + switch (action) { case CLICK -> input.mouseClick(arg, x, y); case DRAG -> input.mouseDrag(arg, x, y); case UP -> input.mouseUp(arg, x, y); @@ -54,7 +55,7 @@ protected void handle(ServerNetworkContext context, ComputerMenu container) { } @Override - public MessageType type() { + public CustomPacketPayload.Type type() { return NetworkMessages.MOUSE_EVENT; } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java b/projects/common/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java index 057718ef9..3c7b20ffb 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java @@ -7,10 +7,12 @@ import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.menu.ComputerMenu; import dan200.computercraft.shared.computer.menu.ServerInputHandler; -import dan200.computercraft.shared.network.MessageType; import dan200.computercraft.shared.network.NetworkMessages; import dan200.computercraft.shared.util.NBTUtil; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.world.inventory.AbstractContainerMenu; import javax.annotation.Nullable; @@ -20,27 +22,28 @@ * * @see ServerInputHandler#queueEvent(String) */ -public class QueueEventServerMessage extends ComputerServerMessage { +public final class QueueEventServerMessage extends ComputerServerMessage { + public static final StreamCodec STREAM_CODEC = StreamCodec.ofMember(QueueEventServerMessage::write, QueueEventServerMessage::new); + private final String event; private final @Nullable Object[] args; public QueueEventServerMessage(AbstractContainerMenu menu, String event, @Nullable Object[] args) { - super(menu); + super(menu.containerId); this.event = event; this.args = args; } - public QueueEventServerMessage(FriendlyByteBuf buf) { - super(buf); + private QueueEventServerMessage(FriendlyByteBuf buf) { + super(buf.readVarInt()); event = buf.readUtf(Short.MAX_VALUE); var args = buf.readNbt(); this.args = args == null ? null : NBTUtil.decodeObjects(args); } - @Override - public void write(FriendlyByteBuf buf) { - super.write(buf); + private void write(RegistryFriendlyByteBuf buf) { + buf.writeVarInt(containerId()); buf.writeUtf(event); buf.writeNbt(args == null ? null : NBTUtil.encodeObjects(args)); } @@ -51,7 +54,7 @@ protected void handle(ServerNetworkContext context, ComputerMenu container) { } @Override - public MessageType type() { + public CustomPacketPayload.Type type() { return NetworkMessages.QUEUE_EVENT; } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/server/ServerNetworking.java b/projects/common/src/main/java/dan200/computercraft/shared/network/server/ServerNetworking.java index f8a2feca4..5b30f0a2b 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/server/ServerNetworking.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/server/ServerNetworking.java @@ -6,7 +6,9 @@ import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.client.ClientNetworkContext; -import dan200.computercraft.shared.platform.PlatformHelper; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.common.ClientCommonPacketListener; +import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; @@ -30,7 +32,7 @@ private ServerNetworking() { * @param player The player to send it to. */ public static void sendToPlayer(NetworkMessage message, ServerPlayer player) { - player.connection.send(PlatformHelper.get().createPacket(message)); + player.connection.send(createPacket(message)); } /** @@ -41,7 +43,7 @@ public static void sendToPlayer(NetworkMessage message, Se */ public static void sendToPlayers(NetworkMessage message, Collection players) { if (players.isEmpty()) return; - var packet = PlatformHelper.get().createPacket(message); + var packet = createPacket(message); for (var player : players) player.connection.send(packet); } @@ -52,7 +54,7 @@ public static void sendToPlayers(NetworkMessage message, C * @param server The current server. */ public static void sendToAllPlayers(NetworkMessage message, MinecraftServer server) { - server.getPlayerList().broadcastAll(PlatformHelper.get().createPacket(message)); + server.getPlayerList().broadcastAll(createPacket(message)); } /** @@ -64,7 +66,7 @@ public static void sendToAllPlayers(NetworkMessage message * @param distance The distance to the centre players must be within. */ public static void sendToAllAround(NetworkMessage message, ServerLevel level, Vec3 pos, float distance) { - level.getServer().getPlayerList().broadcast(null, pos.x, pos.y, pos.z, distance, level.dimension(), PlatformHelper.get().createPacket(message)); + level.getServer().getPlayerList().broadcast(null, pos.x, pos.y, pos.z, distance, level.dimension(), createPacket(message)); } /** @@ -74,9 +76,19 @@ public static void sendToAllAround(NetworkMessage message, * @param chunk The chunk players must be tracking. */ public static void sendToAllTracking(NetworkMessage message, LevelChunk chunk) { - var packet = PlatformHelper.get().createPacket(message); + var packet = createPacket(message); for (var player : ((ServerChunkCache) chunk.getLevel().getChunkSource()).chunkMap.getPlayers(chunk.getPos(), false)) { player.connection.send(packet); } } + + /** + * Convert a clientbound {@link NetworkMessage} to a Minecraft {@link Packet}. + * + * @param message The message to convert. + * @return The converted message. + */ + private static Packet createPacket(NetworkMessage message) { + return new ClientboundCustomPayloadPacket(message); + } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java b/projects/common/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java index d96ec0a81..bf4f35de8 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java @@ -9,10 +9,12 @@ import dan200.computercraft.shared.computer.upload.FileSlice; import dan200.computercraft.shared.computer.upload.FileUpload; import dan200.computercraft.shared.config.Config; -import dan200.computercraft.shared.network.MessageType; import dan200.computercraft.shared.network.NetworkMessages; import io.netty.handler.codec.DecoderException; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.world.inventory.AbstractContainerMenu; import javax.annotation.Nullable; @@ -25,6 +27,8 @@ import static dan200.computercraft.core.util.Nullability.assertNonNull; public class UploadFileMessage extends ComputerServerMessage { + public static final StreamCodec STREAM_CODEC = StreamCodec.ofMember(UploadFileMessage::write, UploadFileMessage::new); + static final int MAX_PACKET_SIZE = 30 * 1024; // Max packet size is 32767. private static final int HEADER_SIZE = 16 + 1; // 16 bytes for the UUID, 4 for the flag. @@ -41,15 +45,15 @@ public class UploadFileMessage extends ComputerServerMessage { final @VisibleForTesting List slices; UploadFileMessage(AbstractContainerMenu menu, UUID uuid, int flag, @Nullable List files, List slices) { - super(menu); + super(menu.containerId); this.uuid = uuid; this.flag = flag; this.files = files; this.slices = slices; } - public UploadFileMessage(FriendlyByteBuf buf) { - super(buf); + private UploadFileMessage(FriendlyByteBuf buf) { + super(buf.readVarInt()); uuid = buf.readUUID(); var flag = this.flag = buf.readByte(); @@ -92,9 +96,8 @@ public UploadFileMessage(FriendlyByteBuf buf) { } } - @Override - public void write(FriendlyByteBuf buf) { - super.write(buf); + private void write(FriendlyByteBuf buf) { + buf.writeVarInt(containerId()); buf.writeUUID(uuid); buf.writeByte(flag); @@ -170,7 +173,7 @@ protected void handle(ServerNetworkContext context, ComputerMenu container) { } @Override - public MessageType type() { + public CustomPacketPayload.Type type() { return NetworkMessages.UPLOAD_FILE; } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveBlock.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveBlock.java index 276322f01..ffab6ad79 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveBlock.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveBlock.java @@ -11,8 +11,9 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; +import net.minecraft.world.ItemInteractionResult; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.BaseEntityBlock; import net.minecraft.world.level.block.Block; @@ -40,7 +41,6 @@ public DiskDriveBlock(Properties settings) { .setValue(STATE, DiskDriveState.EMPTY)); } - @Override protected void createBlockStateDefinition(StateDefinition.Builder properties) { properties.add(FACING, STATE); @@ -52,20 +52,18 @@ protected MapCodec codec() { } @Override - @Deprecated - public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { + protected ItemInteractionResult useItemOn(ItemStack stack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { if (player.isCrouching() && level.getBlockEntity(pos) instanceof DiskDriveBlockEntity drive) { // Try to put a disk into the drive - var disk = player.getItemInHand(hand); - if (disk.isEmpty()) return InteractionResult.PASS; + if (stack.isEmpty()) return ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION; - if (!level.isClientSide && drive.getDiskStack().isEmpty() && MediaProviders.get(disk) != null) { - drive.setDiskStack(disk.split(1)); + if (!level.isClientSide && drive.getDiskStack().isEmpty() && MediaProviders.get(stack) != null) { + drive.setDiskStack(stack.split(1)); } - return InteractionResult.sidedSuccess(level.isClientSide); + return ItemInteractionResult.sidedSuccess(level.isClientSide); } - return super.use(state, level, pos, player, hand, hit); + return super.useItemOn(stack, state, level, pos, player, hand, hit); } @Nullable diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveBlockEntity.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveBlockEntity.java index 337ef87fa..870355e5a 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveBlockEntity.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveBlockEntity.java @@ -11,12 +11,11 @@ import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.common.AbstractContainerBlockEntity; +import dan200.computercraft.shared.container.BasicContainer; import dan200.computercraft.shared.network.client.PlayRecordClientMessage; import dan200.computercraft.shared.network.server.ServerNetworking; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.NonNullList; +import net.minecraft.core.*; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.player.Inventory; @@ -30,6 +29,7 @@ import javax.annotation.Nullable; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -55,7 +55,7 @@ * * @see DiskDrivePeripheral */ -public final class DiskDriveBlockEntity extends AbstractContainerBlockEntity { +public final class DiskDriveBlockEntity extends AbstractContainerBlockEntity implements BasicContainer { private static final String NBT_ITEM = "Item"; private static final class MountInfo { @@ -109,17 +109,17 @@ public Direction getDirection() { } @Override - public void load(CompoundTag nbt) { - super.load(nbt); - setDiskStack(nbt.contains(NBT_ITEM) ? ItemStack.of(nbt.getCompound(NBT_ITEM)) : ItemStack.EMPTY); + public void loadAdditional(CompoundTag nbt, HolderLookup.Provider registries) { + super.loadAdditional(nbt, registries); + setDiskStack(nbt.contains(NBT_ITEM) ? ItemStack.parseOptional(registries, nbt.getCompound(NBT_ITEM)) : ItemStack.EMPTY); } @Override - public void saveAdditional(CompoundTag tag) { - super.saveAdditional(tag); + public void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) { + super.saveAdditional(tag, registries); var stack = getDiskStack(); - if (!stack.isEmpty()) tag.put(NBT_ITEM, stack.save(new CompoundTag())); + if (!stack.isEmpty()) tag.put(NBT_ITEM, stack.save(registries)); } void serverTick() { @@ -135,7 +135,7 @@ var record = media.getAudio(); if (record != null) { recordPlaying = true; var title = media.getAudioTitle(); - sendMessage(new PlayRecordClientMessage(getBlockPos(), record, title)); + sendMessage(new PlayRecordClientMessage(getBlockPos(), Optional.of(Holder.direct(record)), Optional.ofNullable(title))); } } case STOP -> { @@ -147,10 +147,15 @@ var record = media.getAudio(); } @Override - public NonNullList getContents() { + public NonNullList getItems() { return inventory; } + @Override + public void setItems(NonNullList items) { + BasicContainer.defaultSetItems(inventory, items); + } + @Override public void setChanged() { if (level != null && !level.isClientSide) updateMedia(); @@ -162,7 +167,7 @@ public void setChanged() { */ private synchronized void updateMedia() { var newStack = getDiskStack(); - if (ItemStack.isSameItemSameTags(newStack, media.stack())) return; + if (ItemStack.isSameItemSameComponents(newStack, media.stack())) return; var newMedia = MediaStack.of(newStack); @@ -233,7 +238,7 @@ private synchronized void updateDiskFromMedia() { */ @GuardedBy("this") private void updateMediaStack(ItemStack stack, boolean immediate) { - if (ItemStack.isSameItemSameTags(media.stack(), stack)) return; + if (ItemStack.isSameItemSameComponents(media.stack(), stack)) return; media = new MediaStack(stack, media.media()); if (immediate) { diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlock.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlock.java index b28ec6f51..b23cd3d85 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlock.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlock.java @@ -15,7 +15,6 @@ import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.RandomSource; -import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; @@ -91,8 +90,7 @@ public static boolean doesConnectVisually(BlockState state, Level level, BlockPo } @Override - @Deprecated - public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) { + protected VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) { return CableShapes.getShape(state); } @@ -139,7 +137,6 @@ public boolean onCustomDestroyBlock(BlockState state, Level world, BlockPos pos, } @Override - @Deprecated public ItemStack getCloneItemStack(LevelReader world, BlockPos pos, BlockState state) { return state.getValue(CABLE) ? new ItemStack(ModRegistry.Items.CABLE.get()) : new ItemStack(ModRegistry.Items.WIRED_MODEM.get()); } @@ -167,14 +164,12 @@ public void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable L } @Override - @Deprecated - public FluidState getFluidState(BlockState state) { + protected FluidState getFluidState(BlockState state) { return WaterloggableHelpers.getFluidState(state); } @Override - @Deprecated - public BlockState updateShape(BlockState state, Direction side, BlockState otherState, LevelAccessor level, BlockPos pos, BlockPos otherPos) { + protected BlockState updateShape(BlockState state, Direction side, BlockState otherState, LevelAccessor level, BlockPos pos, BlockPos otherPos) { WaterloggableHelpers.updateShape(state, level, pos); // Should never happen, but handle the case where we've no modem or cable. @@ -208,8 +203,7 @@ public BlockState updateShape(BlockState state, Direction side, BlockState other } @Override - @Deprecated - public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { + protected boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { var facing = state.getValue(MODEM).getFacing(); if (facing == null) return true; @@ -248,15 +242,13 @@ public static BlockState correctConnections(Level world, BlockPos pos, BlockStat } @Override - @Deprecated - public final InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { + protected final InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) { if (player.isCrouching() || !player.mayBuild()) return InteractionResult.PASS; return world.getBlockEntity(pos) instanceof CableBlockEntity modem ? modem.use(player) : InteractionResult.PASS; } @Override - @Deprecated - public final void neighborChanged(BlockState state, Level world, BlockPos pos, Block neighbourBlock, BlockPos neighbourPos, boolean isMoving) { + protected final void neighborChanged(BlockState state, Level world, BlockPos pos, Block neighbourBlock, BlockPos neighbourPos, boolean isMoving) { if (world.getBlockEntity(pos) instanceof CableBlockEntity modem) modem.neighborChanged(neighbourPos); } @@ -266,8 +258,7 @@ public final void onNeighborChange(BlockState state, LevelReader world, BlockPos } @Override - @Deprecated - public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource rand) { + protected void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource rand) { if (world.getBlockEntity(pos) instanceof CableBlockEntity modem) modem.blockTick(); } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlockEntity.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlockEntity.java index f5ed863b8..b491b9888 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlockEntity.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlockEntity.java @@ -15,6 +15,7 @@ import dan200.computercraft.shared.util.TickScheduler; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.world.InteractionResult; @@ -145,15 +146,15 @@ InteractionResult use(Player player) { } @Override - public void load(CompoundTag nbt) { - super.load(nbt); + public void loadAdditional(CompoundTag nbt, HolderLookup.Provider registries) { + super.loadAdditional(nbt, registries); peripheral.read(nbt, ""); } @Override - public void saveAdditional(CompoundTag nbt) { + public void saveAdditional(CompoundTag nbt, HolderLookup.Provider registries) { peripheral.write(nbt, ""); - super.saveAdditional(nbt); + super.saveAdditional(nbt, registries); } private void updateBlockState() { diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlockItem.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlockItem.java index cae36c886..56c7ce8ef 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlockItem.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlockItem.java @@ -32,7 +32,7 @@ boolean placeAt(Level world, BlockPos pos, BlockState state) { if (!state.canSurvive(world, pos)) return false; world.setBlockAndUpdate(pos, state); - var soundType = state.getBlock().getSoundType(state); + var soundType = state.getSoundType(); world.playSound(null, pos, soundType.getPlaceSound(), SoundSource.BLOCKS, (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); var tile = world.getBlockEntity(pos); diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemFullBlock.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemFullBlock.java index 6f9e0b958..0ddc14523 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemFullBlock.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemFullBlock.java @@ -10,7 +10,6 @@ import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.RandomSource; -import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; @@ -44,14 +43,12 @@ protected void createBlockStateDefinition(StateDefinition.Builder codec() { } @Override - @Deprecated - public VoxelShape getShape(BlockState blockState, BlockGetter blockView, BlockPos blockPos, CollisionContext context) { + protected VoxelShape getShape(BlockState blockState, BlockGetter blockView, BlockPos blockPos, CollisionContext context) { return ModemShapes.getBounds(blockState.getValue(FACING)); } @Override - @Deprecated - public FluidState getFluidState(BlockState state) { + protected FluidState getFluidState(BlockState state) { return WaterloggableHelpers.getFluidState(state); } @Override - @Deprecated - public BlockState updateShape(BlockState state, Direction side, BlockState otherState, LevelAccessor world, BlockPos pos, BlockPos otherPos) { + protected BlockState updateShape(BlockState state, Direction side, BlockState otherState, LevelAccessor world, BlockPos pos, BlockPos otherPos) { WaterloggableHelpers.updateShape(state, world, pos); return side == state.getValue(FACING) && !state.canSurvive(world, pos) ? state.getFluidState().createLegacyBlock() @@ -81,8 +78,7 @@ public BlockState updateShape(BlockState state, Direction side, BlockState other } @Override - @Deprecated - public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { + protected boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { var facing = state.getValue(FACING); return ModemShapes.canSupport(world, pos.relative(facing), facing.getOpposite()); } @@ -96,20 +92,17 @@ public BlockState getStateForPlacement(BlockPlaceContext placement) { } @Override - @Deprecated - public BlockState mirror(BlockState state, Mirror mirrorIn) { + protected BlockState mirror(BlockState state, Mirror mirrorIn) { return state.rotate(mirrorIn.getRotation(state.getValue(FACING))); } @Override - @Deprecated - public BlockState rotate(BlockState state, Rotation rot) { + protected BlockState rotate(BlockState state, Rotation rot) { return state.setValue(FACING, rot.rotate(state.getValue(FACING))); } @Override - @Deprecated - public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource rand) { + protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource rand) { var te = level.getBlockEntity(pos); if (te instanceof WirelessModemBlockEntity modem) modem.blockTick(); } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorBlock.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorBlock.java index b7d0e4392..36dee39b0 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorBlock.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorBlock.java @@ -13,7 +13,6 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.RandomSource; -import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; @@ -87,8 +86,7 @@ public BlockState getStateForPlacement(BlockPlaceContext context) { } @Override - @Deprecated - public final void onRemove(BlockState block, Level world, BlockPos pos, BlockState replace, boolean bool) { + protected final void onRemove(BlockState block, Level world, BlockPos pos, BlockState replace, boolean bool) { if (block.getBlock() == replace.getBlock()) return; var tile = world.getBlockEntity(pos); @@ -97,15 +95,13 @@ public final void onRemove(BlockState block, Level world, BlockPos pos, BlockSta } @Override - @Deprecated - public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource rand) { + protected void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource rand) { var te = world.getBlockEntity(pos); if (te instanceof MonitorBlockEntity monitor) monitor.blockTick(); } @Override - @Deprecated - public final InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { + protected final InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) { if (player.isCrouching() || !(level.getBlockEntity(pos) instanceof MonitorBlockEntity monitor) || monitor.getFront() != hit.getDirection()) { return InteractionResult.PASS; } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorBlockEntity.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorBlockEntity.java index 5b4deb814..6235d0c49 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorBlockEntity.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorBlockEntity.java @@ -14,6 +14,7 @@ import dan200.computercraft.shared.util.TickScheduler; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.world.level.block.entity.BlockEntity; @@ -98,17 +99,17 @@ public void setRemoved() { } @Override - public void saveAdditional(CompoundTag tag) { + public void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) { tag.putInt(NBT_X, xIndex); tag.putInt(NBT_Y, yIndex); tag.putInt(NBT_WIDTH, width); tag.putInt(NBT_HEIGHT, height); - super.saveAdditional(tag); + super.saveAdditional(tag, registries); } @Override - public void load(CompoundTag nbt) { - super.load(nbt); + public void loadAdditional(CompoundTag nbt, HolderLookup.Provider registries) { + super.loadAdditional(nbt, registries); var oldXIndex = xIndex; var oldYIndex = yIndex; @@ -202,8 +203,8 @@ public final ClientboundBlockEntityDataPacket getUpdatePacket() { } @Override - public final CompoundTag getUpdateTag() { - var nbt = super.getUpdateTag(); + public final CompoundTag getUpdateTag(HolderLookup.Provider registries) { + var nbt = super.getUpdateTag(registries); nbt.putInt(NBT_X, xIndex); nbt.putInt(NBT_Y, yIndex); nbt.putInt(NBT_WIDTH, width); diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java index 2317f9da9..b22499490 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java @@ -14,6 +14,7 @@ import javax.annotation.Nullable; import java.util.ArrayDeque; +import java.util.Optional; import java.util.Queue; public final class MonitorWatcher { @@ -40,7 +41,7 @@ public static void onWatch(LevelChunk chunk, ServerPlayer player) { if (serverMonitor == null || monitor.enqueued) continue; var state = getState(monitor, serverMonitor); - ServerNetworking.sendToPlayer(new MonitorClientMessage(monitor.getBlockPos(), state), player); + ServerNetworking.sendToPlayer(new MonitorClientMessage(monitor.getBlockPos(), Optional.ofNullable(state)), player); } } @@ -66,7 +67,7 @@ public static void onTick() { } var state = getState(tile, monitor); - ServerNetworking.sendToAllTracking(new MonitorClientMessage(pos, state), chunk); + ServerNetworking.sendToAllTracking(new MonitorClientMessage(pos, Optional.ofNullable(state)), chunk); limit -= state == null ? 0 : state.size(); } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterBlockEntity.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterBlockEntity.java index f6037802a..624db28b1 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterBlockEntity.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterBlockEntity.java @@ -5,13 +5,18 @@ package dan200.computercraft.shared.peripheral.printer; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.common.AbstractContainerBlockEntity; import dan200.computercraft.shared.computer.terminal.NetworkedTerminal; +import dan200.computercraft.shared.container.BasicContainer; import dan200.computercraft.shared.container.BasicWorldlyContainer; +import dan200.computercraft.shared.media.items.PrintoutData; import dan200.computercraft.shared.media.items.PrintoutItem; import dan200.computercraft.shared.util.ColourUtils; +import dan200.computercraft.shared.util.DataComponentUtil; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.HolderLookup; import net.minecraft.core.NonNullList; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.ContainerHelper; @@ -23,6 +28,7 @@ import net.minecraft.world.level.block.state.BlockState; import javax.annotation.Nullable; +import java.util.List; public final class PrinterBlockEntity extends AbstractContainerBlockEntity implements BasicWorldlyContainer { private static final String NBT_PRINTING = "Printing"; @@ -37,7 +43,7 @@ public final class PrinterBlockEntity extends AbstractContainerBlockEntity imple private final PrinterPeripheral peripheral = new PrinterPeripheral(this); private final NonNullList inventory = NonNullList.withSize(SLOTS, ItemStack.EMPTY); - private final NetworkedTerminal page = new NetworkedTerminal(PrintoutItem.LINE_MAX_LENGTH, PrintoutItem.LINES_PER_PAGE, true); + private final NetworkedTerminal page = new NetworkedTerminal(PrintoutData.LINE_LENGTH, PrintoutData.LINES_PER_PAGE, true); private String pageTitle = ""; private boolean printing = false; @@ -50,8 +56,8 @@ public IPeripheral peripheral() { } @Override - public void load(CompoundTag nbt) { - super.load(nbt); + public void loadAdditional(CompoundTag nbt, HolderLookup.Provider registries) { + super.loadAdditional(nbt, registries); // Read page synchronized (page) { @@ -61,11 +67,11 @@ public void load(CompoundTag nbt) { } // Read inventory - ContainerHelper.loadAllItems(nbt, inventory); + ContainerHelper.loadAllItems(nbt, inventory, registries); } @Override - public void saveAdditional(CompoundTag tag) { + public void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) { // Write page synchronized (page) { tag.putBoolean(NBT_PRINTING, printing); @@ -74,9 +80,9 @@ public void saveAdditional(CompoundTag tag) { } // Write inventory - ContainerHelper.saveAllItems(tag, inventory); + ContainerHelper.saveAllItems(tag, inventory, registries); - super.saveAdditional(tag); + super.saveAdditional(tag, registries); } boolean isPrinting() { @@ -84,10 +90,15 @@ boolean isPrinting() { } @Override - public NonNullList getContents() { + public NonNullList getItems() { return inventory; } + @Override + public void setItems(NonNullList items) { + BasicContainer.defaultSetItems(inventory, items); + } + @Override public void setChanged() { super.setChanged(); @@ -183,12 +194,13 @@ private boolean inputPage() { page.setTextColour(dye.getId()); page.clear(); - if (paperStack.getItem() instanceof PrintoutItem) { - pageTitle = PrintoutItem.getTitle(paperStack); - var text = PrintoutItem.getText(paperStack); - var textColour = PrintoutItem.getColours(paperStack); + + var printout = paperStack.get(ModRegistry.DataComponents.PRINTOUT.get()); + if (printout != null) { + pageTitle = printout.title(); for (var y = 0; y < page.getHeight(); y++) { - page.setLine(y, text[y], textColour[y], ""); + var line = printout.lines().get(y); + page.setLine(y, line.text(), line.foreground(), ""); } } else { pageTitle = ""; @@ -215,14 +227,16 @@ private boolean inputPage() { private boolean outputPage() { var height = page.getHeight(); - var lines = new String[height]; - var colours = new String[height]; + var lines = new PrintoutData.Line[height]; for (var i = 0; i < height; i++) { - lines[i] = page.getLine(i).toString(); - colours[i] = page.getTextColourLine(i).toString(); + lines[i] = new PrintoutData.Line(page.getLine(i).toString(), page.getTextColourLine(i).toString()); } - var stack = PrintoutItem.createSingleFromTitleAndText(pageTitle, lines, colours); + var stack = DataComponentUtil.createStack( + ModRegistry.Items.PRINTED_PAGE.get(), + ModRegistry.DataComponents.PRINTOUT.get(), new PrintoutData(pageTitle, List.of(lines)) + ); + for (var slot : BOTTOM_SLOTS) { if (inventory.get(slot).isEmpty()) { inventory.set(slot, stack); diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/speaker/EncodedAudio.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/speaker/EncodedAudio.java index 35a853920..94ed7bf87 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/speaker/EncodedAudio.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/speaker/EncodedAudio.java @@ -4,7 +4,10 @@ package dan200.computercraft.shared.peripheral.speaker; -import net.minecraft.network.FriendlyByteBuf; +import dan200.computercraft.shared.network.codec.MoreStreamCodecs; +import io.netty.buffer.ByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; import java.nio.ByteBuffer; @@ -17,23 +20,11 @@ * @param audio The block of encoded audio. */ public record EncodedAudio(int charge, int strength, boolean previousBit, ByteBuffer audio) { - public void write(FriendlyByteBuf buf) { - buf.writeVarInt(charge()); - buf.writeVarInt(strength()); - buf.writeBoolean(previousBit()); - buf.writeVarInt(audio.remaining()); - buf.writeBytes(audio().duplicate()); - } - - public static EncodedAudio read(FriendlyByteBuf buf) { - var charge = buf.readVarInt(); - var strength = buf.readVarInt(); - var previousBit = buf.readBoolean(); - - var length = buf.readVarInt(); - var bytes = new byte[length]; - buf.readBytes(bytes); - - return new EncodedAudio(charge, strength, previousBit, ByteBuffer.wrap(bytes)); - } + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.VAR_INT, EncodedAudio::charge, + ByteBufCodecs.VAR_INT, EncodedAudio::strength, + ByteBufCodecs.BOOL, EncodedAudio::previousBit, + MoreStreamCodecs.BYTE_BUFFER, EncodedAudio::audio, + EncodedAudio::new + ); } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPosition.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPosition.java index ec8c54c62..1bb33ce78 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPosition.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPosition.java @@ -4,7 +4,9 @@ package dan200.computercraft.shared.peripheral.speaker; +import dan200.computercraft.shared.network.codec.MoreStreamCodecs; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; @@ -36,22 +38,11 @@ public record Message( Vec3 position, OptionalInt entity ) { - public static Message read(FriendlyByteBuf buffer) { - var level = buffer.readResourceLocation(); - var position = new Vec3(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()); - var entity = buffer.readBoolean() ? OptionalInt.of(buffer.readInt()) : OptionalInt.empty(); - return new Message(level, position, entity); - } - - public void write(FriendlyByteBuf buffer) { - buffer.writeResourceLocation(level); - - buffer.writeDouble(position.x); - buffer.writeDouble(position.y); - buffer.writeDouble(position.z); - - buffer.writeBoolean(entity.isPresent()); - if (entity.isPresent()) buffer.writeInt(entity.getAsInt()); - } + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ResourceLocation.STREAM_CODEC, Message::level, + MoreStreamCodecs.VEC3, Message::position, + MoreStreamCodecs.OPTIONAL_INT, Message::entity, + Message::new + ); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/platform/PlatformHelper.java b/projects/common/src/main/java/dan200/computercraft/shared/platform/PlatformHelper.java index b93b56dfe..7e9265af7 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/platform/PlatformHelper.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/platform/PlatformHelper.java @@ -10,20 +10,15 @@ import dan200.computercraft.api.network.wired.WiredElement; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.config.ConfigFile; -import dan200.computercraft.shared.network.MessageType; -import dan200.computercraft.shared.network.NetworkMessage; -import dan200.computercraft.shared.network.client.ClientNetworkContext; import dan200.computercraft.shared.network.container.ContainerData; import dan200.computercraft.shared.util.InventoryUtil; import net.minecraft.commands.synchronization.ArgumentTypeInfo; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Registry; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.common.ClientCommonPacketListener; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayerGameMode; @@ -41,18 +36,14 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Recipe; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; import javax.annotation.Nullable; import java.util.List; -import java.util.function.BiFunction; import java.util.function.Consumer; -import java.util.function.Function; import java.util.function.Predicate; /** @@ -102,16 +93,6 @@ static PlatformHelper get() { */ boolean shouldLoadResource(JsonObject object); - /** - * Create a new block entity type which serves a particular block. - * - * @param factory The method which creates a new block entity with this type, typically the constructor. - * @param block The block this block entity exists on. - * @param The type of block entity we're creating. - * @return The new block entity type. - */ - BlockEntityType createBlockEntityType(BiFunction factory, Block block); - /** * Register a new argument type. * @@ -127,13 +108,13 @@ static PlatformHelper get() { /** * Create a menu type which sends additional data when opened. * - * @param reader Parse the additional container data into a usable type. + * @param codec Parse the additional container data into a usable type. * @param factory The factory to create the new menu. * @param The menu/container than we open. * @param The data that we send to the client. * @return The menu type for this container. */ - MenuType createMenuType(Function reader, ContainerData.Factory factory); + MenuType createMenuType(StreamCodec codec, ContainerData.Factory factory); /** * Open a container using a specific {@link ContainerData}. @@ -144,24 +125,6 @@ static PlatformHelper get() { */ void openMenu(Player player, MenuProvider owner, ContainerData menu); - /** - * Create a new {@link MessageType}. - * - * @param The type of this message. - * @param id The id for this message type. - * @param reader The function which reads the packet from a buffer. Should be the inverse to {@link NetworkMessage#write(FriendlyByteBuf)}. - * @return The new {@link MessageType} instance. - */ - > MessageType createMessageType(ResourceLocation id, FriendlyByteBuf.Reader reader); - - /** - * Convert a clientbound {@link NetworkMessage} to a Minecraft {@link Packet}. - * - * @param message The messsge to convert. - * @return The converted message. - */ - Packet createPacket(NetworkMessage message); - /** * Invalidate components on a block enitty. * @@ -313,16 +276,6 @@ default boolean isFakePlayer(ServerPlayer player) { return player.connection == null || player.getClass() != ServerPlayer.class; } - /** - * Get the distance a player can reach. - * - * @param player The player who is reaching. - * @return The distance (in blocks) that a player can reach. - */ - default double getReachDistance(Player player) { - return Player.getPickRange(player.isCreative()); - } - /** * Check if this item is a tool and has some secondary usage. *

@@ -364,7 +317,7 @@ default double getReachDistance(Player player) { * Place an item against a block. *

* Implementations should largely mirror {@link ServerPlayerGameMode#useItemOn(ServerPlayer, Level, ItemStack, InteractionHand, BlockHitResult)} - * (including any loader-specific modifications), except the call to {@link BlockState#use(Level, Player, InteractionHand, BlockHitResult)} + * (including any loader-specific modifications), except the call to {@link BlockState#useItemOn(ItemStack, Level, Player, InteractionHand, BlockHitResult)} * should only be evaluated when {@code canUseBlock} evaluates to true. * * @param player The player which is placing this item. 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..ba660386e 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 @@ -18,7 +18,6 @@ * @param goldIngot All {@link Items#GOLD_INGOT} items. * @param goldBlock All {@link Items#GOLD_BLOCK} items. * @param ironIngot All {@link Items#IRON_INGOT} items. - * @param head All types of skull (player heads, mob skulls, etc...). * @param dye All dye items. * @param enderPearl All {@link Items#ENDER_PEARL} items. * @param woodenChest All wooden chests (both normal and trapped chests). @@ -32,7 +31,6 @@ public record RecipeIngredients( Ingredient goldIngot, Ingredient goldBlock, Ingredient ironIngot, - Ingredient head, Ingredient dye, Ingredient enderPearl, Ingredient woodenChest diff --git a/projects/common/src/main/java/dan200/computercraft/shared/platform/RegistryEntry.java b/projects/common/src/main/java/dan200/computercraft/shared/platform/RegistryEntry.java index 8b699fddf..d2556bb56 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/platform/RegistryEntry.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/platform/RegistryEntry.java @@ -10,7 +10,6 @@ import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.ExtraCodecs; import java.util.function.Supplier; @@ -35,14 +34,13 @@ public T get() { return holder().value(); } } - Codec> codec = ResourceLocation.CODEC.flatXmap( + + return ResourceLocation.CODEC.flatXmap( id -> registry .getHolder(ResourceKey.create(registry.key(), id)) .map(x -> DataResult.success(new HolderEntry<>(id, x))) .orElseGet(() -> DataResult.error(() -> "Unknown registry key in " + registry.key() + ": " + id)), holder -> DataResult.success(holder.id()) ); - - return ExtraCodecs.overrideLifecycle(codec, x -> registry.lifecycle(x.get()), x -> registry.lifecycle(x.get())); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java b/projects/common/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java index a5d75dd5e..d9ad11cae 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java @@ -8,7 +8,7 @@ import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.upgrades.UpgradeData; import dan200.computercraft.core.computer.ComputerSide; -import dan200.computercraft.shared.common.IColouredItem; +import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; @@ -18,7 +18,8 @@ import dan200.computercraft.shared.network.server.ServerNetworking; import dan200.computercraft.shared.pocket.items.PocketComputerItem; import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.component.DataComponents; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; @@ -26,6 +27,7 @@ import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.DyedItemColor; import javax.annotation.Nullable; import java.util.ArrayList; @@ -70,13 +72,13 @@ public Entity getEntity() { @Override public int getColour() { - return IColouredItem.getColourBasic(stack); + return DyedItemColor.getOrDefault(stack, -1); } @Override public void setColour(int colour) { - IColouredItem.setColourBasic(stack, colour); - updateUpgradeNBTData(); + stack.set(DataComponents.DYED_COLOR, colour == -1 ? null : new DyedItemColor(colour, false)); + setItemChanged(); } @Override @@ -91,12 +93,21 @@ public void setLight(int colour) { } @Override - public CompoundTag getUpgradeNBTData() { - return PocketComputerItem.getUpgradeInfo(stack); + public DataComponentPatch getUpgradeData() { + var upgrade = PocketComputerItem.getUpgradeWithData(stack); + return upgrade == null ? DataComponentPatch.EMPTY : upgrade.data(); } @Override - public void updateUpgradeNBTData() { + public void setUpgradeData(DataComponentPatch data) { + var upgrade = PocketComputerItem.getUpgrade(stack); + if (upgrade == null) return; + + PocketComputerItem.setUpgrade(stack, new UpgradeData<>(upgrade, data)); + setItemChanged(); + } + + private void setItemChanged() { if (entity instanceof Player player) player.getInventory().setChanged(); } @@ -107,7 +118,7 @@ public void invalidatePeripheral() { } public @Nullable UpgradeData getUpgrade() { - return upgrade == null ? null : UpgradeData.of(upgrade, getUpgradeNBTData()); + return upgrade == null ? null : UpgradeData.of(upgrade, getUpgradeData()); } /** @@ -119,8 +130,8 @@ public void invalidatePeripheral() { */ public void setUpgrade(@Nullable UpgradeData upgrade) { synchronized (this) { - PocketComputerItem.setUpgrade(stack, upgrade); - updateUpgradeNBTData(); + stack.set(ModRegistry.DataComponents.POCKET_UPGRADE.get(), upgrade); + setItemChanged(); this.upgrade = upgrade == null ? null : upgrade.upgrade(); invalidatePeripheral(); } 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 43f0bfa4a..9ecb666d8 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 @@ -12,19 +12,19 @@ import dan200.computercraft.api.upgrades.UpgradeData; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.impl.PocketUpgrades; -import dan200.computercraft.shared.common.IColouredItem; +import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerContext; -import dan200.computercraft.shared.computer.items.IComputerItem; +import dan200.computercraft.shared.computer.items.ServerComputerReference; import dan200.computercraft.shared.config.Config; import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.pocket.apis.PocketAPI; import dan200.computercraft.shared.pocket.core.PocketServerComputer; import dan200.computercraft.shared.pocket.inventory.PocketComputerMenuProvider; +import dan200.computercraft.shared.util.DataComponentUtil; import dan200.computercraft.shared.util.IDAssigner; -import dan200.computercraft.shared.util.NBTUtil; +import dan200.computercraft.shared.util.NonNegativeId; import net.minecraft.ChatFormatting; -import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; @@ -43,16 +43,8 @@ import javax.annotation.Nullable; import java.util.List; import java.util.Objects; -import java.util.UUID; - -public class PocketComputerItem extends Item implements IComputerItem, IMedia, IColouredItem { - private static final String NBT_UPGRADE = "Upgrade"; - private static final String NBT_UPGRADE_INFO = "UpgradeInfo"; - public static final String NBT_ON = "On"; - - private static final String NBT_INSTANCE = "InstanceId"; - private static final String NBT_SESSION = "SessionId"; +public class PocketComputerItem extends Item implements IMedia { private final ComputerFamily family; public PocketComputerItem(Properties settings, ComputerFamily family) { @@ -60,18 +52,6 @@ public PocketComputerItem(Properties settings, ComputerFamily family) { this.family = family; } - public ItemStack create(int id, @Nullable String label, int colour, @Nullable UpgradeData upgrade) { - 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 (colour != -1) result.getOrCreateTag().putInt(NBT_COLOUR, colour); - return result; - } - private boolean tick(ItemStack stack, Level world, Entity entity, PocketServerComputer computer) { var upgrade = getUpgrade(stack); @@ -80,13 +60,6 @@ private boolean tick(ItemStack stack, Level world, Entity entity, PocketServerCo var changed = false; - // Sync ID - var id = computer.getID(); - if (id != getComputerID(stack)) { - changed = true; - setComputerID(stack, id); - } - // Sync label var label = computer.getLabel(); if (!Objects.equals(label, getLabel(stack))) { @@ -97,7 +70,7 @@ private boolean tick(ItemStack stack, Level world, Entity entity, PocketServerCo var on = computer.isOn(); if (on != isMarkedOn(stack)) { changed = true; - stack.getOrCreateTag().putBoolean(NBT_ON, on); + stack.set(ModRegistry.DataComponents.ON.get(), on); } // Update pocket upgrade @@ -164,11 +137,11 @@ public Component getName(ItemStack stack) { @Override - public void appendHoverText(ItemStack stack, @Nullable Level world, List list, TooltipFlag flag) { + public void appendHoverText(ItemStack stack, TooltipContext context, List list, TooltipFlag flag) { if (flag.isAdvanced() || getLabel(stack) == null) { - var id = getComputerID(stack); - if (id >= 0) { - list.add(Component.translatable("gui.computercraft.tooltip.computer_id", id) + var id = stack.get(ModRegistry.DataComponents.COMPUTER_ID.get()); + if (id != null) { + list.add(Component.translatable("gui.computercraft.tooltip.computer_id", id.id()) .withStyle(ChatFormatting.GRAY)); } } @@ -191,19 +164,13 @@ public String getCreatorModId(ItemStack stack) { public PocketServerComputer createServerComputer(ServerLevel level, Entity entity, @Nullable Container inventory, ItemStack stack) { var registry = ServerContext.get(level.getServer()).registry(); - var computer = (PocketServerComputer) registry.get(getSessionID(stack), getInstanceID(stack)); + var computer = (PocketServerComputer) ServerComputerReference.get(stack, registry); if (computer == null) { - var computerID = getComputerID(stack); - if (computerID < 0) { - computerID = ComputerCraftAPI.createUniqueNumberedSaveDir(level.getServer(), IDAssigner.COMPUTER); - setComputerID(stack, computerID); - } + var computerID = NonNegativeId.getOrCreate(level.getServer(), stack, ModRegistry.DataComponents.COMPUTER_ID.get(), IDAssigner.COMPUTER); + computer = new PocketServerComputer(level, entity.blockPosition(), computerID, getLabel(stack), getFamily()); - computer = new PocketServerComputer(level, entity.blockPosition(), getComputerID(stack), getLabel(stack), getFamily()); - - var tag = stack.getOrCreateTag(); - tag.putInt(NBT_SESSION, registry.getSessionID()); - tag.putUUID(NBT_INSTANCE, computer.register()); + var instanceId = computer.register(); + stack.set(ModRegistry.DataComponents.COMPUTER.get(), new ServerComputerReference(registry.getSessionID(), instanceId)); var upgrade = getUpgrade(stack); @@ -221,94 +188,49 @@ public PocketServerComputer createServerComputer(ServerLevel level, Entity entit @Nullable public static PocketServerComputer getServerComputer(MinecraftServer server, ItemStack stack) { - return (PocketServerComputer) ServerContext.get(server).registry().get(getSessionID(stack), getInstanceID(stack)); - } - - // IComputerItem implementation - - private static void setComputerID(ItemStack stack, int computerID) { - stack.getOrCreateTag().putInt(NBT_ID, computerID); - } - - @Override - public @Nullable String getLabel(ItemStack stack) { - return IComputerItem.super.getLabel(stack); + return (PocketServerComputer) ServerComputerReference.get(stack, ServerContext.get(server).registry()); } public ComputerFamily getFamily() { return family; } - @Override - public ItemStack changeItem(ItemStack stack, Item newItem) { - return newItem instanceof PocketComputerItem pocket ? pocket.create( - getComputerID(stack), getLabel(stack), getColour(stack), - getUpgradeWithData(stack) - ) : ItemStack.EMPTY; - } - // IMedia + @Override + public @Nullable String getLabel(ItemStack stack) { + return DataComponentUtil.getCustomName(stack); + } + @Override public boolean setLabel(ItemStack stack, @Nullable String label) { - if (label != null) { - stack.setHoverName(Component.literal(label)); - } else { - stack.resetHoverName(); - } + DataComponentUtil.setCustomName(stack, label); return true; } @Override public @Nullable Mount createDataMount(ItemStack stack, ServerLevel level) { - var id = getComputerID(stack); - if (id >= 0) { - return ComputerCraftAPI.createSaveDirMount(level.getServer(), "computer/" + id, Config.computerSpaceLimit); + var id = stack.get(ModRegistry.DataComponents.COMPUTER_ID.get()); + if (id != null) { + return ComputerCraftAPI.createSaveDirMount(level.getServer(), "computer/" + id.id(), Config.computerSpaceLimit); } return null; } - public static @Nullable UUID getInstanceID(ItemStack stack) { - var nbt = stack.getTag(); - return nbt != null && nbt.hasUUID(NBT_INSTANCE) ? nbt.getUUID(NBT_INSTANCE) : null; - } - - private static int getSessionID(ItemStack stack) { - var nbt = stack.getTag(); - return nbt != null && nbt.contains(NBT_SESSION) ? nbt.getInt(NBT_SESSION) : -1; - } - private static boolean isMarkedOn(ItemStack stack) { - var nbt = stack.getTag(); - return nbt != null && nbt.getBoolean(NBT_ON); + return stack.getOrDefault(ModRegistry.DataComponents.ON.get(), false); } 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)); + return stack.get(ModRegistry.DataComponents.POCKET_UPGRADE.get()); } 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()); - compound.put(NBT_UPGRADE_INFO, upgrade.data().copy()); - } - } - - public static CompoundTag getUpgradeInfo(ItemStack stack) { - return stack.getOrCreateTagElement(NBT_UPGRADE_INFO); + stack.set(ModRegistry.DataComponents.POCKET_UPGRADE.get(), upgrade); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java b/projects/common/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java index 263935903..5fa758269 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java @@ -9,7 +9,7 @@ import dan200.computercraft.impl.PocketUpgrades; import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.pocket.items.PocketComputerItem; -import net.minecraft.core.RegistryAccess; +import net.minecraft.core.HolderLookup; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CraftingBookCategory; @@ -28,8 +28,8 @@ public boolean canCraftInDimensions(int x, int y) { } @Override - public ItemStack getResultItem(RegistryAccess registryAccess) { - return ModRegistry.Items.POCKET_COMPUTER_NORMAL.get().create(-1, null, -1, null); + public ItemStack getResultItem(HolderLookup.Provider registryAccess) { + return new ItemStack(ModRegistry.Items.POCKET_COMPUTER_NORMAL.get()); } @Override @@ -38,7 +38,7 @@ public boolean matches(CraftingContainer inventory, Level world) { } @Override - public ItemStack assemble(CraftingContainer inventory, RegistryAccess registryAccess) { + public ItemStack assemble(CraftingContainer inventory, HolderLookup.Provider registryAccess) { // Scan the grid for a pocket computer var computer = ItemStack.EMPTY; var computerX = -1; @@ -80,10 +80,9 @@ public ItemStack assemble(CraftingContainer inventory, RegistryAccess registryAc if (upgrade == null) return ItemStack.EMPTY; // Construct the new stack - var computerID = itemComputer.getComputerID(computer); - var label = itemComputer.getLabel(computer); - var colour = itemComputer.getColour(computer); - return itemComputer.create(computerID, label, colour, upgrade); + var result = computer.copyWithCount(1); + result.set(ModRegistry.DataComponents.POCKET_UPGRADE.get(), upgrade); + return result; } @Override diff --git a/projects/common/src/main/java/dan200/computercraft/shared/recipe/BasicRecipeSerialiser.java b/projects/common/src/main/java/dan200/computercraft/shared/recipe/BasicRecipeSerialiser.java new file mode 100644 index 000000000..62f1fd8c3 --- /dev/null +++ b/projects/common/src/main/java/dan200/computercraft/shared/recipe/BasicRecipeSerialiser.java @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.shared.recipe; + +import com.mojang.serialization.DataResult; +import com.mojang.serialization.MapCodec; +import dan200.computercraft.impl.RegistryHelper; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeSerializer; + +import java.util.function.Function; + +/** + * A basic {@link RecipeSerializer} implementation. + * + * @param codec The codec to read/write the recipe from JSON. + * @param streamCodec The codec to read/write the recipe from a network stream. + * @param The type of recipe to serialise. + */ +public record BasicRecipeSerialiser>( + MapCodec codec, StreamCodec streamCodec +) implements RecipeSerializer { + public BasicRecipeSerialiser(MapCodec codec, StreamCodec streamCodec) { + this.codec = codec.flatXmap(this::check, DataResult::success); + this.streamCodec = streamCodec.map(x -> check(x).getOrThrow(), Function.identity()); + } + + private DataResult check(T recipe) { + if (recipe.getSerializer() == this) return DataResult.success(recipe); + + return DataResult.error(() -> + "Expected serialiser to be " + RegistryHelper.getKeyOrThrow(BuiltInRegistries.RECIPE_SERIALIZER, this) + + ", but was " + RegistryHelper.getKeyOrThrow(BuiltInRegistries.RECIPE_SERIALIZER, recipe.getSerializer()) + ); + } +} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/recipe/CustomShapedRecipe.java b/projects/common/src/main/java/dan200/computercraft/shared/recipe/CustomShapedRecipe.java index e966be63d..4c99a8c3c 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/recipe/CustomShapedRecipe.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/recipe/CustomShapedRecipe.java @@ -4,13 +4,6 @@ package dan200.computercraft.shared.recipe; -import com.mojang.serialization.Codec; -import com.mojang.serialization.DataResult; -import dan200.computercraft.impl.RegistryHelper; -import dan200.computercraft.shared.ModRegistry; -import net.minecraft.Util; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.ShapedRecipe; @@ -20,12 +13,8 @@ /** * A custom version of {@link ShapedRecipe}, which can be converted to and from a {@link ShapedRecipeSpec}. - *

- * This recipe may both be used as a normal recipe (behaving mostly the same as {@link ShapedRecipe}, with - * {@linkplain MoreCodecs#ITEM_STACK_WITH_NBT support for putting nbt on the result}), or subclassed to - * customise the crafting behaviour. */ -public class CustomShapedRecipe extends ShapedRecipe { +public abstract class CustomShapedRecipe extends ShapedRecipe { private final ShapedRecipePattern pattern; private final ItemStack result; @@ -40,46 +29,12 @@ public final ShapedRecipeSpec toSpec() { } @Override - public RecipeSerializer getSerializer() { - return ModRegistry.RecipeSerializers.SHAPED.get(); - } + public abstract RecipeSerializer getSerializer(); public static RecipeSerializer serialiser(Function factory) { - return new Serialiser<>(r -> DataResult.success(factory.apply(r))); - } - - public static RecipeSerializer validatingSerialiser(Function> factory) { - return new Serialiser<>(factory); - } - - private static final class Serialiser implements RecipeSerializer { - private final Function> factory; - private final Codec codec; - - private Serialiser(Function> factory) { - this.factory = r -> factory.apply(r).flatMap(x -> { - if (x.getSerializer() != this) { - return DataResult.error(() -> "Expected serialiser to be " + RegistryHelper.getKeyOrThrow(BuiltInRegistries.RECIPE_SERIALIZER, this) - + ", but was " + RegistryHelper.getKeyOrThrow(BuiltInRegistries.RECIPE_SERIALIZER, x.getSerializer())); - } - return DataResult.success(x); - }); - this.codec = ShapedRecipeSpec.CODEC.flatXmap(factory, x -> DataResult.success(x.toSpec())).codec(); - } - - @Override - public Codec codec() { - return codec; - } - - @Override - public T fromNetwork(FriendlyByteBuf buffer) { - return Util.getOrThrow(factory.apply(ShapedRecipeSpec.fromNetwork(buffer)), IllegalStateException::new); - } - - @Override - public void toNetwork(FriendlyByteBuf buffer, T recipe) { - recipe.toSpec().toNetwork(buffer); - } + return new BasicRecipeSerialiser( + ShapedRecipeSpec.CODEC.xmap(factory, CustomShapedRecipe::toSpec), + ShapedRecipeSpec.STREAM_CODEC.map(factory, CustomShapedRecipe::toSpec) + ); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/recipe/CustomShapelessRecipe.java b/projects/common/src/main/java/dan200/computercraft/shared/recipe/CustomShapelessRecipe.java index c9a4749a4..b413008d9 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/recipe/CustomShapelessRecipe.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/recipe/CustomShapelessRecipe.java @@ -4,13 +4,6 @@ package dan200.computercraft.shared.recipe; -import com.mojang.serialization.Codec; -import com.mojang.serialization.DataResult; -import dan200.computercraft.impl.RegistryHelper; -import dan200.computercraft.shared.ModRegistry; -import net.minecraft.Util; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.ShapelessRecipe; @@ -19,16 +12,12 @@ /** * A custom version of {@link ShapelessRecipe}, which can be converted to and from a {@link ShapelessRecipeSpec}. - *

- * This recipe may both be used as a normal recipe (behaving mostly the same as {@link ShapelessRecipe}, with - * {@linkplain MoreCodecs#ITEM_STACK_WITH_NBT support for putting nbt on the result}), or subclassed to - * customise the crafting behaviour. */ -public class CustomShapelessRecipe extends ShapelessRecipe { +public abstract class CustomShapelessRecipe extends ShapelessRecipe { private final ItemStack result; private final boolean showNotification; - public CustomShapelessRecipe(ShapelessRecipeSpec recipe) { + protected CustomShapelessRecipe(ShapelessRecipeSpec recipe) { super(recipe.properties().group(), recipe.properties().category(), recipe.result(), recipe.ingredients()); this.result = recipe.result(); this.showNotification = recipe.properties().showNotification(); @@ -44,46 +33,12 @@ public final boolean showNotification() { } @Override - public RecipeSerializer getSerializer() { - return ModRegistry.RecipeSerializers.SHAPELESS.get(); - } + public abstract RecipeSerializer getSerializer(); public static RecipeSerializer serialiser(Function factory) { - return new CustomShapelessRecipe.Serialiser<>(r -> DataResult.success(factory.apply(r))); - } - - public static RecipeSerializer validatingSerialiser(Function> factory) { - return new CustomShapelessRecipe.Serialiser<>(factory); - } - - private static final class Serialiser implements RecipeSerializer { - private final Function> factory; - private final Codec codec; - - private Serialiser(Function> factory) { - this.factory = r -> factory.apply(r).flatMap(x -> { - if (x.getSerializer() != this) { - return DataResult.error(() -> "Expected serialiser to be " + RegistryHelper.getKeyOrThrow(BuiltInRegistries.RECIPE_SERIALIZER, this) - + ", but was " + RegistryHelper.getKeyOrThrow(BuiltInRegistries.RECIPE_SERIALIZER, x.getSerializer())); - } - return DataResult.success(x); - }); - this.codec = ShapelessRecipeSpec.CODEC.flatXmap(factory, x -> DataResult.success(x.toSpec())).codec(); - } - - @Override - public Codec codec() { - return codec; - } - - @Override - public T fromNetwork(FriendlyByteBuf buffer) { - return Util.getOrThrow(factory.apply(ShapelessRecipeSpec.fromNetwork(buffer)), IllegalStateException::new); - } - - @Override - public void toNetwork(FriendlyByteBuf buffer, T recipe) { - recipe.toSpec().toNetwork(buffer); - } + return new BasicRecipeSerialiser<>( + ShapelessRecipeSpec.CODEC.xmap(factory, CustomShapelessRecipe::toSpec), + ShapelessRecipeSpec.STREAM_CODEC.map(factory, CustomShapelessRecipe::toSpec) + ); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/recipe/ImpostorShapedRecipe.java b/projects/common/src/main/java/dan200/computercraft/shared/recipe/ImpostorShapedRecipe.java index fa09ba49f..f2eabcfc0 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/recipe/ImpostorShapedRecipe.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/recipe/ImpostorShapedRecipe.java @@ -5,7 +5,7 @@ package dan200.computercraft.shared.recipe; import dan200.computercraft.shared.ModRegistry; -import net.minecraft.core.RegistryAccess; +import net.minecraft.core.HolderLookup; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CustomRecipe; @@ -29,7 +29,7 @@ public boolean matches(CraftingContainer inv, Level world) { } @Override - public ItemStack assemble(CraftingContainer inventory, RegistryAccess registryAccess) { + public ItemStack assemble(CraftingContainer inventory, HolderLookup.Provider registryAccess) { return ItemStack.EMPTY; } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/recipe/ImpostorShapelessRecipe.java b/projects/common/src/main/java/dan200/computercraft/shared/recipe/ImpostorShapelessRecipe.java index 4bace646c..1bb329251 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/recipe/ImpostorShapelessRecipe.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/recipe/ImpostorShapelessRecipe.java @@ -5,7 +5,7 @@ package dan200.computercraft.shared.recipe; import dan200.computercraft.shared.ModRegistry; -import net.minecraft.core.RegistryAccess; +import net.minecraft.core.HolderLookup; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CustomRecipe; @@ -29,7 +29,7 @@ public boolean matches(CraftingContainer inv, Level world) { } @Override - public ItemStack assemble(CraftingContainer inventory, RegistryAccess access) { + public ItemStack assemble(CraftingContainer inventory, HolderLookup.Provider access) { return ItemStack.EMPTY; } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/recipe/MoreCodecs.java b/projects/common/src/main/java/dan200/computercraft/shared/recipe/MoreCodecs.java deleted file mode 100644 index 99204ed35..000000000 --- a/projects/common/src/main/java/dan200/computercraft/shared/recipe/MoreCodecs.java +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers -// -// SPDX-License-Identifier: MPL-2.0 - -package dan200.computercraft.shared.recipe; - -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.datafixers.util.Either; -import com.mojang.serialization.Codec; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.minecraft.core.NonNullList; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.TagParser; -import net.minecraft.util.ExtraCodecs; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.item.crafting.Ingredient; -import net.minecraft.world.item.crafting.ShapelessRecipe; -import net.minecraft.world.level.ItemLike; - -import java.util.Optional; - - -/** - * Additional codecs for working with recipes. - */ -public class MoreCodecs { - /** - * A non-air item. - */ - private static final Codec ITEM_NOT_AIR = ExtraCodecs.validate( - BuiltInRegistries.ITEM.byNameCodec(), - item -> item == Items.AIR ? DataResult.error(() -> "Crafting result must not be minecraft:air") : DataResult.success(item) - ); - - /** - * A codec for {@link CompoundTag}s, which either accepts a NBT-string or a JSON object. - */ - public static final Codec TAG = Codec.either(Codec.STRING, CompoundTag.CODEC).flatXmap( - either -> either.map(MoreCodecs::parseTag, DataResult::success), - nbtCompound -> DataResult.success(Either.left(nbtCompound.getAsString())) - ); - - /** - * A {@link ItemStack}, similar to {@link ItemStack#ITEM_WITH_COUNT_CODEC} or {@link ItemStack#CODEC}, - * but using {@link #TAG} to parse the stack's NBT. - */ - public static final Codec ITEM_STACK_WITH_NBT = RecordCodecBuilder.create(instance -> instance.group( - ITEM_NOT_AIR.fieldOf("item").forGetter(ItemStack::getItem), - ExtraCodecs.strictOptionalField(ExtraCodecs.POSITIVE_INT, "count", 1).forGetter(ItemStack::getCount), - ExtraCodecs.strictOptionalField(TAG, "nbt").forGetter(x -> Optional.ofNullable(x.getTag())) - ).apply(instance, MoreCodecs::createTag)); - - /** - * A list of {@link Ingredient}s, usable in a {@linkplain ShapelessRecipe shapeless recipe}. - */ - public static final Codec> SHAPELESS_INGREDIENTS = Ingredient.CODEC_NONEMPTY.listOf().flatXmap(list -> { - var ingredients = list.stream().filter(ingredient -> !ingredient.isEmpty()).toArray(Ingredient[]::new); - if (ingredients.length == 0) return DataResult.error(() -> "No ingredients for shapeless recipe"); - if (ingredients.length > 9) return DataResult.error(() -> "Too many ingredients for shapeless recipe"); - return DataResult.success(NonNullList.of(Ingredient.EMPTY, ingredients)); - }, DataResult::success); - - private static DataResult parseTag(String contents) { - try { - return DataResult.success(TagParser.parseTag(contents)); - } catch (CommandSyntaxException e) { - return DataResult.error(e::getMessage); - } - } - - private static ItemStack createTag(ItemLike item, int count, Optional tag) { - var stack = new ItemStack(item, count); - tag.ifPresent(stack::setTag); - return stack; - } -} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/recipe/RecipeProperties.java b/projects/common/src/main/java/dan200/computercraft/shared/recipe/RecipeProperties.java index 725409ead..459a34d29 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/recipe/RecipeProperties.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/recipe/RecipeProperties.java @@ -7,8 +7,9 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.util.ExtraCodecs; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.world.item.crafting.CraftingBookCategory; import net.minecraft.world.item.crafting.CraftingRecipe; @@ -21,25 +22,19 @@ */ public record RecipeProperties(String group, CraftingBookCategory category, boolean showNotification) { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( - ExtraCodecs.strictOptionalField(Codec.STRING, "group", "").forGetter(RecipeProperties::group), + Codec.STRING.optionalFieldOf("group", "").forGetter(RecipeProperties::group), CraftingBookCategory.CODEC.fieldOf("category").orElse(CraftingBookCategory.MISC).forGetter(RecipeProperties::category), - ExtraCodecs.strictOptionalField(Codec.BOOL, "show_notification", true).forGetter(RecipeProperties::showNotification) + Codec.BOOL.optionalFieldOf("show_notification", true).forGetter(RecipeProperties::showNotification) ).apply(instance, RecipeProperties::new)); + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.STRING_UTF8, RecipeProperties::group, + CraftingBookCategory.STREAM_CODEC, RecipeProperties::category, + ByteBufCodecs.BOOL, RecipeProperties::showNotification, + RecipeProperties::new + ); + public static RecipeProperties of(CraftingRecipe recipe) { return new RecipeProperties(recipe.getGroup(), recipe.category(), recipe.showNotification()); } - - public static RecipeProperties fromNetwork(FriendlyByteBuf buffer) { - var group = buffer.readUtf(); - var category = buffer.readEnum(CraftingBookCategory.class); - var showNotification = buffer.readBoolean(); - return new RecipeProperties(group, category, showNotification); - } - - public void toNetwork(FriendlyByteBuf buffer) { - buffer.writeUtf(group()); - buffer.writeEnum(category()); - buffer.writeBoolean(showNotification()); - } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/recipe/RecipeUtil.java b/projects/common/src/main/java/dan200/computercraft/shared/recipe/RecipeUtil.java deleted file mode 100644 index f22141262..000000000 --- a/projects/common/src/main/java/dan200/computercraft/shared/recipe/RecipeUtil.java +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-FileCopyrightText: 2017 The CC: Tweaked Developers -// -// SPDX-License-Identifier: MPL-2.0 - -package dan200.computercraft.shared.recipe; - -import net.minecraft.core.NonNullList; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.item.crafting.Ingredient; - -public final class RecipeUtil { - private RecipeUtil() { - } - - public static NonNullList readIngredients(FriendlyByteBuf buffer) { - var count = buffer.readVarInt(); - var ingredients = NonNullList.withSize(count, Ingredient.EMPTY); - for (var i = 0; i < ingredients.size(); i++) ingredients.set(i, Ingredient.fromNetwork(buffer)); - return ingredients; - } - - public static void writeIngredients(FriendlyByteBuf buffer, NonNullList ingredients) { - buffer.writeCollection(ingredients, (a, b) -> b.toNetwork(a)); - } -} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/recipe/ShapedRecipeSpec.java b/projects/common/src/main/java/dan200/computercraft/shared/recipe/ShapedRecipeSpec.java index fd61842e0..96a202031 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/recipe/ShapedRecipeSpec.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/recipe/ShapedRecipeSpec.java @@ -6,7 +6,8 @@ import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.ShapedRecipe; import net.minecraft.world.item.crafting.ShapedRecipePattern; @@ -25,19 +26,13 @@ public record ShapedRecipeSpec(RecipeProperties properties, ShapedRecipePattern public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( RecipeProperties.CODEC.forGetter(ShapedRecipeSpec::properties), ShapedRecipePattern.MAP_CODEC.forGetter(ShapedRecipeSpec::pattern), - MoreCodecs.ITEM_STACK_WITH_NBT.fieldOf("result").forGetter(ShapedRecipeSpec::result) + ItemStack.STRICT_CODEC.fieldOf("result").forGetter(ShapedRecipeSpec::result) ).apply(instance, ShapedRecipeSpec::new)); - public static ShapedRecipeSpec fromNetwork(FriendlyByteBuf buffer) { - var properties = RecipeProperties.fromNetwork(buffer); - var template = ShapedRecipePattern.fromNetwork(buffer); - var result = buffer.readItem(); - return new ShapedRecipeSpec(properties, template, result); - } - - public void toNetwork(FriendlyByteBuf buffer) { - properties().toNetwork(buffer); - pattern().toNetwork(buffer); - buffer.writeItem(result()); - } + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + RecipeProperties.STREAM_CODEC, ShapedRecipeSpec::properties, + ShapedRecipePattern.STREAM_CODEC, ShapedRecipeSpec::pattern, + ItemStack.STREAM_CODEC, ShapedRecipeSpec::result, + ShapedRecipeSpec::new + ); } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/recipe/ShapelessRecipeSpec.java b/projects/common/src/main/java/dan200/computercraft/shared/recipe/ShapelessRecipeSpec.java index 3ad95f503..1d54f4a91 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/recipe/ShapelessRecipeSpec.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/recipe/ShapelessRecipeSpec.java @@ -4,10 +4,14 @@ package dan200.computercraft.shared.recipe; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import dan200.computercraft.shared.network.codec.MoreStreamCodecs; import net.minecraft.core.NonNullList; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.ShapelessRecipe; @@ -23,23 +27,26 @@ * @param result The result of the recipe. */ public record ShapelessRecipeSpec(RecipeProperties properties, NonNullList ingredients, ItemStack result) { + /** + * A list of {@link Ingredient}s, usable in a {@linkplain ShapelessRecipe shapeless recipe}. + */ + private static final Codec> INGREDIENT_CODEC = Ingredient.CODEC_NONEMPTY.listOf().flatXmap(list -> { + var ingredients = list.stream().filter(ingredient -> !ingredient.isEmpty()).toArray(Ingredient[]::new); + if (ingredients.length == 0) return DataResult.error(() -> "No ingredients for shapeless recipe"); + if (ingredients.length > 9) return DataResult.error(() -> "Too many ingredients for shapeless recipe"); + return DataResult.success(NonNullList.of(Ingredient.EMPTY, ingredients)); + }, DataResult::success); + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( RecipeProperties.CODEC.forGetter(ShapelessRecipeSpec::properties), - MoreCodecs.SHAPELESS_INGREDIENTS.fieldOf("ingredients").forGetter(ShapelessRecipeSpec::ingredients), - MoreCodecs.ITEM_STACK_WITH_NBT.fieldOf("result").forGetter(ShapelessRecipeSpec::result) + INGREDIENT_CODEC.fieldOf("ingredients").forGetter(ShapelessRecipeSpec::ingredients), + ItemStack.STRICT_CODEC.fieldOf("result").forGetter(ShapelessRecipeSpec::result) ).apply(instance, ShapelessRecipeSpec::new)); - public static ShapelessRecipeSpec fromNetwork(FriendlyByteBuf buffer) { - var properties = RecipeProperties.fromNetwork(buffer); - var ingredients = RecipeUtil.readIngredients(buffer); - var result = buffer.readItem(); - - return new ShapelessRecipeSpec(properties, ingredients, result); - } - - public void toNetwork(FriendlyByteBuf buffer) { - properties().toNetwork(buffer); - RecipeUtil.writeIngredients(buffer, ingredients()); - buffer.writeItem(result()); - } + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + RecipeProperties.STREAM_CODEC, ShapelessRecipeSpec::properties, + MoreStreamCodecs.nonNullList(Ingredient.CONTENTS_STREAM_CODEC, Ingredient.EMPTY), ShapelessRecipeSpec::ingredients, + ItemStack.STREAM_CODEC, ShapelessRecipeSpec::result, + ShapelessRecipeSpec::new + ); } 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 93836f8f5..0193a0086 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 @@ -7,22 +7,18 @@ import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import dan200.computercraft.annotations.ForgeOverride; -import dan200.computercraft.api.turtle.ITurtleUpgrade; -import dan200.computercraft.api.turtle.TurtleSide; -import dan200.computercraft.api.upgrades.UpgradeData; import dan200.computercraft.shared.computer.blocks.AbstractComputerBlock; import dan200.computercraft.shared.computer.blocks.AbstractComputerBlockEntity; import dan200.computercraft.shared.platform.RegistryEntry; -import dan200.computercraft.shared.turtle.core.TurtleBrain; -import dan200.computercraft.shared.turtle.items.TurtleItem; import dan200.computercraft.shared.util.BlockCodecs; import dan200.computercraft.shared.util.BlockEntityHelpers; import dan200.computercraft.shared.util.WaterloggableHelpers; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.component.DataComponents; import net.minecraft.world.Containers; import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; +import net.minecraft.world.ItemInteractionResult; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.AbstractHurtingProjectile; @@ -99,14 +95,12 @@ protected MapCodec codec() { } @Override - @Deprecated - public RenderShape getRenderShape(BlockState state) { + protected RenderShape getRenderShape(BlockState state) { return RenderShape.ENTITYBLOCK_ANIMATED; } @Override - @Deprecated - public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) { + protected VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) { var tile = world.getBlockEntity(pos); var offset = tile instanceof TurtleBlockEntity turtle ? turtle.getRenderOffset(1.0f) : Vec3.ZERO; return offset.equals(Vec3.ZERO) ? DEFAULT_SHAPE : DEFAULT_SHAPE.move(offset.x, offset.y, offset.z); @@ -121,21 +115,18 @@ public BlockState getStateForPlacement(BlockPlaceContext placement) { } @Override - @Deprecated - public FluidState getFluidState(BlockState state) { + protected FluidState getFluidState(BlockState state) { return WaterloggableHelpers.getFluidState(state); } @Override - @Deprecated - public BlockState updateShape(BlockState state, Direction side, BlockState otherState, LevelAccessor world, BlockPos pos, BlockPos otherPos) { + protected BlockState updateShape(BlockState state, Direction side, BlockState otherState, LevelAccessor world, BlockPos pos, BlockPos otherPos) { WaterloggableHelpers.updateShape(state, world, pos); return state; } @Override - @Deprecated - public final void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) { + protected final void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) { if (state.is(newState.getBlock())) return; if (!level.isClientSide && level.getBlockEntity(pos) instanceof TurtleBlockEntity turtle && !turtle.hasMoved()) { @@ -146,46 +137,17 @@ public final void onRemove(BlockState state, Level level, BlockPos pos, BlockSta } @Override - public void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable LivingEntity entity, ItemStack stack) { - super.setPlacedBy(world, pos, state, entity, stack); - - var tile = world.getBlockEntity(pos); - if (!world.isClientSide && tile instanceof TurtleBlockEntity turtle) { - if (entity instanceof Player player) turtle.setOwningPlayer(player.getGameProfile()); - - if (stack.getItem() instanceof TurtleItem item) { - // Set Upgrades - for (var side : TurtleSide.values()) { - turtle.getAccess().setUpgradeWithData(side, item.getUpgradeWithData(stack, side)); - } - - turtle.getAccess().setFuelLevel(item.getFuelLevel(stack)); - - // Set colour - var colour = item.getColour(stack); - if (colour != -1) turtle.getAccess().setColour(colour); - - // Set overlay - var overlay = item.getOverlay(stack); - if (overlay != null) ((TurtleBrain) turtle.getAccess()).setOverlay(overlay); - } - } - } - - @Override - @Deprecated - public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { - var currentItem = player.getItemInHand(hand); - if (currentItem.getItem() == Items.NAME_TAG && currentItem.hasCustomHoverName() && level.getBlockEntity(pos) instanceof AbstractComputerBlockEntity computer) { + protected ItemInteractionResult useItemOn(ItemStack currentItem, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { + if (currentItem.getItem() == Items.NAME_TAG && currentItem.has(DataComponents.CUSTOM_NAME) && level.getBlockEntity(pos) instanceof AbstractComputerBlockEntity computer) { // Label to rename computer if (!level.isClientSide) { computer.setLabel(currentItem.getHoverName().getString()); currentItem.shrink(1); } - return InteractionResult.sidedSuccess(level.isClientSide); + return ItemInteractionResult.sidedSuccess(level.isClientSide); } - return super.use(state, level, pos, player, hand, hit); + return super.useItemOn(currentItem, state, level, pos, player, hand, hit); } @ForgeOverride @@ -198,24 +160,6 @@ public float getExplosionResistance(BlockState state, BlockGetter world, BlockPo return getExplosionResistance(); } - @Override - protected ItemStack getItem(AbstractComputerBlockEntity tile) { - if (!(tile instanceof TurtleBlockEntity turtle)) return ItemStack.EMPTY; - if (!(asItem() instanceof TurtleItem item)) return ItemStack.EMPTY; - - var access = turtle.getAccess(); - return item.create( - turtle.getComputerID(), turtle.getLabel(), access.getColour(), - withPersistedData(access.getUpgradeWithData(TurtleSide.LEFT)), - withPersistedData(access.getUpgradeWithData(TurtleSide.RIGHT)), - access.getFuelLevel(), turtle.getOverlay() - ); - } - - private static @Nullable UpgradeData withPersistedData(@Nullable UpgradeData upgrade) { - return upgrade == null ? null : UpgradeData.of(upgrade.upgrade(), upgrade.upgrade().getPersistedData(upgrade.data())); - } - @Override @Nullable public BlockEntityTicker getTicker(Level level, BlockState state, BlockEntityType type) { diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/blocks/TurtleBlockEntity.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/blocks/TurtleBlockEntity.java index 4bd61d0d7..1c6d0b28f 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/blocks/TurtleBlockEntity.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/blocks/TurtleBlockEntity.java @@ -9,7 +9,9 @@ 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.core.computer.ComputerSide; +import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.computer.blocks.AbstractComputerBlockEntity; import dan200.computercraft.shared.computer.blocks.ComputerPeripheral; import dan200.computercraft.shared.computer.core.ComputerFamily; @@ -23,7 +25,10 @@ import dan200.computercraft.shared.turtle.inventory.TurtleMenu; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.HolderLookup; import net.minecraft.core.NonNullList; +import net.minecraft.core.component.DataComponentMap; +import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; @@ -33,6 +38,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.DyedItemColor; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; @@ -89,8 +95,8 @@ protected void unload() { } @Override - protected int getInteractRange() { - return Container.DEFAULT_DISTANCE_LIMIT + 4; + protected float getInteractRange() { + return Container.DEFAULT_DISTANCE_BUFFER + 4; } @Override @@ -127,26 +133,65 @@ public void notifyMoveEnd() { } @Override - public void loadServer(CompoundTag nbt) { - super.loadServer(nbt); + public void loadServer(CompoundTag nbt, HolderLookup.Provider registries) { + super.loadServer(nbt, registries); // Read inventory - ContainerHelper.loadAllItems(nbt, inventory); + ContainerHelper.loadAllItems(nbt, inventory, registries); for (var i = 0; i < inventory.size(); i++) inventorySnapshot.set(i, inventory.get(i).copy()); // Read state - brain.readFromNBT(nbt); + brain.readFromNBT(nbt, registries); } @Override - public void saveAdditional(CompoundTag nbt) { + public void saveAdditional(CompoundTag nbt, HolderLookup.Provider registries) { // Write inventory - ContainerHelper.saveAllItems(nbt, inventory); + ContainerHelper.saveAllItems(nbt, inventory, registries); // Write brain - nbt = brain.writeToNBT(nbt); + brain.writeToNBT(nbt, registries); - super.saveAdditional(nbt); + super.saveAdditional(nbt, registries); + } + + @Override + protected void applyImplicitComponents(DataComponentInput component) { + super.applyImplicitComponents(component); + + var colour = component.get(DataComponents.DYED_COLOR); + if (colour != null) brain.setColour(colour.rgb()); + + brain.setFuelLevel(component.getOrDefault(ModRegistry.DataComponents.FUEL.get(), 0)); + brain.setOverlay(component.get(ModRegistry.DataComponents.OVERLAY.get())); + brain.setUpgrade(TurtleSide.LEFT, component.get(ModRegistry.DataComponents.LEFT_TURTLE_UPGRADE.get())); + brain.setUpgrade(TurtleSide.RIGHT, component.get(ModRegistry.DataComponents.RIGHT_TURTLE_UPGRADE.get())); + } + + @Override + protected void collectImplicitComponents(DataComponentMap.Builder builder) { + super.collectImplicitComponents(builder); + + builder.set(DataComponents.DYED_COLOR, brain.getColour() == -1 ? null : new DyedItemColor(brain.getColour(), false)); + builder.set(ModRegistry.DataComponents.OVERLAY.get(), brain.getOverlay()); + builder.set(ModRegistry.DataComponents.FUEL.get(), brain.getFuelLevel()); + builder.set(ModRegistry.DataComponents.LEFT_TURTLE_UPGRADE.get(), withPersistedData(brain.getUpgradeWithData(TurtleSide.LEFT))); + builder.set(ModRegistry.DataComponents.RIGHT_TURTLE_UPGRADE.get(), withPersistedData(brain.getUpgradeWithData(TurtleSide.RIGHT))); + } + + private static @Nullable UpgradeData withPersistedData(@Nullable UpgradeData upgrade) { + return upgrade == null ? null : UpgradeData.of(upgrade.upgrade(), upgrade.upgrade().getPersistedData(upgrade.data())); + } + + @Override + @Deprecated + public void removeComponentsFromTag(CompoundTag tag) { + super.removeComponentsFromTag(tag); + tag.remove(TurtleBrain.NBT_COLOUR); + tag.remove(TurtleBrain.NBT_FUEL); + tag.remove(TurtleBrain.NBT_OVERLAY); + tag.remove(TurtleBrain.NBT_LEFT_UPGRADE); + tag.remove(TurtleBrain.NBT_RIGHT_UPGRADE); } @Override @@ -205,7 +250,7 @@ void setOwningPlayer(GameProfile player) { // IInventory @Override - public NonNullList getContents() { + public NonNullList getItems() { return inventory; } @@ -238,16 +283,16 @@ public void onTileEntityChange() { // Networking stuff @Override - public CompoundTag getUpdateTag() { - var nbt = super.getUpdateTag(); - brain.writeDescription(nbt); + public CompoundTag getUpdateTag(HolderLookup.Provider registries) { + var nbt = super.getUpdateTag(registries); + brain.writeDescription(nbt, registries); return nbt; } @Override - public void loadClient(CompoundTag nbt) { - super.loadClient(nbt); - brain.readDescription(nbt); + public void loadClient(CompoundTag nbt, HolderLookup.Provider registries) { + super.loadClient(nbt, registries); + brain.readDescription(nbt, registries); } // Privates 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 64f484198..652583f47 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 @@ -23,8 +23,11 @@ import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity; import dan200.computercraft.shared.util.BlockEntityHelpers; import dan200.computercraft.shared.util.Holiday; +import dan200.computercraft.shared.util.NBTUtil; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.component.DataComponentPatch; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; @@ -44,16 +47,14 @@ import java.util.*; import java.util.concurrent.TimeUnit; -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 String NBT_FUEL = "Fuel"; public static final String NBT_OVERLAY = "Overlay"; + public static final String NBT_COLOUR = "Color"; + public static final String NBT_LEFT_UPGRADE = "LeftUpgrade"; + public static final String NBT_RIGHT_UPGRADE = "RightUpgrade"; private static final String NBT_SLOT = "Slot"; @@ -67,9 +68,7 @@ public class TurtleBrain implements TurtleAccessInternal { private final Queue commandQueue = new ArrayDeque<>(); private int commandsIssued = 0; - private final Map upgrades = new EnumMap<>(TurtleSide.class); - private final Map peripherals = new EnumMap<>(TurtleSide.class); - private final Map upgradeNBTData = new EnumMap<>(TurtleSide.class); + private final UpgradeInstance[] upgrades = { new UpgradeInstance(), new UpgradeInstance() }; private int selectedSlot = 0; private int fuelLevel = 0; @@ -118,59 +117,41 @@ public void update() { updateAnimation(); // Advance upgrades - if (!upgrades.isEmpty()) { - for (var entry : upgrades.entrySet()) { - entry.getValue().update(this, entry.getKey()); - } + for (var side : TurtleSide.values()) { + var upgrade = upgrades[side.ordinal()].upgrade; + if (upgrade != null) upgrade.update(this, side); } } /** * Read common data for saving and client synchronisation. * - * @param nbt The tag to read from + * @param nbt The tag to read from + * @param registries The current registries. */ - private void readCommon(CompoundTag nbt) { + private void readCommon(CompoundTag nbt, HolderLookup.Provider registries) { // Read fields colourHex = nbt.contains(NBT_COLOUR) ? nbt.getInt(NBT_COLOUR) : -1; fuelLevel = nbt.contains(NBT_FUEL) ? nbt.getInt(NBT_FUEL) : 0; 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)); + setUpgradeDirect(TurtleSide.LEFT, NBTUtil.decodeFrom(TurtleUpgrades.instance().codec(), registries, nbt, NBT_LEFT_UPGRADE)); + setUpgradeDirect(TurtleSide.RIGHT, NBTUtil.decodeFrom(TurtleUpgrades.instance().codec(), registries, nbt, NBT_RIGHT_UPGRADE)); } - 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)); - } - - private void writeCommon(CompoundTag nbt) { + private void writeCommon(CompoundTag nbt, HolderLookup.Provider registries) { nbt.putInt(NBT_FUEL, fuelLevel); if (colourHex != -1) nbt.putInt(NBT_COLOUR, colourHex); 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()); - } + NBTUtil.encodeTo(TurtleUpgrades.instance().codec(), registries, nbt, NBT_LEFT_UPGRADE, getUpgradeWithData(TurtleSide.LEFT)); + NBTUtil.encodeTo(TurtleUpgrades.instance().codec(), registries, nbt, NBT_RIGHT_UPGRADE, getUpgradeWithData(TurtleSide.RIGHT)); } - public void readFromNBT(CompoundTag nbt) { - readCommon(nbt); + public void readFromNBT(CompoundTag nbt, HolderLookup.Provider registries) { + readCommon(nbt, registries); // Read state selectedSlot = nbt.getInt(NBT_SLOT); @@ -187,8 +168,8 @@ public void readFromNBT(CompoundTag nbt) { } } - public CompoundTag writeToNBT(CompoundTag nbt) { - writeCommon(nbt); + public void writeToNBT(CompoundTag nbt, HolderLookup.Provider registries) { + writeCommon(nbt, registries); // Write state nbt.putInt(NBT_SLOT, selectedSlot); @@ -202,16 +183,10 @@ public CompoundTag writeToNBT(CompoundTag nbt) { owner.putLong("LowerId", owningPlayer.getId().getLeastSignificantBits()); owner.putString("Name", owningPlayer.getName()); } - - return nbt; } - private static @Nullable String getUpgradeId(@Nullable ITurtleUpgrade upgrade) { - return upgrade != null ? upgrade.getUpgradeID().toString() : null; - } - - public void readDescription(CompoundTag nbt) { - readCommon(nbt); + public void readDescription(CompoundTag nbt, HolderLookup.Provider registries) { + readCommon(nbt, registries); // Animation var anim = TurtleAnimation.values()[nbt.getInt("Animation")]; @@ -225,8 +200,8 @@ public void readDescription(CompoundTag nbt) { } } - public void writeDescription(CompoundTag nbt) { - writeCommon(nbt); + public void writeDescription(CompoundTag nbt, HolderLookup.Provider registries) { + writeCommon(nbt, registries); nbt.putInt("Animation", animation.ordinal()); } @@ -484,11 +459,16 @@ public GameProfile getOwningPlayer() { @Override public @Nullable ITurtleUpgrade getUpgrade(TurtleSide side) { - return upgrades.get(side); + return upgrades[side.ordinal()].upgrade; } @Override - public void setUpgradeWithData(TurtleSide side, @Nullable UpgradeData upgrade) { + public @Nullable UpgradeData getUpgradeWithData(TurtleSide side) { + return upgrades[side.ordinal()].getUpgrade(); + } + + @Override + public void setUpgrade(TurtleSide side, @Nullable UpgradeData upgrade) { if (!setUpgradeDirect(side, upgrade) || owner.getLevel() == null) return; // This is a separate function to avoid updating the block when reading the NBT. We don't need to do this as @@ -503,39 +483,35 @@ public void setUpgradeWithData(TurtleSide side, @Nullable UpgradeData upgrade) { // Remove old upgrade - var oldUpgrade = upgrades.remove(side); - if (oldUpgrade == null && upgrade == null) return false; + var instance = upgrades[side.ordinal()]; + if (instance.upgrade == null && upgrade == null) return false; // Set new upgrade - if (upgrade == null) { - upgradeNBTData.remove(side); - } else { - upgrades.put(side, upgrade.upgrade()); - upgradeNBTData.put(side, upgrade.data().copy()); - } + instance.setUpgrade(upgrade); - // Notify clients and create peripherals - if (owner.getLevel() != null && !owner.getLevel().isClientSide) { - updatePeripherals(owner.createServerComputer()); - } + // Create peripherals + if (owner.getLevel() != null && !owner.getLevel().isClientSide) updatePeripherals(owner.createServerComputer()); return true; } @Override public @Nullable IPeripheral getPeripheral(TurtleSide side) { - return peripherals.get(side); + return upgrades[side.ordinal()].peripheral; } @Override - public CompoundTag getUpgradeNBTData(TurtleSide side) { - var nbt = upgradeNBTData.get(side); - if (nbt == null) upgradeNBTData.put(side, nbt = new CompoundTag()); - return nbt; + public DataComponentPatch getUpgradeData(TurtleSide side) { + return upgrades[side.ordinal()].data; } @Override - public void updateUpgradeNBTData(TurtleSide side) { + public void setUpgradeData(TurtleSide side, DataComponentPatch data) { + var upgrade = upgrades[side.ordinal()]; + if (Objects.equals(upgrade.data, data)) return; + + upgrade.data = data; + upgrade.cachedUpgradeData = null; BlockEntityHelpers.updateBlock(owner); } @@ -589,13 +565,13 @@ private void updatePeripherals(ServerComputer serverComputer) { peripheral = upgrade.createPeripheral(this, side); } - var existing = peripherals.get(side); - if (PeripheralHelpers.equals(existing, peripheral)) { + var instance = upgrades[side.ordinal()]; + if (PeripheralHelpers.equals(instance.peripheral, peripheral)) { // If the peripheral is the same, just use that. - peripheral = existing; + peripheral = instance.peripheral; } else { // Otherwise update our map - peripherals.put(side, peripheral); + instance.peripheral = peripheral; } // Always update the computer: it may not be the same computer as before! @@ -769,4 +745,33 @@ public MethodResult resume(Object[] response) { return MethodResult.of(Arrays.copyOfRange(response, 2, response.length)); } } + + private static final class UpgradeInstance { + private @Nullable ITurtleUpgrade upgrade; + private DataComponentPatch data = DataComponentPatch.EMPTY; + private @Nullable IPeripheral peripheral; + + private @Nullable UpgradeData cachedUpgradeData; + + public void setUpgrade(@Nullable UpgradeData upgrade) { + if (upgrade == null) { + this.upgrade = null; + data = DataComponentPatch.EMPTY; + cachedUpgradeData = null; + } else { + this.upgrade = upgrade.upgrade(); + this.data = upgrade.data(); + this.cachedUpgradeData = upgrade; + } + } + + public @Nullable UpgradeData getUpgrade() { + if (upgrade == null) return null; + + var cached = cachedUpgradeData; + if (cached != null) return cached; + + return cachedUpgradeData = UpgradeData.of(upgrade, data); + } + } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java index 81cfe16e3..66a24b4c9 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java @@ -20,7 +20,7 @@ public TurtleCompareToCommand(int slot) { public TurtleCommandResult execute(ITurtleAccess turtle) { var selectedStack = turtle.getInventory().getItem(turtle.getSelectedSlot()); var stack = turtle.getInventory().getItem(slot); - return ItemStack.isSameItemSameTags(selectedStack, stack) + return ItemStack.isSameItemSameComponents(selectedStack, stack) ? TurtleCommandResult.success() : TurtleCommandResult.failure(); } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java index ae373f697..b4b7e910d 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java @@ -34,7 +34,7 @@ public TurtleCommandResult execute(ITurtleAccess turtle) { // Do the swapping: if (newUpgrade != null) turtle.getInventory().removeItem(turtle.getSelectedSlot(), 1); if (oldUpgrade != null) TurtleUtil.storeItemOrDrop(turtle, oldUpgrade.getUpgradeItem()); - turtle.setUpgradeWithData(side, newUpgrade); + turtle.setUpgrade(side, newUpgrade); // Animate if (newUpgrade != null || oldUpgrade != null) { diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index cad9fc63e..0df008103 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -198,7 +198,7 @@ private static boolean deployOnBlock( * @param turtlePlayer The player which represents the turtle * @param hit Where the block we're placing against was clicked. * @param adjacent If the block is directly adjacent to the turtle, and so can be interacted with via - * {@link BlockState#use(Level, Player, InteractionHand, BlockHitResult)}. + * {@link BlockState#useItemOn(ItemStack, Level, Player, InteractionHand, BlockHitResult)}. * @return If this item was deployed. */ private static InteractionResult doDeployOnBlock(ItemStack stack, TurtlePlayer turtlePlayer, BlockHitResult hit, boolean adjacent) { diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/inventory/UpgradeContainer.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/inventory/UpgradeContainer.java index 9fff2789a..6f98972c9 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/inventory/UpgradeContainer.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/inventory/UpgradeContainer.java @@ -59,7 +59,7 @@ public ItemStack getItem(int slot) { private ItemStack setUpgradeStack(int slot, @Nullable UpgradeData upgrade) { var stack = upgrade == null ? ItemStack.EMPTY : upgrade.getUpgradeItem(); - lastUpgrade.set(slot, UpgradeData.copyOf(upgrade)); + lastUpgrade.set(slot, upgrade); lastStack.set(slot, stack); return stack; } @@ -67,7 +67,7 @@ private ItemStack setUpgradeStack(int slot, @Nullable UpgradeData leftUpgrade, @Nullable UpgradeData rightUpgrade, - int fuelLevel, @Nullable ResourceLocation overlay - ) { - // Build the stack - var stack = new ItemStack(this); - if (label != null) stack.setHoverName(Component.literal(label)); - if (id >= 0) stack.getOrCreateTag().putInt(NBT_ID, id); - IColouredItem.setColourBasic(stack, colour); - 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()); - } - - return stack; - } - @Override public Component getName(ItemStack stack) { var baseString = getDescriptionId(stack); @@ -103,54 +72,31 @@ public String getCreatorModId(ItemStack stack) { return ComputerCraftAPI.MOD_ID; } - @Override - public ItemStack changeItem(ItemStack stack, Item newItem) { - return newItem instanceof TurtleItem turtle ? turtle.create( - getComputerID(stack), getLabel(stack), - getColour(stack), - getUpgradeWithData(stack, TurtleSide.LEFT), getUpgradeWithData(stack, TurtleSide.RIGHT), - getFuelLevel(stack), getOverlay(stack) - ) : ItemStack.EMPTY; + public static @Nullable ITurtleUpgrade getUpgrade(ItemStack stack, TurtleSide side) { + var upgrade = getUpgradeWithData(stack, side); + return upgrade == null ? null : upgrade.upgrade(); } - 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)); + public static @Nullable UpgradeData getUpgradeWithData(ItemStack stack, TurtleSide side) { + return stack.get(side == TurtleSide.LEFT ? ModRegistry.DataComponents.LEFT_TURTLE_UPGRADE.get() : ModRegistry.DataComponents.RIGHT_TURTLE_UPGRADE.get()); } - 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)); + public static @Nullable ResourceLocation getOverlay(ItemStack stack) { + return stack.get(ModRegistry.DataComponents.OVERLAY.get()); } - public @Nullable ResourceLocation getOverlay(ItemStack stack) { - var tag = stack.getTag(); - return tag != null && tag.contains(NBT_OVERLAY) ? new ResourceLocation(tag.getString(NBT_OVERLAY)) : null; - } - - public int getFuelLevel(ItemStack stack) { - var tag = stack.getTag(); - return tag != null && tag.contains(NBT_FUEL) ? tag.getInt(NBT_FUEL) : 0; + public static int getFuelLevel(ItemStack stack) { + var fuel = stack.get(ModRegistry.DataComponents.FUEL.get()); + return fuel == null ? 0 : fuel; } public static final CauldronInteraction CAULDRON_INTERACTION = (blockState, level, pos, player, hand, stack) -> { - if (IColouredItem.getColourBasic(stack) == -1) return InteractionResult.PASS; + if (!stack.has(DataComponents.DYED_COLOR)) return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; if (!level.isClientSide) { - IColouredItem.setColourBasic(stack, -1); + stack.remove(DataComponents.DYED_COLOR); LayeredCauldronBlock.lowerFillLevel(blockState, level, pos); } - return InteractionResult.sidedSuccess(level.isClientSide); + return ItemInteractionResult.sidedSuccess(level.isClientSide); }; } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleOverlayRecipe.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleOverlayRecipe.java index 38a7a567b..1c2ad765f 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleOverlayRecipe.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleOverlayRecipe.java @@ -4,15 +4,17 @@ package dan200.computercraft.shared.turtle.recipes; -import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; -import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.ModRegistry; +import dan200.computercraft.shared.recipe.BasicRecipeSerialiser; import dan200.computercraft.shared.recipe.CustomShapelessRecipe; import dan200.computercraft.shared.recipe.ShapelessRecipeSpec; import dan200.computercraft.shared.turtle.items.TurtleItem; -import net.minecraft.core.RegistryAccess; -import net.minecraft.network.FriendlyByteBuf; +import dan200.computercraft.shared.util.DataComponentUtil; +import net.minecraft.core.HolderLookup; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; @@ -23,6 +25,17 @@ * A {@link ShapelessRecipe} which sets the {@linkplain TurtleItem#getOverlay(ItemStack)} turtle's overlay} instead. */ public class TurtleOverlayRecipe extends CustomShapelessRecipe { + private static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( + ShapelessRecipeSpec.CODEC.forGetter(CustomShapelessRecipe::toSpec), + ResourceLocation.CODEC.fieldOf("overlay").forGetter(x -> x.overlay) + ).apply(instance, TurtleOverlayRecipe::new)); + + private static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ShapelessRecipeSpec.STREAM_CODEC, CustomShapelessRecipe::toSpec, + ResourceLocation.STREAM_CODEC, x -> x.overlay, + TurtleOverlayRecipe::new + ); + private final ResourceLocation overlay; public TurtleOverlayRecipe(ShapelessRecipeSpec spec, ResourceLocation overlay) { @@ -30,23 +43,15 @@ public TurtleOverlayRecipe(ShapelessRecipeSpec spec, ResourceLocation overlay) { this.overlay = overlay; } - private static ItemStack make(ItemStack stack, TurtleItem turtle, ResourceLocation overlay) { - return turtle.create( - turtle.getComputerID(stack), - turtle.getLabel(stack), - turtle.getColour(stack), - turtle.getUpgradeWithData(stack, TurtleSide.LEFT), - turtle.getUpgradeWithData(stack, TurtleSide.RIGHT), - turtle.getFuelLevel(stack), - overlay - ); + private static ItemStack make(ItemStack stack, ResourceLocation overlay) { + return DataComponentUtil.createResult(stack, ModRegistry.DataComponents.OVERLAY.get(), overlay); } @Override - public ItemStack assemble(CraftingContainer inventory, RegistryAccess registryAccess) { + public ItemStack assemble(CraftingContainer inventory, HolderLookup.Provider registryAccess) { for (var i = 0; i < inventory.getContainerSize(); i++) { var stack = inventory.getItem(i); - if (stack.getItem() instanceof TurtleItem turtle) return make(stack, turtle, overlay); + if (stack.getItem() instanceof TurtleItem) return make(stack, overlay); } return ItemStack.EMPTY; @@ -57,27 +62,7 @@ public RecipeSerializer getSerializer() { return ModRegistry.RecipeSerializers.TURTLE_OVERLAY.get(); } - public static class Serialiser implements RecipeSerializer { - private static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - ShapelessRecipeSpec.CODEC.forGetter(CustomShapelessRecipe::toSpec), - ResourceLocation.CODEC.fieldOf("overlay").forGetter(x -> x.overlay) - ).apply(instance, TurtleOverlayRecipe::new)); - @Override - public Codec codec() { - return CODEC; - } - - @Override - public TurtleOverlayRecipe fromNetwork(FriendlyByteBuf buffer) { - var recipe = ShapelessRecipeSpec.fromNetwork(buffer); - var overlay = buffer.readResourceLocation(); - return new TurtleOverlayRecipe(recipe, overlay); - } - - @Override - public void toNetwork(FriendlyByteBuf buffer, TurtleOverlayRecipe recipe) { - recipe.toSpec().toNetwork(buffer); - buffer.writeResourceLocation(recipe.overlay); - } + public static RecipeSerializer serialiser() { + return new BasicRecipeSerialiser<>(CODEC, STREAM_CODEC); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java deleted file mode 100644 index 7097d7db0..000000000 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. -// -// SPDX-License-Identifier: LicenseRef-CCPL - -package dan200.computercraft.shared.turtle.recipes; - -import com.mojang.serialization.DataResult; -import dan200.computercraft.shared.ModRegistry; -import dan200.computercraft.shared.computer.items.IComputerItem; -import dan200.computercraft.shared.computer.recipe.ComputerConvertRecipe; -import dan200.computercraft.shared.recipe.ShapedRecipeSpec; -import dan200.computercraft.shared.turtle.items.TurtleItem; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.RecipeSerializer; - -/** - * The recipe which crafts a turtle from an existing computer item. - */ -public final class TurtleRecipe extends ComputerConvertRecipe { - private final TurtleItem turtle; - - private TurtleRecipe(ShapedRecipeSpec recipe, TurtleItem turtle) { - super(recipe); - this.turtle = turtle; - } - - public static DataResult of(ShapedRecipeSpec recipe) { - if (!(recipe.result().getItem() instanceof TurtleItem turtle)) { - return DataResult.error(() -> recipe.result().getItem() + " is not a turtle item"); - } - - return DataResult.success(new TurtleRecipe(recipe, turtle)); - } - - @Override - protected ItemStack convert(IComputerItem item, ItemStack stack) { - var computerID = item.getComputerID(stack); - var label = item.getLabel(stack); - - return turtle.create(computerID, label, -1, null, null, 0, null); - } - - @Override - public RecipeSerializer getSerializer() { - return ModRegistry.RecipeSerializers.TURTLE.get(); - } -} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java index 868c2a1da..ab703cd80 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java @@ -10,7 +10,7 @@ import dan200.computercraft.impl.TurtleUpgrades; import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.turtle.items.TurtleItem; -import net.minecraft.core.RegistryAccess; +import net.minecraft.core.HolderLookup; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CraftingBookCategory; @@ -29,8 +29,8 @@ public boolean canCraftInDimensions(int x, int y) { } @Override - public ItemStack getResultItem(RegistryAccess registryAccess) { - return ModRegistry.Items.TURTLE_NORMAL.get().create(-1, null, -1, null, null, 0, null); + public ItemStack getResultItem(HolderLookup.Provider registryAccess) { + return new ItemStack(ModRegistry.Items.TURTLE_NORMAL.get()); } @Override @@ -39,7 +39,7 @@ public boolean matches(CraftingContainer inventory, Level world) { } @Override - public ItemStack assemble(CraftingContainer inventory, RegistryAccess registryAccess) { + public ItemStack assemble(CraftingContainer inventory, HolderLookup.Provider registryAccess) { // Scan the grid for a row containing a turtle and 1 or 2 items var leftItem = ItemStack.EMPTY; var turtle = ItemStack.EMPTY; @@ -103,11 +103,10 @@ public ItemStack assemble(CraftingContainer inventory, RegistryAccess registryAc // At this point we have a turtle + 1 or 2 items // Get the turtle we already have - var itemTurtle = (TurtleItem) turtle.getItem(); @SuppressWarnings({ "unchecked", "rawtypes" }) UpgradeData[] upgrades = new UpgradeData[]{ - itemTurtle.getUpgradeWithData(turtle, TurtleSide.LEFT), - itemTurtle.getUpgradeWithData(turtle, TurtleSide.RIGHT), + TurtleItem.getUpgradeWithData(turtle, TurtleSide.LEFT), + TurtleItem.getUpgradeWithData(turtle, TurtleSide.RIGHT), }; // Get the upgrades for the new items @@ -120,13 +119,10 @@ public ItemStack assemble(CraftingContainer inventory, RegistryAccess registryAc } } - // Construct the new stack - var computerID = itemTurtle.getComputerID(turtle); - var label = itemTurtle.getLabel(turtle); - var fuelLevel = itemTurtle.getFuelLevel(turtle); - var colour = itemTurtle.getColour(turtle); - var overlay = itemTurtle.getOverlay(turtle); - return itemTurtle.create(computerID, label, colour, upgrades[0], upgrades[1], fuelLevel, overlay); + var newStack = turtle.copyWithCount(1); + newStack.set(ModRegistry.DataComponents.LEFT_TURTLE_UPGRADE.get(), upgrades[0]); + newStack.set(ModRegistry.DataComponents.RIGHT_TURTLE_UPGRADE.get(), upgrades[1]); + return newStack; } @Override diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java index 1f9de26e7..f550f7b5d 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java @@ -100,7 +100,7 @@ public List doCrafting(Level world, int maxCount) { // afterwards). if (existing.isEmpty()) { setItem(slot, remainder); - } else if (ItemStack.isSameItemSameTags(existing, remainder)) { + } else if (ItemStack.isSameItemSameComponents(existing, remainder)) { remainder.grow(existing.getCount()); setItem(slot, remainder); } else { 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 7235d4431..eb00a11ba 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 @@ -6,10 +6,11 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.*; +import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral; import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; +import net.minecraft.core.component.DataComponentPatch; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; @@ -72,15 +73,14 @@ public void update(ITurtleAccess turtle, TurtleSide side) { if (peripheral instanceof Peripheral modem) { var state = modem.getModemState(); if (state.pollChanged()) { - turtle.getUpgradeNBTData(side).putBoolean("active", state.isOpen()); - turtle.updateUpgradeNBTData(side); + turtle.setUpgradeData(side, DataComponentPatch.builder().set(ModRegistry.DataComponents.ON.get(), state.isOpen()).build()); } } } } @Override - public CompoundTag getPersistedData(CompoundTag upgradeData) { - return new CompoundTag(); + public DataComponentPatch getPersistedData(DataComponentPatch upgradeData) { + return DataComponentPatch.EMPTY; } } 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 6341b1f70..42034b06d 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 @@ -14,7 +14,8 @@ import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.component.DataComponents; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; @@ -23,7 +24,6 @@ import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; -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; @@ -38,18 +38,12 @@ import net.minecraft.world.phys.EntityHitResult; import javax.annotation.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 { 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 damageMulitiplier; final boolean allowEnchantments; @@ -76,79 +70,63 @@ public boolean isItemSuitable(ItemStack stack) { } private static boolean isEnchanted(ItemStack stack) { - return !stack.isEmpty() && isEnchanted(stack.getTag()); - } + var enchantments = stack.get(DataComponents.ENCHANTMENTS); + if (enchantments != null && !enchantments.isEmpty()) return true; - private static boolean isEnchanted(@Nullable CompoundTag tag) { - if (tag == null || tag.isEmpty()) return false; - return (tag.contains(ItemStack.TAG_ENCH, TAG_LIST) && !tag.getList(ItemStack.TAG_ENCH, TAG_COMPOUND).isEmpty()) - || (tag.contains("AttributeModifiers", TAG_LIST) && !tag.getList("AttributeModifiers", TAG_COMPOUND).isEmpty()); + var modifiers = stack.get(DataComponents.ATTRIBUTE_MODIFIERS); + if (modifiers != null && !modifiers.modifiers().isEmpty()) return true; + + return false; } @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 DataComponentPatch getUpgradeData(ItemStack stack) { + return stack.getComponentsPatch(); } @Override - public ItemStack getUpgradeItem(CompoundTag upgradeData) { + public ItemStack getUpgradeItem(DataComponentPatch upgradeData) { // Copy upgrade data back to the item. var item = super.getUpgradeItem(upgradeData).copy(); - item.setTag(upgradeData.contains(TAG_ITEM_TAG, TAG_COMPOUND) ? upgradeData.getCompound(TAG_ITEM_TAG) : null); + item.applyComponents(upgradeData); return item; } private ItemStack getToolStack(ITurtleAccess turtle, TurtleSide side) { - return getUpgradeItem(turtle.getUpgradeNBTData(side)).copy(); + return getUpgradeItem(turtle.getUpgradeData(side)); } - private void setToolStack(ITurtleAccess turtle, TurtleSide side, ItemStack stack) { - var upgradeData = turtle.getUpgradeNBTData(side); + private void setToolStack(ITurtleAccess turtle, TurtleSide side, ItemStack oldStack, ItemStack stack) { + var upgradeData = turtle.getUpgradeData(side); 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); + turtle.setUpgrade(side, null); return; } // If the tool has changed, no clue what's going on. if (stack.getItem() != item.getItem()) return; - var itemTag = stack.getTag(); - - // 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 (itemTag == null) { - upgradeData.remove(TAG_ITEM_TAG); - } else { - upgradeData.put(TAG_ITEM_TAG, itemTag); - } - - turtle.updateUpgradeNBTData(side); + turtle.setUpgradeData(side, stack.getComponentsPatch()); } private T withEquippedItem(ITurtleAccess turtle, TurtleSide side, Direction direction, Function action) { var turtlePlayer = TurtlePlayer.getWithPosition(turtle, turtle.getPosition(), direction); - turtlePlayer.loadInventory(getToolStack(turtle, side)); + var stack = getToolStack(turtle, side); + + turtlePlayer.loadInventory(stack.copy()); var result = action.apply(turtlePlayer); - setToolStack(turtle, side, turtlePlayer.player().getItemInHand(InteractionHand.MAIN_HAND)); + setToolStack(turtle, side, stack, turtlePlayer.player().getItemInHand(InteractionHand.MAIN_HAND)); turtlePlayer.player().getInventory().clearContent(); return result; @@ -196,7 +174,7 @@ private TurtleCommandResult attack(ITurtleAccess turtle, TurtleSide side, Direct if (hit instanceof EntityHitResult entityHit) { // Load up the turtle's inventory var stack = getToolStack(turtle, side); - turtlePlayer.loadInventory(stack); + turtlePlayer.loadInventory(stack.copy()); var hitEntity = entityHit.getEntity(); @@ -215,7 +193,7 @@ private TurtleCommandResult attack(ITurtleAccess turtle, TurtleSide side, Direct TurtleUtil.stopConsuming(turtle); // Put everything we collected into the turtles inventory. - setToolStack(turtle, side, player.getItemInHand(InteractionHand.MAIN_HAND)); + setToolStack(turtle, side, stack, player.getItemInHand(InteractionHand.MAIN_HAND)); player.getInventory().clearContent(); } @@ -238,9 +216,7 @@ private TurtleCommandResult attack(ITurtleAccess turtle, TurtleSide side, Direct */ private boolean attack(ServerPlayer player, Direction direction, Entity entity) { var baseDamage = (float) player.getAttributeValue(Attributes.ATTACK_DAMAGE) * damageMulitiplier; - var bonusDamage = EnchantmentHelper.getDamageBonus( - player.getItemInHand(InteractionHand.MAIN_HAND), entity instanceof LivingEntity target ? target.getMobType() : MobType.UNDEFINED - ); + var bonusDamage = EnchantmentHelper.getDamageBonus(player.getItemInHand(InteractionHand.MAIN_HAND), entity.getType()); var damage = baseDamage + bonusDamage; if (damage <= 0) return false; @@ -252,7 +228,7 @@ private boolean attack(ServerPlayer player, Direction direction, Entity entity) var onFire = false; if (entity instanceof LivingEntity target && fireAspect > 0 && !target.isOnFire()) { onFire = true; - target.setSecondsOnFire(1); + target.igniteForSeconds(1); } var source = player.damageSources().playerAttack(player); @@ -285,7 +261,7 @@ private boolean attack(ServerPlayer player, Direction direction, Entity entity) // Apply fire aspect if (entity instanceof LivingEntity target && fireAspect > 0 && !target.isOnFire()) { - target.setSecondsOnFire(4 * fireAspect); + target.igniteForSeconds(4 * fireAspect); } return true; 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 f859b22e5..e8e965d07 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 dan200.computercraft.api.turtle.TurtleToolDurability; import dan200.computercraft.api.upgrades.UpgradeBase; import dan200.computercraft.api.upgrades.UpgradeSerialiser; -import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; 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.level.block.Block; -import java.util.Objects; - public final class TurtleToolSerialiser implements UpgradeSerialiser { public static final TurtleToolSerialiser INSTANCE = new TurtleToolSerialiser(); @@ -44,11 +42,10 @@ public TurtleTool fromJson(ResourceLocation id, JsonObject object) { } @Override - public TurtleTool fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) { + public TurtleTool fromNetwork(ResourceLocation id, RegistryFriendlyByteBuf buffer) { var adjective = buffer.readUtf(); - var craftingItem = buffer.readById(BuiltInRegistries.ITEM); - Objects.requireNonNull(craftingItem, "Unknown crafting item"); - var toolItem = buffer.readItem(); + var craftingItem = ByteBufCodecs.registry(Registries.ITEM).decode(buffer); + var toolItem = ItemStack.STREAM_CODEC.decode(buffer); // damageMultiplier and breakable aren't used by the client, but we need to construct the upgrade exactly // as otherwise syncing on an SP world will overwrite the (shared) upgrade registry with an invalid upgrade! var damageMultiplier = buffer.readFloat(); @@ -60,10 +57,10 @@ public TurtleTool fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) { } @Override - public void toNetwork(FriendlyByteBuf buffer, TurtleTool upgrade) { + public void toNetwork(RegistryFriendlyByteBuf buffer, TurtleTool upgrade) { buffer.writeUtf(upgrade.getUnlocalisedAdjective()); - buffer.writeId(BuiltInRegistries.ITEM, upgrade.getCraftingItem().getItem()); - buffer.writeItem(upgrade.item); + ByteBufCodecs.registry(Registries.ITEM).encode(buffer, upgrade.getCraftingItem().getItem()); + ItemStack.STREAM_CODEC.encode(buffer, upgrade.item); buffer.writeFloat(upgrade.damageMulitiplier); buffer.writeBoolean(upgrade.allowEnchantments); buffer.writeEnum(upgrade.consumeDurability); diff --git a/projects/common/src/main/java/dan200/computercraft/shared/util/ComponentizationFixers.java b/projects/common/src/main/java/dan200/computercraft/shared/util/ComponentizationFixers.java new file mode 100644 index 000000000..e1ed34cf2 --- /dev/null +++ b/projects/common/src/main/java/dan200/computercraft/shared/util/ComponentizationFixers.java @@ -0,0 +1,181 @@ +// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.shared.util; + +import com.mojang.datafixers.DSL; +import com.mojang.datafixers.Typed; +import com.mojang.datafixers.schemas.Schema; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.OptionalDynamic; +import dan200.computercraft.api.upgrades.UpgradeData; +import dan200.computercraft.shared.media.items.PrintoutData; +import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix; +import net.minecraft.util.datafix.fixes.References; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Additional fixers to convert CC's item NBT to use components. + * + * @see ItemStackComponentizationFix + */ +public class ComponentizationFixers { + private static final String TURTLE_NORMAL = "computercraft:turtle_normal"; + private static final String TURTLE_ADVANCED = "computercraft:turtle_advanced"; + + private static final Set COMPUTER = Set.of("computercraft:computer_normal", "computercraft:computer_advanced"); + private static final Set TURTLES = Set.of(TURTLE_NORMAL, TURTLE_ADVANCED); + private static final Set POCKET_COMPUTERS = Set.of("computercraft:pocket_computer_normal", "computercraft:pocket_computer_advanced"); + + private static final Set ALL_COMPUTERS = Stream.of(COMPUTER, TURTLES, POCKET_COMPUTERS).flatMap(Set::stream).collect(Collectors.toUnmodifiableSet()); + + private static final Set PRINTOUTS = Set.of("computercraft:printed_page", "computercraft:printed_pages", "computercraft:printed_book"); + + private static final String DISK = "computercraft:disk"; + private static final String TREASURE_DISK = "computercraft:treasure_disk"; + + private static final Set DYEABLE = Stream.concat( + Stream.of(TURTLES, POCKET_COMPUTERS).flatMap(Set::stream), + Stream.of(DISK, TREASURE_DISK) + ).collect(Collectors.toUnmodifiableSet()); + + /** + * Fix components in item stacks. + * + * @param item The current item data. + * @param ops A {@link Dynamic} instance, used to create new {@link Dynamic} values. + */ + public static void fixItemComponents(ItemStackComponentizationFix.ItemStackData item, Dynamic ops) { + // Set computer ID + if (item.is(ALL_COMPUTERS)) item.moveTagToComponent("ComputerId", "computercraft:computer_id"); + + // Set dyed colour + if (item.is(DYEABLE)) { + item.removeTag("Color").asNumber().result().map(Number::intValue).ifPresent(col -> + item.setComponent("minecraft:dyed_color", ops.emptyMap() + .set("rgb", ops.createInt(col)) + .set("show_in_tooltip", ops.createBoolean(false)) + )); + } + + if (item.is(POCKET_COMPUTERS)) { + item.moveTagToComponent("On", "computercraft:on"); + + moveUpgradeToComponent(item, ops, "Upgrade", "UpgradeInfo", "computercraft:pocket_upgrade"); + + // Remove instance/session, so they don't end up in minecraft:custom_data. + item.removeTag("InstanceId"); + item.removeTag("SessionId"); + } + + if (item.is(TURTLES)) { + item.moveTagToComponent("Fuel", "computercraft:fuel"); + item.moveTagToComponent("Overlay", "computercraft:overlay"); + + moveUpgradeToComponent(item, ops, "LeftUpgrade", "LeftUpgradeNbt", "computercraft:left_turtle_upgrade"); + moveUpgradeToComponent(item, ops, "RightUpgrade", "RightUpgradeNbt", "computercraft:right_turtle_upgrade"); + } + + if (item.is(DISK)) item.moveTagToComponent("DiskId", "computercraft:disk"); + + if (item.is(TREASURE_DISK)) { + var name = item.removeTag("Title").asString().result(); + var path = item.removeTag("SubPath").asString().result(); + if (name.isPresent() && path.isPresent()) { + item.setComponent("computercraft:treasure_disk", ops.emptyMap() + .set("name", ops.createString(name.get())) + .set("path", ops.createString(path.get()))); + } + } + + 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); + if (upgrade == null) return; + data.setComponent(component, createUpgradeData(ops, upgrade, data.removeTag(dataKey))); + } + + /** + * Move printout data to a component. + * + * @param item The item data to convert. + * @param ops A {@link Dynamic} instance, for creating new dynamic values. + * @see PrintoutData + */ + private static void movePrintoutToComponent(ItemStackComponentizationFix.ItemStackData item, Dynamic ops) { + var title = item.removeTag("Title").asString(""); + var pages = item.removeTag("Pages").asInt(0); + if (pages <= 0) return; + + List> lines = new ArrayList<>(pages * PrintoutData.LINES_PER_PAGE); + for (var i = 0; i < pages * PrintoutData.LINES_PER_PAGE; i++) { + var text = item.removeTag("Text" + i).asString(PrintoutData.Line.EMPTY.text()); + var colour = item.removeTag("Color" + i).asString(PrintoutData.Line.EMPTY.foreground()); + lines.add(ops.emptyMap().set("text", ops.createString(text)).set("foreground", ops.createString(colour))); + } + + item.setComponent("computercraft:printout", ops.emptyMap() + .set("title", ops.createString(title)) + .set("lines", ops.createList(lines.stream()))); + } + + /** + * Make a fixer for {@linkplain References#BLOCK_ENTITY block entities}. + * + * @param input The input schema. + * @param output The output schema. + * @return A function that fixes block entities. + */ + public static Function, Typed> makeBlockEntityRewrites(Schema input, Schema output) { + return fixTurtleBlockEntity(input, output, TURTLE_NORMAL).compose(fixTurtleBlockEntity(input, output, TURTLE_ADVANCED)); + } + + private static Function, Typed> fixTurtleBlockEntity(Schema inputSchema, Schema outputSchema, String name) { + 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 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); + if (upgradeId == null) return ops; + + return ops.set(key, createUpgradeData(ops, upgradeId, ops.get(dataKey))).remove(dataKey); + } + + /** + * Create a new upgrade data. + * + * @param ops A {@link Dynamic} instance, for creating new dynamic values. + * @param upgradeId The upgrade ID + * @param upgradeData Additional upgrade data + * @return The newly created {@link UpgradeData}-compatible value. + */ + private static Dynamic createUpgradeData(Dynamic ops, String upgradeId, OptionalDynamic upgradeData) { + var newUpgrade = ops.emptyMap().set("id", ops.createString(upgradeId)); + + var data = upgradeData.result().orElse(null); + if (data != null && !data.equals(ops.emptyMap())) { + // Migrate all existing data to minecraft:custom_data + newUpgrade = newUpgrade.set("components", ops.emptyMap().set("minecraft:custom_data", data)); + } + + return newUpgrade; + } +} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/util/DataComponentUtil.java b/projects/common/src/main/java/dan200/computercraft/shared/util/DataComponentUtil.java new file mode 100644 index 000000000..163e08541 --- /dev/null +++ b/projects/common/src/main/java/dan200/computercraft/shared/util/DataComponentUtil.java @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.shared.util; + +import net.minecraft.core.component.DataComponentHolder; +import net.minecraft.core.component.DataComponentType; +import net.minecraft.core.component.DataComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ItemLike; +import org.jetbrains.annotations.Contract; + +import javax.annotation.Nullable; + +/** + * Utilities for working with {@linkplain DataComponentType data components}. + */ +public class DataComponentUtil { + public static @Nullable String getCustomName(DataComponentHolder holder) { + return getCustomName(holder.get(DataComponents.CUSTOM_NAME)); + } + + @Contract("null -> null; !null -> !null") + public static @Nullable String getCustomName(@Nullable Component name) { + return name != null ? name.getString() : null; + } + + public static void setCustomName(ItemStack stack, @Nullable String label) { + stack.set(DataComponents.CUSTOM_NAME, label == null ? null : Component.literal(label)); + } + + private static ItemStack set(ItemStack stack, DataComponentType type, @Nullable T value) { + stack.set(type, value); + return stack; + } + + public static ItemStack createResult(ItemStack stack, DataComponentType type, @Nullable T value) { + return set(stack.copyWithCount(1), type, value); + } + + public static ItemStack createStack(ItemLike item, DataComponentType type, @Nullable T value) { + return set(new ItemStack(item), type, value); + } +} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java b/projects/common/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java index 22b361ff7..d645ad454 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java @@ -90,6 +90,6 @@ private static boolean canMergeItems(ItemStack stack1, ItemStack stack2) { if (stack1.getItem() != stack2.getItem()) return false; if (stack1.getDamageValue() != stack2.getDamageValue()) return false; if (stack1.getCount() > stack1.getMaxStackSize()) return false; - return ItemStack.isSameItemSameTags(stack1, stack2); + return ItemStack.isSameItemSameComponents(stack1, stack2); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/util/NBTUtil.java b/projects/common/src/main/java/dan200/computercraft/shared/util/NBTUtil.java index 96cdc6194..90c25157e 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/util/NBTUtil.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/util/NBTUtil.java @@ -6,8 +6,9 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.io.BaseEncoding; +import com.mojang.serialization.Codec; import dan200.computercraft.core.util.Nullability; -import dan200.computercraft.shared.platform.PlatformHelper; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,40 +27,21 @@ public final class NBTUtil { @VisibleForTesting static final BaseEncoding ENCODING = BaseEncoding.base16().lowerCase(); - private static final CompoundTag EMPTY_TAG; - - static { - // If in a development environment, create a magic immutable compound tag. - // We avoid doing this in prod, as I fear it might mess up the JIT inlining things. - if (PlatformHelper.get().isDevelopmentEnvironment()) { - try { - var ctor = CompoundTag.class.getDeclaredConstructor(Map.class); - ctor.setAccessible(true); - EMPTY_TAG = ctor.newInstance(Map.of()); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } else { - EMPTY_TAG = new CompoundTag(); - } - } - private NBTUtil() { } - /** - * Get a singleton empty {@link CompoundTag}. This tag should never be modified. - * - * @return The empty compound tag. - */ - public static CompoundTag emptyTag() { - if (EMPTY_TAG.size() != 0) LOG.error("The empty tag has been modified."); - return EMPTY_TAG; + public static @Nullable T decodeFrom(Codec codec, HolderLookup.Provider registries, CompoundTag tag, String key) { + var childTag = tag.get(key); + return childTag == null ? null : codec.parse(registries.createSerializationContext(NbtOps.INSTANCE), childTag) + .resultOrPartial(e -> LOG.warn("Failed to parse NBT: {}", e)) + .orElse(null); } - public static CompoundTag getCompoundOrEmpty(CompoundTag tag, String key) { - var childTag = tag.get(key); - return childTag != null && childTag.getId() == Tag.TAG_COMPOUND ? (CompoundTag) childTag : emptyTag(); + public static void encodeTo(Codec codec, HolderLookup.Provider registries, CompoundTag destination, String key, @Nullable T value) { + if (value == null) return; + codec.encodeStart(registries.createSerializationContext(NbtOps.INSTANCE), value) + .resultOrPartial(e -> LOG.warn("Failed to save NBT: {}", e)) + .ifPresent(x -> destination.put(key, x)); } private static @Nullable Tag toNBTTag(@Nullable Object object) { @@ -184,7 +166,7 @@ public static CompoundTag getCompoundOrEmpty(CompoundTag tag, String key) { } @Nullable - public static String getNBTHash(@Nullable CompoundTag tag) { + public static String getNBTHash(@Nullable Tag tag) { if (tag == null) return null; try { diff --git a/projects/common/src/main/java/dan200/computercraft/shared/util/NonNegativeId.java b/projects/common/src/main/java/dan200/computercraft/shared/util/NonNegativeId.java new file mode 100644 index 000000000..db0664506 --- /dev/null +++ b/projects/common/src/main/java/dan200/computercraft/shared/util/NonNegativeId.java @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.shared.util; + +import com.mojang.serialization.Codec; +import dan200.computercraft.api.ComputerCraftAPI; +import io.netty.buffer.ByteBuf; +import net.minecraft.core.component.DataComponentType; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.ExtraCodecs; +import net.minecraft.world.item.ItemStack; + +import javax.annotation.Nullable; + +/** + * A non-negative integer id, used for computer and disk ids. + * + * @param id The id of this entity. + * @see dan200.computercraft.shared.ModRegistry.DataComponents#COMPUTER_ID + * @see dan200.computercraft.shared.ModRegistry.DataComponents#DISK_ID + */ +public record NonNegativeId(int id) { + public static final Codec CODEC = ExtraCodecs.NON_NEGATIVE_INT.xmap(NonNegativeId::new, NonNegativeId::id); + + public static final StreamCodec STREAM_CODEC = ByteBufCodecs.INT.map(NonNegativeId::new, NonNegativeId::id); + + public NonNegativeId { + if (id < 0) throw new IllegalArgumentException("ID must be >= 0"); + } + + public static int getId(@Nullable NonNegativeId id) { + return id == null ? -1 : id.id(); + } + + public static @Nullable NonNegativeId of(int id) { + return id >= 0 ? new NonNegativeId(id) : null; + } + + public static int getOrCreate(MinecraftServer server, ItemStack stack, DataComponentType component, String type) { + var id = stack.get(component); + if (id != null) return id.id(); + + var diskID = ComputerCraftAPI.createUniqueNumberedSaveDir(server, type); + stack.set(component, new NonNegativeId(diskID)); + return diskID; + } +} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/util/TickScheduler.java b/projects/common/src/main/java/dan200/computercraft/shared/util/TickScheduler.java index fd459e5c1..89e8e0446 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/util/TickScheduler.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/util/TickScheduler.java @@ -13,8 +13,8 @@ import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.status.ChunkStatus; import java.util.*; import java.util.concurrent.ConcurrentLinkedDeque; diff --git a/projects/common/src/main/java/dan200/computercraft/shared/util/WorldUtil.java b/projects/common/src/main/java/dan200/computercraft/shared/util/WorldUtil.java index 049e4bf37..65a7778c5 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/util/WorldUtil.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/util/WorldUtil.java @@ -4,7 +4,6 @@ package dan200.computercraft.shared.util; -import dan200.computercraft.shared.platform.PlatformHelper; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Position; @@ -114,9 +113,7 @@ public static Vec3 getRayStart(Player entity) { } public static Vec3 getRayEnd(Player player) { - var reach = PlatformHelper.get().getReachDistance(player); - var look = player.getLookAngle(); - return getRayStart(player).add(look.x * reach, look.y * reach, look.z * reach); + return getRayStart(player).add(player.getLookAngle().scale(player.blockInteractionRange())); } private static final double DROP_SPEED = 0.0172275 * 6; diff --git a/projects/common/src/main/resources/assets/minecraft/shaders/core/computercraft/monitor_tbo.vsh b/projects/common/src/main/resources/assets/minecraft/shaders/core/computercraft/monitor_tbo.vsh index d46a089ce..681f36cc3 100644 --- a/projects/common/src/main/resources/assets/minecraft/shaders/core/computercraft/monitor_tbo.vsh +++ b/projects/common/src/main/resources/assets/minecraft/shaders/core/computercraft/monitor_tbo.vsh @@ -11,15 +11,16 @@ in vec2 UV0; uniform mat4 ModelViewMat; uniform mat4 ProjMat; -uniform mat3 IViewRotMat; +uniform vec3 ChunkOffset; uniform int FogShape; out float vertexDistance; out vec2 fontPos; void main() { - gl_Position = ProjMat * ModelViewMat * vec4(Position, 1); + vec3 pos = Position + ChunkOffset; + gl_Position = ProjMat * ModelViewMat * vec4(pos, 1.0); - vertexDistance = fog_distance(ModelViewMat, IViewRotMat * Position, FogShape); + vertexDistance = fog_distance(pos, FogShape); fontPos = UV0; } diff --git a/projects/common/src/main/resources/computercraft-common.accesswidener b/projects/common/src/main/resources/computercraft-common.accesswidener index 58be6fab6..a0ffacef9 100644 --- a/projects/common/src/main/resources/computercraft-common.accesswidener +++ b/projects/common/src/main/resources/computercraft-common.accesswidener @@ -7,6 +7,8 @@ accessWidener v1 named # Additional access wideners for vanilla code. This is a effectively the subset of Fabric's transitive access wideners # that we actually use +accessible class net/minecraft/world/level/block/entity/BlockEntityType$BlockEntitySupplier + accessible method net/minecraft/client/renderer/blockentity/BlockEntityRenderers register (Lnet/minecraft/world/level/block/entity/BlockEntityType;Lnet/minecraft/client/renderer/blockentity/BlockEntityRendererProvider;)V accessible class net/minecraft/world/item/CreativeModeTab$Output accessible field net/minecraft/world/item/CreativeModeTabs OP_BLOCKS Lnet/minecraft/resources/ResourceKey; diff --git a/projects/common/src/main/resources/computercraft.accesswidener b/projects/common/src/main/resources/computercraft.accesswidener index 99517fee9..081b21533 100644 --- a/projects/common/src/main/resources/computercraft.accesswidener +++ b/projects/common/src/main/resources/computercraft.accesswidener @@ -20,7 +20,6 @@ accessible field com/mojang/blaze3d/vertex/VertexBuffer format Lcom/mojang/blaze # ClientTableFormatter accessible field net/minecraft/client/gui/components/ChatComponent allMessages Ljava/util/List; -accessible method net/minecraft/client/gui/components/ChatComponent refreshTrimmedMessage ()V # ItemPocketRenderer/ItemPrintoutRenderer accessible method net/minecraft/client/renderer/ItemInHandRenderer calculateMapTilt (F)F @@ -33,3 +32,5 @@ accessible field net/minecraft/client/sounds/SoundEngine executor Lnet/minecraft # Turtle model accessible method net/minecraft/client/renderer/block/model/ItemOverrides ()V + +accessible class net/minecraft/util/datafix/fixes/ItemStackComponentizationFix$ItemStackData diff --git a/projects/common/src/main/resources/computercraft.mixins.json b/projects/common/src/main/resources/computercraft.mixins.json index adade5ea5..941fe0857 100644 --- a/projects/common/src/main/resources/computercraft.mixins.json +++ b/projects/common/src/main/resources/computercraft.mixins.json @@ -7,7 +7,9 @@ "defaultRequire": 1 }, "mixins": [ - "V1460Mixin" + "V1460Mixin", + "V3818_3Mixin", + "ItemStackComponentizationFixMixin" ], "refmap": "computercraft.refmap.json" } diff --git a/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java b/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java index e3d6d0ffe..91b07fd40 100644 --- a/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java +++ b/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java @@ -13,22 +13,15 @@ import dan200.computercraft.impl.AbstractComputerCraftAPI; import dan200.computercraft.impl.ComputerCraftAPIService; import dan200.computercraft.shared.config.ConfigFile; -import dan200.computercraft.shared.network.MessageType; -import dan200.computercraft.shared.network.NetworkMessage; -import dan200.computercraft.shared.network.client.ClientNetworkContext; import dan200.computercraft.shared.network.container.ContainerData; import dan200.computercraft.shared.platform.*; import net.minecraft.commands.synchronization.ArgumentTypeInfo; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Registry; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.common.ClientCommonPacketListener; -import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; -import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.tags.TagKey; @@ -45,18 +38,14 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Recipe; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; import javax.annotation.Nullable; import java.util.List; -import java.util.function.BiFunction; import java.util.function.Consumer; -import java.util.function.Function; import java.util.function.Predicate; @AutoService({ PlatformHelper.class, dan200.computercraft.impl.PlatformHelper.class, ComputerCraftAPIService.class }) @@ -86,11 +75,6 @@ public void addRequiredModCondition(JsonObject object, String modId) { throw new UnsupportedOperationException("Cannot use resource conditions"); } - @Override - public BlockEntityType createBlockEntityType(BiFunction factory, Block block) { - throw new UnsupportedOperationException("Cannot create BlockEntityType inside tests"); - } - @Override public , T extends ArgumentTypeInfo.Template, I extends ArgumentTypeInfo> I registerArgumentTypeInfo(Class klass, I info) { throw new UnsupportedOperationException("Cannot register ArgumentTypeInfo inside tests"); @@ -102,7 +86,7 @@ public List> getDyeTags() { } @Override - public MenuType createMenuType(Function reader, ContainerData.Factory factory) { + public MenuType createMenuType(StreamCodec reader, ContainerData.Factory factory) { throw new UnsupportedOperationException("Cannot create MenuType inside tests"); } @@ -111,28 +95,6 @@ public void openMenu(Player player, MenuProvider owner, ContainerData menu) { throw new UnsupportedOperationException("Cannot open menu inside tests"); } - @Override - public > MessageType createMessageType(ResourceLocation id, FriendlyByteBuf.Reader reader) { - record TypeImpl>(ResourceLocation id) implements MessageType { - } - return new TypeImpl<>(id); - } - - @Override - public Packet createPacket(NetworkMessage message) { - return new ClientboundCustomPayloadPacket(new CustomPacketPayload() { - @Override - public void write(FriendlyByteBuf friendlyByteBuf) { - message.write(friendlyByteBuf); - } - - @Override - public ResourceLocation id() { - return message.type().id(); - } - }); - } - @Override public ComponentAccess createPeripheralAccess(BlockEntity owner, Consumer invalidate) { throw new UnsupportedOperationException("Cannot interact with the world inside tests"); diff --git a/projects/common/src/test/java/dan200/computercraft/shared/computer/core/ResourceMountTest.java b/projects/common/src/test/java/dan200/computercraft/shared/computer/core/ResourceMountTest.java index 6552df2d5..44751bfc2 100644 --- a/projects/common/src/test/java/dan200/computercraft/shared/computer/core/ResourceMountTest.java +++ b/projects/common/src/test/java/dan200/computercraft/shared/computer/core/ResourceMountTest.java @@ -10,8 +10,11 @@ import dan200.computercraft.test.core.CloseScope; import dan200.computercraft.test.core.filesystem.MountContract; import net.minecraft.Util; +import net.minecraft.network.chat.Component; +import net.minecraft.server.packs.PackLocationInfo; import net.minecraft.server.packs.PackType; import net.minecraft.server.packs.PathPackResources; +import net.minecraft.server.packs.repository.PackSource; import net.minecraft.server.packs.resources.ReloadableResourceManager; import net.minecraft.util.Unit; import org.junit.jupiter.api.AfterEach; @@ -19,6 +22,7 @@ import java.io.IOException; import java.nio.file.Files; import java.util.List; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -38,7 +42,7 @@ public Mount createSkeleton() throws IOException { var manager = new ReloadableResourceManager(PackType.SERVER_DATA); var reload = manager.createReload(Util.backgroundExecutor(), Util.backgroundExecutor(), CompletableFuture.completedFuture(Unit.INSTANCE), List.of( - new PathPackResources("resources", path, false) + new PathPackResources(new PackLocationInfo("resources", Component.literal("resources"), PackSource.WORLD, Optional.empty()), path) )); try { diff --git a/projects/common/src/test/java/dan200/computercraft/shared/computer/terminal/TerminalStateTest.java b/projects/common/src/test/java/dan200/computercraft/shared/computer/terminal/TerminalStateTest.java index 1d953dd2a..25bfe02cb 100644 --- a/projects/common/src/test/java/dan200/computercraft/shared/computer/terminal/TerminalStateTest.java +++ b/projects/common/src/test/java/dan200/computercraft/shared/computer/terminal/TerminalStateTest.java @@ -23,7 +23,7 @@ public void testRoundTrip() { var terminal = randomTerminal(); var buffer = new FriendlyByteBuf(Unpooled.directBuffer()); - new TerminalState(terminal).write(buffer); + TerminalState.STREAM_CODEC.encode(buffer, new TerminalState(terminal)); checkEqual(terminal, read(buffer)); assertEquals(0, buffer.readableBytes()); @@ -53,6 +53,6 @@ private static void checkEqual(Terminal expected, Terminal actual) { } private static NetworkedTerminal read(FriendlyByteBuf buffer) { - return new TerminalState(buffer).create(); + return TerminalState.STREAM_CODEC.decode(buffer).create(); } } diff --git a/projects/common/src/test/java/dan200/computercraft/shared/network/client/PlayRecordClientMessageTest.java b/projects/common/src/test/java/dan200/computercraft/shared/network/client/PlayRecordClientMessageTest.java deleted file mode 100644 index 746adf57a..000000000 --- a/projects/common/src/test/java/dan200/computercraft/shared/network/client/PlayRecordClientMessageTest.java +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers -// -// SPDX-License-Identifier: MPL-2.0 - -package dan200.computercraft.shared.network.client; - -import dan200.computercraft.test.core.StructuralEquality; -import dan200.computercraft.test.shared.MinecraftArbitraries; -import dan200.computercraft.test.shared.WithMinecraft; -import io.netty.buffer.Unpooled; -import net.jqwik.api.*; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.sounds.SoundEvent; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; - -@WithMinecraft -class PlayRecordClientMessageTest { - static { - WithMinecraft.Setup.bootstrap(); // @Property doesn't run test lifecycle methods. - } - - /** - * Sends packets on a roundtrip, ensuring that their contents are reassembled on the other end. - * - * @param message The message to send. - */ - @Property - public void testRoundTrip(@ForAll("message") PlayRecordClientMessage message) { - var buffer = new FriendlyByteBuf(Unpooled.directBuffer()); - message.write(buffer); - - var converted = new PlayRecordClientMessage(buffer); - assertEquals(buffer.readableBytes(), 0, "Whole packet was read"); - - assertThat("Messages are equal", converted, equality.asMatcher(PlayRecordClientMessage.class, message)); - } - - @Provide - Arbitrary message() { - return Combinators.combine( - MinecraftArbitraries.blockPos(), - MinecraftArbitraries.soundEvent().injectNull(0.3), - Arbitraries.strings().ofMaxLength(1000).injectNull(0.3) - ).as(PlayRecordClientMessage::new); - } - - private static final StructuralEquality equality = StructuralEquality.all( - StructuralEquality.field(PlayRecordClientMessage.class, "pos"), - StructuralEquality.field(PlayRecordClientMessage.class, "name"), - StructuralEquality.field(PlayRecordClientMessage.class, "soundEvent", StructuralEquality.all( - StructuralEquality.at("location", SoundEvent::getLocation), - StructuralEquality.field(SoundEvent.class, "range"), - StructuralEquality.field(SoundEvent.class, "newSystem") - )) - ); -} diff --git a/projects/common/src/test/java/dan200/computercraft/shared/network/server/UploadFileMessageTest.java b/projects/common/src/test/java/dan200/computercraft/shared/network/server/UploadFileMessageTest.java index f6a2a2b5b..edbc864a8 100644 --- a/projects/common/src/test/java/dan200/computercraft/shared/network/server/UploadFileMessageTest.java +++ b/projects/common/src/test/java/dan200/computercraft/shared/network/server/UploadFileMessageTest.java @@ -11,7 +11,8 @@ import dan200.computercraft.test.shared.WithMinecraft; import io.netty.buffer.Unpooled; import net.jqwik.api.*; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.core.RegistryAccess; +import net.minecraft.network.RegistryFriendlyByteBuf; import org.hamcrest.Matcher; import java.nio.ByteBuffer; @@ -62,8 +63,8 @@ private static List send(List uploads) { */ private static List roundtripPackets(List packets) { return packets.stream().map(packet -> { - var buffer = new FriendlyByteBuf(Unpooled.directBuffer()); - packet.write(buffer); + var buffer = new RegistryFriendlyByteBuf(Unpooled.directBuffer(), RegistryAccess.EMPTY); + STREAM_CODEC.encode(buffer, packet); // We include things like file size in the packet, but not in the count, so grant a slightly larger threshold. assertThat("Packet is too large", buffer.writerIndex(), lessThanOrEqualTo(MAX_PACKET_SIZE + 128)); if ((packet.flag & FLAG_LAST) == 0) { @@ -75,7 +76,7 @@ private static List roundtripPackets(List ); } - var result = new UploadFileMessage(buffer); + var result = UploadFileMessage.STREAM_CODEC.decode(buffer); buffer.release(); assertEquals(0, buffer.refCnt(), "Buffer should have no references"); diff --git a/projects/common/src/test/java/dan200/computercraft/shared/peripheral/speaker/EncodedAudioTest.java b/projects/common/src/test/java/dan200/computercraft/shared/peripheral/speaker/EncodedAudioTest.java deleted file mode 100644 index 18751a82f..000000000 --- a/projects/common/src/test/java/dan200/computercraft/shared/peripheral/speaker/EncodedAudioTest.java +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers -// -// SPDX-License-Identifier: MPL-2.0 - -package dan200.computercraft.shared.peripheral.speaker; - -import dan200.computercraft.test.core.ArbitraryByteBuffer; -import io.netty.buffer.Unpooled; -import net.jqwik.api.*; -import net.minecraft.network.FriendlyByteBuf; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.jupiter.api.Assertions.assertEquals; - -class EncodedAudioTest { - /** - * Sends the audio on a roundtrip, ensuring that its contents are reassembled on the other end. - * - * @param audio The message to send. - */ - @Property - public void testRoundTrip(@ForAll("audio") EncodedAudio audio) { - var buffer = new FriendlyByteBuf(Unpooled.directBuffer()); - audio.write(buffer); - - var converted = EncodedAudio.read(buffer); - assertEquals(buffer.readableBytes(), 0, "Whole packet was read"); - - assertThat("Messages are equal", converted, equalTo(converted)); - } - - @Provide - Arbitrary audio() { - return Combinators.combine( - Arbitraries.integers(), - Arbitraries.integers(), - Arbitraries.of(true, false), - ArbitraryByteBuffer.bytes().ofMaxSize(1000) - ).as(EncodedAudio::new); - } -} diff --git a/projects/common/src/test/java/dan200/computercraft/shared/recipe/RecipeArbitraries.java b/projects/common/src/test/java/dan200/computercraft/shared/recipe/RecipeArbitraries.java deleted file mode 100644 index 759272302..000000000 --- a/projects/common/src/test/java/dan200/computercraft/shared/recipe/RecipeArbitraries.java +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers -// -// SPDX-License-Identifier: MPL-2.0 - -package dan200.computercraft.shared.recipe; - -import dan200.computercraft.test.shared.MinecraftArbitraries; -import it.unimi.dsi.fastutil.ints.IntIntImmutablePair; -import net.jqwik.api.Arbitraries; -import net.jqwik.api.Arbitrary; -import net.jqwik.api.Combinators; -import net.minecraft.core.NonNullList; -import net.minecraft.world.item.crafting.CraftingBookCategory; -import net.minecraft.world.item.crafting.Ingredient; -import net.minecraft.world.item.crafting.ShapedRecipePattern; - -import java.util.Optional; - -/** - * {@link Arbitrary} implementations for recipes. - */ -public final class RecipeArbitraries { - public static Arbitrary recipeProperties() { - return Combinators.combine( - Arbitraries.strings().ofMinLength(1).withChars("abcdefghijklmnopqrstuvwxyz_"), - Arbitraries.of(CraftingBookCategory.values()), - Arbitraries.of(true, false) - ).as(RecipeProperties::new); - } - - public static Arbitrary shapelessRecipeSpec() { - return Combinators.combine( - recipeProperties(), - MinecraftArbitraries.ingredient().array(Ingredient[].class).ofMinSize(1).map(x -> NonNullList.of(Ingredient.EMPTY, x)), - MinecraftArbitraries.nonEmptyItemStack() - ).as(ShapelessRecipeSpec::new); - } - - public static Arbitrary shapedPattern() { - return Combinators.combine(Arbitraries.integers().between(1, 3), Arbitraries.integers().between(1, 3)) - .as(IntIntImmutablePair::new) - .flatMap(x -> MinecraftArbitraries.ingredient().array(Ingredient[].class).ofSize(x.leftInt() * x.rightInt()) - .map(i -> new ShapedRecipePattern(x.leftInt(), x.rightInt(), NonNullList.of(Ingredient.EMPTY, i), Optional.empty())) - ); - } - - public static Arbitrary shapedRecipeSpec() { - return Combinators.combine( - recipeProperties(), - shapedPattern(), - MinecraftArbitraries.nonEmptyItemStack() - ).as(ShapedRecipeSpec::new); - } -} diff --git a/projects/common/src/test/java/dan200/computercraft/shared/recipe/RecipeEqualities.java b/projects/common/src/test/java/dan200/computercraft/shared/recipe/RecipeEqualities.java deleted file mode 100644 index 1ab5fac23..000000000 --- a/projects/common/src/test/java/dan200/computercraft/shared/recipe/RecipeEqualities.java +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers -// -// SPDX-License-Identifier: MPL-2.0 - -package dan200.computercraft.shared.recipe; - -import dan200.computercraft.test.core.StructuralEquality; -import dan200.computercraft.test.shared.MinecraftEqualities; -import net.minecraft.world.item.crafting.ShapedRecipePattern; - -/** - * {@link StructuralEquality} implementations for recipes. - */ -public final class RecipeEqualities { - private RecipeEqualities() { - } - - public static final StructuralEquality shapelessRecipeSpec = StructuralEquality.all( - StructuralEquality.at("properties", ShapelessRecipeSpec::properties), - StructuralEquality.at("ingredients", ShapelessRecipeSpec::ingredients, MinecraftEqualities.ingredient.list()), - StructuralEquality.at("result", ShapelessRecipeSpec::result, MinecraftEqualities.itemStack) - ); - - public static final StructuralEquality shapedPattern = StructuralEquality.all( - StructuralEquality.at("width", ShapedRecipePattern::width), - StructuralEquality.at("height", ShapedRecipePattern::height), - StructuralEquality.at("ingredients", ShapedRecipePattern::ingredients, MinecraftEqualities.ingredient.list()) - ); - - public static final StructuralEquality shapedRecipeSpec = StructuralEquality.all( - StructuralEquality.at("properties", ShapedRecipeSpec::properties), - StructuralEquality.at("ingredients", ShapedRecipeSpec::pattern, shapedPattern), - StructuralEquality.at("result", ShapedRecipeSpec::result, MinecraftEqualities.itemStack) - ); -} diff --git a/projects/common/src/test/java/dan200/computercraft/shared/recipe/ShapedRecipeSpecTest.java b/projects/common/src/test/java/dan200/computercraft/shared/recipe/ShapedRecipeSpecTest.java deleted file mode 100644 index eaae17a04..000000000 --- a/projects/common/src/test/java/dan200/computercraft/shared/recipe/ShapedRecipeSpecTest.java +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers -// -// SPDX-License-Identifier: MPL-2.0 - -package dan200.computercraft.shared.recipe; - -import dan200.computercraft.test.shared.NetworkSupport; -import dan200.computercraft.test.shared.WithMinecraft; -import net.jqwik.api.Arbitrary; -import net.jqwik.api.ForAll; -import net.jqwik.api.Property; -import net.jqwik.api.Provide; - -import static org.hamcrest.MatcherAssert.assertThat; - -@WithMinecraft -public class ShapedRecipeSpecTest { - static { - WithMinecraft.Setup.bootstrap(); // @Property doesn't run test lifecycle methods. - } - - @Property - public void testRoundTrip(@ForAll("recipe") ShapedRecipeSpec spec) { - var converted = NetworkSupport.roundTrip(spec, ShapedRecipeSpec::toNetwork, ShapedRecipeSpec::fromNetwork); - assertThat("Recipes are equal", converted, RecipeEqualities.shapedRecipeSpec.asMatcher(ShapedRecipeSpec.class, spec)); - } - - @Provide - Arbitrary recipe() { - return RecipeArbitraries.shapedRecipeSpec(); - } -} diff --git a/projects/common/src/test/java/dan200/computercraft/shared/recipe/ShapelessRecipeSpecTest.java b/projects/common/src/test/java/dan200/computercraft/shared/recipe/ShapelessRecipeSpecTest.java deleted file mode 100644 index 3e145a269..000000000 --- a/projects/common/src/test/java/dan200/computercraft/shared/recipe/ShapelessRecipeSpecTest.java +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers -// -// SPDX-License-Identifier: MPL-2.0 - -package dan200.computercraft.shared.recipe; - -import dan200.computercraft.test.shared.NetworkSupport; -import dan200.computercraft.test.shared.WithMinecraft; -import net.jqwik.api.Arbitrary; -import net.jqwik.api.ForAll; -import net.jqwik.api.Property; -import net.jqwik.api.Provide; - -import static org.hamcrest.MatcherAssert.assertThat; - -@WithMinecraft -public class ShapelessRecipeSpecTest { - static { - WithMinecraft.Setup.bootstrap(); // @Property doesn't run test lifecycle methods. - } - - @Property - public void testRoundTrip(@ForAll("recipe") ShapelessRecipeSpec spec) { - var converted = NetworkSupport.roundTrip(spec, ShapelessRecipeSpec::toNetwork, ShapelessRecipeSpec::fromNetwork); - assertThat("Recipes are equal", converted, RecipeEqualities.shapelessRecipeSpec.asMatcher(ShapelessRecipeSpec.class, spec)); - } - - @Provide - Arbitrary recipe() { - return RecipeArbitraries.shapelessRecipeSpec(); - } -} 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 338acdc1c..43d8bb1f4 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 @@ -45,7 +45,7 @@ Arbitrary tool() { MinecraftArbitraries.resourceLocation(), Arbitraries.strings().ofMaxLength(100), MinecraftArbitraries.item(), - MinecraftArbitraries.itemStack(), + MinecraftArbitraries.nonEmptyItemStack(), Arbitraries.floats(), Arbitraries.of(true, false), Arbitraries.of(TurtleToolDurability.values()), diff --git a/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/ItemStackMatcher.java b/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/ItemStackMatcher.java index 2c12f3019..cccb7b884 100644 --- a/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/ItemStackMatcher.java +++ b/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/ItemStackMatcher.java @@ -19,12 +19,12 @@ public ItemStackMatcher(ItemStack stack) { @Override protected boolean matchesSafely(ItemStack item) { - return ItemStack.isSameItemSameTags(item, stack) && item.getCount() == stack.getCount(); + return ItemStack.isSameItemSameComponents(item, stack) && item.getCount() == stack.getCount(); } @Override public void describeTo(Description description) { - description.appendValue(stack).appendValue(stack.getTag()); + description.appendValue(stack).appendValue(stack.getComponentsPatch()); } public static Matcher isStack(ItemStack stack) { diff --git a/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/MinecraftArbitraries.java b/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/MinecraftArbitraries.java index a293f550e..08473e1b2 100644 --- a/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/MinecraftArbitraries.java +++ b/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/MinecraftArbitraries.java @@ -12,14 +12,10 @@ import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; -import net.minecraft.sounds.SoundEvent; import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; -import net.minecraft.world.item.crafting.Ingredient; - -import java.util.List; /** * {@link Arbitrary} implementations for Minecraft types. @@ -41,14 +37,6 @@ public static Arbitrary nonEmptyItemStack() { return Combinators.combine(item().filter(x -> x != Items.AIR), Arbitraries.integers().between(1, 64)).as(ItemStack::new); } - public static Arbitrary itemStack() { - return Arbitraries.oneOf(List.of(Arbitraries.just(ItemStack.EMPTY), nonEmptyItemStack())); - } - - public static Arbitrary ingredient() { - return nonEmptyItemStack().list().ofMinSize(1).map(x -> Ingredient.of(x.stream())); - } - public static Arbitrary blockPos() { // BlockPos has a maximum range that can be sent over the network - use those. var xz = Arbitraries.integers().between(-3_000_000, -3_000_000); @@ -62,11 +50,4 @@ public static Arbitrary resourceLocation() { Arbitraries.strings().ofMinLength(1).withChars("abcdefghijklmnopqrstuvwxyz_-/") ).as(ResourceLocation::new); } - - public static Arbitrary soundEvent() { - return Arbitraries.oneOf(List.of( - resourceLocation().map(SoundEvent::createVariableRangeEvent), - Combinators.combine(resourceLocation(), Arbitraries.floats()).as(SoundEvent::createFixedRangeEvent) - )); - } } diff --git a/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/MinecraftEqualities.java b/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/MinecraftEqualities.java index a4bc6e4f4..342623048 100644 --- a/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/MinecraftEqualities.java +++ b/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/MinecraftEqualities.java @@ -4,13 +4,8 @@ package dan200.computercraft.test.shared; -import com.google.gson.JsonElement; -import com.google.gson.JsonParseException; -import com.mojang.serialization.JsonOps; import dan200.computercraft.test.core.StructuralEquality; -import net.minecraft.Util; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.Ingredient; import org.hamcrest.Description; /** @@ -20,28 +15,12 @@ public class MinecraftEqualities { public static final StructuralEquality itemStack = new StructuralEquality<>() { @Override public boolean equals(ItemStack left, ItemStack right) { - return ItemStack.isSameItemSameTags(left, right) && left.getCount() == right.getCount(); + return ItemStack.isSameItemSameComponents(left, right) && left.getCount() == right.getCount(); } @Override public void describe(Description description, ItemStack object) { - description.appendValue(object).appendValue(object.getTag()); - } - }; - - public static final StructuralEquality ingredient = new StructuralEquality<>() { - private static JsonElement toJson(Ingredient ingredient) { - return Util.getOrThrow(Ingredient.CODEC.encodeStart(JsonOps.INSTANCE, ingredient), JsonParseException::new); - } - - @Override - public boolean equals(Ingredient left, Ingredient right) { - return toJson(left).equals(toJson(right)); - } - - @Override - public void describe(Description description, Ingredient object) { - description.appendValue(toJson(object)); + description.appendValue(object).appendValue(object.getComponentsPatch()); } }; } diff --git a/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/NetworkSupport.java b/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/NetworkSupport.java index 9e723d5ff..d187879d0 100644 --- a/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/NetworkSupport.java +++ b/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/NetworkSupport.java @@ -5,7 +5,9 @@ package dan200.computercraft.test.shared; import io.netty.buffer.Unpooled; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.crafting.RecipeSerializer; @@ -31,8 +33,8 @@ private NetworkSupport() { * @param The type of the value to round trip. * @return The converted value, for checking equivalency. */ - public static T roundTrip(T value, BiConsumer write, Function read) { - var buffer = new FriendlyByteBuf(Unpooled.directBuffer()); + public static T roundTrip(T value, BiConsumer write, Function read) { + var buffer = new RegistryFriendlyByteBuf(Unpooled.directBuffer(), RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY)); write.accept(value, buffer); var converted = read.apply(buffer); @@ -50,7 +52,7 @@ public static T roundTrip(T value, BiConsumer write, Fun * @param The type of the value to round trip. * @return The converted value, for checking equivalency. */ - public static T roundTripSerialiser(ResourceLocation id, T value, BiConsumer write, BiFunction read) { + public static T roundTripSerialiser(ResourceLocation id, T value, BiConsumer write, BiFunction read) { return roundTrip(value, (x, b) -> write.accept(b, x), b -> read.apply(id, b)); } } diff --git a/projects/common/src/testMod/java/dan200/computercraft/export/Exporter.java b/projects/common/src/testMod/java/dan200/computercraft/export/Exporter.java index db6eef2b8..be7b56b43 100644 --- a/projects/common/src/testMod/java/dan200/computercraft/export/Exporter.java +++ b/projects/common/src/testMod/java/dan200/computercraft/export/Exporter.java @@ -89,7 +89,7 @@ private static void export(Path root, ImageRenderer renderer) throws IOException if (!RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, result.getItem()).getNamespace().equals(ComputerCraftAPI.MOD_ID)) { continue; } - if (result.hasTag()) { + if (!result.getComponentsPatch().isEmpty()) { TestHooks.LOG.warn("Skipping recipe {} as it has NBT", recipe.id()); continue; } diff --git a/projects/common/src/testMod/java/dan200/computercraft/export/ImageRenderer.java b/projects/common/src/testMod/java/dan200/computercraft/export/ImageRenderer.java index 032fc7bb7..0212ec0f5 100644 --- a/projects/common/src/testMod/java/dan200/computercraft/export/ImageRenderer.java +++ b/projects/common/src/testMod/java/dan200/computercraft/export/ImageRenderer.java @@ -40,8 +40,8 @@ public void setupState() { RenderSystem.setProjectionMatrix(new Matrix4f().identity().ortho(0, 16, 0, 16, 1000, 3000), VertexSorting.DISTANCE_TO_ORIGIN); var transform = RenderSystem.getModelViewStack(); - transform.pushPose(); - transform.setIdentity(); + transform.pushMatrix(); + transform.identity(); transform.translate(0.0f, 0.0f, -2000.0f); FogRenderer.setupNoFog(); @@ -50,7 +50,7 @@ public void setupState() { public void clearState() { if (projectionMatrix == null) throw new IllegalStateException("Not currently rendering"); RenderSystem.setProjectionMatrix(projectionMatrix, VertexSorting.DISTANCE_TO_ORIGIN); - RenderSystem.getModelViewStack().popPose(); + RenderSystem.getModelViewStack().popMatrix(); } public void captureRender(Path output, Runnable render) throws IOException { diff --git a/projects/common/src/testMod/java/dan200/computercraft/gametest/core/CCTestCommand.java b/projects/common/src/testMod/java/dan200/computercraft/gametest/core/CCTestCommand.java index d6ff5e364..3b44cedb4 100644 --- a/projects/common/src/testMod/java/dan200/computercraft/gametest/core/CCTestCommand.java +++ b/projects/common/src/testMod/java/dan200/computercraft/gametest/core/CCTestCommand.java @@ -8,8 +8,10 @@ import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.mixin.gametest.TestCommandAccessor; import dan200.computercraft.shared.ModRegistry; +import dan200.computercraft.shared.util.NonNegativeId; import net.minecraft.ChatFormatting; import net.minecraft.commands.CommandSourceStack; +import net.minecraft.core.component.DataComponents; import net.minecraft.gametest.framework.GameTestRegistry; import net.minecraft.gametest.framework.StructureUtils; import net.minecraft.nbt.CompoundTag; @@ -17,6 +19,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.entity.StructureBlockEntity; import net.minecraft.world.level.storage.LevelResource; @@ -44,21 +47,21 @@ public static void register(CommandDispatcher dispatcher) { exportFiles(context.getSource().getServer()); for (var function : GameTestRegistry.getAllTestFunctions()) { - TestCommandAccessor.callExportTestStructure(context.getSource(), function.getStructureName()); + TestCommandAccessor.callExportTestStructure(context.getSource(), function.structureName()); } return 0; })) .then(literal("regen-structures").executes(context -> { for (var function : GameTestRegistry.getAllTestFunctions()) { - dispatcher.execute("test import " + function.getTestName(), context.getSource()); - TestCommandAccessor.callExportTestStructure(context.getSource(), function.getStructureName()); + dispatcher.execute("test import " + function.testName(), context.getSource()); + TestCommandAccessor.callExportTestStructure(context.getSource(), function.structureName()); } return 0; })) .then(literal("marker").executes(context -> { var player = context.getSource().getPlayerOrException(); - var pos = StructureUtils.findNearestStructureBlock(player.blockPosition(), 15, player.serverLevel()); + var pos = StructureUtils.findNearestStructureBlock(player.blockPosition(), 15, player.serverLevel()).orElse(null); if (pos == null) return error(context.getSource(), "No nearby test"); var structureBlock = (StructureBlockEntity) player.level().getBlockEntity(pos); @@ -67,7 +70,7 @@ public static void register(CommandDispatcher dispatcher) { // Kill the existing armor stand player - .serverLevel().getEntities(EntityType.ARMOR_STAND, x -> x.isAlive() && x.getName().getString().equals(info.getTestName())) + .serverLevel().getEntities(EntityType.ARMOR_STAND, x -> x.isAlive() && x.getName().getString().equals(info.testName())) .forEach(Entity::kill); // And create a new one @@ -77,21 +80,23 @@ public static void register(CommandDispatcher dispatcher) { var armorStand = assertNonNull(EntityType.ARMOR_STAND.create(player.level())); armorStand.readAdditionalSaveData(nbt); armorStand.copyPosition(player); - armorStand.setCustomName(Component.literal(info.getTestName())); + armorStand.setCustomName(Component.literal(info.testName())); player.level().addFreshEntity(armorStand); return 0; })) .then(literal("give-computer").executes(context -> { var player = context.getSource().getPlayerOrException(); - var pos = StructureUtils.findNearestStructureBlock(player.blockPosition(), 15, player.serverLevel()); + var pos = StructureUtils.findNearestStructureBlock(player.blockPosition(), 15, player.serverLevel()).orElse(null); if (pos == null) return error(context.getSource(), "No nearby test"); var structureBlock = (StructureBlockEntity) player.level().getBlockEntity(pos); if (structureBlock == null) return error(context.getSource(), "No nearby structure block"); var info = GameTestRegistry.getTestFunction(structureBlock.getMetaData()); - var item = ModRegistry.Items.COMPUTER_ADVANCED.get().create(1, info.getTestName()); + var item = new ItemStack(ModRegistry.Items.COMPUTER_ADVANCED.get()); + item.set(ModRegistry.DataComponents.COMPUTER_ID.get(), new NonNegativeId(1)); + item.set(DataComponents.CUSTOM_NAME, Component.literal(info.testName())); if (!player.getInventory().add(item)) { var itemEntity = player.drop(item, false); if (itemEntity != null) { diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Disk_Drive_Test.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Disk_Drive_Test.kt index 11fd18344..4cd6b8ffc 100644 --- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Disk_Drive_Test.kt +++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Disk_Drive_Test.kt @@ -5,15 +5,15 @@ package dan200.computercraft.gametest import dan200.computercraft.core.apis.FSAPI -import dan200.computercraft.core.util.Colour import dan200.computercraft.gametest.api.* import dan200.computercraft.shared.ModRegistry -import dan200.computercraft.shared.media.items.DiskItem import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveBlock import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveState +import dan200.computercraft.shared.util.DataComponentUtil import dan200.computercraft.test.core.assertArrayEquals import dan200.computercraft.test.core.computer.getApi import net.minecraft.core.BlockPos +import net.minecraft.core.component.DataComponents import net.minecraft.gametest.framework.GameTest import net.minecraft.gametest.framework.GameTestHelper import net.minecraft.network.chat.Component @@ -88,7 +88,7 @@ fun Queues_event(helper: GameTestHelper) = helper.sequence { fun Adds_removes_mount(helper: GameTestHelper) = helper.sequence { thenOnComputer { } // Wait for the computer to start up thenExecute { - helper.setContainerItem(BlockPos(1, 2, 2), 0, DiskItem.createFromIDAndColour(1, null, Colour.BLACK.hex)) + helper.setContainerItem(BlockPos(1, 2, 2), 0, ItemStack(ModRegistry.Items.DISK.get())) } thenOnComputer { getApi().getDrive("disk").assertArrayEquals("right") @@ -106,7 +106,9 @@ fun Creates_disk_id(helper: GameTestHelper) = helper.sequence { val drivePos = BlockPos(2, 2, 2) thenWaitUntil { val drive = helper.getBlockEntity(drivePos, ModRegistry.BlockEntities.DISK_DRIVE.get()) - if (DiskItem.getDiskID(drive.getItem(0)) == -1) helper.fail("Disk has no item", drivePos) + if (!drive.getItem(0).has(ModRegistry.DataComponents.DISK_ID.get())) { + helper.fail("Disk has no item", drivePos) + } } } @@ -169,7 +171,7 @@ fun Drops_contents(helper: GameTestHelper) = helper.sequence { thenExecute { helper.level.destroyBlock(helper.absolutePos(BlockPos(2, 2, 2)), true) helper.assertExactlyItems( - ItemStack(ModRegistry.Items.DISK_DRIVE.get()).setHoverName(Component.literal("My Disk Drive")), + DataComponentUtil.createStack(ModRegistry.Items.DISK_DRIVE.get(), DataComponents.CUSTOM_NAME, Component.literal("My Disk Drive")), ItemStack(ModRegistry.Items.TREASURE_DISK.get()), message = "Breaking a disk drive should drop the contents", ) 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 9df702940..881e61125 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 @@ -11,11 +11,13 @@ import dan200.computercraft.mixin.gametest.GameTestHelperAccessor import dan200.computercraft.shared.ModRegistry import dan200.computercraft.shared.computer.core.ComputerState -import dan200.computercraft.shared.pocket.items.PocketComputerItem import dan200.computercraft.test.core.computer.getApi import net.minecraft.core.BlockPos +import net.minecraft.core.component.DataComponents import net.minecraft.gametest.framework.GameTestHelper import net.minecraft.gametest.framework.GameTestSequence +import net.minecraft.network.chat.Component +import net.minecraft.world.item.ItemStack import org.junit.jupiter.api.Assertions.assertEquals import kotlin.random.Random @@ -97,8 +99,9 @@ fun Renders_map_view(context: GameTestHelper) = context.sequence { val testName = (this as GameTestHelperAccessor).testInfo.testName val label = testName + (if (name == null) "" else ".$name") - val item = ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get().create(1, label, -1, null) - item.getOrCreateTag().putBoolean(PocketComputerItem.NBT_ON, true) + val item = ItemStack(ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get()) + item.set(DataComponents.CUSTOM_NAME, Component.literal(label)) + item.set(ModRegistry.DataComponents.ON.get(), true) player.inventory.setItem(0, item) } } diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Printer_Test.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Printer_Test.kt index fd8577c3e..8d1aeec21 100644 --- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Printer_Test.kt +++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Printer_Test.kt @@ -10,7 +10,9 @@ import dan200.computercraft.gametest.api.sequence import dan200.computercraft.shared.ModRegistry import dan200.computercraft.shared.peripheral.printer.PrinterBlock +import dan200.computercraft.shared.util.DataComponentUtil import net.minecraft.core.BlockPos +import net.minecraft.core.component.DataComponents import net.minecraft.gametest.framework.GameTest import net.minecraft.gametest.framework.GameTestHelper import net.minecraft.network.chat.Component @@ -87,7 +89,7 @@ fun Drops_contents(helper: GameTestHelper) = helper.sequence { thenExecute { helper.level.destroyBlock(helper.absolutePos(BlockPos(2, 2, 2)), true) helper.assertExactlyItems( - ItemStack(ModRegistry.Items.PRINTER.get()).setHoverName(Component.literal("My Printer")), + DataComponentUtil.createStack(ModRegistry.Items.PRINTER.get(), DataComponents.CUSTOM_NAME, Component.literal("My Printer")), ItemStack(Items.PAPER), ItemStack(Items.BLACK_DYE), message = "Breaking a printer should drop the contents", 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 7b24528db..699075d9d 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 @@ -8,17 +8,18 @@ import dan200.computercraft.gametest.api.Structures import dan200.computercraft.gametest.api.sequence import dan200.computercraft.shared.ModRegistry +import net.minecraft.core.component.DataComponentPatch +import net.minecraft.core.component.DataComponents import net.minecraft.gametest.framework.GameTest import net.minecraft.gametest.framework.GameTestAssertException import net.minecraft.gametest.framework.GameTestHelper -import net.minecraft.nbt.CompoundTag -import net.minecraft.nbt.NbtUtils import net.minecraft.world.entity.player.Player import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.inventory.MenuType import net.minecraft.world.inventory.TransientCraftingContainer import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Items +import net.minecraft.world.item.component.ResolvableProfile import net.minecraft.world.item.crafting.RecipeType import org.junit.jupiter.api.Assertions.assertEquals import java.util.* @@ -44,10 +45,8 @@ fun Craft_result_has_nbt(context: GameTestHelper) = context.sequence { val profile = GameProfile(UUID.fromString("f3c8d69b-0776-4512-8434-d1b2165909eb"), "dan200") - val tag = CompoundTag() - tag.put("SkullOwner", NbtUtils.writeGameProfile(CompoundTag(), profile)) - - assertEquals(tag, result.tag, "Expected NBT tags to be the same") + val tag = DataComponentPatch.builder().set(DataComponents.PROFILE, ResolvableProfile(profile)).build() + assertEquals(tag, result.componentsPatch, "Expected NBT tags to be the same") } } 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 40ed67cf4..becb5fc8c 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 @@ -30,6 +30,7 @@ import net.minecraft.core.BlockPos import net.minecraft.gametest.framework.GameTest import net.minecraft.gametest.framework.GameTestHelper +import net.minecraft.resources.ResourceLocation import net.minecraft.world.entity.EntityType import net.minecraft.world.entity.item.PrimedTnt import net.minecraft.world.item.ItemStack @@ -232,7 +233,12 @@ fun Dig_consume_durability(helper: GameTestHelper) = helper.sequence { val turtle = helper.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.TURTLE_NORMAL.get()).access val upgrade = turtle.getUpgrade(TurtleSide.LEFT) - assertEquals(TurtleUpgrades.instance().get("cctest:wooden_pickaxe"), upgrade, "Upgrade is a wooden pickaxe") + assertEquals( + TurtleUpgrades.instance() + .get(ResourceLocation("cctest", "wooden_pickaxe")), + upgrade, + "Upgrade is a wooden pickaxe", + ) val item = ItemStack(Items.WOODEN_PICKAXE) item.damageValue = 1 @@ -256,7 +262,7 @@ fun Dig_breaks_tool(helper: GameTestHelper) = helper.sequence { helper.assertUpgradeItem( ItemStack(Items.WOODEN_PICKAXE), - UpgradeData.ofDefault(TurtleUpgrades.instance().get("cctest:wooden_pickaxe")), + UpgradeData.ofDefault(TurtleUpgrades.instance().get(ResourceLocation("cctest", "wooden_pickaxe"))), ) } } @@ -275,7 +281,7 @@ fun Dig_enchanted_consume_durability(helper: GameTestHelper) = helper.sequence { val turtle = helper.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.TURTLE_NORMAL.get()).access val upgrade = turtle.getUpgrade(TurtleSide.LEFT) assertEquals( - TurtleUpgrades.instance().get("cctest:netherite_pickaxe"), + TurtleUpgrades.instance().get(ResourceLocation("cctest", "netherite_pickaxe")), upgrade, "Upgrade is a netherite pickaxe", ) @@ -283,7 +289,6 @@ fun Dig_enchanted_consume_durability(helper: GameTestHelper) = helper.sequence { val item = ItemStack(Items.NETHERITE_PICKAXE) item.damageValue = 1 item.enchant(Enchantments.SILK_TOUCH, 1) - item.setRepairCost(1) helper.assertUpgradeItem(item, turtle.getUpgradeWithData(TurtleSide.LEFT)!!) } @@ -291,7 +296,7 @@ fun Dig_enchanted_consume_durability(helper: GameTestHelper) = helper.sequence { private fun GameTestHelper.assertUpgradeItem(expected: ItemStack, upgrade: UpgradeData) { if (!ItemStack.matches(expected, upgrade.upgradeItem)) { - fail("Invalid upgrade item\n Expected => ${expected.tag}\n Actual => ${upgrade.upgradeItem.tag}") + fail("Invalid upgrade item\n Expected => ${expected.componentsPatch}\n Actual => ${upgrade.upgradeItem.componentsPatch}") } if (!ItemStack.matches(ItemStack(expected.item), upgrade.upgrade.craftingItem)) { 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 a44261b6b..ed76bae18 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 @@ -7,7 +7,6 @@ import dan200.computercraft.api.peripheral.IPeripheral import dan200.computercraft.gametest.core.ManagedComputers import dan200.computercraft.impl.RegistryHelper -import dan200.computercraft.mixin.gametest.GameTestHelperAccessor import dan200.computercraft.mixin.gametest.GameTestInfoAccessor import dan200.computercraft.mixin.gametest.GameTestSequenceAccessor import dan200.computercraft.shared.platform.PlatformHelper @@ -25,6 +24,7 @@ import net.minecraft.world.entity.EntityType import net.minecraft.world.item.ItemStack import net.minecraft.world.item.context.UseOnContext +import net.minecraft.world.level.GameType import net.minecraft.world.level.block.Blocks import net.minecraft.world.level.block.entity.BarrelBlockEntity import net.minecraft.world.level.block.entity.BlockEntity @@ -226,7 +226,7 @@ Items do not match (first mismatch at slot $slot). */ private fun GameTestHelper.getPeripheralAt(pos: BlockPos, direction: Direction): IPeripheral? { val be = BarrelBlockEntity(absolutePos(pos).relative(direction), Blocks.BARREL.defaultBlockState()) - be.setLevel(level) + be.level = level return PlatformHelper.get().createPeripheralAccess(be) { }.get(direction.opposite) } @@ -269,14 +269,6 @@ private fun getName(type: BlockEntityType<*>): ResourceLocation = } } -/** - * Get all entities of a specific type within the test structure. - */ -fun GameTestHelper.getEntities(type: EntityType): List { - val info = (this as GameTestHelperAccessor).testInfo - return level.getEntities(type, info.structureBounds!!) { it.isAlive } -} - /** * Get an [Entity] inside the game structure, requiring there to be a single one. */ @@ -317,7 +309,7 @@ private fun getName(type: BlockEntityType<*>): ResourceLocation = * This is required for compatibility with Forge, which uses the in-hand stack, rather than the stack requested. */ fun GameTestHelper.placeItemAt(stack: ItemStack, pos: BlockPos, direction: Direction) { - val player = makeMockPlayer() + val player = makeMockPlayer(GameType.CREATIVE) player.setItemInHand(InteractionHand.MAIN_HAND, stack) val absolutePos = absolutePos(pos.relative(direction)) val hit = BlockHitResult(Vec3.atCenterOf(absolutePos), direction, absolutePos, false) diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/core/ClientTestHooks.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/core/ClientTestHooks.kt index e63c81d5c..e42b19ae9 100644 --- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/core/ClientTestHooks.kt +++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/core/ClientTestHooks.kt @@ -14,7 +14,7 @@ import net.minecraft.client.gui.screens.Screen import net.minecraft.client.gui.screens.TitleScreen import net.minecraft.client.tutorial.TutorialSteps -import net.minecraft.core.BlockPos +import net.minecraft.core.registries.Registries import net.minecraft.gametest.framework.* import net.minecraft.server.MinecraftServer import net.minecraft.sounds.SoundSource @@ -23,7 +23,6 @@ import net.minecraft.world.level.GameType import net.minecraft.world.level.LevelSettings import net.minecraft.world.level.WorldDataConfiguration -import net.minecraft.world.level.block.Rotation import net.minecraft.world.level.levelgen.WorldOptions import net.minecraft.world.level.levelgen.presets.WorldPresets import org.slf4j.Logger @@ -81,7 +80,7 @@ private fun openWorld(screen: Screen) { if (minecraft.levelSource.levelExists(LEVEL_NAME)) { LOG.info("World already exists, opening.") - minecraft.createWorldOpenFlows().checkForBackupAndLoad(LEVEL_NAME) { minecraft.setScreen(screen) } + minecraft.createWorldOpenFlows().openWorld(LEVEL_NAME) { minecraft.setScreen(screen) } } else { LOG.info("World does not exist, creating it.") val rules = GameRules() @@ -93,7 +92,10 @@ private fun openWorld(screen: Screen) { LEVEL_NAME, LevelSettings("Test Level", GameType.CREATIVE, false, Difficulty.EASY, true, rules, WorldDataConfiguration.DEFAULT), WorldOptions(WorldOptions.randomSeed(), false, false), - { WorldPresets.createNormalWorldDimensions(it) }, + { + it.registryOrThrow(Registries.WORLD_PRESET).getHolderOrThrow(WorldPresets.FLAT).value() + .createWorldDimensions() + }, screen, ) } @@ -119,27 +121,30 @@ fun onServerTick(server: MinecraftServer) { LOG.info("Server ready, starting.") - val tests = GameTestRunner.runTestBatches( - GameTestRunner.groupTestsIntoBatches(GameTestRegistry.getAllTestFunctions()), - BlockPos(0, -60, 0), - Rotation.NONE, + val tests = GameTestRunner.Builder.fromBatches( + GameTestBatchFactory.fromTestFunction(GameTestRegistry.getAllTestFunctions(), server.overworld()), server.overworld(), - GameTestTicker.SINGLETON, - 8, ) - val testTracker = MultipleTestTracker(tests) + .newStructureSpawner(StructureGridSpawner(TestHooks.getTestOrigin(server), 8)) + .build() + + val testTracker = MultipleTestTracker(tests.testInfos) testTracker.addListener( object : GameTestListener { + override fun testPassed(test: GameTestInfo, runner: GameTestRunner) = testFinished() + override fun testFailed(test: GameTestInfo, runner: GameTestRunner) = testFinished() + override fun testStructureLoaded(test: GameTestInfo) = Unit + override fun testAddedForRerun(test: GameTestInfo, newTest: GameTestInfo, runner: GameTestRunner) { + } + fun testFinished() { for (it in server.playerList.players) it.setupForTest() } - - override fun testPassed(test: GameTestInfo) = testFinished() - override fun testFailed(test: GameTestInfo) = testFinished() - override fun testStructureLoaded(test: GameTestInfo) = Unit }, ) + tests.start() + LOG.info("{} tests are now running!", testTracker.totalCount) this.testTracker = testTracker testTracker diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/core/ManagedComputers.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/core/ManagedComputers.kt index 05a06ee4f..6769df7a9 100644 --- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/core/ManagedComputers.kt +++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/core/ManagedComputers.kt @@ -96,7 +96,7 @@ private fun fail(message: String): Nothing { throw GameTestAssertException(message) } else { val pos = computer.position - val relativePos = pos.subtract(test.structureBlockPos) + val relativePos = pos.subtract(test.structureBlockPos!!) throw GameTestAssertPosException(message, pos, relativePos, (test as GameTestInfoAccessor).`computercraft$getTick`()) } } diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/core/TestHooks.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/core/TestHooks.kt index 656f14147..0a4bfc159 100644 --- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/core/TestHooks.kt +++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/core/TestHooks.kt @@ -14,6 +14,7 @@ import net.minecraft.gametest.framework.* import net.minecraft.server.MinecraftServer import net.minecraft.world.level.GameRules +import net.minecraft.world.level.block.entity.StructureBlockEntity import org.slf4j.Logger import org.slf4j.LoggerFactory import java.io.File @@ -54,6 +55,11 @@ fun init() { } } + fun getTestOrigin(server: MinecraftServer): BlockPos { + val spawn = server.overworld().sharedSpawnPos + return BlockPos(spawn.x, -59, spawn.y) + } + @JvmStatic fun onServerStarted(server: MinecraftServer) { val rules = server.gameRules @@ -61,7 +67,12 @@ fun onServerStarted(server: MinecraftServer) { server.overworld().dayTime = Times.NOON LOG.info("Cleaning up after last run") - GameTestRunner.clearAllTests(server.overworld(), BlockPos(0, -60, 0), GameTestTicker.SINGLETON, 200) + + val level = server.overworld() + StructureUtils.findStructureBlocks(getTestOrigin(server), 200, level).forEach { pos -> + val structure = level.getBlockEntity(pos) as StructureBlockEntity? ?: return@forEach + StructureUtils.clearSpaceForStructure(StructureUtils.getStructureBoundingBox(structure), level) + } // Delete server context and add one with a mutable machine factory. This allows us to set the factory for // specific test batches without having to reset all computers. @@ -131,7 +142,10 @@ private fun registerTest(testClass: Class<*>, method: Method, fallbackRegister: StructureUtils.getRotationForRotationSteps(testInfo.rotationSteps), adjustTimeout(testInfo.timeoutTicks), testInfo.setupTicks, - testInfo.required, testInfo.requiredSuccesses, testInfo.attempts, + testInfo.required, testInfo.manualOnly, + testInfo.attempts, + testInfo.requiredSuccesses, + testInfo.skyAccess, ) { value -> safeInvoke(method, value) }, ) GameTestRegistry.getAllTestClassNames().add(testClass.simpleName) diff --git a/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.attack_entity.snbt b/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.attack_entity.snbt index 93c3f0341..a80fe6a67 100644 --- a/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.attack_entity.snbt +++ b/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.attack_entity.snbt @@ -129,7 +129,7 @@ {pos: [4, 4, 4], state: "minecraft:air"} ], entities: [ - {blockPos: [2, 1, 3], pos: [2.5d, 1.0d, 3.5d], nbt: {AbsorptionAmount: 0.0f, Age: 0, Air: 300s, ArmorDropChances: [0.085f, 0.085f, 0.085f, 0.085f], ArmorItems: [{}, {}, {}, {}], Attributes: [{Base: 0.08d, Name: "forge:entity_gravity"}, {Base: 16.0d, Modifiers: [{Amount: -0.035951819981951794d, Name: "Random spawn bonus", Operation: 1, UUID: [I; 1700656572, -1622061405, -2001517321, -1044884103]}], Name: "minecraft:generic.follow_range"}, {Base: 0.23000000417232513d, Name: "minecraft:generic.movement_speed"}], Brain: {memories: {}}, CanPickUpLoot: 0b, CanUpdate: 1b, Color: 0b, DeathTime: 0s, FallDistance: 0.0f, FallFlying: 0b, Fire: -1s, ForcedAge: 0, HandDropChances: [0.085f, 0.085f], HandItems: [{}, {}], Health: 8.0f, HurtByTimestamp: 0, HurtTime: 0s, InLove: 0, Invulnerable: 0b, LeftHanded: 0b, Motion: [0.0d, -0.0784000015258789d, 0.0d], OnGround: 1b, PersistenceRequired: 0b, PortalCooldown: 0, Pos: [92.5d, -58.0d, 35.5d], Rotation: [5.6449127f, 0.0f], Sheared: 0b, UUID: [I; -551270274, -502513578, -1253838680, -1186962441], id: "minecraft:sheep"}} + {blockPos: [2, 1, 3], pos: [2.5d, 1.0d, 3.5d], nbt: {AbsorptionAmount: 0.0f, Age: 0, Air: 300s, ArmorDropChances: [0.085f, 0.085f, 0.085f, 0.085f], ArmorItems: [{}, {}, {}, {}], Brain: {memories: {}}, CanPickUpLoot: 0b, CanUpdate: 1b, Color: 0b, DeathTime: 0s, FallDistance: 0.0f, FallFlying: 0b, Fire: -1s, ForcedAge: 0, HandDropChances: [0.085f, 0.085f], HandItems: [{}, {}], Health: 8.0f, HurtByTimestamp: 0, HurtTime: 0s, InLove: 0, Invulnerable: 0b, LeftHanded: 0b, Motion: [0.0d, -0.0784000015258789d, 0.0d], OnGround: 1b, PersistenceRequired: 0b, PortalCooldown: 0, Pos: [92.5d, -58.0d, 35.5d], Rotation: [5.6449127f, 0.0f], Sheared: 0b, UUID: [I; -551270274, -502513578, -1253838680, -1186962441], id: "minecraft:sheep"}} ], palette: [ "minecraft:polished_andesite", diff --git a/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.dig_breaks_tool.snbt b/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.dig_breaks_tool.snbt index 7a1f5a7a8..afdfff97e 100644 --- a/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.dig_breaks_tool.snbt +++ b/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.dig_breaks_tool.snbt @@ -1,5 +1,5 @@ { - DataVersion: 3218, + DataVersion: 3832, size: [5, 5, 5], data: [ {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, @@ -39,7 +39,7 @@ {pos: [1, 1, 4], state: "minecraft:air"}, {pos: [2, 1, 0], state: "minecraft:air"}, {pos: [2, 1, 1], state: "minecraft:air"}, - {pos: [2, 1, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 80, Items: [], Label: "turtle_test.dig_breaks_tool", LeftUpgrade: "cctest:wooden_pickaxe", LeftUpgradeNbt: {Tag: {Damage: 58}}, On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [2, 1, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 80, Items: [], Label: "turtle_test.dig_breaks_tool", LeftUpgrade: {id: "cctest:wooden_pickaxe", components: {"minecraft:damage": 58}}, On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, {pos: [2, 1, 3], state: "minecraft:stone"}, {pos: [2, 1, 4], state: "minecraft:air"}, {pos: [3, 1, 0], state: "minecraft:air"}, diff --git a/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.dig_enchanted_consume_durability.snbt b/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.dig_enchanted_consume_durability.snbt index e461da3ea..f4c26982c 100644 --- a/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.dig_enchanted_consume_durability.snbt +++ b/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.dig_enchanted_consume_durability.snbt @@ -1,5 +1,5 @@ { - DataVersion: 3337, + DataVersion: 3832, size: [5, 5, 5], data: [ {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, @@ -39,7 +39,7 @@ {pos: [1, 1, 4], state: "minecraft:air"}, {pos: [2, 1, 0], state: "minecraft:air"}, {pos: [2, 1, 1], state: "minecraft:air"}, - {pos: [2, 1, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 80, Items: [], Label: "turtle_test.dig_enchanted_consume_durability", LeftUpgrade: "cctest:netherite_pickaxe", LeftUpgradeNbt: {Tag: {Damage: 0, Enchantments: [{id: "minecraft:silk_touch", lvl: 1s}], RepairCost: 1}}, On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [2, 1, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 80, Items: [], Label: "turtle_test.dig_enchanted_consume_durability", LeftUpgrade: {id: "cctest:netherite_pickaxe", components: {"minecraft:enchantments": {levels: {"minecraft:silk_touch": 1}}}}, On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, {pos: [2, 1, 3], state: "minecraft:stone"}, {pos: [2, 1, 4], state: "minecraft:air"}, {pos: [3, 1, 0], state: "minecraft:air"}, diff --git a/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.render_turtle_blocks.snbt b/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.render_turtle_blocks.snbt index fd929d435..cef85bc73 100644 --- a/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.render_turtle_blocks.snbt +++ b/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.render_turtle_blocks.snbt @@ -35,7 +35,7 @@ {pos: [1, 1, 0], state: "minecraft:air"}, {pos: [1, 1, 1], state: "minecraft:air"}, {pos: [1, 1, 2], state: "minecraft:air"}, - {pos: [1, 1, 3], state: "computercraft:turtle_normal{facing:east,waterlogged:false}", nbt: {ComputerId: 8, Fuel: 0, Items: [], LeftUpgrade: "cctest:netherite_pickaxe", LeftUpgradeNbt: {Tag: {Damage: 0, Enchantments: [{id: "minecraft:efficiency", lvl: 5s}], RepairCost: 1}}, On: 1b, Owner: {LowerId: -7931330074873442406L, Name: "Player848", UpperId: 7430876841693101418L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [1, 1, 3], state: "computercraft:turtle_normal{facing:east,waterlogged:false}", nbt: {ComputerId: 8, Fuel: 0, Items: [], LeftUpgrade: {id: "cctest:netherite_pickaxe", components: {"minecraft:enchantments": {levels: {"minecraft:silk_touch": 1}}}}, On: 1b, Owner: {LowerId: -7931330074873442406L, Name: "Player848", UpperId: 7430876841693101418L}, Slot: 0, id: "computercraft:turtle_normal"}}, {pos: [1, 1, 4], state: "minecraft:air"}, {pos: [2, 1, 0], state: "minecraft:air"}, {pos: [2, 1, 1], state: "minecraft:air"}, @@ -85,7 +85,7 @@ {pos: [1, 3, 0], state: "minecraft:air"}, {pos: [1, 3, 1], state: "minecraft:air"}, {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "computercraft:turtle_normal{facing:east,waterlogged:false}", nbt: {ComputerId: 8, Fuel: 0, Items: [], Label: "Dinnerbone", LeftUpgrade: "cctest:netherite_pickaxe", LeftUpgradeNbt: {Tag: {Damage: 0, Enchantments: [{id: "minecraft:efficiency", lvl: 5s}], RepairCost: 1}}, On: 1b, Owner: {LowerId: -7931330074873442406L, Name: "Player848", UpperId: 7430876841693101418L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [1, 3, 3], state: "computercraft:turtle_normal{facing:east,waterlogged:false}", nbt: {ComputerId: 8, Fuel: 0, Items: [], Label: "Dinnerbone", LeftUpgrade: {id: "cctest:netherite_pickaxe", components: {"minecraft:enchantments": {levels: {"minecraft:silk_touch": 1}}}}, On: 1b, Owner: {LowerId: -7931330074873442406L, Name: "Player848", UpperId: 7430876841693101418L}, Slot: 0, id: "computercraft:turtle_normal"}}, {pos: [1, 3, 4], state: "minecraft:air"}, {pos: [2, 3, 0], state: "minecraft:air"}, {pos: [2, 3, 1], state: "minecraft:air"}, diff --git a/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.render_turtle_items.snbt b/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.render_turtle_items.snbt index d772a0196..5c1c64d75 100644 --- a/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.render_turtle_items.snbt +++ b/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.render_turtle_items.snbt @@ -132,8 +132,8 @@ {blockPos: [2, 1, 0], pos: [2.5d, 1.0d, 0.5d], nbt: {AbsorptionAmount: 0.0f, Air: 300s, ArmorItems: [{}, {}, {}, {}], Attributes: [{Base: 0.699999988079071d, Name: "minecraft:generic.movement_speed"}], Brain: {memories: {}}, CustomName: '{"text":"turtle_test.render_turtle_items"}', DeathTime: 0s, DisabledSlots: 0, FallDistance: 0.0f, FallFlying: 0b, Fire: -1s, HandItems: [{}, {}], Health: 20.0f, HurtByTimestamp: 0, HurtTime: 0s, Invisible: 1b, Invulnerable: 0b, Marker: 1b, Motion: [0.0d, 0.0d, 0.0d], NoBasePlate: 0b, OnGround: 0b, PortalCooldown: 0, Pos: [125.5d, -58.0d, 53.6501934495752d], Pose: {}, Rotation: [0.14965993f, 4.066999f], ShowArms: 0b, Small: 0b, UUID: [I; -1678989666, 1780632657, -1267321893, 665166246], id: "minecraft:armor_stand"}}, {blockPos: [3, 1, 3], pos: [3.5d, 1.5d, 3.5d], nbt: {Air: 300s, FallDistance: 0.0f, Fire: 0s, Invulnerable: 0b, Motion: [0.0d, 0.0d, 0.0d], OnGround: 0b, PortalCooldown: 0, Pos: [126.5d, -57.5d, 56.5d], Rotation: [-90.0f, 0.0f], UUID: [I; 671334450, -268547745, -1360971514, -649716242], billboard: "fixed", glow_color_override: -1, height: 0.0f, id: "minecraft:item_display", interpolation_duration: 0, item: {Count: 1b, id: "computercraft:turtle_normal", tag: {ComputerId: 8, Fuel: 0, Items: [], display: {Name: '{"text":"Dinnerbone"}'}, On: 1b, RightUpgrade: "minecraft:diamond_pickaxe", RightUpgradeNbt: {Tag: {Damage: 0}}}}, item_display: "none", shadow_radius: 0.0f, shadow_strength: 1.0f, transformation: {left_rotation: [0.0f, 0.0f, 0.0f, 1.0f], right_rotation: [0.0f, 0.0f, 0.0f, 1.0f], scale: [1.0f, 1.0f, 1.0f], translation: [0.0f, 0.0f, 0.0f]}, view_range: 1.0f, width: 0.0f}}, {blockPos: [3, 3, 3], pos: [3.5d, 3.5d, 3.5d], nbt: {Air: 300s, FallDistance: 0.0f, Fire: 0s, Invulnerable: 0b, Motion: [0.0d, 0.0d, 0.0d], OnGround: 0b, PortalCooldown: 0, Pos: [126.5d, -57.5d, 56.5d], Rotation: [-90.0f, 0.0f], UUID: [I; 671334422, -268542345, -1362491514, -649716242], billboard: "fixed", glow_color_override: -1, height: 0.0f, id: "minecraft:item_display", interpolation_duration: 0, item: {Count: 1b, id: "computercraft:turtle_normal", tag: {ComputerId: 8, Fuel: 0, Items: [], On: 1b, RightUpgrade: "minecraft:diamond_pickaxe", RightUpgradeNbt: {Tag: {Damage: 0}}}}, item_display: "none", shadow_radius: 0.0f, shadow_strength: 1.0f, transformation: {left_rotation: [0.0f, 0.0f, 0.0f, 1.0f], right_rotation: [0.0f, 0.0f, 0.0f, 1.0f], scale: [1.0f, 1.0f, 1.0f], translation: [0.0f, 0.0f, 0.0f]}, view_range: 1.0f, width: 0.0f}}, - {blockPos: [1, 1, 3], pos: [1.5d, 1.5d, 3.5d], nbt: {Air: 300s, FallDistance: 0.0f, Fire: 0s, Invulnerable: 0b, Motion: [0.0d, 0.0d, 0.0d], OnGround: 0b, PortalCooldown: 0, Pos: [126.5d, -57.5d, 56.5d], Rotation: [90.0f, 0.0f], UUID: [I; 625334450, -268647745, -1360971514, -649724242], billboard: "fixed", glow_color_override: -1, height: 0.0f, id: "minecraft:item_display", interpolation_duration: 0, item: {Count: 1b, id: "computercraft:turtle_normal", tag: {ComputerId: 8, Fuel: 0, Items: [], On: 1b, LeftUpgrade: "cctest:netherite_pickaxe", LeftUpgradeNbt: {Tag: {Damage: 0, Enchantments: [{id: "minecraft:efficiency", lvl: 5s}], RepairCost: 1}}}}, item_display: "none", shadow_radius: 0.0f, shadow_strength: 1.0f, transformation: {left_rotation: [0.0f, 0.0f, 0.0f, 1.0f], right_rotation: [0.0f, 0.0f, 0.0f, 1.0f], scale: [1.0f, 1.0f, 1.0f], translation: [0.0f, 0.0f, 0.0f]}, view_range: 1.0f, width: 0.0f}}, - {blockPos: [1, 3, 3], pos: [1.5d, 3.5d, 3.5d], nbt: {Air: 300s, FallDistance: 0.0f, Fire: 0s, Invulnerable: 0b, Motion: [0.0d, 0.0d, 0.0d], OnGround: 0b, PortalCooldown: 0, Pos: [126.5d, -57.5d, 56.5d], Rotation: [90.0f, 0.0f], UUID: [I; 675334422, -268542245, -1362491514, -649755242], billboard: "fixed", glow_color_override: -1, height: 0.0f, id: "minecraft:item_display", interpolation_duration: 0, item: {Count: 1b, id: "computercraft:turtle_normal", tag: {ComputerId: 8, Fuel: 0, Items: [], display: {Name: '{"text":"Dinnerbone"}'}, On: 1b, LeftUpgrade: "cctest:netherite_pickaxe", LeftUpgradeNbt: {Tag: {Damage: 0, Enchantments: [{id: "minecraft:efficiency", lvl: 5s}], RepairCost: 1}}}}, item_display: "none", shadow_radius: 0.0f, shadow_strength: 1.0f, transformation: {left_rotation: [0.0f, 0.0f, 0.0f, 1.0f], right_rotation: [0.0f, 0.0f, 0.0f, 1.0f], scale: [1.0f, 1.0f, 1.0f], translation: [0.0f, 0.0f, 0.0f]}, view_range: 1.0f, width: 0.0f}} + {blockPos: [1, 1, 3], pos: [1.5d, 1.5d, 3.5d], nbt: {Air: 300s, FallDistance: 0.0f, Fire: 0s, Invulnerable: 0b, Motion: [0.0d, 0.0d, 0.0d], OnGround: 0b, PortalCooldown: 0, Pos: [126.5d, -57.5d, 56.5d], Rotation: [90.0f, 0.0f], UUID: [I; 625334450, -268647745, -1360971514, -649724242], billboard: "fixed", glow_color_override: -1, height: 0.0f, id: "minecraft:item_display", interpolation_duration: 0, item: {Count: 1b, id: "computercraft:turtle_normal", tag: {ComputerId: 8, Fuel: 0, Items: [], On: 1b, LeftUpgrade: {id: "cctest:netherite_pickaxe", components: {"minecraft:enchantments": {levels: {"minecraft:silk_touch": 1}}}}}}, item_display: "none", shadow_radius: 0.0f, shadow_strength: 1.0f, transformation: {left_rotation: [0.0f, 0.0f, 0.0f, 1.0f], right_rotation: [0.0f, 0.0f, 0.0f, 1.0f], scale: [1.0f, 1.0f, 1.0f], translation: [0.0f, 0.0f, 0.0f]}, view_range: 1.0f, width: 0.0f}}, + {blockPos: [1, 3, 3], pos: [1.5d, 3.5d, 3.5d], nbt: {Air: 300s, FallDistance: 0.0f, Fire: 0s, Invulnerable: 0b, Motion: [0.0d, 0.0d, 0.0d], OnGround: 0b, PortalCooldown: 0, Pos: [126.5d, -57.5d, 56.5d], Rotation: [90.0f, 0.0f], UUID: [I; 675334422, -268542245, -1362491514, -649755242], billboard: "fixed", glow_color_override: -1, height: 0.0f, id: "minecraft:item_display", interpolation_duration: 0, item: {Count: 1b, id: "computercraft:turtle_normal", tag: {ComputerId: 8, Fuel: 0, Items: [], display: {Name: '{"text":"Dinnerbone"}'}, On: 1b, LeftUpgrade: {id: "cctest:netherite_pickaxe", components: {"minecraft:enchantments": {levels: {"minecraft:silk_touch": 1}}}}}}, item_display: "none", shadow_radius: 0.0f, shadow_strength: 1.0f, transformation: {left_rotation: [0.0f, 0.0f, 0.0f, 1.0f], right_rotation: [0.0f, 0.0f, 0.0f, 1.0f], scale: [1.0f, 1.0f, 1.0f], translation: [0.0f, 0.0f, 0.0f]}, view_range: 1.0f, width: 0.0f}} ], palette: [ "minecraft:polished_andesite", diff --git a/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.resists_entity_explosions.snbt b/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.resists_entity_explosions.snbt index 79b2f8ef6..3670bd3c7 100644 --- a/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.resists_entity_explosions.snbt +++ b/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.resists_entity_explosions.snbt @@ -129,7 +129,7 @@ {pos: [4, 4, 4], state: "minecraft:air"} ], entities: [ - {blockPos: [1, 1, 2], pos: [1.5d, 1.0d, 2.5d], nbt: {AbsorptionAmount: 0.0f, Air: 300s, ArmorDropChances: [0.085f, 0.085f, 0.085f, 0.085f], ArmorItems: [{}, {}, {}, {}], Attributes: [{Base: 0.0d, Name: "forge:step_height_addition"}, {Base: 0.25d, Name: "minecraft:generic.movement_speed"}, {Base: 0.08d, Name: "forge:entity_gravity"}, {Base: 16.0d, Modifiers: [{Amount: -0.0871987524284032d, Name: "Random spawn bonus", Operation: 1, UUID: [I; -1592956383, -599506679, -1812844190, 1076877318]}], Name: "minecraft:generic.follow_range"}], Brain: {memories: {}}, CanPickUpLoot: 0b, CanUpdate: 1b, DeathTime: 0s, ExplosionRadius: 3b, FallDistance: 0.0f, FallFlying: 0b, Fire: -1s, Fuse: 30s, HandDropChances: [0.085f, 0.085f], HandItems: [{}, {}], Health: 20.0f, HurtByTimestamp: 0, HurtTime: 0s, Invulnerable: 0b, LeftHanded: 0b, Motion: [0.0d, -0.0784000015258789d, 0.0d], OnGround: 1b, PersistenceRequired: 0b, PortalCooldown: 0, Pos: [2.5d, -58.0d, 3.5d], Rotation: [143.85756f, 0.0f], UUID: [I; 1463798444, -662876850, -1423329658, 948503391], id: "minecraft:creeper", ignited: 0b}} + {blockPos: [1, 1, 2], pos: [1.5d, 1.0d, 2.5d], nbt: {AbsorptionAmount: 0.0f, Air: 300s, ArmorDropChances: [0.085f, 0.085f, 0.085f, 0.085f], ArmorItems: [{}, {}, {}, {}], Brain: {memories: {}}, CanPickUpLoot: 0b, CanUpdate: 1b, DeathTime: 0s, ExplosionRadius: 3b, FallDistance: 0.0f, FallFlying: 0b, Fire: -1s, Fuse: 30s, HandDropChances: [0.085f, 0.085f], HandItems: [{}, {}], Health: 20.0f, HurtByTimestamp: 0, HurtTime: 0s, Invulnerable: 0b, LeftHanded: 0b, Motion: [0.0d, -0.0784000015258789d, 0.0d], OnGround: 1b, PersistenceRequired: 0b, PortalCooldown: 0, Pos: [2.5d, -58.0d, 3.5d], Rotation: [143.85756f, 0.0f], UUID: [I; 1463798444, -662876850, -1423329658, 948503391], id: "minecraft:creeper", ignited: 0b}} ], palette: [ "minecraft:polished_andesite", diff --git a/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.shears_sheep.snbt b/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.shears_sheep.snbt index 4f6afef2c..6a521b12d 100644 --- a/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.shears_sheep.snbt +++ b/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.shears_sheep.snbt @@ -129,7 +129,7 @@ {pos: [4, 4, 4], state: "minecraft:air"} ], entities: [ - {blockPos: [2, 1, 2], pos: [2.5d, 1.0d, 2.5d], nbt: {AbsorptionAmount: 0.0f, Age: 0, Air: 300s, ArmorDropChances: [0.085f, 0.085f, 0.085f, 0.085f], ArmorItems: [{}, {}, {}, {}], Attributes: [{Base: 8.0d, Name: "generic.maxHealth"}, {Base: 0.0d, Name: "generic.knockbackResistance"}, {Base: 0.23000000417232513d, Name: "generic.movementSpeed"}, {Base: 0.0d, Name: "generic.armor"}, {Base: 0.0d, Name: "generic.armorToughness"}, {Base: 1.0d, Name: "forge.swimSpeed"}, {Base: 64.0d, Name: "forge.nameTagDistance"}, {Base: 0.08d, Name: "forge.entity_gravity"}, {Base: 16.0d, Modifiers: [{Amount: -0.04393447767139704d, Name: "Random spawn bonus", Operation: 1, UUIDLeast: -7913974980122166977L, UUIDMost: 2135385928807173041L}], Name: "generic.followRange"}, {Base: 0.0d, Name: "generic.attackKnockback"}], Brain: {memories: {}}, CanPickUpLoot: 0b, CanUpdate: 1b, Color: 0b, DeathTime: 0s, Dimension: 0, FallDistance: 0.0f, FallFlying: 0b, Fire: -1s, ForcedAge: 0, HandDropChances: [0.085f, 0.085f], HandItems: [{}, {}], Health: 8.0f, HurtByTimestamp: 0, HurtTime: 0s, InLove: 0, Invulnerable: 0b, LeftHanded: 0b, Motion: [0.0d, -0.0784000015258789d, 0.0d], OnGround: 1b, PersistenceRequired: 0b, PortalCooldown: 0, Pos: [-12.5d, 6.0d, 110.5d], Rotation: [99.779915f, 0.0f], Sheared: 0b, UUIDLeast: -5245632071702074643L, UUIDMost: -3792049278188698748L, id: "minecraft:sheep"}} + {blockPos: [2, 1, 2], pos: [2.5d, 1.0d, 2.5d], nbt: {AbsorptionAmount: 0.0f, Age: 0, Air: 300s, ArmorDropChances: [0.085f, 0.085f, 0.085f, 0.085f], ArmorItems: [{}, {}, {}, {}], Brain: {memories: {}}, CanPickUpLoot: 0b, CanUpdate: 1b, Color: 0b, DeathTime: 0s, Dimension: 0, FallDistance: 0.0f, FallFlying: 0b, Fire: -1s, ForcedAge: 0, HandDropChances: [0.085f, 0.085f], HandItems: [{}, {}], Health: 8.0f, HurtByTimestamp: 0, HurtTime: 0s, InLove: 0, Invulnerable: 0b, LeftHanded: 0b, Motion: [0.0d, -0.0784000015258789d, 0.0d], OnGround: 1b, PersistenceRequired: 0b, PortalCooldown: 0, Pos: [-12.5d, 6.0d, 110.5d], Rotation: [99.779915f, 0.0f], Sheared: 0b, UUIDLeast: -5245632071702074643L, UUIDMost: -3792049278188698748L, id: "minecraft:sheep"}} ], palette: [ "minecraft:polished_andesite", diff --git a/projects/core/src/main/java/dan200/computercraft/core/computer/computerthread/ComputerThread.java b/projects/core/src/main/java/dan200/computercraft/core/computer/computerthread/ComputerThread.java index 6b109d7be..3756d3247 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/computer/computerthread/ComputerThread.java +++ b/projects/core/src/main/java/dan200/computercraft/core/computer/computerthread/ComputerThread.java @@ -479,7 +479,7 @@ public void run() { private void runImpl() { var workerThreadIds = new long[workersReadOnly().length]; - Arrays.fill(workerThreadIds, Thread.currentThread().getId()); + Arrays.fill(workerThreadIds, Thread.currentThread().threadId()); while (state.get() < CLOSED) { computerLock.lock(); @@ -512,7 +512,7 @@ private void checkRunners(long[] workerThreadIds) { // up being easier (and not too inefficient) to just recompute the array each time. for (var i = 0; i < workers.length; i++) { var runner = workers[i]; - if (runner != null) workerThreadIds[i] = runner.owner.getId(); + if (runner != null) workerThreadIds[i] = runner.owner.threadId(); } allocations = ThreadAllocations.getAllocatedBytes(workerThreadIds); } else { @@ -814,7 +814,7 @@ void beforeWork() { timeout.startTimer(scaledPeriod()); if (ThreadAllocations.isSupported()) { - var current = Thread.currentThread().getId(); + var current = Thread.currentThread().threadId(); THREAD_ALLOCATION.set(this, new ThreadAllocation(current, ThreadAllocations.getAllocatedBytes(current), System.nanoTime())); } } @@ -829,7 +829,7 @@ boolean afterWork() { metrics.observe(Metrics.COMPUTER_TASKS, timeout.getExecutionTime()); if (ThreadAllocations.isSupported()) { - var current = Thread.currentThread().getId(); + var current = Thread.currentThread().threadId(); var info = THREAD_ALLOCATION.getAndSet(this, null); assert info.threadId() == current; diff --git a/projects/core/src/main/java/dan200/computercraft/core/util/Colour.java b/projects/core/src/main/java/dan200/computercraft/core/util/Colour.java index fded29173..98ebc2bc7 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/util/Colour.java +++ b/projects/core/src/main/java/dan200/computercraft/core/util/Colour.java @@ -4,8 +4,6 @@ package dan200.computercraft.core.util; -import javax.annotation.Nullable; - public enum Colour { BLACK(0x111111), RED(0xcc4c4c), @@ -30,15 +28,6 @@ public static Colour fromInt(int colour) { return Colour.VALUES[colour]; } - @Nullable - public static Colour fromHex(int colour) { - for (var entry : VALUES) { - if (entry.getHex() == colour) return entry; - } - - return null; - } - private final int hex; private final float red, green, blue; @@ -49,18 +38,24 @@ public static Colour fromHex(int colour) { blue = (hex & 0xFF) / 255.0f; } - public Colour getNext() { - return VALUES[(ordinal() + 1) % 16]; - } - - public Colour getPrevious() { - return VALUES[(ordinal() + 15) % 16]; - } - + /** + * Get this colour as a packed 32-bit RGB value. + * + * @return This colour as an RGB value. + */ public int getHex() { return hex; } + /** + * Get this colour as a packed 32-bit ARGB value. + * + * @return This colour as an ARGB value. + */ + public int getARGB() { + return hex | 0xFF000000; + } + public float getR() { return red; } diff --git a/projects/fabric/src/client/java/dan200/computercraft/client/ComputerCraftClient.java b/projects/fabric/src/client/java/dan200/computercraft/client/ComputerCraftClient.java index 22727a12f..3f4c28de2 100644 --- a/projects/fabric/src/client/java/dan200/computercraft/client/ComputerCraftClient.java +++ b/projects/fabric/src/client/java/dan200/computercraft/client/ComputerCraftClient.java @@ -7,6 +7,7 @@ import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.client.FabricComputerCraftAPIClient; import dan200.computercraft.client.model.CustomModelLoader; +import dan200.computercraft.core.util.Nullability; import dan200.computercraft.impl.Services; import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.config.ConfigSpec; @@ -14,7 +15,6 @@ import dan200.computercraft.shared.network.client.ClientNetworkContext; import dan200.computercraft.shared.peripheral.modem.wired.CableBlock; import dan200.computercraft.shared.platform.FabricConfigFile; -import dan200.computercraft.shared.platform.FabricMessageType; import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; @@ -42,7 +42,7 @@ public static void init() { var clientNetwork = Services.load(ClientNetworkContext.class); for (var type : NetworkMessages.getClientbound()) { ClientPlayNetworking.registerGlobalReceiver( - FabricMessageType.toFabricType(type), (packet, player, responseSender) -> packet.payload().handle(clientNetwork) + type.type(), (packet, responseSender) -> packet.handle(clientNetwork) ); } @@ -70,7 +70,7 @@ public static void init() { WorldRenderEvents.BLOCK_OUTLINE.register((context, hitResult) -> { var hit = Minecraft.getInstance().hitResult; if (hit instanceof BlockHitResult blockHit && blockHit.getBlockPos().equals(hitResult.blockPos())) { - return !ClientHooks.drawHighlight(context.matrixStack(), assertNonNull(context.consumers()), context.camera(), blockHit); + return !ClientHooks.drawHighlight(Nullability.assertNonNull(context.matrixStack()), assertNonNull(context.consumers()), context.camera(), blockHit); } else { return true; } diff --git a/projects/fabric/src/client/java/dan200/computercraft/client/integration/rei/REIComputerCraft.java b/projects/fabric/src/client/java/dan200/computercraft/client/integration/rei/REIComputerCraft.java index c3addf41e..fb8b22a9a 100644 --- a/projects/fabric/src/client/java/dan200/computercraft/client/integration/rei/REIComputerCraft.java +++ b/projects/fabric/src/client/java/dan200/computercraft/client/integration/rei/REIComputerCraft.java @@ -24,12 +24,10 @@ public class REIComputerCraft implements REIClientPlugin { @Override public void registerItemComparators(ItemComparatorRegistry registry) { registry.register((context, stack) -> { - var turtle = (TurtleItem) stack.getItem(); - long hash = 1; - var left = turtle.getUpgrade(stack, TurtleSide.LEFT); - var right = turtle.getUpgrade(stack, TurtleSide.RIGHT); + var left = TurtleItem.getUpgrade(stack, TurtleSide.LEFT); + var right = TurtleItem.getUpgrade(stack, TurtleSide.RIGHT); if (left != null) hash = hash * 31 + left.getUpgradeID().hashCode(); if (right != null) hash = hash * 31 + right.getUpgradeID().hashCode(); diff --git a/projects/fabric/src/client/java/dan200/computercraft/client/platform/ClientPlatformHelperImpl.java b/projects/fabric/src/client/java/dan200/computercraft/client/platform/ClientPlatformHelperImpl.java index 4d01e7256..58a072006 100644 --- a/projects/fabric/src/client/java/dan200/computercraft/client/platform/ClientPlatformHelperImpl.java +++ b/projects/fabric/src/client/java/dan200/computercraft/client/platform/ClientPlatformHelperImpl.java @@ -8,10 +8,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import dan200.computercraft.client.model.FoiledModel; import dan200.computercraft.client.render.ModelRenderer; -import dan200.computercraft.shared.network.NetworkMessage; -import dan200.computercraft.shared.network.server.ServerNetworkContext; -import dan200.computercraft.shared.platform.FabricMessageType; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; @@ -20,8 +16,6 @@ import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.ModelManager; import net.minecraft.core.BlockPos; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.common.ServerCommonPacketListener; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvent; import net.minecraft.util.RandomSource; @@ -32,11 +26,6 @@ public class ClientPlatformHelperImpl implements ClientPlatformHelper { private static final RandomSource random = RandomSource.create(0); - @Override - public Packet createPacket(NetworkMessage message) { - return ClientPlayNetworking.createC2SPacket(FabricMessageType.toFabricPacket(message)); - } - @Override public BakedModel getModel(ModelManager manager, ResourceLocation location) { var model = manager.getModel(location); diff --git a/projects/fabric/src/generated/resources/data/c/tags/items/skulls.json b/projects/fabric/src/generated/resources/data/c/tags/items/skulls.json deleted file mode 100644 index 0ce68d9e5..000000000 --- a/projects/fabric/src/generated/resources/data/c/tags/items/skulls.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:creeper_head", - "minecraft:dragon_head", - "minecraft:player_head", - "minecraft:skeleton_skull", - "minecraft:wither_skeleton_skull", - "minecraft:zombie_head" - ] -} diff --git a/projects/fabric/src/generated/resources/data/c/tags/items/wooden_chests.json b/projects/fabric/src/generated/resources/data/c/tags/items/wooden_chests.json deleted file mode 100644 index afebd2be5..000000000 --- a/projects/fabric/src/generated/resources/data/c/tags/items/wooden_chests.json +++ /dev/null @@ -1 +0,0 @@ -{"replace": false, "values": ["minecraft:chest", "minecraft:trapped_chest"]} diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/decorations/skull_cloudy.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/decorations/skull_cloudy.json index cf1f52ebf..02af6d7cb 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/decorations/skull_cloudy.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/decorations/skull_cloudy.json @@ -2,7 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_monitor": { - "conditions": {"items": [{"items": ["computercraft:monitor_normal"]}]}, + "conditions": {"items": [{"items": "computercraft:monitor_normal"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -10,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_monitor", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:skull_cloudy"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_monitor"]], + "rewards": {"recipes": ["computercraft:skull_cloudy"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/decorations/skull_dan200.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/decorations/skull_dan200.json index 36b971447..bdbb2f5d2 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/decorations/skull_dan200.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/decorations/skull_dan200.json @@ -2,7 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_computer": { - "conditions": {"items": [{"items": ["computercraft:computer_advanced"]}]}, + "conditions": {"items": [{"items": "computercraft:computer_advanced"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -10,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_computer", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:skull_dan200"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_computer"]], + "rewards": {"recipes": ["computercraft:skull_dan200"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/cable.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/cable.json index d7b112316..738142ca1 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/cable.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/cable.json @@ -2,16 +2,15 @@ "parent": "minecraft:recipes/root", "criteria": { "has_computer": { - "conditions": {"items": [{"tag": "computercraft:computer"}]}, + "conditions": {"items": [{"items": "#computercraft:computer"}]}, "trigger": "minecraft:inventory_changed" }, "has_modem": { - "conditions": {"items": [{"tag": "computercraft:wired_modem"}]}, + "conditions": {"items": [{"items": "#computercraft:wired_modem"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:cable"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_computer", "has_modem", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:cable"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_computer", "has_modem"]], + "rewards": {"recipes": ["computercraft:cable"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/computer_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/computer_advanced.json index 20c2b4480..004e3c883 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/computer_advanced.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/computer_advanced.json @@ -2,7 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_components": { - "conditions": {"items": [{"tag": "c:redstone_dusts"}, {"tag": "c:gold_ingots"}]}, + "conditions": {"items": [{"items": "#c:dusts/redstone"}, {"items": "#c:ingots/gold"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -10,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_components", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:computer_advanced"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_components"]], + "rewards": {"recipes": ["computercraft:computer_advanced"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/computer_advanced_upgrade.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/computer_advanced_upgrade.json index ae3228c53..8cc817046 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/computer_advanced_upgrade.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/computer_advanced_upgrade.json @@ -2,7 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_components": { - "conditions": {"items": [{"items": ["computercraft:computer_normal"]}, {"tag": "c:gold_ingots"}]}, + "conditions": {"items": [{"items": "computercraft:computer_normal"}, {"items": "#c:ingots/gold"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -10,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_components", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:computer_advanced_upgrade"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_components"]], + "rewards": {"recipes": ["computercraft:computer_advanced_upgrade"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/computer_command.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/computer_command.json index 28e9d2f82..7f8bdb216 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/computer_command.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/computer_command.json @@ -2,7 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_components": { - "conditions": {"items": [{"items": ["minecraft:command_block"]}]}, + "conditions": {"items": [{"items": "minecraft:command_block"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -10,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_components", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:computer_command"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_components"]], + "rewards": {"recipes": ["computercraft:computer_command"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/computer_normal.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/computer_normal.json index 2a38c3b43..1816e9c4f 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/computer_normal.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/computer_normal.json @@ -2,7 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_redstone": { - "conditions": {"items": [{"tag": "c:redstone_dusts"}]}, + "conditions": {"items": [{"items": "#c:dusts/redstone"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -10,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_redstone", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:computer_normal"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_redstone"]], + "rewards": {"recipes": ["computercraft:computer_normal"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_1.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_1.json index 041bf213e..2a7291ff1 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_1.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_1.json @@ -2,12 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_drive": { - "conditions": {"items": [{"items": ["computercraft:disk_drive"]}]}, + "conditions": {"items": [{"items": "computercraft:disk_drive"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:disk_1"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_drive", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:disk_1"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_drive"]], + "rewards": {"recipes": ["computercraft:disk_1"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_10.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_10.json index 30b4d2105..742dc3be7 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_10.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_10.json @@ -2,12 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_drive": { - "conditions": {"items": [{"items": ["computercraft:disk_drive"]}]}, + "conditions": {"items": [{"items": "computercraft:disk_drive"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:disk_10"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_drive", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:disk_10"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_drive"]], + "rewards": {"recipes": ["computercraft:disk_10"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_11.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_11.json index 69d669473..86873eb07 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_11.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_11.json @@ -2,12 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_drive": { - "conditions": {"items": [{"items": ["computercraft:disk_drive"]}]}, + "conditions": {"items": [{"items": "computercraft:disk_drive"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:disk_11"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_drive", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:disk_11"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_drive"]], + "rewards": {"recipes": ["computercraft:disk_11"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_12.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_12.json index 281008add..d200eec09 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_12.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_12.json @@ -2,12 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_drive": { - "conditions": {"items": [{"items": ["computercraft:disk_drive"]}]}, + "conditions": {"items": [{"items": "computercraft:disk_drive"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:disk_12"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_drive", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:disk_12"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_drive"]], + "rewards": {"recipes": ["computercraft:disk_12"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_13.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_13.json index 2f2ad2540..c8e8dbec0 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_13.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_13.json @@ -2,12 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_drive": { - "conditions": {"items": [{"items": ["computercraft:disk_drive"]}]}, + "conditions": {"items": [{"items": "computercraft:disk_drive"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:disk_13"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_drive", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:disk_13"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_drive"]], + "rewards": {"recipes": ["computercraft:disk_13"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_14.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_14.json index 83a078af7..b08657cbf 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_14.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_14.json @@ -2,12 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_drive": { - "conditions": {"items": [{"items": ["computercraft:disk_drive"]}]}, + "conditions": {"items": [{"items": "computercraft:disk_drive"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:disk_14"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_drive", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:disk_14"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_drive"]], + "rewards": {"recipes": ["computercraft:disk_14"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_15.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_15.json index ec35fc88d..56444f527 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_15.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_15.json @@ -2,12 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_drive": { - "conditions": {"items": [{"items": ["computercraft:disk_drive"]}]}, + "conditions": {"items": [{"items": "computercraft:disk_drive"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:disk_15"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_drive", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:disk_15"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_drive"]], + "rewards": {"recipes": ["computercraft:disk_15"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_16.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_16.json index 1a660c1a5..b4a5255b3 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_16.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_16.json @@ -2,12 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_drive": { - "conditions": {"items": [{"items": ["computercraft:disk_drive"]}]}, + "conditions": {"items": [{"items": "computercraft:disk_drive"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:disk_16"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_drive", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:disk_16"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_drive"]], + "rewards": {"recipes": ["computercraft:disk_16"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_2.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_2.json index 1ff11cb17..e96d9280a 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_2.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_2.json @@ -2,12 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_drive": { - "conditions": {"items": [{"items": ["computercraft:disk_drive"]}]}, + "conditions": {"items": [{"items": "computercraft:disk_drive"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:disk_2"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_drive", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:disk_2"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_drive"]], + "rewards": {"recipes": ["computercraft:disk_2"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_3.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_3.json index baaa5c84f..d63ba4171 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_3.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_3.json @@ -2,12 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_drive": { - "conditions": {"items": [{"items": ["computercraft:disk_drive"]}]}, + "conditions": {"items": [{"items": "computercraft:disk_drive"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:disk_3"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_drive", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:disk_3"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_drive"]], + "rewards": {"recipes": ["computercraft:disk_3"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_4.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_4.json index 943e99b3e..dffcef439 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_4.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_4.json @@ -2,12 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_drive": { - "conditions": {"items": [{"items": ["computercraft:disk_drive"]}]}, + "conditions": {"items": [{"items": "computercraft:disk_drive"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:disk_4"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_drive", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:disk_4"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_drive"]], + "rewards": {"recipes": ["computercraft:disk_4"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_5.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_5.json index 66ae8f2b3..488c1220d 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_5.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_5.json @@ -2,12 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_drive": { - "conditions": {"items": [{"items": ["computercraft:disk_drive"]}]}, + "conditions": {"items": [{"items": "computercraft:disk_drive"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:disk_5"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_drive", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:disk_5"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_drive"]], + "rewards": {"recipes": ["computercraft:disk_5"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_6.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_6.json index 8f5132e16..1feaae00c 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_6.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_6.json @@ -2,12 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_drive": { - "conditions": {"items": [{"items": ["computercraft:disk_drive"]}]}, + "conditions": {"items": [{"items": "computercraft:disk_drive"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:disk_6"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_drive", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:disk_6"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_drive"]], + "rewards": {"recipes": ["computercraft:disk_6"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_7.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_7.json index 54aa2b0cb..6498b602a 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_7.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_7.json @@ -2,12 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_drive": { - "conditions": {"items": [{"items": ["computercraft:disk_drive"]}]}, + "conditions": {"items": [{"items": "computercraft:disk_drive"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:disk_7"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_drive", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:disk_7"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_drive"]], + "rewards": {"recipes": ["computercraft:disk_7"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_8.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_8.json index fa62cc0af..ff252f732 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_8.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_8.json @@ -2,12 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_drive": { - "conditions": {"items": [{"items": ["computercraft:disk_drive"]}]}, + "conditions": {"items": [{"items": "computercraft:disk_drive"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:disk_8"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_drive", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:disk_8"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_drive"]], + "rewards": {"recipes": ["computercraft:disk_8"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_9.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_9.json index ef0f3c270..250094755 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_9.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_9.json @@ -2,12 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_drive": { - "conditions": {"items": [{"items": ["computercraft:disk_drive"]}]}, + "conditions": {"items": [{"items": "computercraft:disk_drive"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:disk_9"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_drive", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:disk_9"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_drive"]], + "rewards": {"recipes": ["computercraft:disk_9"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_drive.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_drive.json index 028e87603..507ebd806 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_drive.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/disk_drive.json @@ -2,12 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_computer": { - "conditions": {"items": [{"tag": "computercraft:computer"}]}, + "conditions": {"items": [{"items": "#computercraft:computer"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:disk_drive"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_computer", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:disk_drive"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_computer"]], + "rewards": {"recipes": ["computercraft:disk_drive"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/monitor_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/monitor_advanced.json index 9c3d1dcbd..434fda897 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/monitor_advanced.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/monitor_advanced.json @@ -2,7 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_computer": { - "conditions": {"items": [{"tag": "computercraft:computer"}]}, + "conditions": {"items": [{"items": "#computercraft:computer"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -10,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_computer", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:monitor_advanced"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_computer"]], + "rewards": {"recipes": ["computercraft:monitor_advanced"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/monitor_normal.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/monitor_normal.json index 52a1f2388..bba178596 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/monitor_normal.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/monitor_normal.json @@ -2,7 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_computer": { - "conditions": {"items": [{"tag": "computercraft:computer"}]}, + "conditions": {"items": [{"items": "#computercraft:computer"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -10,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_computer", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:monitor_normal"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_computer"]], + "rewards": {"recipes": ["computercraft:monitor_normal"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_advanced/computercraft/speaker.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_advanced/computercraft/speaker.json index 1bc6a18f6..c4eb7f4fd 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_advanced/computercraft/speaker.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_advanced/computercraft/speaker.json @@ -3,7 +3,7 @@ "criteria": { "has_items": { "conditions": { - "items": [{"items": ["computercraft:pocket_computer_advanced"]}, {"items": ["computercraft:speaker"]}] + "items": [{"items": "computercraft:pocket_computer_advanced"}, {"items": "computercraft:speaker"}] }, "trigger": "minecraft:inventory_changed" }, @@ -12,7 +12,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:pocket_advanced/computercraft/speaker"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:pocket_advanced/computercraft/speaker"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_advanced/computercraft/wireless_modem_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_advanced/computercraft/wireless_modem_advanced.json index ec0ca1356..4dfafbdd7 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_advanced/computercraft/wireless_modem_advanced.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_advanced/computercraft/wireless_modem_advanced.json @@ -4,8 +4,8 @@ "has_items": { "conditions": { "items": [ - {"items": ["computercraft:pocket_computer_advanced"]}, - {"items": ["computercraft:wireless_modem_advanced"]} + {"items": "computercraft:pocket_computer_advanced"}, + {"items": "computercraft:wireless_modem_advanced"} ] }, "trigger": "minecraft:inventory_changed" @@ -15,7 +15,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:pocket_advanced/computercraft/wireless_modem_advanced"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:pocket_advanced/computercraft/wireless_modem_advanced"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_advanced/computercraft/wireless_modem_normal.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_advanced/computercraft/wireless_modem_normal.json index e7c84103d..0e5f86fb3 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_advanced/computercraft/wireless_modem_normal.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_advanced/computercraft/wireless_modem_normal.json @@ -4,8 +4,8 @@ "has_items": { "conditions": { "items": [ - {"items": ["computercraft:pocket_computer_advanced"]}, - {"items": ["computercraft:wireless_modem_normal"]} + {"items": "computercraft:pocket_computer_advanced"}, + {"items": "computercraft:wireless_modem_normal"} ] }, "trigger": "minecraft:inventory_changed" @@ -15,7 +15,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:pocket_advanced/computercraft/wireless_modem_normal"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:pocket_advanced/computercraft/wireless_modem_normal"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_computer_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_computer_advanced.json index 906548693..3897e95e4 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_computer_advanced.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_computer_advanced.json @@ -2,11 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_apple": { - "conditions": {"items": [{"items": ["minecraft:golden_apple"]}]}, + "conditions": {"items": [{"items": "minecraft:golden_apple"}]}, "trigger": "minecraft:inventory_changed" }, "has_computer": { - "conditions": {"items": [{"tag": "computercraft:computer"}]}, + "conditions": {"items": [{"items": "#computercraft:computer"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -14,7 +14,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_computer", "has_apple", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:pocket_computer_advanced"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_computer", "has_apple"]], + "rewards": {"recipes": ["computercraft:pocket_computer_advanced"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_computer_advanced_upgrade.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_computer_advanced_upgrade.json index 2203205fe..13cf3c49d 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_computer_advanced_upgrade.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_computer_advanced_upgrade.json @@ -2,7 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_components": { - "conditions": {"items": [{"items": ["computercraft:pocket_computer_normal"]}, {"tag": "c:gold_ingots"}]}, + "conditions": {"items": [{"items": "computercraft:pocket_computer_normal"}, {"items": "#c:ingots/gold"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -10,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_components", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:pocket_computer_advanced_upgrade"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_components"]], + "rewards": {"recipes": ["computercraft:pocket_computer_advanced_upgrade"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_computer_normal.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_computer_normal.json index 5dcd29e99..7f2c61aab 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_computer_normal.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_computer_normal.json @@ -2,11 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_apple": { - "conditions": {"items": [{"items": ["minecraft:golden_apple"]}]}, + "conditions": {"items": [{"items": "minecraft:golden_apple"}]}, "trigger": "minecraft:inventory_changed" }, "has_computer": { - "conditions": {"items": [{"tag": "computercraft:computer"}]}, + "conditions": {"items": [{"items": "#computercraft:computer"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -14,7 +14,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_computer", "has_apple", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:pocket_computer_normal"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_computer", "has_apple"]], + "rewards": {"recipes": ["computercraft:pocket_computer_normal"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_normal/computercraft/speaker.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_normal/computercraft/speaker.json index 615d3e25f..e3fc2a5fa 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_normal/computercraft/speaker.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_normal/computercraft/speaker.json @@ -3,7 +3,7 @@ "criteria": { "has_items": { "conditions": { - "items": [{"items": ["computercraft:pocket_computer_normal"]}, {"items": ["computercraft:speaker"]}] + "items": [{"items": "computercraft:pocket_computer_normal"}, {"items": "computercraft:speaker"}] }, "trigger": "minecraft:inventory_changed" }, @@ -12,7 +12,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:pocket_normal/computercraft/speaker"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:pocket_normal/computercraft/speaker"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_normal/computercraft/wireless_modem_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_normal/computercraft/wireless_modem_advanced.json index 2f4085006..f437cd4a1 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_normal/computercraft/wireless_modem_advanced.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_normal/computercraft/wireless_modem_advanced.json @@ -4,8 +4,8 @@ "has_items": { "conditions": { "items": [ - {"items": ["computercraft:pocket_computer_normal"]}, - {"items": ["computercraft:wireless_modem_advanced"]} + {"items": "computercraft:pocket_computer_normal"}, + {"items": "computercraft:wireless_modem_advanced"} ] }, "trigger": "minecraft:inventory_changed" @@ -15,7 +15,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:pocket_normal/computercraft/wireless_modem_advanced"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:pocket_normal/computercraft/wireless_modem_advanced"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_normal/computercraft/wireless_modem_normal.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_normal/computercraft/wireless_modem_normal.json index 491fd13dd..a8c4f93d8 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_normal/computercraft/wireless_modem_normal.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/pocket_normal/computercraft/wireless_modem_normal.json @@ -4,8 +4,8 @@ "has_items": { "conditions": { "items": [ - {"items": ["computercraft:pocket_computer_normal"]}, - {"items": ["computercraft:wireless_modem_normal"]} + {"items": "computercraft:pocket_computer_normal"}, + {"items": "computercraft:wireless_modem_normal"} ] }, "trigger": "minecraft:inventory_changed" @@ -15,7 +15,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:pocket_normal/computercraft/wireless_modem_normal"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:pocket_normal/computercraft/wireless_modem_normal"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/printed_book.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/printed_book.json index 67a2ed56a..fad03d29c 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/printed_book.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/printed_book.json @@ -2,7 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_printer": { - "conditions": {"items": [{"items": ["computercraft:printer"]}]}, + "conditions": {"items": [{"items": "computercraft:printer"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -10,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_printer", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:printed_book"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_printer"]], + "rewards": {"recipes": ["computercraft:printed_book"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/printed_pages.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/printed_pages.json index 4c2115c9e..9e1e4dbf3 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/printed_pages.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/printed_pages.json @@ -2,7 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_printer": { - "conditions": {"items": [{"items": ["computercraft:printer"]}]}, + "conditions": {"items": [{"items": "computercraft:printer"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -10,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_printer", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:printed_pages"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_printer"]], + "rewards": {"recipes": ["computercraft:printed_pages"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/printer.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/printer.json index 53794f510..feffc0511 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/printer.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/printer.json @@ -2,12 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_computer": { - "conditions": {"items": [{"tag": "computercraft:computer"}]}, + "conditions": {"items": [{"items": "#computercraft:computer"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:printer"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_computer", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:printer"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_computer"]], + "rewards": {"recipes": ["computercraft:printer"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/speaker.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/speaker.json index c4af541b6..cbca87465 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/speaker.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/speaker.json @@ -2,12 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_computer": { - "conditions": {"items": [{"tag": "computercraft:computer"}]}, + "conditions": {"items": [{"items": "#computercraft:computer"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": {"conditions": {"recipe": "computercraft:speaker"}, "trigger": "minecraft:recipe_unlocked"} }, - "requirements": [["has_computer", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:speaker"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_computer"]], + "rewards": {"recipes": ["computercraft:speaker"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced.json index 1fe46c9b6..efebd2035 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced.json @@ -2,7 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_computer": { - "conditions": {"items": [{"items": ["computercraft:computer_normal"]}]}, + "conditions": {"items": [{"items": "computercraft:computer_normal"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -10,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_computer", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_advanced"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_computer"]], + "rewards": {"recipes": ["computercraft:turtle_advanced"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/computercraft/speaker.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/computercraft/speaker.json index e593bbe53..971e61be9 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/computercraft/speaker.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/computercraft/speaker.json @@ -2,9 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_items": { - "conditions": { - "items": [{"items": ["computercraft:turtle_advanced"]}, {"items": ["computercraft:speaker"]}] - }, + "conditions": {"items": [{"items": "computercraft:turtle_advanced"}, {"items": "computercraft:speaker"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -12,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_advanced/computercraft/speaker"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:turtle_advanced/computercraft/speaker"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/computercraft/wireless_modem_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/computercraft/wireless_modem_advanced.json index 464eff645..df20901b8 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/computercraft/wireless_modem_advanced.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/computercraft/wireless_modem_advanced.json @@ -3,10 +3,7 @@ "criteria": { "has_items": { "conditions": { - "items": [ - {"items": ["computercraft:turtle_advanced"]}, - {"items": ["computercraft:wireless_modem_advanced"]} - ] + "items": [{"items": "computercraft:turtle_advanced"}, {"items": "computercraft:wireless_modem_advanced"}] }, "trigger": "minecraft:inventory_changed" }, @@ -15,7 +12,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_advanced/computercraft/wireless_modem_advanced"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:turtle_advanced/computercraft/wireless_modem_advanced"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/computercraft/wireless_modem_normal.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/computercraft/wireless_modem_normal.json index d5ba842ea..b2d4ff695 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/computercraft/wireless_modem_normal.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/computercraft/wireless_modem_normal.json @@ -3,10 +3,7 @@ "criteria": { "has_items": { "conditions": { - "items": [ - {"items": ["computercraft:turtle_advanced"]}, - {"items": ["computercraft:wireless_modem_normal"]} - ] + "items": [{"items": "computercraft:turtle_advanced"}, {"items": "computercraft:wireless_modem_normal"}] }, "trigger": "minecraft:inventory_changed" }, @@ -15,7 +12,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_advanced/computercraft/wireless_modem_normal"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:turtle_advanced/computercraft/wireless_modem_normal"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/crafting_table.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/crafting_table.json index 8e5349225..bebb9331d 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/crafting_table.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/crafting_table.json @@ -3,7 +3,7 @@ "criteria": { "has_items": { "conditions": { - "items": [{"items": ["computercraft:turtle_advanced"]}, {"items": ["minecraft:crafting_table"]}] + "items": [{"items": "computercraft:turtle_advanced"}, {"items": "minecraft:crafting_table"}] }, "trigger": "minecraft:inventory_changed" }, @@ -12,7 +12,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_advanced/minecraft/crafting_table"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:turtle_advanced/minecraft/crafting_table"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_axe.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_axe.json index 7d16aeb75..7d1d7e466 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_axe.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_axe.json @@ -2,9 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_items": { - "conditions": { - "items": [{"items": ["computercraft:turtle_advanced"]}, {"items": ["minecraft:diamond_axe"]}] - }, + "conditions": {"items": [{"items": "computercraft:turtle_advanced"}, {"items": "minecraft:diamond_axe"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -12,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_advanced/minecraft/diamond_axe"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:turtle_advanced/minecraft/diamond_axe"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_hoe.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_hoe.json index 4fc20015c..9f6e79243 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_hoe.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_hoe.json @@ -2,9 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_items": { - "conditions": { - "items": [{"items": ["computercraft:turtle_advanced"]}, {"items": ["minecraft:diamond_hoe"]}] - }, + "conditions": {"items": [{"items": "computercraft:turtle_advanced"}, {"items": "minecraft:diamond_hoe"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -12,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_advanced/minecraft/diamond_hoe"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:turtle_advanced/minecraft/diamond_hoe"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_pickaxe.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_pickaxe.json index 7a70fc554..25c5cc6dd 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_pickaxe.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_pickaxe.json @@ -3,7 +3,7 @@ "criteria": { "has_items": { "conditions": { - "items": [{"items": ["computercraft:turtle_advanced"]}, {"items": ["minecraft:diamond_pickaxe"]}] + "items": [{"items": "computercraft:turtle_advanced"}, {"items": "minecraft:diamond_pickaxe"}] }, "trigger": "minecraft:inventory_changed" }, @@ -12,7 +12,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_advanced/minecraft/diamond_pickaxe"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:turtle_advanced/minecraft/diamond_pickaxe"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_shovel.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_shovel.json index 89be37705..4233683fd 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_shovel.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_shovel.json @@ -3,7 +3,7 @@ "criteria": { "has_items": { "conditions": { - "items": [{"items": ["computercraft:turtle_advanced"]}, {"items": ["minecraft:diamond_shovel"]}] + "items": [{"items": "computercraft:turtle_advanced"}, {"items": "minecraft:diamond_shovel"}] }, "trigger": "minecraft:inventory_changed" }, @@ -12,7 +12,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_advanced/minecraft/diamond_shovel"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:turtle_advanced/minecraft/diamond_shovel"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_sword.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_sword.json index 94706972b..7df44fbf3 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_sword.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced/minecraft/diamond_sword.json @@ -3,7 +3,7 @@ "criteria": { "has_items": { "conditions": { - "items": [{"items": ["computercraft:turtle_advanced"]}, {"items": ["minecraft:diamond_sword"]}] + "items": [{"items": "computercraft:turtle_advanced"}, {"items": "minecraft:diamond_sword"}] }, "trigger": "minecraft:inventory_changed" }, @@ -12,7 +12,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_advanced/minecraft/diamond_sword"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:turtle_advanced/minecraft/diamond_sword"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced_overlays/turtle_rainbow_overlay.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced_overlays/turtle_rainbow_overlay.json index 0b22bd773..1022665f5 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced_overlays/turtle_rainbow_overlay.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced_overlays/turtle_rainbow_overlay.json @@ -1,17 +1,16 @@ { "parent": "minecraft:recipes/root", "criteria": { - "has_dye": {"conditions": {"items": [{"tag": "c:dyes"}]}, "trigger": "minecraft:inventory_changed"}, + "has_dye": {"conditions": {"items": [{"items": "#c:dyes"}]}, "trigger": "minecraft:inventory_changed"}, "has_the_recipe": { "conditions": {"recipe": "computercraft:turtle_advanced_overlays/turtle_rainbow_overlay"}, "trigger": "minecraft:recipe_unlocked" }, "has_turtle": { - "conditions": {"items": [{"items": ["computercraft:turtle_advanced"]}]}, + "conditions": {"items": [{"items": "computercraft:turtle_advanced"}]}, "trigger": "minecraft:inventory_changed" } }, - "requirements": [["has_turtle", "has_dye", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_advanced_overlays/turtle_rainbow_overlay"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_turtle", "has_dye"]], + "rewards": {"recipes": ["computercraft:turtle_advanced_overlays/turtle_rainbow_overlay"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced_overlays/turtle_trans_overlay.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced_overlays/turtle_trans_overlay.json index e118f12c5..45978b7fd 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced_overlays/turtle_trans_overlay.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced_overlays/turtle_trans_overlay.json @@ -1,17 +1,16 @@ { "parent": "minecraft:recipes/root", "criteria": { - "has_dye": {"conditions": {"items": [{"tag": "c:dyes"}]}, "trigger": "minecraft:inventory_changed"}, + "has_dye": {"conditions": {"items": [{"items": "#c:dyes"}]}, "trigger": "minecraft:inventory_changed"}, "has_the_recipe": { "conditions": {"recipe": "computercraft:turtle_advanced_overlays/turtle_trans_overlay"}, "trigger": "minecraft:recipe_unlocked" }, "has_turtle": { - "conditions": {"items": [{"items": ["computercraft:turtle_advanced"]}]}, + "conditions": {"items": [{"items": "computercraft:turtle_advanced"}]}, "trigger": "minecraft:inventory_changed" } }, - "requirements": [["has_turtle", "has_dye", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_advanced_overlays/turtle_trans_overlay"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_turtle", "has_dye"]], + "rewards": {"recipes": ["computercraft:turtle_advanced_overlays/turtle_trans_overlay"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced_upgrade.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced_upgrade.json index f5dd4d1d3..d21808a16 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced_upgrade.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_advanced_upgrade.json @@ -2,7 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_components": { - "conditions": {"items": [{"items": ["computercraft:turtle_normal"]}, {"tag": "c:gold_ingots"}]}, + "conditions": {"items": [{"items": "computercraft:turtle_normal"}, {"items": "#c:ingots/gold"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -10,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_components", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_advanced_upgrade"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_components"]], + "rewards": {"recipes": ["computercraft:turtle_advanced_upgrade"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal.json index 168e8a9e9..e2403cc5d 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal.json @@ -2,7 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_computer": { - "conditions": {"items": [{"items": ["computercraft:computer_normal"]}]}, + "conditions": {"items": [{"items": "computercraft:computer_normal"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -10,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_computer", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_normal"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_computer"]], + "rewards": {"recipes": ["computercraft:turtle_normal"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/computercraft/speaker.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/computercraft/speaker.json index de0d7cdd7..5c89ab2f1 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/computercraft/speaker.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/computercraft/speaker.json @@ -2,9 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_items": { - "conditions": { - "items": [{"items": ["computercraft:turtle_normal"]}, {"items": ["computercraft:speaker"]}] - }, + "conditions": {"items": [{"items": "computercraft:turtle_normal"}, {"items": "computercraft:speaker"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -12,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_normal/computercraft/speaker"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:turtle_normal/computercraft/speaker"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/computercraft/wireless_modem_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/computercraft/wireless_modem_advanced.json index b89ee1be9..43b506d01 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/computercraft/wireless_modem_advanced.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/computercraft/wireless_modem_advanced.json @@ -3,10 +3,7 @@ "criteria": { "has_items": { "conditions": { - "items": [ - {"items": ["computercraft:turtle_normal"]}, - {"items": ["computercraft:wireless_modem_advanced"]} - ] + "items": [{"items": "computercraft:turtle_normal"}, {"items": "computercraft:wireless_modem_advanced"}] }, "trigger": "minecraft:inventory_changed" }, @@ -15,7 +12,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_normal/computercraft/wireless_modem_advanced"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:turtle_normal/computercraft/wireless_modem_advanced"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/computercraft/wireless_modem_normal.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/computercraft/wireless_modem_normal.json index 637cc592f..0712e98a3 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/computercraft/wireless_modem_normal.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/computercraft/wireless_modem_normal.json @@ -3,10 +3,7 @@ "criteria": { "has_items": { "conditions": { - "items": [ - {"items": ["computercraft:turtle_normal"]}, - {"items": ["computercraft:wireless_modem_normal"]} - ] + "items": [{"items": "computercraft:turtle_normal"}, {"items": "computercraft:wireless_modem_normal"}] }, "trigger": "minecraft:inventory_changed" }, @@ -15,7 +12,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_normal/computercraft/wireless_modem_normal"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:turtle_normal/computercraft/wireless_modem_normal"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/crafting_table.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/crafting_table.json index 495259756..007a078f5 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/crafting_table.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/crafting_table.json @@ -2,9 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_items": { - "conditions": { - "items": [{"items": ["computercraft:turtle_normal"]}, {"items": ["minecraft:crafting_table"]}] - }, + "conditions": {"items": [{"items": "computercraft:turtle_normal"}, {"items": "minecraft:crafting_table"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -12,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_normal/minecraft/crafting_table"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:turtle_normal/minecraft/crafting_table"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_axe.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_axe.json index 89be86b62..709b05dfe 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_axe.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_axe.json @@ -2,9 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_items": { - "conditions": { - "items": [{"items": ["computercraft:turtle_normal"]}, {"items": ["minecraft:diamond_axe"]}] - }, + "conditions": {"items": [{"items": "computercraft:turtle_normal"}, {"items": "minecraft:diamond_axe"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -12,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_normal/minecraft/diamond_axe"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:turtle_normal/minecraft/diamond_axe"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_hoe.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_hoe.json index a2799e005..4a4e6767f 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_hoe.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_hoe.json @@ -2,9 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_items": { - "conditions": { - "items": [{"items": ["computercraft:turtle_normal"]}, {"items": ["minecraft:diamond_hoe"]}] - }, + "conditions": {"items": [{"items": "computercraft:turtle_normal"}, {"items": "minecraft:diamond_hoe"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -12,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_normal/minecraft/diamond_hoe"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:turtle_normal/minecraft/diamond_hoe"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_pickaxe.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_pickaxe.json index 955d05e97..1d73f7282 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_pickaxe.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_pickaxe.json @@ -3,7 +3,7 @@ "criteria": { "has_items": { "conditions": { - "items": [{"items": ["computercraft:turtle_normal"]}, {"items": ["minecraft:diamond_pickaxe"]}] + "items": [{"items": "computercraft:turtle_normal"}, {"items": "minecraft:diamond_pickaxe"}] }, "trigger": "minecraft:inventory_changed" }, @@ -12,7 +12,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_normal/minecraft/diamond_pickaxe"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:turtle_normal/minecraft/diamond_pickaxe"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_shovel.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_shovel.json index 1d8f6d79b..d57be6ac3 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_shovel.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_shovel.json @@ -2,9 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_items": { - "conditions": { - "items": [{"items": ["computercraft:turtle_normal"]}, {"items": ["minecraft:diamond_shovel"]}] - }, + "conditions": {"items": [{"items": "computercraft:turtle_normal"}, {"items": "minecraft:diamond_shovel"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -12,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_normal/minecraft/diamond_shovel"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:turtle_normal/minecraft/diamond_shovel"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_sword.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_sword.json index e328d63ad..585195cc6 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_sword.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal/minecraft/diamond_sword.json @@ -2,9 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_items": { - "conditions": { - "items": [{"items": ["computercraft:turtle_normal"]}, {"items": ["minecraft:diamond_sword"]}] - }, + "conditions": {"items": [{"items": "computercraft:turtle_normal"}, {"items": "minecraft:diamond_sword"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -12,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_items", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_normal/minecraft/diamond_sword"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_items"]], + "rewards": {"recipes": ["computercraft:turtle_normal/minecraft/diamond_sword"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal_overlays/turtle_rainbow_overlay.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal_overlays/turtle_rainbow_overlay.json index 04837d351..8a4e65614 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal_overlays/turtle_rainbow_overlay.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal_overlays/turtle_rainbow_overlay.json @@ -1,17 +1,16 @@ { "parent": "minecraft:recipes/root", "criteria": { - "has_dye": {"conditions": {"items": [{"tag": "c:dyes"}]}, "trigger": "minecraft:inventory_changed"}, + "has_dye": {"conditions": {"items": [{"items": "#c:dyes"}]}, "trigger": "minecraft:inventory_changed"}, "has_the_recipe": { "conditions": {"recipe": "computercraft:turtle_normal_overlays/turtle_rainbow_overlay"}, "trigger": "minecraft:recipe_unlocked" }, "has_turtle": { - "conditions": {"items": [{"items": ["computercraft:turtle_normal"]}]}, + "conditions": {"items": [{"items": "computercraft:turtle_normal"}]}, "trigger": "minecraft:inventory_changed" } }, - "requirements": [["has_turtle", "has_dye", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_normal_overlays/turtle_rainbow_overlay"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_turtle", "has_dye"]], + "rewards": {"recipes": ["computercraft:turtle_normal_overlays/turtle_rainbow_overlay"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal_overlays/turtle_trans_overlay.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal_overlays/turtle_trans_overlay.json index 80bf565f7..5ab930860 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal_overlays/turtle_trans_overlay.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/turtle_normal_overlays/turtle_trans_overlay.json @@ -1,17 +1,16 @@ { "parent": "minecraft:recipes/root", "criteria": { - "has_dye": {"conditions": {"items": [{"tag": "c:dyes"}]}, "trigger": "minecraft:inventory_changed"}, + "has_dye": {"conditions": {"items": [{"items": "#c:dyes"}]}, "trigger": "minecraft:inventory_changed"}, "has_the_recipe": { "conditions": {"recipe": "computercraft:turtle_normal_overlays/turtle_trans_overlay"}, "trigger": "minecraft:recipe_unlocked" }, "has_turtle": { - "conditions": {"items": [{"items": ["computercraft:turtle_normal"]}]}, + "conditions": {"items": [{"items": "computercraft:turtle_normal"}]}, "trigger": "minecraft:inventory_changed" } }, - "requirements": [["has_turtle", "has_dye", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:turtle_normal_overlays/turtle_trans_overlay"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_turtle", "has_dye"]], + "rewards": {"recipes": ["computercraft:turtle_normal_overlays/turtle_trans_overlay"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wired_modem.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wired_modem.json index 15d106669..e95de9a44 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wired_modem.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wired_modem.json @@ -2,11 +2,11 @@ "parent": "minecraft:recipes/root", "criteria": { "has_cable": { - "conditions": {"items": [{"items": ["computercraft:cable"]}]}, + "conditions": {"items": [{"items": "computercraft:cable"}]}, "trigger": "minecraft:inventory_changed" }, "has_computer": { - "conditions": {"items": [{"tag": "computercraft:computer"}]}, + "conditions": {"items": [{"items": "#computercraft:computer"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -14,7 +14,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_computer", "has_cable", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:wired_modem"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_computer", "has_cable"]], + "rewards": {"recipes": ["computercraft:wired_modem"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wired_modem_full_from.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wired_modem_full_from.json index c6f39a9db..66f22c878 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wired_modem_full_from.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wired_modem_full_from.json @@ -2,7 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_modem": { - "conditions": {"items": [{"tag": "computercraft:wired_modem"}]}, + "conditions": {"items": [{"items": "#computercraft:wired_modem"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -10,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_modem", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:wired_modem_full_from"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_modem"]], + "rewards": {"recipes": ["computercraft:wired_modem_full_from"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wired_modem_full_to.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wired_modem_full_to.json index 4250a54af..e6ce46a27 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wired_modem_full_to.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wired_modem_full_to.json @@ -2,7 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_modem": { - "conditions": {"items": [{"tag": "computercraft:wired_modem"}]}, + "conditions": {"items": [{"items": "#computercraft:wired_modem"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -10,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_modem", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:wired_modem_full_to"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_modem"]], + "rewards": {"recipes": ["computercraft:wired_modem_full_to"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wireless_modem_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wireless_modem_advanced.json index a79d740a6..b0116064a 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wireless_modem_advanced.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wireless_modem_advanced.json @@ -2,7 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_computer": { - "conditions": {"items": [{"tag": "computercraft:computer"}]}, + "conditions": {"items": [{"items": "#computercraft:computer"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -10,11 +10,10 @@ "trigger": "minecraft:recipe_unlocked" }, "has_wireless": { - "conditions": {"items": [{"items": ["computercraft:wireless_modem_normal"]}]}, + "conditions": {"items": [{"items": "computercraft:wireless_modem_normal"}]}, "trigger": "minecraft:inventory_changed" } }, - "requirements": [["has_computer", "has_wireless", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:wireless_modem_advanced"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_computer", "has_wireless"]], + "rewards": {"recipes": ["computercraft:wireless_modem_advanced"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wireless_modem_normal.json b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wireless_modem_normal.json index f404da1b7..523e86376 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wireless_modem_normal.json +++ b/projects/fabric/src/generated/resources/data/computercraft/advancements/recipes/redstone/wireless_modem_normal.json @@ -2,7 +2,7 @@ "parent": "minecraft:recipes/root", "criteria": { "has_computer": { - "conditions": {"items": [{"tag": "computercraft:computer"}]}, + "conditions": {"items": [{"items": "#computercraft:computer"}]}, "trigger": "minecraft:inventory_changed" }, "has_the_recipe": { @@ -10,7 +10,6 @@ "trigger": "minecraft:recipe_unlocked" } }, - "requirements": [["has_computer", "has_the_recipe"]], - "rewards": {"recipes": ["computercraft:wireless_modem_normal"]}, - "sends_telemetry_event": false + "requirements": [["has_the_recipe", "has_computer"]], + "rewards": {"recipes": ["computercraft:wireless_modem_normal"]} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/computer_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/computer_advanced.json index a49d76dbe..42d328a22 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/computer_advanced.json +++ b/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/computer_advanced.json @@ -13,7 +13,13 @@ ] } ], - "entries": [{"type": "minecraft:dynamic", "name": "computercraft:computer"}], + "entries": [ + { + "type": "minecraft:item", + "functions": [{"function": "minecraft:copy_components", "source": "block_entity"}], + "name": "computercraft:computer_advanced" + } + ], "rolls": 1.0 } ] diff --git a/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/computer_command.json b/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/computer_command.json index a49d76dbe..a11813215 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/computer_command.json +++ b/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/computer_command.json @@ -13,7 +13,13 @@ ] } ], - "entries": [{"type": "minecraft:dynamic", "name": "computercraft:computer"}], + "entries": [ + { + "type": "minecraft:item", + "functions": [{"function": "minecraft:copy_components", "source": "block_entity"}], + "name": "computercraft:computer_command" + } + ], "rolls": 1.0 } ] diff --git a/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/computer_normal.json b/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/computer_normal.json index a49d76dbe..bd73161e8 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/computer_normal.json +++ b/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/computer_normal.json @@ -13,7 +13,13 @@ ] } ], - "entries": [{"type": "minecraft:dynamic", "name": "computercraft:computer"}], + "entries": [ + { + "type": "minecraft:item", + "functions": [{"function": "minecraft:copy_components", "source": "block_entity"}], + "name": "computercraft:computer_normal" + } + ], "rolls": 1.0 } ] diff --git a/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json index a49d76dbe..9e1ba7727 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json +++ b/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json @@ -13,7 +13,13 @@ ] } ], - "entries": [{"type": "minecraft:dynamic", "name": "computercraft:computer"}], + "entries": [ + { + "type": "minecraft:item", + "functions": [{"function": "minecraft:copy_components", "source": "block_entity"}], + "name": "computercraft:turtle_advanced" + } + ], "rolls": 1.0 } ] diff --git a/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_normal.json b/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_normal.json index a49d76dbe..d9a5cf7af 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_normal.json +++ b/projects/fabric/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_normal.json @@ -13,7 +13,13 @@ ] } ], - "entries": [{"type": "minecraft:dynamic", "name": "computercraft:computer"}], + "entries": [ + { + "type": "minecraft:item", + "functions": [{"function": "minecraft:copy_components", "source": "block_entity"}], + "name": "computercraft:turtle_normal" + } + ], "rolls": 1.0 } ] diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/cable.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/cable.json index e1b9ab9cc..89384fc4c 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/cable.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/cable.json @@ -1,8 +1,7 @@ { "type": "minecraft:crafting_shaped", "category": "redstone", - "key": {"#": {"item": "minecraft:stone"}, "R": {"tag": "c:redstone_dusts"}}, + "key": {"#": {"item": "minecraft:stone"}, "R": {"tag": "c:dusts/redstone"}}, "pattern": [" # ", "#R#", " # "], - "result": {"count": 6, "item": "computercraft:cable"}, - "show_notification": true + "result": {"count": 6, "id": "computercraft:cable"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/computer_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/computer_advanced.json index 31879e2ab..9a335214f 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/computer_advanced.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/computer_advanced.json @@ -1,8 +1,7 @@ { "type": "minecraft:crafting_shaped", "category": "redstone", - "key": {"#": {"tag": "c:gold_ingots"}, "G": {"tag": "c:glass_panes"}, "R": {"tag": "c:redstone_dusts"}}, + "key": {"#": {"tag": "c:ingots/gold"}, "G": {"tag": "c:glass_panes"}, "R": {"tag": "c:dusts/redstone"}}, "pattern": ["###", "#R#", "#G#"], - "result": {"item": "computercraft:computer_advanced"}, - "show_notification": true + "result": {"count": 1, "id": "computercraft:computer_advanced"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/computer_advanced_upgrade.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/computer_advanced_upgrade.json index 03289f803..a9392af47 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/computer_advanced_upgrade.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/computer_advanced_upgrade.json @@ -1,8 +1,7 @@ { - "type": "computercraft:computer_upgrade", + "type": "computercraft:computer_convert", "category": "redstone", - "key": {"#": {"tag": "c:gold_ingots"}, "C": {"item": "computercraft:computer_normal"}}, + "key": {"#": {"tag": "c:ingots/gold"}, "C": {"item": "computercraft:computer_normal"}}, "pattern": ["###", "#C#", "# #"], - "result": {"item": "computercraft:computer_advanced"}, - "show_notification": true + "result": {"count": 1, "id": "computercraft:computer_advanced"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/computer_command.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/computer_command.json index b114f9265..4ad39c549 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/computer_command.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/computer_command.json @@ -2,11 +2,10 @@ "type": "minecraft:crafting_shaped", "category": "redstone", "key": { - "#": {"tag": "c:gold_ingots"}, + "#": {"tag": "c:ingots/gold"}, "G": {"tag": "c:glass_panes"}, "R": {"item": "minecraft:command_block"} }, "pattern": ["###", "#R#", "#G#"], - "result": {"item": "computercraft:computer_command"}, - "show_notification": true + "result": {"count": 1, "id": "computercraft:computer_command"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/computer_normal.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/computer_normal.json index fb83d46ac..84117ee95 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/computer_normal.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/computer_normal.json @@ -1,8 +1,7 @@ { "type": "minecraft:crafting_shaped", "category": "redstone", - "key": {"#": {"item": "minecraft:stone"}, "G": {"tag": "c:glass_panes"}, "R": {"tag": "c:redstone_dusts"}}, + "key": {"#": {"item": "minecraft:stone"}, "G": {"tag": "c:glass_panes"}, "R": {"tag": "c:dusts/redstone"}}, "pattern": ["###", "#R#", "#G#"], - "result": {"item": "computercraft:computer_normal"}, - "show_notification": true + "result": {"count": 1, "id": "computercraft:computer_normal"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_1.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_1.json index 8cbb171ba..b7f19e31b 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_1.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_1.json @@ -2,6 +2,10 @@ "type": "computercraft:impostor_shapeless", "category": "redstone", "group": "computercraft:disk", - "ingredients": [{"tag": "c:redstone_dusts"}, {"item": "minecraft:paper"}, {"item": "minecraft:black_dye"}], - "result": {"item": "computercraft:disk", "nbt": "{Color:1118481}"} + "ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:black_dye"}], + "result": { + "components": {"minecraft:dyed_color": {"rgb": 1118481, "show_in_tooltip": false}}, + "count": 1, + "id": "computercraft:disk" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_10.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_10.json index e3af58226..b427391b1 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_10.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_10.json @@ -2,6 +2,10 @@ "type": "computercraft:impostor_shapeless", "category": "redstone", "group": "computercraft:disk", - "ingredients": [{"tag": "c:redstone_dusts"}, {"item": "minecraft:paper"}, {"item": "minecraft:pink_dye"}], - "result": {"item": "computercraft:disk", "nbt": "{Color:15905484}"} + "ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:pink_dye"}], + "result": { + "components": {"minecraft:dyed_color": {"rgb": 15905484, "show_in_tooltip": false}}, + "count": 1, + "id": "computercraft:disk" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_11.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_11.json index ba3fd96f9..fcc0b9b38 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_11.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_11.json @@ -2,6 +2,10 @@ "type": "computercraft:impostor_shapeless", "category": "redstone", "group": "computercraft:disk", - "ingredients": [{"tag": "c:redstone_dusts"}, {"item": "minecraft:paper"}, {"item": "minecraft:lime_dye"}], - "result": {"item": "computercraft:disk", "nbt": "{Color:8375321}"} + "ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:lime_dye"}], + "result": { + "components": {"minecraft:dyed_color": {"rgb": 8375321, "show_in_tooltip": false}}, + "count": 1, + "id": "computercraft:disk" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_12.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_12.json index b0897df90..615cb1ddd 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_12.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_12.json @@ -2,6 +2,10 @@ "type": "computercraft:impostor_shapeless", "category": "redstone", "group": "computercraft:disk", - "ingredients": [{"tag": "c:redstone_dusts"}, {"item": "minecraft:paper"}, {"item": "minecraft:yellow_dye"}], - "result": {"item": "computercraft:disk", "nbt": "{Color:14605932}"} + "ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:yellow_dye"}], + "result": { + "components": {"minecraft:dyed_color": {"rgb": 14605932, "show_in_tooltip": false}}, + "count": 1, + "id": "computercraft:disk" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_13.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_13.json index 9e3a66f81..50d462d73 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_13.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_13.json @@ -3,9 +3,13 @@ "category": "redstone", "group": "computercraft:disk", "ingredients": [ - {"tag": "c:redstone_dusts"}, + {"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:light_blue_dye"} ], - "result": {"item": "computercraft:disk", "nbt": "{Color:10072818}"} + "result": { + "components": {"minecraft:dyed_color": {"rgb": 10072818, "show_in_tooltip": false}}, + "count": 1, + "id": "computercraft:disk" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_14.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_14.json index 600acafaf..3b1301f5b 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_14.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_14.json @@ -2,6 +2,10 @@ "type": "computercraft:impostor_shapeless", "category": "redstone", "group": "computercraft:disk", - "ingredients": [{"tag": "c:redstone_dusts"}, {"item": "minecraft:paper"}, {"item": "minecraft:magenta_dye"}], - "result": {"item": "computercraft:disk", "nbt": "{Color:15040472}"} + "ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:magenta_dye"}], + "result": { + "components": {"minecraft:dyed_color": {"rgb": 15040472, "show_in_tooltip": false}}, + "count": 1, + "id": "computercraft:disk" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_15.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_15.json index 2da4825f1..83beaae21 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_15.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_15.json @@ -2,6 +2,10 @@ "type": "computercraft:impostor_shapeless", "category": "redstone", "group": "computercraft:disk", - "ingredients": [{"tag": "c:redstone_dusts"}, {"item": "minecraft:paper"}, {"item": "minecraft:orange_dye"}], - "result": {"item": "computercraft:disk", "nbt": "{Color:15905331}"} + "ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:orange_dye"}], + "result": { + "components": {"minecraft:dyed_color": {"rgb": 15905331, "show_in_tooltip": false}}, + "count": 1, + "id": "computercraft:disk" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_16.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_16.json index 5b3b67334..1d49329a2 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_16.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_16.json @@ -2,6 +2,10 @@ "type": "computercraft:impostor_shapeless", "category": "redstone", "group": "computercraft:disk", - "ingredients": [{"tag": "c:redstone_dusts"}, {"item": "minecraft:paper"}, {"item": "minecraft:white_dye"}], - "result": {"item": "computercraft:disk", "nbt": "{Color:15790320}"} + "ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:white_dye"}], + "result": { + "components": {"minecraft:dyed_color": {"rgb": 15790320, "show_in_tooltip": false}}, + "count": 1, + "id": "computercraft:disk" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_2.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_2.json index faeee01b3..232d5ea43 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_2.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_2.json @@ -2,6 +2,10 @@ "type": "computercraft:impostor_shapeless", "category": "redstone", "group": "computercraft:disk", - "ingredients": [{"tag": "c:redstone_dusts"}, {"item": "minecraft:paper"}, {"item": "minecraft:red_dye"}], - "result": {"item": "computercraft:disk", "nbt": "{Color:13388876}"} + "ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:red_dye"}], + "result": { + "components": {"minecraft:dyed_color": {"rgb": 13388876, "show_in_tooltip": false}}, + "count": 1, + "id": "computercraft:disk" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_3.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_3.json index 41b381378..08da162d8 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_3.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_3.json @@ -2,6 +2,10 @@ "type": "computercraft:impostor_shapeless", "category": "redstone", "group": "computercraft:disk", - "ingredients": [{"tag": "c:redstone_dusts"}, {"item": "minecraft:paper"}, {"item": "minecraft:green_dye"}], - "result": {"item": "computercraft:disk", "nbt": "{Color:5744206}"} + "ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:green_dye"}], + "result": { + "components": {"minecraft:dyed_color": {"rgb": 5744206, "show_in_tooltip": false}}, + "count": 1, + "id": "computercraft:disk" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_4.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_4.json index 085dc3e83..795b1c0a6 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_4.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_4.json @@ -2,6 +2,10 @@ "type": "computercraft:impostor_shapeless", "category": "redstone", "group": "computercraft:disk", - "ingredients": [{"tag": "c:redstone_dusts"}, {"item": "minecraft:paper"}, {"item": "minecraft:brown_dye"}], - "result": {"item": "computercraft:disk", "nbt": "{Color:8349260}"} + "ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:brown_dye"}], + "result": { + "components": {"minecraft:dyed_color": {"rgb": 8349260, "show_in_tooltip": false}}, + "count": 1, + "id": "computercraft:disk" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_5.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_5.json index 3ce11c706..cd3c6716a 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_5.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_5.json @@ -2,6 +2,10 @@ "type": "computercraft:impostor_shapeless", "category": "redstone", "group": "computercraft:disk", - "ingredients": [{"tag": "c:redstone_dusts"}, {"item": "minecraft:paper"}, {"item": "minecraft:blue_dye"}], - "result": {"item": "computercraft:disk", "nbt": "{Color:3368652}"} + "ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:blue_dye"}], + "result": { + "components": {"minecraft:dyed_color": {"rgb": 3368652, "show_in_tooltip": false}}, + "count": 1, + "id": "computercraft:disk" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_6.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_6.json index ff2fcf2bd..0832d11bb 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_6.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_6.json @@ -2,6 +2,10 @@ "type": "computercraft:impostor_shapeless", "category": "redstone", "group": "computercraft:disk", - "ingredients": [{"tag": "c:redstone_dusts"}, {"item": "minecraft:paper"}, {"item": "minecraft:purple_dye"}], - "result": {"item": "computercraft:disk", "nbt": "{Color:11691749}"} + "ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:purple_dye"}], + "result": { + "components": {"minecraft:dyed_color": {"rgb": 11691749, "show_in_tooltip": false}}, + "count": 1, + "id": "computercraft:disk" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_7.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_7.json index f9052f7d0..3ba73a7dd 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_7.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_7.json @@ -2,6 +2,10 @@ "type": "computercraft:impostor_shapeless", "category": "redstone", "group": "computercraft:disk", - "ingredients": [{"tag": "c:redstone_dusts"}, {"item": "minecraft:paper"}, {"item": "minecraft:cyan_dye"}], - "result": {"item": "computercraft:disk", "nbt": "{Color:5020082}"} + "ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:cyan_dye"}], + "result": { + "components": {"minecraft:dyed_color": {"rgb": 5020082, "show_in_tooltip": false}}, + "count": 1, + "id": "computercraft:disk" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_8.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_8.json index 53c0ca6e9..c1b111e67 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_8.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_8.json @@ -3,9 +3,13 @@ "category": "redstone", "group": "computercraft:disk", "ingredients": [ - {"tag": "c:redstone_dusts"}, + {"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:light_gray_dye"} ], - "result": {"item": "computercraft:disk", "nbt": "{Color:10066329}"} + "result": { + "components": {"minecraft:dyed_color": {"rgb": 10066329, "show_in_tooltip": false}}, + "count": 1, + "id": "computercraft:disk" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_9.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_9.json index 9b71f9f6f..b6a22ced8 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_9.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_9.json @@ -2,6 +2,10 @@ "type": "computercraft:impostor_shapeless", "category": "redstone", "group": "computercraft:disk", - "ingredients": [{"tag": "c:redstone_dusts"}, {"item": "minecraft:paper"}, {"item": "minecraft:gray_dye"}], - "result": {"item": "computercraft:disk", "nbt": "{Color:5000268}"} + "ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:gray_dye"}], + "result": { + "components": {"minecraft:dyed_color": {"rgb": 5000268, "show_in_tooltip": false}}, + "count": 1, + "id": "computercraft:disk" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_drive.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_drive.json index 0fb14248b..3a0026016 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_drive.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/disk_drive.json @@ -1,8 +1,7 @@ { "type": "minecraft:crafting_shaped", "category": "redstone", - "key": {"#": {"item": "minecraft:stone"}, "R": {"tag": "c:redstone_dusts"}}, + "key": {"#": {"item": "minecraft:stone"}, "R": {"tag": "c:dusts/redstone"}}, "pattern": ["###", "#R#", "#R#"], - "result": {"item": "computercraft:disk_drive"}, - "show_notification": true + "result": {"count": 1, "id": "computercraft:disk_drive"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/monitor_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/monitor_advanced.json index c3c11767a..070392fe2 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/monitor_advanced.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/monitor_advanced.json @@ -1,8 +1,7 @@ { "type": "minecraft:crafting_shaped", "category": "redstone", - "key": {"#": {"tag": "c:gold_ingots"}, "G": {"tag": "c:glass_panes"}}, + "key": {"#": {"tag": "c:ingots/gold"}, "G": {"tag": "c:glass_panes"}}, "pattern": ["###", "#G#", "###"], - "result": {"count": 4, "item": "computercraft:monitor_advanced"}, - "show_notification": true + "result": {"count": 4, "id": "computercraft:monitor_advanced"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/monitor_normal.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/monitor_normal.json index 1216882e2..a52103dd7 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/monitor_normal.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/monitor_normal.json @@ -3,6 +3,5 @@ "category": "redstone", "key": {"#": {"item": "minecraft:stone"}, "G": {"tag": "c:glass_panes"}}, "pattern": ["###", "#G#", "###"], - "result": {"item": "computercraft:monitor_normal"}, - "show_notification": true + "result": {"count": 1, "id": "computercraft:monitor_normal"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/speaker.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/speaker.json index b58414a84..5848ae4c3 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/speaker.json +++ b/projects/fabric/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\"}"}, - "show_notification": true + "result": { + "components": {"computercraft:pocket_upgrade": {"id": "computercraft:speaker"}}, + "count": 1, + "id": "computercraft:pocket_computer_advanced" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_advanced.json index a5128aaf9..c88b00878 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_advanced.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_advanced.json @@ -8,8 +8,8 @@ }, "pattern": ["#", "P"], "result": { - "item": "computercraft:pocket_computer_advanced", - "nbt": "{Upgrade:\"computercraft:wireless_modem_advanced\"}" - }, - "show_notification": true + "components": {"computercraft:pocket_upgrade": {"id": "computercraft:wireless_modem_advanced"}}, + "count": 1, + "id": "computercraft:pocket_computer_advanced" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_normal.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_normal.json index c8f5ab064..43180d4ff 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_normal.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_normal.json @@ -8,8 +8,8 @@ }, "pattern": ["#", "P"], "result": { - "item": "computercraft:pocket_computer_advanced", - "nbt": "{Upgrade:\"computercraft:wireless_modem_normal\"}" - }, - "show_notification": true + "components": {"computercraft:pocket_upgrade": {"id": "computercraft:wireless_modem_normal"}}, + "count": 1, + "id": "computercraft:pocket_computer_advanced" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_computer_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_computer_advanced.json index 40061f60b..911f07c81 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_computer_advanced.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_computer_advanced.json @@ -1,8 +1,7 @@ { "type": "minecraft:crafting_shaped", "category": "redstone", - "key": {"#": {"tag": "c:gold_ingots"}, "A": {"item": "minecraft:golden_apple"}, "G": {"tag": "c:glass_panes"}}, + "key": {"#": {"tag": "c:ingots/gold"}, "A": {"item": "minecraft:golden_apple"}, "G": {"tag": "c:glass_panes"}}, "pattern": ["###", "#A#", "#G#"], - "result": {"item": "computercraft:pocket_computer_advanced"}, - "show_notification": true + "result": {"count": 1, "id": "computercraft:pocket_computer_advanced"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_computer_advanced_upgrade.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_computer_advanced_upgrade.json index 765944e32..10c8aeeb9 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_computer_advanced_upgrade.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_computer_advanced_upgrade.json @@ -1,8 +1,7 @@ { - "type": "computercraft:computer_upgrade", + "type": "computercraft:computer_convert", "category": "redstone", - "key": {"#": {"tag": "c:gold_ingots"}, "C": {"item": "computercraft:pocket_computer_normal"}}, + "key": {"#": {"tag": "c:ingots/gold"}, "C": {"item": "computercraft:pocket_computer_normal"}}, "pattern": ["###", "#C#", "# #"], - "result": {"item": "computercraft:pocket_computer_advanced"}, - "show_notification": true + "result": {"count": 1, "id": "computercraft:pocket_computer_advanced"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_computer_normal.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_computer_normal.json index b63edabf0..4bef87ac8 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_computer_normal.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_computer_normal.json @@ -7,6 +7,5 @@ "G": {"tag": "c:glass_panes"} }, "pattern": ["###", "#A#", "#G#"], - "result": {"item": "computercraft:pocket_computer_normal"}, - "show_notification": true + "result": {"count": 1, "id": "computercraft:pocket_computer_normal"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/speaker.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/speaker.json index 216e55664..f13b2cafa 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/speaker.json +++ b/projects/fabric/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\"}"}, - "show_notification": true + "result": { + "components": {"computercraft:pocket_upgrade": {"id": "computercraft:speaker"}}, + "count": 1, + "id": "computercraft:pocket_computer_normal" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_advanced.json index e4a8a2475..63f38c618 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_advanced.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_advanced.json @@ -8,8 +8,8 @@ }, "pattern": ["#", "P"], "result": { - "item": "computercraft:pocket_computer_normal", - "nbt": "{Upgrade:\"computercraft:wireless_modem_advanced\"}" - }, - "show_notification": true + "components": {"computercraft:pocket_upgrade": {"id": "computercraft:wireless_modem_advanced"}}, + "count": 1, + "id": "computercraft:pocket_computer_normal" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_normal.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_normal.json index 1f14fe111..a875e7413 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_normal.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_normal.json @@ -8,8 +8,8 @@ }, "pattern": ["#", "P"], "result": { - "item": "computercraft:pocket_computer_normal", - "nbt": "{Upgrade:\"computercraft:wireless_modem_normal\"}" - }, - "show_notification": true + "components": {"computercraft:pocket_upgrade": {"id": "computercraft:wireless_modem_normal"}}, + "count": 1, + "id": "computercraft:pocket_computer_normal" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/printed_book.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/printed_book.json index 7d873b7f0..87bd22939 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/printed_book.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/printed_book.json @@ -6,5 +6,5 @@ {"item": "computercraft:printed_page"}, {"item": "minecraft:string"} ], - "result": {"item": "computercraft:printed_book"} + "result": {"count": 1, "id": "computercraft:printed_book"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/printed_pages.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/printed_pages.json index 2cb9495f4..d256a6127 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/printed_pages.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/printed_pages.json @@ -6,5 +6,5 @@ {"item": "computercraft:printed_page"}, {"item": "minecraft:string"} ], - "result": {"item": "computercraft:printed_pages"} + "result": {"count": 1, "id": "computercraft:printed_pages"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/printer.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/printer.json index cd4a527c7..6fb87d2c3 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/printer.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/printer.json @@ -1,8 +1,7 @@ { "type": "minecraft:crafting_shaped", "category": "redstone", - "key": {"#": {"item": "minecraft:stone"}, "D": {"tag": "c:dyes"}, "R": {"tag": "c:redstone_dusts"}}, + "key": {"#": {"item": "minecraft:stone"}, "D": {"tag": "c:dyes"}, "R": {"tag": "c:dusts/redstone"}}, "pattern": ["###", "#R#", "#D#"], - "result": {"item": "computercraft:printer"}, - "show_notification": true + "result": {"count": 1, "id": "computercraft:printer"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/skull_cloudy.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/skull_cloudy.json index d69e4e195..6b32018d3 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/skull_cloudy.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/skull_cloudy.json @@ -1,9 +1,12 @@ { - "type": "computercraft:shapeless", + "type": "minecraft:crafting_shapeless", "category": "misc", - "ingredients": [{"tag": "c:skulls"}, {"item": "computercraft:monitor_normal"}], + "ingredients": [{"tag": "minecraft:skulls"}, {"item": "computercraft:monitor_normal"}], "result": { - "item": "minecraft:player_head", - "nbt": "{SkullOwner:{Id:[I;1829193526,-1310112904,-1449411193,2005015708],Name:\"Cloudhunter\"}}" + "components": { + "minecraft:profile": {"id": [1829193526, -1310112904, -1449411193, 2005015708], "name": "Cloudhunter"} + }, + "count": 1, + "id": "minecraft:player_head" } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/skull_dan200.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/skull_dan200.json index 8c21bd49d..38dd3a135 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/skull_dan200.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/skull_dan200.json @@ -1,9 +1,10 @@ { - "type": "computercraft:shapeless", + "type": "minecraft:crafting_shapeless", "category": "misc", - "ingredients": [{"tag": "c:skulls"}, {"item": "computercraft:computer_advanced"}], + "ingredients": [{"tag": "minecraft:skulls"}, {"item": "computercraft:computer_advanced"}], "result": { - "item": "minecraft:player_head", - "nbt": "{SkullOwner:{Id:[I;-204941669,125191442,-2076913230,374933995],Name:\"dan200\"}}" + "components": {"minecraft:profile": {"id": [-204941669, 125191442, -2076913230, 374933995], "name": "dan200"}}, + "count": 1, + "id": "minecraft:player_head" } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/speaker.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/speaker.json index ba855977e..0e61faa47 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/speaker.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/speaker.json @@ -4,9 +4,8 @@ "key": { "#": {"item": "minecraft:stone"}, "N": {"item": "minecraft:note_block"}, - "R": {"tag": "c:redstone_dusts"} + "R": {"tag": "c:dusts/redstone"} }, "pattern": ["###", "#N#", "#R#"], - "result": {"item": "computercraft:speaker"}, - "show_notification": true + "result": {"count": 1, "id": "computercraft:speaker"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced.json index a720038df..02e450f72 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced.json @@ -1,12 +1,11 @@ { - "type": "computercraft:turtle", + "type": "computercraft:computer_convert", "category": "redstone", "key": { - "#": {"tag": "c:gold_ingots"}, + "#": {"tag": "c:ingots/gold"}, "C": {"item": "computercraft:computer_advanced"}, - "I": {"tag": "c:wooden_chests"} + "I": {"tag": "c:chests/wooden"} }, "pattern": ["###", "#C#", "#I#"], - "result": {"item": "computercraft:turtle_advanced"}, - "show_notification": true + "result": {"count": 1, "id": "computercraft:turtle_advanced"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/speaker.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/speaker.json index c1c2ee567..521802cc8 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/speaker.json +++ b/projects/fabric/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\"}"}, - "show_notification": true + "result": { + "components": {"computercraft:right_turtle_upgrade": {"id": "computercraft:speaker"}}, + "count": 1, + "id": "computercraft:turtle_advanced" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_advanced.json index c38f055cd..a6cda706d 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_advanced.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_advanced.json @@ -5,8 +5,8 @@ "key": {"#": {"item": "computercraft:wireless_modem_advanced"}, "T": {"item": "computercraft:turtle_advanced"}}, "pattern": ["#T"], "result": { - "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"computercraft:wireless_modem_advanced\"}" - }, - "show_notification": true + "components": {"computercraft:right_turtle_upgrade": {"id": "computercraft:wireless_modem_advanced"}}, + "count": 1, + "id": "computercraft:turtle_advanced" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_normal.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_normal.json index 3a82c6f72..166cff86e 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_normal.json +++ b/projects/fabric/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\"}"}, - "show_notification": true + "result": { + "components": {"computercraft:right_turtle_upgrade": {"id": "computercraft:wireless_modem_normal"}}, + "count": 1, + "id": "computercraft:turtle_advanced" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/crafting_table.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/crafting_table.json index bbd4847be..8866543ba 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/crafting_table.json +++ b/projects/fabric/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\"}"}, - "show_notification": true + "result": { + "components": {"computercraft:right_turtle_upgrade": {"id": "minecraft:crafting_table"}}, + "count": 1, + "id": "computercraft:turtle_advanced" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_axe.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_axe.json index e4198aa6f..f7c255e29 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_axe.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_axe.json @@ -5,8 +5,8 @@ "key": {"#": {"item": "minecraft:diamond_axe"}, "T": {"item": "computercraft:turtle_advanced"}}, "pattern": ["#T"], "result": { - "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"minecraft:diamond_axe\",RightUpgradeNbt:{Tag:{Damage:0}}}" - }, - "show_notification": true + "components": {"computercraft:right_turtle_upgrade": {"id": "minecraft:diamond_axe"}}, + "count": 1, + "id": "computercraft:turtle_advanced" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_hoe.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_hoe.json index b87716788..e921bba79 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_hoe.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_hoe.json @@ -5,8 +5,8 @@ "key": {"#": {"item": "minecraft:diamond_hoe"}, "T": {"item": "computercraft:turtle_advanced"}}, "pattern": ["#T"], "result": { - "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"minecraft:diamond_hoe\",RightUpgradeNbt:{Tag:{Damage:0}}}" - }, - "show_notification": true + "components": {"computercraft:right_turtle_upgrade": {"id": "minecraft:diamond_hoe"}}, + "count": 1, + "id": "computercraft:turtle_advanced" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_pickaxe.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_pickaxe.json index 1e9ce962a..fc267afc0 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_pickaxe.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_pickaxe.json @@ -5,8 +5,8 @@ "key": {"#": {"item": "minecraft:diamond_pickaxe"}, "T": {"item": "computercraft:turtle_advanced"}}, "pattern": ["#T"], "result": { - "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"minecraft:diamond_pickaxe\",RightUpgradeNbt:{Tag:{Damage:0}}}" - }, - "show_notification": true + "components": {"computercraft:right_turtle_upgrade": {"id": "minecraft:diamond_pickaxe"}}, + "count": 1, + "id": "computercraft:turtle_advanced" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_shovel.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_shovel.json index 557c3b507..77bba7a39 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_shovel.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_shovel.json @@ -5,8 +5,8 @@ "key": {"#": {"item": "minecraft:diamond_shovel"}, "T": {"item": "computercraft:turtle_advanced"}}, "pattern": ["#T"], "result": { - "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"minecraft:diamond_shovel\",RightUpgradeNbt:{Tag:{Damage:0}}}" - }, - "show_notification": true + "components": {"computercraft:right_turtle_upgrade": {"id": "minecraft:diamond_shovel"}}, + "count": 1, + "id": "computercraft:turtle_advanced" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_sword.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_sword.json index d618d7e51..53078aa9a 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_sword.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_sword.json @@ -5,8 +5,8 @@ "key": {"#": {"item": "minecraft:diamond_sword"}, "T": {"item": "computercraft:turtle_advanced"}}, "pattern": ["#T"], "result": { - "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"minecraft:diamond_sword\",RightUpgradeNbt:{Tag:{Damage:0}}}" - }, - "show_notification": true + "components": {"computercraft:right_turtle_upgrade": {"id": "minecraft:diamond_sword"}}, + "count": 1, + "id": "computercraft:turtle_advanced" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced_overlays/turtle_rainbow_overlay.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced_overlays/turtle_rainbow_overlay.json index e002322bd..8e652cd1b 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced_overlays/turtle_rainbow_overlay.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced_overlays/turtle_rainbow_overlay.json @@ -3,15 +3,15 @@ "category": "redstone", "group": "computercraft:turtle_advanced_overlay", "ingredients": [ - {"tag": "c:red_dyes"}, - {"tag": "c:orange_dyes"}, - {"tag": "c:yellow_dyes"}, - {"tag": "c:green_dyes"}, - {"tag": "c:blue_dyes"}, - {"tag": "c:purple_dyes"}, + {"tag": "c:dyes/red"}, + {"tag": "c:dyes/orange"}, + {"tag": "c:dyes/yellow"}, + {"tag": "c:dyes/green"}, + {"tag": "c:dyes/blue"}, + {"tag": "c:dyes/purple"}, {"item": "minecraft:stick"}, {"item": "computercraft:turtle_advanced"} ], "overlay": "computercraft:block/turtle_rainbow_overlay", - "result": {"item": "computercraft:turtle_advanced"} + "result": {"count": 1, "id": "computercraft:turtle_advanced"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced_overlays/turtle_trans_overlay.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced_overlays/turtle_trans_overlay.json index 739cd63ca..b1349d76e 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced_overlays/turtle_trans_overlay.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced_overlays/turtle_trans_overlay.json @@ -3,12 +3,12 @@ "category": "redstone", "group": "computercraft:turtle_advanced_overlay", "ingredients": [ - {"tag": "c:light_blue_dyes"}, - {"tag": "c:pink_dyes"}, - {"tag": "c:white_dyes"}, + {"tag": "c:dyes/light_blue"}, + {"tag": "c:dyes/pink"}, + {"tag": "c:dyes/white"}, {"item": "minecraft:stick"}, {"item": "computercraft:turtle_advanced"} ], "overlay": "computercraft:block/turtle_trans_overlay", - "result": {"item": "computercraft:turtle_advanced"} + "result": {"count": 1, "id": "computercraft:turtle_advanced"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced_upgrade.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced_upgrade.json index 6a50ccec9..b38b8bb5b 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced_upgrade.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_advanced_upgrade.json @@ -1,12 +1,11 @@ { - "type": "computercraft:computer_upgrade", + "type": "computercraft:computer_convert", "category": "redstone", "key": { - "#": {"tag": "c:gold_ingots"}, + "#": {"tag": "c:ingots/gold"}, "B": {"item": "minecraft:gold_block"}, "C": {"item": "computercraft:turtle_normal"} }, "pattern": ["###", "#C#", " B "], - "result": {"item": "computercraft:turtle_advanced"}, - "show_notification": true + "result": {"count": 1, "id": "computercraft:turtle_advanced"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal.json index 09f79a331..14b764b3d 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal.json @@ -1,12 +1,11 @@ { - "type": "computercraft:turtle", + "type": "computercraft:computer_convert", "category": "redstone", "key": { - "#": {"tag": "c:iron_ingots"}, + "#": {"tag": "c:ingots/iron"}, "C": {"item": "computercraft:computer_normal"}, - "I": {"tag": "c:wooden_chests"} + "I": {"tag": "c:chests/wooden"} }, "pattern": ["###", "#C#", "#I#"], - "result": {"item": "computercraft:turtle_normal"}, - "show_notification": true + "result": {"count": 1, "id": "computercraft:turtle_normal"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/speaker.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/speaker.json index bbb98011b..cda30b349 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/speaker.json +++ b/projects/fabric/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\"}"}, - "show_notification": true + "result": { + "components": {"computercraft:right_turtle_upgrade": {"id": "computercraft:speaker"}}, + "count": 1, + "id": "computercraft:turtle_normal" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_advanced.json index d6479ae5a..ee6fa8db1 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_advanced.json +++ b/projects/fabric/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\"}"}, - "show_notification": true + "result": { + "components": {"computercraft:right_turtle_upgrade": {"id": "computercraft:wireless_modem_advanced"}}, + "count": 1, + "id": "computercraft:turtle_normal" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_normal.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_normal.json index 2edbe58cf..845f47579 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_normal.json +++ b/projects/fabric/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\"}"}, - "show_notification": true + "result": { + "components": {"computercraft:right_turtle_upgrade": {"id": "computercraft:wireless_modem_normal"}}, + "count": 1, + "id": "computercraft:turtle_normal" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/crafting_table.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/crafting_table.json index 1f6233d88..06d5e6e27 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/crafting_table.json +++ b/projects/fabric/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\"}"}, - "show_notification": true + "result": { + "components": {"computercraft:right_turtle_upgrade": {"id": "minecraft:crafting_table"}}, + "count": 1, + "id": "computercraft:turtle_normal" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_axe.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_axe.json index bf6750a01..471d4ae22 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_axe.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_axe.json @@ -5,8 +5,8 @@ "key": {"#": {"item": "minecraft:diamond_axe"}, "T": {"item": "computercraft:turtle_normal"}}, "pattern": ["#T"], "result": { - "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"minecraft:diamond_axe\",RightUpgradeNbt:{Tag:{Damage:0}}}" - }, - "show_notification": true + "components": {"computercraft:right_turtle_upgrade": {"id": "minecraft:diamond_axe"}}, + "count": 1, + "id": "computercraft:turtle_normal" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_hoe.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_hoe.json index b55ceca7c..cca3c656a 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_hoe.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_hoe.json @@ -5,8 +5,8 @@ "key": {"#": {"item": "minecraft:diamond_hoe"}, "T": {"item": "computercraft:turtle_normal"}}, "pattern": ["#T"], "result": { - "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"minecraft:diamond_hoe\",RightUpgradeNbt:{Tag:{Damage:0}}}" - }, - "show_notification": true + "components": {"computercraft:right_turtle_upgrade": {"id": "minecraft:diamond_hoe"}}, + "count": 1, + "id": "computercraft:turtle_normal" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_pickaxe.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_pickaxe.json index bf8a729a4..7d9dd4e05 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_pickaxe.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_pickaxe.json @@ -5,8 +5,8 @@ "key": {"#": {"item": "minecraft:diamond_pickaxe"}, "T": {"item": "computercraft:turtle_normal"}}, "pattern": ["#T"], "result": { - "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"minecraft:diamond_pickaxe\",RightUpgradeNbt:{Tag:{Damage:0}}}" - }, - "show_notification": true + "components": {"computercraft:right_turtle_upgrade": {"id": "minecraft:diamond_pickaxe"}}, + "count": 1, + "id": "computercraft:turtle_normal" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_shovel.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_shovel.json index 15913ef34..b358bb1fb 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_shovel.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_shovel.json @@ -5,8 +5,8 @@ "key": {"#": {"item": "minecraft:diamond_shovel"}, "T": {"item": "computercraft:turtle_normal"}}, "pattern": ["#T"], "result": { - "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"minecraft:diamond_shovel\",RightUpgradeNbt:{Tag:{Damage:0}}}" - }, - "show_notification": true + "components": {"computercraft:right_turtle_upgrade": {"id": "minecraft:diamond_shovel"}}, + "count": 1, + "id": "computercraft:turtle_normal" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_sword.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_sword.json index b4862e713..145a44b99 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_sword.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_sword.json @@ -5,8 +5,8 @@ "key": {"#": {"item": "minecraft:diamond_sword"}, "T": {"item": "computercraft:turtle_normal"}}, "pattern": ["#T"], "result": { - "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"minecraft:diamond_sword\",RightUpgradeNbt:{Tag:{Damage:0}}}" - }, - "show_notification": true + "components": {"computercraft:right_turtle_upgrade": {"id": "minecraft:diamond_sword"}}, + "count": 1, + "id": "computercraft:turtle_normal" + } } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal_overlays/turtle_rainbow_overlay.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal_overlays/turtle_rainbow_overlay.json index f5f8eb8fc..12673b797 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal_overlays/turtle_rainbow_overlay.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal_overlays/turtle_rainbow_overlay.json @@ -3,15 +3,15 @@ "category": "redstone", "group": "computercraft:turtle_normal_overlay", "ingredients": [ - {"tag": "c:red_dyes"}, - {"tag": "c:orange_dyes"}, - {"tag": "c:yellow_dyes"}, - {"tag": "c:green_dyes"}, - {"tag": "c:blue_dyes"}, - {"tag": "c:purple_dyes"}, + {"tag": "c:dyes/red"}, + {"tag": "c:dyes/orange"}, + {"tag": "c:dyes/yellow"}, + {"tag": "c:dyes/green"}, + {"tag": "c:dyes/blue"}, + {"tag": "c:dyes/purple"}, {"item": "minecraft:stick"}, {"item": "computercraft:turtle_normal"} ], "overlay": "computercraft:block/turtle_rainbow_overlay", - "result": {"item": "computercraft:turtle_normal"} + "result": {"count": 1, "id": "computercraft:turtle_normal"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal_overlays/turtle_trans_overlay.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal_overlays/turtle_trans_overlay.json index a64e2df11..e91c5a456 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal_overlays/turtle_trans_overlay.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/turtle_normal_overlays/turtle_trans_overlay.json @@ -3,12 +3,12 @@ "category": "redstone", "group": "computercraft:turtle_normal_overlay", "ingredients": [ - {"tag": "c:light_blue_dyes"}, - {"tag": "c:pink_dyes"}, - {"tag": "c:white_dyes"}, + {"tag": "c:dyes/light_blue"}, + {"tag": "c:dyes/pink"}, + {"tag": "c:dyes/white"}, {"item": "minecraft:stick"}, {"item": "computercraft:turtle_normal"} ], "overlay": "computercraft:block/turtle_trans_overlay", - "result": {"item": "computercraft:turtle_normal"} + "result": {"count": 1, "id": "computercraft:turtle_normal"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/wired_modem.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/wired_modem.json index 399927323..77c138e22 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/wired_modem.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/wired_modem.json @@ -1,8 +1,7 @@ { "type": "minecraft:crafting_shaped", "category": "redstone", - "key": {"#": {"item": "minecraft:stone"}, "R": {"tag": "c:redstone_dusts"}}, + "key": {"#": {"item": "minecraft:stone"}, "R": {"tag": "c:dusts/redstone"}}, "pattern": ["###", "#R#", "###"], - "result": {"item": "computercraft:wired_modem"}, - "show_notification": true + "result": {"count": 1, "id": "computercraft:wired_modem"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/wired_modem_full_from.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/wired_modem_full_from.json index 39de834c4..342c81ea3 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/wired_modem_full_from.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/wired_modem_full_from.json @@ -2,5 +2,5 @@ "type": "minecraft:crafting_shapeless", "category": "redstone", "ingredients": [{"item": "computercraft:wired_modem"}], - "result": {"item": "computercraft:wired_modem_full"} + "result": {"count": 1, "id": "computercraft:wired_modem_full"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/wired_modem_full_to.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/wired_modem_full_to.json index cb2123f0f..45c7673c0 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/wired_modem_full_to.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/wired_modem_full_to.json @@ -2,5 +2,5 @@ "type": "minecraft:crafting_shapeless", "category": "redstone", "ingredients": [{"item": "computercraft:wired_modem_full"}], - "result": {"item": "computercraft:wired_modem"} + "result": {"count": 1, "id": "computercraft:wired_modem"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/wireless_modem_advanced.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/wireless_modem_advanced.json index 4393b6b89..0b1f48f57 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/wireless_modem_advanced.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/wireless_modem_advanced.json @@ -1,8 +1,7 @@ { "type": "minecraft:crafting_shaped", "category": "redstone", - "key": {"#": {"tag": "c:gold_ingots"}, "E": {"item": "minecraft:ender_eye"}}, + "key": {"#": {"tag": "c:ingots/gold"}, "E": {"item": "minecraft:ender_eye"}}, "pattern": ["###", "#E#", "###"], - "result": {"item": "computercraft:wireless_modem_advanced"}, - "show_notification": true + "result": {"count": 1, "id": "computercraft:wireless_modem_advanced"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/recipes/wireless_modem_normal.json b/projects/fabric/src/generated/resources/data/computercraft/recipes/wireless_modem_normal.json index 54897af97..f22a0d925 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/recipes/wireless_modem_normal.json +++ b/projects/fabric/src/generated/resources/data/computercraft/recipes/wireless_modem_normal.json @@ -3,6 +3,5 @@ "category": "redstone", "key": {"#": {"item": "minecraft:stone"}, "E": {"item": "minecraft:ender_pearl"}}, "pattern": ["###", "#E#", "###"], - "result": {"item": "computercraft:wireless_modem_normal"}, - "show_notification": true + "result": {"count": 1, "id": "computercraft:wireless_modem_normal"} } diff --git a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/computer.json b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/computer.json index 729a9ae47..b3acd11d5 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/computer.json +++ b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/computer.json @@ -1,4 +1 @@ -{ - "replace": false, - "values": ["computercraft:computer_normal", "computercraft:computer_advanced", "computercraft:computer_command"] -} +{"values": ["computercraft:computer_normal", "computercraft:computer_advanced", "computercraft:computer_command"]} diff --git a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/monitor.json b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/monitor.json index 6e4da8ff4..c785ed666 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/monitor.json +++ b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/monitor.json @@ -1 +1 @@ -{"replace": false, "values": ["computercraft:monitor_normal", "computercraft:monitor_advanced"]} +{"values": ["computercraft:monitor_normal", "computercraft:monitor_advanced"]} diff --git a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/peripheral_hub_ignore.json b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/peripheral_hub_ignore.json index 94cd7b2e9..cc8178826 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/peripheral_hub_ignore.json +++ b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/peripheral_hub_ignore.json @@ -1 +1 @@ -{"replace": false, "values": ["#computercraft:wired_modem"]} +{"values": ["#computercraft:wired_modem"]} diff --git a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle.json b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle.json index 2db823bf0..10ee058bf 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle.json +++ b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle.json @@ -1 +1 @@ -{"replace": false, "values": ["computercraft:turtle_normal", "computercraft:turtle_advanced"]} +{"values": ["computercraft:turtle_normal", "computercraft:turtle_advanced"]} diff --git a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_always_breakable.json b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_always_breakable.json index 21f9e4f15..0a7481abd 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_always_breakable.json +++ b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_always_breakable.json @@ -1 +1 @@ -{"replace": false, "values": ["#minecraft:leaves", "minecraft:bamboo", "minecraft:bamboo_sapling"]} +{"values": ["#minecraft:leaves", "minecraft:bamboo", "minecraft:bamboo_sapling"]} diff --git a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_can_use.json b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_can_use.json index 713970d69..18c71801e 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_can_use.json +++ b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_can_use.json @@ -1 +1 @@ -{"replace": false, "values": ["#minecraft:beehives", "#minecraft:cauldrons", "minecraft:composter"]} +{"values": ["#minecraft:beehives", "#minecraft:cauldrons", "minecraft:composter"]} diff --git a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_hoe_harvestable.json b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_hoe_harvestable.json index 6f687aeb6..14565b30d 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_hoe_harvestable.json +++ b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_hoe_harvestable.json @@ -1,5 +1,4 @@ { - "replace": false, "values": [ "#minecraft:crops", "#minecraft:mineable/hoe", diff --git a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_shovel_harvestable.json b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_shovel_harvestable.json index 06ba799d8..3538ae3a5 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_shovel_harvestable.json +++ b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_shovel_harvestable.json @@ -1,5 +1,4 @@ { - "replace": false, "values": [ "#minecraft:mineable/shovel", "minecraft:melon", diff --git a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_sword_harvestable.json b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_sword_harvestable.json index a17d3f42f..6dd8645bf 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_sword_harvestable.json +++ b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/turtle_sword_harvestable.json @@ -1 +1 @@ -{"replace": false, "values": ["#minecraft:wool", "minecraft:cobweb"]} +{"values": ["#minecraft:wool", "minecraft:cobweb"]} diff --git a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/wired_modem.json b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/wired_modem.json index bd775eb4d..f37071ed7 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/wired_modem.json +++ b/projects/fabric/src/generated/resources/data/computercraft/tags/blocks/wired_modem.json @@ -1 +1 @@ -{"replace": false, "values": ["computercraft:cable", "computercraft:wired_modem_full"]} +{"values": ["computercraft:cable", "computercraft:wired_modem_full"]} diff --git a/projects/fabric/src/generated/resources/data/computercraft/tags/items/computer.json b/projects/fabric/src/generated/resources/data/computercraft/tags/items/computer.json index 729a9ae47..b3acd11d5 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/tags/items/computer.json +++ b/projects/fabric/src/generated/resources/data/computercraft/tags/items/computer.json @@ -1,4 +1 @@ -{ - "replace": false, - "values": ["computercraft:computer_normal", "computercraft:computer_advanced", "computercraft:computer_command"] -} +{"values": ["computercraft:computer_normal", "computercraft:computer_advanced", "computercraft:computer_command"]} diff --git a/projects/fabric/src/generated/resources/data/computercraft/tags/items/dyeable.json b/projects/fabric/src/generated/resources/data/computercraft/tags/items/dyeable.json new file mode 100644 index 000000000..9a1d985ee --- /dev/null +++ b/projects/fabric/src/generated/resources/data/computercraft/tags/items/dyeable.json @@ -0,0 +1,8 @@ +{ + "values": [ + "#computercraft:turtle", + "computercraft:disk", + "computercraft:pocket_computer_normal", + "computercraft:pocket_computer_advanced" + ] +} diff --git a/projects/fabric/src/generated/resources/data/computercraft/tags/items/monitor.json b/projects/fabric/src/generated/resources/data/computercraft/tags/items/monitor.json index 6e4da8ff4..c785ed666 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/tags/items/monitor.json +++ b/projects/fabric/src/generated/resources/data/computercraft/tags/items/monitor.json @@ -1 +1 @@ -{"replace": false, "values": ["computercraft:monitor_normal", "computercraft:monitor_advanced"]} +{"values": ["computercraft:monitor_normal", "computercraft:monitor_advanced"]} diff --git a/projects/fabric/src/generated/resources/data/computercraft/tags/items/turtle.json b/projects/fabric/src/generated/resources/data/computercraft/tags/items/turtle.json index 2db823bf0..10ee058bf 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/tags/items/turtle.json +++ b/projects/fabric/src/generated/resources/data/computercraft/tags/items/turtle.json @@ -1 +1 @@ -{"replace": false, "values": ["computercraft:turtle_normal", "computercraft:turtle_advanced"]} +{"values": ["computercraft:turtle_normal", "computercraft:turtle_advanced"]} diff --git a/projects/fabric/src/generated/resources/data/computercraft/tags/items/turtle_can_place.json b/projects/fabric/src/generated/resources/data/computercraft/tags/items/turtle_can_place.json index d9bd78575..d2f8770ac 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/tags/items/turtle_can_place.json +++ b/projects/fabric/src/generated/resources/data/computercraft/tags/items/turtle_can_place.json @@ -1 +1 @@ -{"replace": false, "values": ["minecraft:glass_bottle", "#minecraft:boats"]} +{"values": ["minecraft:glass_bottle", "#minecraft:boats"]} diff --git a/projects/fabric/src/generated/resources/data/computercraft/tags/items/wired_modem.json b/projects/fabric/src/generated/resources/data/computercraft/tags/items/wired_modem.json index 7f724b9d1..02f492412 100644 --- a/projects/fabric/src/generated/resources/data/computercraft/tags/items/wired_modem.json +++ b/projects/fabric/src/generated/resources/data/computercraft/tags/items/wired_modem.json @@ -1 +1 @@ -{"replace": false, "values": ["computercraft:wired_modem", "computercraft:wired_modem_full"]} +{"values": ["computercraft:wired_modem", "computercraft:wired_modem_full"]} diff --git a/projects/fabric/src/generated/resources/data/create/tags/blocks/brittle.json b/projects/fabric/src/generated/resources/data/create/tags/blocks/brittle.json index 32e528bcf..137d8de24 100644 --- a/projects/fabric/src/generated/resources/data/create/tags/blocks/brittle.json +++ b/projects/fabric/src/generated/resources/data/create/tags/blocks/brittle.json @@ -1,4 +1 @@ -{ - "replace": false, - "values": ["computercraft:cable", "computercraft:wireless_modem_normal", "computercraft:wireless_modem_advanced"] -} +{"values": ["computercraft:cable", "computercraft:wireless_modem_normal", "computercraft:wireless_modem_advanced"]} diff --git a/projects/fabric/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json b/projects/fabric/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json index 832d21271..e5a4c9d20 100644 --- a/projects/fabric/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json +++ b/projects/fabric/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json @@ -1,5 +1,4 @@ { - "replace": false, "values": [ "computercraft:computer_normal", "computercraft:computer_advanced", diff --git a/projects/fabric/src/generated/resources/data/minecraft/tags/blocks/wither_immune.json b/projects/fabric/src/generated/resources/data/minecraft/tags/blocks/wither_immune.json index acf2c81ae..e1cc18b5d 100644 --- a/projects/fabric/src/generated/resources/data/minecraft/tags/blocks/wither_immune.json +++ b/projects/fabric/src/generated/resources/data/minecraft/tags/blocks/wither_immune.json @@ -1 +1 @@ -{"replace": false, "values": ["computercraft:computer_command"]} +{"values": ["computercraft:computer_command"]} diff --git a/projects/fabric/src/generated/resources/data/minecraft/tags/items/bookshelf_books.json b/projects/fabric/src/generated/resources/data/minecraft/tags/items/bookshelf_books.json index d34c32bfe..ea1e2e76a 100644 --- a/projects/fabric/src/generated/resources/data/minecraft/tags/items/bookshelf_books.json +++ b/projects/fabric/src/generated/resources/data/minecraft/tags/items/bookshelf_books.json @@ -1 +1 @@ -{"replace": false, "values": ["computercraft:printed_book"]} +{"values": ["computercraft:printed_book"]} diff --git a/projects/fabric/src/generated/resources/data/minecraft/tags/items/piglin_loved.json b/projects/fabric/src/generated/resources/data/minecraft/tags/items/piglin_loved.json index 534e2a988..73068ed5d 100644 --- a/projects/fabric/src/generated/resources/data/minecraft/tags/items/piglin_loved.json +++ b/projects/fabric/src/generated/resources/data/minecraft/tags/items/piglin_loved.json @@ -1,5 +1,4 @@ { - "replace": false, "values": [ "computercraft:computer_advanced", "computercraft:turtle_advanced", diff --git a/projects/fabric/src/main/java/dan200/computercraft/data/FabricDataGenerators.java b/projects/fabric/src/main/java/dan200/computercraft/data/FabricDataGenerators.java index 706dcaa67..42e11d813 100644 --- a/projects/fabric/src/main/java/dan200/computercraft/data/FabricDataGenerators.java +++ b/projects/fabric/src/main/java/dan200/computercraft/data/FabricDataGenerators.java @@ -14,13 +14,13 @@ import net.fabricmc.fabric.api.datagen.v1.provider.SimpleFabricLootTableProvider; import net.minecraft.core.HolderLookup; import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.data.CachedOutput; import net.minecraft.data.DataProvider; import net.minecraft.data.PackOutput; import net.minecraft.data.loot.LootTableProvider; import net.minecraft.data.models.BlockModelGenerators; import net.minecraft.data.models.ItemModelGenerators; import net.minecraft.data.tags.TagsProvider; +import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.PackType; import net.minecraft.tags.TagKey; @@ -31,6 +31,7 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; +import java.util.function.BiFunction; import java.util.function.Consumer; public class FabricDataGenerators implements DataGeneratorEntrypoint { @@ -38,7 +39,6 @@ public class FabricDataGenerators implements DataGeneratorEntrypoint { public void onInitializeDataGenerator(FabricDataGenerator generator) { var pack = new PlatformGeneratorsImpl(generator.createPack()); DataProviders.add(pack); - pack.addWithRegistries((out, reg) -> addName("Conventional Tags", new MoreConventionalTagsProvider(out, reg))); } private record PlatformGeneratorsImpl(FabricDataGenerator.Pack generator) implements DataProviders.GeneratorSink { @@ -52,24 +52,29 @@ public T addWithRegistries(FabricDataGenerator.Pack.Reg @Override public T add(DataProvider.Factory factory) { - return generator.addProvider((PackOutput p) -> new PrettyDataProvider<>(factory.create(p))).provider(); + return addWithFabricOutput(factory::create); + } + + @Override + public T add(BiFunction, T> factory) { + return addWithRegistries(factory::apply); } @Override public void addFromCodec(String name, PackType type, String directory, Codec codec, Consumer> output) { - addWithFabricOutput((FabricDataOutput out) -> { + addWithRegistries((out, registries) -> { var ourType = switch (type) { case SERVER_DATA -> PackOutput.Target.DATA_PACK; case CLIENT_RESOURCES -> PackOutput.Target.RESOURCE_PACK; }; - return new FabricCodecDataProvider(out, ourType, directory, codec) { + return new FabricCodecDataProvider(out, registries, ourType, directory, codec) { @Override public String getName() { return name; } @Override - protected void configure(BiConsumer provider) { + protected void configure(BiConsumer provider, HolderLookup.Provider registries) { output.accept(provider); } }; @@ -79,10 +84,10 @@ protected void configure(BiConsumer provider) { @Override public void lootTable(List tables) { for (var table : tables) { - addWithFabricOutput((FabricDataOutput out) -> new SimpleFabricLootTableProvider(out, table.paramSet()) { + addWithRegistries((out, registries) -> new SimpleFabricLootTableProvider(out, registries, table.paramSet()) { @Override - public void generate(BiConsumer exporter) { - table.provider().get().generate(exporter); + public void generate(HolderLookup.Provider registries, BiConsumer, LootTable.Builder> exporter) { + table.provider().get().generate(registries, exporter); } }); } @@ -134,26 +139,4 @@ public void generateItemModels(ItemModelGenerators generator) { }); } } - - - /** - * Add a name to a data provider to disambiguate them. - * - * @param suffix The suffix to add. - * @param provider The data provider to wrap. - * @return The wrapped data provider. - */ - private static DataProvider addName(String suffix, DataProvider provider) { - return new DataProvider() { - @Override - public CompletableFuture run(CachedOutput output) { - return provider.run(output); - } - - @Override - public String getName() { - return provider.getName() + " - " + suffix; - } - }; - } } diff --git a/projects/fabric/src/main/java/dan200/computercraft/data/MoreConventionalTagsProvider.java b/projects/fabric/src/main/java/dan200/computercraft/data/MoreConventionalTagsProvider.java deleted file mode 100644 index 97c07e4db..000000000 --- a/projects/fabric/src/main/java/dan200/computercraft/data/MoreConventionalTagsProvider.java +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers -// -// SPDX-License-Identifier: MPL-2.0 - -package dan200.computercraft.data; - -import dan200.computercraft.shared.platform.MoreConventionalTags; -import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; -import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider; -import net.minecraft.core.HolderLookup; -import net.minecraft.world.item.Items; - -import java.util.concurrent.CompletableFuture; - -public class MoreConventionalTagsProvider extends FabricTagProvider.ItemTagProvider { - public MoreConventionalTagsProvider(FabricDataOutput output, CompletableFuture providers) { - super(output, providers); - } - - @Override - protected void addTags(HolderLookup.Provider arg) { - getOrCreateTagBuilder(MoreConventionalTags.SKULLS).add( - Items.CREEPER_HEAD, Items.DRAGON_HEAD, Items.PLAYER_HEAD, Items.SKELETON_SKULL, Items.WITHER_SKELETON_SKULL, - Items.ZOMBIE_HEAD - ); - getOrCreateTagBuilder(MoreConventionalTags.WOODEN_CHESTS).add(Items.CHEST, Items.TRAPPED_CHEST); - } -} diff --git a/projects/fabric/src/main/java/dan200/computercraft/shared/ComputerCraft.java b/projects/fabric/src/main/java/dan200/computercraft/shared/ComputerCraft.java index fd0951fc7..eeeabf821 100644 --- a/projects/fabric/src/main/java/dan200/computercraft/shared/ComputerCraft.java +++ b/projects/fabric/src/main/java/dan200/computercraft/shared/ComputerCraft.java @@ -22,7 +22,6 @@ import dan200.computercraft.shared.peripheral.modem.wired.WiredModemFullBlockEntity; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemBlockEntity; import dan200.computercraft.shared.platform.FabricConfigFile; -import dan200.computercraft.shared.platform.FabricMessageType; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; @@ -31,11 +30,14 @@ import net.fabricmc.fabric.api.event.player.UseBlockCallback; import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents; import net.fabricmc.fabric.api.loot.v2.LootTableEvents; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.PackType; import net.minecraft.server.packs.resources.PreparableReloadListener; @@ -51,10 +53,11 @@ public class ComputerCraft { private static final LevelResource SERVERCONFIG = new LevelResource("serverconfig"); public static void init() { + for (var type : NetworkMessages.getServerbound()) registerPayloadType(PayloadTypeRegistry.playC2S(), type); + for (var type : NetworkMessages.getClientbound()) registerPayloadType(PayloadTypeRegistry.playS2C(), type); + for (var type : NetworkMessages.getServerbound()) { - ServerPlayNetworking.registerGlobalReceiver( - FabricMessageType.toFabricType(type), (packet, player, sender) -> packet.payload().handle(() -> player) - ); + ServerPlayNetworking.registerGlobalReceiver(type.type(), (packet, player) -> packet.handle(player::player)); } ModRegistry.register(); @@ -107,7 +110,7 @@ public static void init() { PlayerBlockBreakEvents.BEFORE.register(FabricCommonHooks::onBlockDestroy); UseBlockCallback.EVENT.register(FabricCommonHooks::useOnBlock); - LootTableEvents.MODIFY.register((resourceManager, lootManager, id, tableBuilder, source) -> { + LootTableEvents.MODIFY.register((id, tableBuilder, source) -> { var pool = CommonHooks.getExtraLootPool(id); if (pool != null) tableBuilder.withPool(pool); }); @@ -126,6 +129,10 @@ public static void init() { Peripherals.addGenericLookup(InventoryMethods::extractContainer); } + private static void registerPayloadType(PayloadTypeRegistry registry, CustomPacketPayload.TypeAndCodec type) { + registry.register(type.type(), type.codec()); + } + private record ReloadListener(String name, PreparableReloadListener listener) implements IdentifiableResourceReloadListener { diff --git a/projects/fabric/src/main/java/dan200/computercraft/shared/FabricCommonHooks.java b/projects/fabric/src/main/java/dan200/computercraft/shared/FabricCommonHooks.java index 73a1ab689..bfcbf2b0c 100644 --- a/projects/fabric/src/main/java/dan200/computercraft/shared/FabricCommonHooks.java +++ b/projects/fabric/src/main/java/dan200/computercraft/shared/FabricCommonHooks.java @@ -43,8 +43,8 @@ public static InteractionResult useOnBlock(Player player, Level level, Interacti if (block.getBlock() != ModRegistry.Blocks.DISK_DRIVE.get()) return InteractionResult.PASS; if (player.isSecondaryUseActive() && doesSneakBypassUse(player.getMainHandItem()) && doesSneakBypassUse(player.getOffhandItem())) { - var result = block.use(level, player, hand, hitResult); - if (result.consumesAction()) return result; + var result = block.useItemOn(player.getMainHandItem(), level, player, hand, hitResult); + if (result.consumesAction()) return result.result(); } return InteractionResult.PASS; diff --git a/projects/fabric/src/main/java/dan200/computercraft/shared/platform/FabricMessageType.java b/projects/fabric/src/main/java/dan200/computercraft/shared/platform/FabricMessageType.java deleted file mode 100644 index 885b2d971..000000000 --- a/projects/fabric/src/main/java/dan200/computercraft/shared/platform/FabricMessageType.java +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers -// -// SPDX-License-Identifier: MPL-2.0 - -package dan200.computercraft.shared.platform; - -import dan200.computercraft.shared.network.MessageType; -import dan200.computercraft.shared.network.NetworkMessage; -import net.fabricmc.fabric.api.networking.v1.FabricPacket; -import net.fabricmc.fabric.api.networking.v1.PacketType; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.resources.ResourceLocation; - -import java.util.function.Function; - -/** - * An implementation of {@link MessageType} for Fabric. - *

- * This provides conversions between the {@link FabricPacket}/{@link PacketType} and {@link NetworkMessage}/{@link MessageType} - * interfaces, allowing us to interop between the two. - * - * @param type The underlying {@link PacketType} - * @param The type of the message. - */ -public record FabricMessageType>( - PacketType> type -) implements MessageType { - public FabricMessageType(ResourceLocation id, Function reader) { - this(PacketType.create(id, b -> new PacketWrapper<>(reader.apply(b)))); - } - - @Override - public ResourceLocation id() { - return type().getId(); - } - - public static > PacketType> toFabricType(MessageType type) { - return ((FabricMessageType) type).type(); - } - - public static FabricPacket toFabricPacket(NetworkMessage message) { - return new PacketWrapper<>(message); - } - - public record PacketWrapper>(T payload) implements FabricPacket { - @Override - public void write(FriendlyByteBuf buf) { - payload().write(buf); - } - - @Override - public PacketType getType() { - return FabricMessageType.toFabricType(payload().type()); - } - } -} diff --git a/projects/fabric/src/main/java/dan200/computercraft/shared/platform/FakePlayer.java b/projects/fabric/src/main/java/dan200/computercraft/shared/platform/FakePlayer.java index 4bce69373..978970b81 100644 --- a/projects/fabric/src/main/java/dan200/computercraft/shared/platform/FakePlayer.java +++ b/projects/fabric/src/main/java/dan200/computercraft/shared/platform/FakePlayer.java @@ -15,8 +15,11 @@ import static dan200.computercraft.shared.platform.FakePlayerConstants.MAX_REACH; public final class FakePlayer extends net.fabricmc.fabric.api.entity.FakePlayer { + private static final EntityDimensions DIMENSIONS = EntityDimensions.fixed(0, 0); + private FakePlayer(ServerLevel serverLevel, GameProfile gameProfile) { super(serverLevel, gameProfile); + refreshDimensions(); } static FakePlayer create(ServerLevel serverLevel, GameProfile profile) { @@ -33,11 +36,12 @@ public void die(DamageSource damageSource) { } @Override - public float getStandingEyeHeight(Pose pose, EntityDimensions dimensions) { - return 0; + public EntityDimensions getDefaultDimensions(Pose pose) { + return DIMENSIONS; } public double getBlockReach() { + // TODO: Replace with normal reach attribute return MAX_REACH; } diff --git a/projects/fabric/src/main/java/dan200/computercraft/shared/platform/MoreConventionalTags.java b/projects/fabric/src/main/java/dan200/computercraft/shared/platform/MoreConventionalTags.java deleted file mode 100644 index 0aa89af3d..000000000 --- a/projects/fabric/src/main/java/dan200/computercraft/shared/platform/MoreConventionalTags.java +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers -// -// SPDX-License-Identifier: MPL-2.0 - -package dan200.computercraft.shared.platform; - -import net.fabricmc.fabric.api.tag.convention.v1.ConventionalItemTags; -import net.minecraft.core.registries.Registries; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.tags.TagKey; -import net.minecraft.world.item.Item; - -/** - * Extension to {@link ConventionalItemTags}. - *

- * Try to keep these consistent with the wiki page. - */ -public class MoreConventionalTags { - public static final TagKey SKULLS = item("skulls"); - public static final TagKey WOODEN_CHESTS = item("wooden_chests"); - - private static TagKey item(String name) { - return TagKey.create(Registries.ITEM, new ResourceLocation("c", name)); - } -} 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 1187a03e1..c2d358ccc 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 @@ -9,6 +9,7 @@ import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.serialization.JsonOps; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.network.wired.WiredElement; import dan200.computercraft.api.network.wired.WiredElementLookup; @@ -17,9 +18,6 @@ import dan200.computercraft.impl.Peripherals; import dan200.computercraft.mixin.ArgumentTypeInfosAccessor; import dan200.computercraft.shared.config.ConfigFile; -import dan200.computercraft.shared.network.MessageType; -import dan200.computercraft.shared.network.NetworkMessage; -import dan200.computercraft.shared.network.client.ClientNetworkContext; import dan200.computercraft.shared.network.container.ContainerData; import dan200.computercraft.shared.util.InventoryUtil; import net.fabricmc.fabric.api.event.player.AttackEntityCallback; @@ -28,14 +26,12 @@ import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup; import net.fabricmc.fabric.api.lookup.v1.block.BlockApiCache; import net.fabricmc.fabric.api.lookup.v1.block.BlockApiLookup; -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; import net.fabricmc.fabric.api.registry.FuelRegistry; -import net.fabricmc.fabric.api.resource.conditions.v1.DefaultResourceConditions; +import net.fabricmc.fabric.api.resource.conditions.v1.ResourceCondition; import net.fabricmc.fabric.api.resource.conditions.v1.ResourceConditions; import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerType; -import net.fabricmc.fabric.api.tag.convention.v1.ConventionalItemTags; +import net.fabricmc.fabric.api.tag.convention.v2.ConventionalItemTags; import net.fabricmc.fabric.api.transfer.v1.item.InventoryStorage; import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage; import net.fabricmc.loader.api.FabricLoader; @@ -44,10 +40,9 @@ import net.minecraft.core.Direction; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.common.ClientCommonPacketListener; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; @@ -70,9 +65,7 @@ import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.Recipe; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.EntityHitResult; @@ -82,7 +75,9 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.function.*; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.Supplier; @AutoService(dan200.computercraft.impl.PlatformHelper.class) public class PlatformHelperImpl implements PlatformHelper { @@ -110,7 +105,7 @@ public RegistrationHelper createRegistrationHelper(ResourceKey BlockEntityType createBlockEntityType(BiFunction factory, Block block) { - return FabricBlockEntityTypeBuilder.create(factory::apply).addBlock(block).build(); + conditions.add(ResourceCondition.CODEC.encodeStart(JsonOps.INSTANCE, ResourceConditions.allModsLoaded(modId)).getOrThrow()); } @Override @@ -136,23 +126,13 @@ public , T extends ArgumentTypeInfo.Template, I ext } @Override - public MenuType createMenuType(Function reader, ContainerData.Factory factory) { - return new ExtendedScreenHandlerType<>((id, player, data) -> factory.create(id, player, reader.apply(data))); + public MenuType createMenuType(StreamCodec codec, ContainerData.Factory factory) { + return new ExtendedScreenHandlerType<>(factory::create, codec); } @Override public void openMenu(Player player, MenuProvider owner, ContainerData menu) { - player.openMenu(new WrappedMenuProvider(owner, menu)); - } - - @Override - public > MessageType createMessageType(ResourceLocation channel, FriendlyByteBuf.Reader reader) { - return new FabricMessageType<>(channel, reader); - } - - @Override - public Packet createPacket(NetworkMessage message) { - return ServerPlayNetworking.createS2CPacket(FabricMessageType.toFabricPacket(message)); + player.openMenu(new WrappedMenuProvider<>(owner, menu)); } @Override @@ -196,10 +176,9 @@ public RecipeIngredients getRecipeIngredients() { Ingredient.of(ConventionalItemTags.GOLD_INGOTS), Ingredient.of(Items.GOLD_BLOCK), Ingredient.of(ConventionalItemTags.IRON_INGOTS), - Ingredient.of(MoreConventionalTags.SKULLS), Ingredient.of(ConventionalItemTags.DYES), Ingredient.of(Items.ENDER_PEARL), - Ingredient.of(MoreConventionalTags.WOODEN_CHESTS) + Ingredient.of(ConventionalItemTags.WOODEN_CHESTS) ); } @@ -286,8 +265,11 @@ public InteractionResult useOn(ServerPlayer player, ItemStack stack, BlockHitRes var block = player.level().getBlockState(hit.getBlockPos()); if (!block.isAir() && canUseBlock.test(block)) { - var useResult = block.use(player.level(), player, InteractionHand.MAIN_HAND, hit); - if (useResult.consumesAction()) return useResult; + var useResult = block.useItemOn(stack, player.level(), player, InteractionHand.MAIN_HAND, hit); + if (useResult.consumesAction()) return useResult.result(); + + // TODO(1.20.5): Should we do this unconditionally now? Or at least a better way of configuring it. + // TODO(1.20.5: What to do with useWithoutItem } return stack.useOn(new UseOnContext(player, InteractionHand.MAIN_HAND, hit)); @@ -340,7 +322,9 @@ public T get() { } } - private record WrappedMenuProvider(MenuProvider owner, ContainerData menu) implements ExtendedScreenHandlerFactory { + private record WrappedMenuProvider( + MenuProvider owner, T menu + ) implements ExtendedScreenHandlerFactory { @Nullable @Override public AbstractContainerMenu createMenu(int id, Inventory inventory, Player player) { @@ -353,8 +337,8 @@ public Component getDisplayName() { } @Override - public void writeScreenOpeningData(ServerPlayer player, FriendlyByteBuf buf) { - menu.toBytes(buf); + public T getScreenOpeningData(ServerPlayer player) { + return menu; } } diff --git a/projects/fabric/src/main/resources/fabric.mod.json b/projects/fabric/src/main/resources/fabric.mod.json index 33e99e61b..2d7fef45b 100644 --- a/projects/fabric/src/main/resources/fabric.mod.json +++ b/projects/fabric/src/main/resources/fabric.mod.json @@ -45,9 +45,9 @@ } ], "depends": { - "fabricloader": ">=0.14.21", - "fabric-api": ">=0.86.1", - "minecraft": "=1.20.4" + "fabricloader": ">=0.15.10", + "fabric-api": ">=0.97.3", + "minecraft": "=1.20.5" }, "accessWidener": "computercraft.accesswidener" } diff --git a/projects/forge/build.gradle.kts b/projects/forge/build.gradle.kts index 8eb1edf3c..7eafe4a32 100644 --- a/projects/forge/build.gradle.kts +++ b/projects/forge/build.gradle.kts @@ -126,25 +126,11 @@ dependencies { clientApi(clientClasses(project(":forge-api"))) { cct.exclude(this) } implementation(project(":core")) { cct.exclude(this) } - "minecraftLibrary"(libs.cobalt) { - val version = libs.versions.cobalt.get() - jarJar.ranged(this, "[$version,${getNextVersion(version)})") - } - "minecraftLibrary"(libs.jzlib) { - jarJar.ranged(this, "[${libs.versions.jzlib.get()},)") - } - "minecraftLibrary"(libs.netty.http) { - jarJar.ranged(this, "[${libs.versions.netty.get()},)") - isTransitive = false - } - "minecraftLibrary"(libs.netty.socks) { - jarJar.ranged(this, "[${libs.versions.netty.get()},)") - isTransitive = false - } - "minecraftLibrary"(libs.netty.proxy) { - jarJar.ranged(this, "[${libs.versions.netty.get()},)") - isTransitive = false - } + "minecraftLibrary"(libs.cobalt) + "minecraftLibrary"(libs.jzlib) + "minecraftLibrary"(libs.netty.http) + "minecraftLibrary"(libs.netty.socks) + "minecraftLibrary"(libs.netty.proxy) testFixturesApi(libs.bundles.test) testFixturesApi(libs.bundles.kotlin) @@ -186,6 +172,8 @@ tasks.sourcesJar { for (source in cct.sourceDirectories.get()) from(source.sourceSet.allSource) } +jarJar.enable() + tasks.jarJar { archiveClassifier.set("") configuration(project.configurations["minecraftLibrary"]) @@ -203,11 +191,6 @@ tasks.test { systemProperty("cct.test-files", layout.buildDirectory.dir("tmp/testFiles").getAbsolutePath()) } -tasks.checkDependencyConsistency { - // Forge pulls in slf4j 2.0.9 instead of 2.0.7, so we need to override that. - override(libs.slf4j.asProvider(), "2.0.9") -} - val runGametest by tasks.registering(JavaExec::class) { group = LifecycleBasePlugin.VERIFICATION_GROUP description = "Runs tests on a temporary Minecraft instance." @@ -250,8 +233,6 @@ tasks.withType(GenerateModuleMetadata::class).configureEach { isEnabled = false publishing { publications { named("maven", MavenPublication::class) { - jarJar.component(this) - mavenDependencies { cct.configureExcludes(this) } diff --git a/projects/forge/src/client/java/dan200/computercraft/client/ForgeClientHooks.java b/projects/forge/src/client/java/dan200/computercraft/client/ForgeClientHooks.java index ec406e85a..22371b56e 100644 --- a/projects/forge/src/client/java/dan200/computercraft/client/ForgeClientHooks.java +++ b/projects/forge/src/client/java/dan200/computercraft/client/ForgeClientHooks.java @@ -9,7 +9,7 @@ import net.minecraft.commands.CommandSourceStack; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.Mod; +import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.neoforge.client.event.*; import net.neoforged.neoforge.client.event.sound.PlayStreamingSourceEvent; import net.neoforged.neoforge.event.TickEvent; @@ -18,7 +18,7 @@ /** * Forge-specific dispatch for {@link ClientHooks}. */ -@Mod.EventBusSubscriber(modid = ComputerCraftAPI.MOD_ID, value = Dist.CLIENT) +@EventBusSubscriber(modid = ComputerCraftAPI.MOD_ID, value = Dist.CLIENT) public final class ForgeClientHooks { private ForgeClientHooks() { } diff --git a/projects/forge/src/client/java/dan200/computercraft/client/ForgeClientRegistry.java b/projects/forge/src/client/java/dan200/computercraft/client/ForgeClientRegistry.java index 212075c51..81279dbf0 100644 --- a/projects/forge/src/client/java/dan200/computercraft/client/ForgeClientRegistry.java +++ b/projects/forge/src/client/java/dan200/computercraft/client/ForgeClientRegistry.java @@ -14,7 +14,7 @@ import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.ModLoader; -import net.neoforged.fml.common.Mod; +import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; import net.neoforged.neoforge.client.event.*; @@ -23,7 +23,7 @@ /** * Registers textures and models for items. */ -@Mod.EventBusSubscriber(modid = ComputerCraftAPI.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD) +@EventBusSubscriber(modid = ComputerCraftAPI.MOD_ID, value = Dist.CLIENT, bus = EventBusSubscriber.Bus.MOD) public final class ForgeClientRegistry { private static final Object lock = new Object(); private static boolean gatheredModellers = false; @@ -49,7 +49,7 @@ private static void gatherModellers() { if (gatheredModellers) return; gatheredModellers = true; - ModLoader.get().postEvent(new RegisterTurtleModellersEvent(TurtleUpgradeModellers::register)); + ModLoader.postEvent(new RegisterTurtleModellersEvent(TurtleUpgradeModellers::register)); } } diff --git a/projects/forge/src/client/java/dan200/computercraft/client/platform/ClientPlatformHelperImpl.java b/projects/forge/src/client/java/dan200/computercraft/client/platform/ClientPlatformHelperImpl.java index d985ba9f6..381b8dd7c 100644 --- a/projects/forge/src/client/java/dan200/computercraft/client/platform/ClientPlatformHelperImpl.java +++ b/projects/forge/src/client/java/dan200/computercraft/client/platform/ClientPlatformHelperImpl.java @@ -8,18 +8,12 @@ import com.mojang.blaze3d.vertex.PoseStack; import dan200.computercraft.client.model.FoiledModel; import dan200.computercraft.client.render.ModelRenderer; -import dan200.computercraft.shared.network.NetworkMessage; -import dan200.computercraft.shared.network.server.ServerNetworkContext; -import dan200.computercraft.shared.platform.ForgeMessageType; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.ModelManager; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.common.ServerCommonPacketListener; -import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvent; import net.minecraft.util.RandomSource; @@ -44,11 +38,6 @@ public BakedModel createdFoiledModel(BakedModel model) { return new FoiledModel(model); } - @Override - public Packet createPacket(NetworkMessage message) { - return new ServerboundCustomPayloadPacket(ForgeMessageType.createPayload(message)); - } - @Override public void renderBakedModel(PoseStack transform, MultiBufferSource buffers, BakedModel model, int lightmapCoord, int overlayLight, @Nullable int[] tints) { for (var renderType : model.getRenderTypes(ItemStack.EMPTY, true)) { diff --git a/projects/forge/src/main/java/dan200/computercraft/ComputerCraft.java b/projects/forge/src/main/java/dan200/computercraft/ComputerCraft.java index 4c11b9d31..a4d1e30b6 100644 --- a/projects/forge/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/projects/forge/src/main/java/dan200/computercraft/ComputerCraft.java @@ -18,8 +18,10 @@ import dan200.computercraft.shared.config.Config; import dan200.computercraft.shared.config.ConfigSpec; import dan200.computercraft.shared.details.FluidData; +import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.NetworkMessages; import dan200.computercraft.shared.network.client.ClientNetworkContext; +import dan200.computercraft.shared.network.server.ServerNetworkContext; import dan200.computercraft.shared.peripheral.commandblock.CommandBlockPeripheral; import dan200.computercraft.shared.peripheral.generic.methods.EnergyMethods; import dan200.computercraft.shared.peripheral.generic.methods.FluidMethods; @@ -28,12 +30,14 @@ import dan200.computercraft.shared.peripheral.modem.wired.WiredModemFullBlockEntity; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemBlockEntity; import dan200.computercraft.shared.platform.ForgeConfigFile; -import dan200.computercraft.shared.platform.ForgeMessageType; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.level.block.entity.BlockEntityType; import net.neoforged.bus.api.IEventBus; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.ModLoadingContext; +import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.fml.common.Mod; import net.neoforged.fml.config.ModConfig; import net.neoforged.fml.event.config.ModConfigEvent; @@ -41,22 +45,24 @@ import net.neoforged.neoforge.capabilities.Capabilities; import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent; import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent; -import net.neoforged.neoforge.network.event.RegisterPayloadHandlerEvent; +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; +import net.neoforged.neoforge.network.registration.PayloadRegistrar; import net.neoforged.neoforge.registries.NewRegistryEvent; import net.neoforged.neoforge.registries.RegistryBuilder; import javax.annotation.Nullable; @Mod(ComputerCraftAPI.MOD_ID) -@Mod.EventBusSubscriber(modid = ComputerCraftAPI.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) +@EventBusSubscriber(modid = ComputerCraftAPI.MOD_ID, bus = EventBusSubscriber.Bus.MOD) public final class ComputerCraft { private static @Nullable IEventBus eventBus; public ComputerCraft(IEventBus eventBus) { withEventBus(eventBus, ModRegistry::register); - ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, ((ForgeConfigFile) ConfigSpec.serverSpec).spec()); - ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, ((ForgeConfigFile) ConfigSpec.clientSpec).spec()); + var container = ModLoadingContext.get().getActiveContainer(); + container.registerConfig(ModConfig.Type.SERVER, ((ForgeConfigFile) ConfigSpec.serverSpec).spec()); + container.registerConfig(ModConfig.Type.CLIENT, ((ForgeConfigFile) ConfigSpec.clientSpec).spec()); } private static void withEventBus(IEventBus eventBus, Runnable task) { @@ -93,22 +99,19 @@ public static void init(FMLCommonSetupEvent event) { } @SubscribeEvent - public static void registerNetwork(RegisterPayloadHandlerEvent event) { + public static void registerNetwork(RegisterPayloadHandlersEvent event) { var registrar = event.registrar(ComputerCraftAPI.MOD_ID).versioned(ComputerCraftAPI.getInstalledVersion()); - for (var type : NetworkMessages.getServerbound()) { - var forgeType = ForgeMessageType.cast(type); - registrar.play(forgeType.id(), forgeType.reader(), builder -> builder.server( - (t, context) -> context.workHandler().execute(() -> t.payload().handle(() -> (ServerPlayer) context.player().orElseThrow())) - )); - } + for (var type : NetworkMessages.getServerbound()) registerServerbound(registrar, type); + for (var type : NetworkMessages.getClientbound()) registerClientbound(registrar, type); + } - for (var type : NetworkMessages.getClientbound()) { - var forgeType = ForgeMessageType.cast(type); - registrar.play(forgeType.id(), forgeType.reader(), builder -> builder.client( - (t, context) -> context.workHandler().execute(() -> t.payload().handle(ClientHolderHolder.get())) - )); - } + private static > void registerServerbound(PayloadRegistrar registrar, CustomPacketPayload.TypeAndCodec type) { + registrar.playToServer(type.type(), type.codec(), (t, context) -> context.enqueueWork(() -> t.handle(() -> (ServerPlayer) context.player()))); + } + + private static > void registerClientbound(PayloadRegistrar registrar, CustomPacketPayload.TypeAndCodec type) { + registrar.playToClient(type.type(), type.codec(), (t, context) -> context.enqueueWork(() -> t.handle(ClientHolderHolder.get()))); } /** diff --git a/projects/forge/src/main/java/dan200/computercraft/data/Generators.java b/projects/forge/src/main/java/dan200/computercraft/data/Generators.java index 48126ef7c..e52c9de35 100644 --- a/projects/forge/src/main/java/dan200/computercraft/data/Generators.java +++ b/projects/forge/src/main/java/dan200/computercraft/data/Generators.java @@ -22,7 +22,7 @@ import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.Mod; +import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.neoforge.common.data.BlockTagsProvider; import net.neoforged.neoforge.common.data.ExistingFileHelper; import net.neoforged.neoforge.common.data.JsonCodecProvider; @@ -32,9 +32,10 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; +import java.util.function.BiFunction; import java.util.function.Consumer; -@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +@EventBusSubscriber(bus = EventBusSubscriber.Bus.MOD) public class Generators { @SubscribeEvent public static void gather(GatherDataEvent event) { @@ -52,6 +53,11 @@ public T add(DataProvider.Factory factory) { return generator.addProvider(p -> new PrettyDataProvider<>(factory.create(p))).provider(); } + @Override + public T add(BiFunction, T> factory) { + return generator.addProvider(p -> factory.apply(p, registries)); + } + @Override public void addFromCodec(String name, PackType type, String directory, Codec codec, Consumer> output) { add(out -> { @@ -70,7 +76,7 @@ protected void gather() { @Override public void lootTable(List tables) { - add(out -> new LootTableProvider(out, Set.of(), tables)); + add((out, registries) -> new LootTableProvider(out, Set.of(), tables, registries)); } @Override diff --git a/projects/forge/src/main/java/dan200/computercraft/shared/ForgeCommonHooks.java b/projects/forge/src/main/java/dan200/computercraft/shared/ForgeCommonHooks.java index 4aed5aaac..7aea705a8 100644 --- a/projects/forge/src/main/java/dan200/computercraft/shared/ForgeCommonHooks.java +++ b/projects/forge/src/main/java/dan200/computercraft/shared/ForgeCommonHooks.java @@ -8,11 +8,13 @@ import dan200.computercraft.shared.command.CommandComputerCraft; import dan200.computercraft.shared.network.client.UpgradesLoadedMessage; import dan200.computercraft.shared.network.server.ServerNetworking; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.chunk.LevelChunk; import net.neoforged.bus.api.EventPriority; import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.Mod; +import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.neoforge.event.*; import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent; import net.neoforged.neoforge.event.entity.living.LivingDropsEvent; @@ -26,7 +28,7 @@ /** * Forge-specific dispatch for {@link CommonHooks}. */ -@Mod.EventBusSubscriber(modid = ComputerCraftAPI.MOD_ID) +@EventBusSubscriber(modid = ComputerCraftAPI.MOD_ID) public class ForgeCommonHooks { @SubscribeEvent public static void onServerTick(TickEvent.ServerTickEvent event) { @@ -90,7 +92,7 @@ public static void onDatapackSync(OnDatapackSyncEvent event) { @SubscribeEvent public static void lootLoad(LootTableLoadEvent event) { - var pool = CommonHooks.getExtraLootPool(event.getName()); + var pool = CommonHooks.getExtraLootPool(ResourceKey.create(Registries.LOOT_TABLE, event.getName())); if (pool != null) event.getTable().addPool(pool.build()); } diff --git a/projects/forge/src/main/java/dan200/computercraft/shared/platform/FakePlayerExt.java b/projects/forge/src/main/java/dan200/computercraft/shared/platform/FakePlayerExt.java index d4d39d396..d05f59ba0 100644 --- a/projects/forge/src/main/java/dan200/computercraft/shared/platform/FakePlayerExt.java +++ b/projects/forge/src/main/java/dan200/computercraft/shared/platform/FakePlayerExt.java @@ -17,9 +17,9 @@ import javax.annotation.Nullable; import java.util.OptionalInt; -import static dan200.computercraft.shared.platform.FakePlayerConstants.MAX_REACH; - class FakePlayerExt extends FakePlayer { + private static final EntityDimensions DIMENSIONS = EntityDimensions.fixed(0, 0); + FakePlayerExt(ServerLevel serverLevel, GameProfile profile) { super(serverLevel, profile); } @@ -45,18 +45,8 @@ public boolean startRiding(Entity vehicle, boolean force) { } @Override - public float getStandingEyeHeight(Pose pose, EntityDimensions dimensions) { - return 0; - } - - @Override - public double getBlockReach() { - return MAX_REACH; - } - - @Override - public double getEntityReach() { - return MAX_REACH; + public EntityDimensions getDefaultDimensions(Pose pose) { + return DIMENSIONS; } @Override diff --git a/projects/forge/src/main/java/dan200/computercraft/shared/platform/ForgeContainerTransfer.java b/projects/forge/src/main/java/dan200/computercraft/shared/platform/ForgeContainerTransfer.java index 3e24c0321..985d3bec7 100644 --- a/projects/forge/src/main/java/dan200/computercraft/shared/platform/ForgeContainerTransfer.java +++ b/projects/forge/src/main/java/dan200/computercraft/shared/platform/ForgeContainerTransfer.java @@ -63,7 +63,7 @@ public static int moveItem(ForgeContainerTransfer src, ForgeContainerTransfer de if (movedStack.isEmpty()) { movedStack = stack.copy(); if (stack.getMaxStackSize() < maxAmount) maxAmount = stack.getMaxStackSize(); - } else if (!ItemStack.isSameItemSameTags(stack, movedStack)) { + } else if (!ItemStack.isSameItemSameComponents(stack, movedStack)) { continue; } diff --git a/projects/forge/src/main/java/dan200/computercraft/shared/platform/ForgeMessageType.java b/projects/forge/src/main/java/dan200/computercraft/shared/platform/ForgeMessageType.java deleted file mode 100644 index 512ed4095..000000000 --- a/projects/forge/src/main/java/dan200/computercraft/shared/platform/ForgeMessageType.java +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers -// -// SPDX-License-Identifier: MPL-2.0 - -package dan200.computercraft.shared.platform; - -import dan200.computercraft.shared.network.MessageType; -import dan200.computercraft.shared.network.NetworkMessage; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -import net.minecraft.resources.ResourceLocation; - -/** - * A {@link MessageType} implementation for Forge. - *

- * This wraps {@link NetworkMessage}s into a {@link CustomPacketPayload}, allowing us to easily use Minecraft's existing - * custom packets. - * - * @param id The id of this message. - * @param reader Read this message from a network buffer. - * @param The type of our {@link NetworkMessage}. - */ -public record ForgeMessageType>( - ResourceLocation id, FriendlyByteBuf.Reader> reader -) implements MessageType { - public static > ForgeMessageType cast(MessageType type) { - return (ForgeMessageType) type; - } - - public static CustomPacketPayload createPayload(NetworkMessage message) { - return new Payload<>(message); - } - - public record Payload>(T payload) implements CustomPacketPayload { - @Override - public void write(FriendlyByteBuf buf) { - payload().write(buf); - } - - @Override - public ResourceLocation id() { - return payload().type().id(); - } - } -} 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 8cb0694b6..9c37bbec3 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 @@ -18,9 +18,6 @@ import dan200.computercraft.api.peripheral.PeripheralCapability; import dan200.computercraft.impl.Peripherals; import dan200.computercraft.shared.config.ConfigFile; -import dan200.computercraft.shared.network.MessageType; -import dan200.computercraft.shared.network.NetworkMessage; -import dan200.computercraft.shared.network.client.ClientNetworkContext; import dan200.computercraft.shared.network.container.ContainerData; import dan200.computercraft.shared.util.InventoryUtil; import net.minecraft.commands.synchronization.ArgumentTypeInfo; @@ -28,10 +25,8 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Registry; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.common.ClientCommonPacketListener; -import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; @@ -54,9 +49,7 @@ import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.Recipe; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; @@ -81,8 +74,9 @@ import java.util.EnumSet; import java.util.List; import java.util.Objects; -import java.util.Set; -import java.util.function.*; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.Supplier; @AutoService(dan200.computercraft.impl.PlatformHelper.class) public class PlatformHelperImpl implements PlatformHelper { @@ -115,13 +109,7 @@ public void addRequiredModCondition(JsonObject object, String modId) { object.add(ConditionalOps.DEFAULT_CONDITIONS_KEY, conditions); } - conditions.add(ICondition.CODEC.encodeStart(JsonOps.INSTANCE, new ModLoadedCondition(modId)).getOrThrow(false, x -> { - })); - } - - @Override - public BlockEntityType createBlockEntityType(BiFunction factory, Block block) { - return new BlockEntityType<>(factory::apply, Set.of(block), null); + conditions.add(ICondition.CODEC.encodeStart(JsonOps.INSTANCE, new ModLoadedCondition(modId)).getOrThrow()); } @Override @@ -130,23 +118,13 @@ public , T extends ArgumentTypeInfo.Template, I ext } @Override - public MenuType createMenuType(Function reader, ContainerData.Factory factory) { - return IMenuTypeExtension.create((id, player, data) -> factory.create(id, player, reader.apply(data))); + public MenuType createMenuType(StreamCodec codec, ContainerData.Factory factory) { + return IMenuTypeExtension.create((id, player, data) -> factory.create(id, player, codec.decode(data))); } @Override public void openMenu(Player player, MenuProvider owner, ContainerData menu) { - ((ServerPlayer) player).openMenu(owner, menu::toBytes); - } - - @Override - public > MessageType createMessageType(ResourceLocation id, FriendlyByteBuf.Reader reader) { - return new ForgeMessageType<>(id, b -> new ForgeMessageType.Payload<>(reader.apply(b))); - } - - @Override - public Packet createPacket(NetworkMessage message) { - return new ClientboundCustomPayloadPacket(ForgeMessageType.createPayload(message)); + player.openMenu(owner, menu::toBytes); } @Override @@ -189,14 +167,13 @@ public ContainerTransfer getContainer(ServerLevel level, BlockPos pos, Direction public RecipeIngredients getRecipeIngredients() { return new RecipeIngredients( Ingredient.of(Tags.Items.DUSTS_REDSTONE), - Ingredient.of(Tags.Items.STRING), - Ingredient.of(Tags.Items.LEATHER), - Ingredient.of(Tags.Items.STONE), + Ingredient.of(Tags.Items.STRINGS), + Ingredient.of(Tags.Items.LEATHERS), + Ingredient.of(Tags.Items.STONES), Ingredient.of(Tags.Items.GLASS_PANES), Ingredient.of(Tags.Items.INGOTS_GOLD), Ingredient.of(Tags.Items.STORAGE_BLOCKS_GOLD), Ingredient.of(Tags.Items.INGOTS_IRON), - Ingredient.of(Tags.Items.HEADS), Ingredient.of(Tags.Items.DYES), Ingredient.of(Tags.Items.ENDER_PEARLS), Ingredient.of(Tags.Items.CHESTS_WOODEN) @@ -227,7 +204,7 @@ public List> getDyeTags() { @Override public int getBurnTime(ItemStack stack) { - return CommonHooks.getBurnTime(stack, null); + return stack.getBurnTime(null); } @Override @@ -263,11 +240,6 @@ public ServerPlayer createFakePlayer(ServerLevel world, GameProfile profile) { return new FakePlayerExt(world, profile); } - @Override - public double getReachDistance(Player player) { - return player.getBlockReach(); - } - @Override public boolean hasToolUsage(ItemStack stack) { return stack.canPerformAction(ToolActions.SHOVEL_FLATTEN) || stack.canPerformAction(ToolActions.HOE_TILL); @@ -305,8 +277,8 @@ public InteractionResult useOn(ServerPlayer player, ItemStack stack, BlockHitRes var block = level.getBlockState(hit.getBlockPos()); if (event.getUseBlock() != Event.Result.DENY && !block.isAir() && canUseBlock.test(block)) { - var useResult = block.use(level, player, InteractionHand.MAIN_HAND, hit); - if (useResult.consumesAction()) return useResult; + var useResult = block.useItemOn(stack, level, player, InteractionHand.MAIN_HAND, hit); + if (useResult.consumesAction()) return useResult.result(); } return event.getUseItem() == Event.Result.DENY ? InteractionResult.PASS : stack.useOn(context); diff --git a/projects/forge/src/main/resources/META-INF/accesstransformer.cfg b/projects/forge/src/main/resources/META-INF/accesstransformer.cfg index b5da3bbda..dcfea532f 100644 --- a/projects/forge/src/main/resources/META-INF/accesstransformer.cfg +++ b/projects/forge/src/main/resources/META-INF/accesstransformer.cfg @@ -12,7 +12,6 @@ protected com.mojang.blaze3d.vertex.VertexBuffer format # ClientTableFormatter public net.minecraft.client.gui.components.ChatComponent allMessages -public net.minecraft.client.gui.components.ChatComponent refreshTrimmedMessage()V # ItemPocketRenderer/ItemPrintoutRenderer public net.minecraft.client.renderer.ItemInHandRenderer calculateMapTilt(F)F @@ -33,3 +32,5 @@ public net.minecraft.data.models.ItemModelGenerators output public net.minecraft.data.models.ItemModelGenerators generateFlatItem(Lnet/minecraft/world/item/Item;Lnet/minecraft/data/models/model/ModelTemplate;)V 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; + +public net.minecraft.util.datafix.fixes.ItemStackComponentizationFix$ItemStackData diff --git a/projects/forge/src/main/resources/META-INF/mods.toml b/projects/forge/src/main/resources/META-INF/mods.toml index 5502fb35f..511f14437 100644 --- a/projects/forge/src/main/resources/META-INF/mods.toml +++ b/projects/forge/src/main/resources/META-INF/mods.toml @@ -26,7 +26,7 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a [[dependencies.computercraft]] modId="neoforge" type="required" - versionRange="[${neoVersion},20.5)" + versionRange="[${neoVersion},20.6)" ordering="NONE" side="BOTH" diff --git a/settings.gradle.kts b/settings.gradle.kts index 774ee0a66..acb91691f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -36,6 +36,10 @@ pluginManagement { } } +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version("0.8.0") +} + val mcVersion: String by settings rootProject.name = "cc-tweaked-$mcVersion"