mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 05:33:00 +00:00 
			
		
		
		
	Update to MC 1.20.6
- Update EMI and REI integration, and fix some issues with the upgrade crafting hooks. - Just use smooth stone for recipes, not #c:stone. We're mirroring redstone's crafting recipes here. - Some cleanup to printouts. - Remote upgrade data generators - these can be replaced with the standard registry data generators. - Remove the API's PlatformHelper - we no longer have any platform-specific code in the API.
This commit is contained in:
		| @@ -30,11 +30,6 @@ subsystems { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| dependencies { | ||||
|     val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs") | ||||
|     implementation("net.neoforged:neoforge:${libs.findVersion("neoForge").get()}") | ||||
| } | ||||
| 
 | ||||
| MinecraftConfigurations.setup(project) | ||||
| 
 | ||||
| extensions.configure(CCTweakedExtension::class.java) { | ||||
|   | ||||
| @@ -56,7 +56,6 @@ repositories { | ||||
|             includeGroup("mezz.jei") | ||||
|             includeGroup("org.teavm") | ||||
|             includeModule("com.terraformersmc", "modmenu") | ||||
|             includeModule("me.lucko", "fabric-permissions-api") | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -13,4 +13,4 @@ isUnstable=true | ||||
| modVersion=1.110.3 | ||||
|  | ||||
| # Minecraft properties: We want to configure this here so we can read it in settings.gradle | ||||
| mcVersion=1.20.5 | ||||
| mcVersion=1.20.6 | ||||
|   | ||||
| @@ -7,14 +7,14 @@ | ||||
| # Minecraft | ||||
| # MC version is specified in gradle.properties, as we need that in settings.gradle. | ||||
| # Remember to update corresponding versions in fabric.mod.json/neoforge.mods.toml | ||||
| fabric-api = "0.97.6+1.20.5" | ||||
| fabric-api = "0.98.0+1.20.6" | ||||
| fabric-loader = "0.15.10" | ||||
| neoForge = "20.5.20-beta" | ||||
| neoForge = "20.6.48-beta" | ||||
| neoForgeSpi = "8.0.1" | ||||
| mixin = "0.8.5" | ||||
| parchment = "2024.04.14" | ||||
| parchmentMc = "1.20.4" | ||||
| yarn = "1.20.5+build.1" | ||||
| parchment = "2024.05.01" | ||||
| parchmentMc = "1.20.6" | ||||
| yarn = "1.20.6+build.1" | ||||
|  | ||||
| # Core dependencies (these versions are tied to the version Minecraft uses) | ||||
| fastutil = "8.5.12" | ||||
| @@ -36,14 +36,14 @@ kotlin-coroutines = "1.7.3" | ||||
| nightConfig = "3.6.7" | ||||
|  | ||||
| # Minecraft mods | ||||
| emi = "1.0.30+1.20.4" | ||||
| fabricPermissions = "0.3.20230723" | ||||
| emi = "1.1.5+1.20.6" | ||||
| fabricPermissions = "0.3.1" | ||||
| iris = "1.6.14+1.20.4" | ||||
| jei = "17.3.0.48" | ||||
| modmenu = "9.0.0" | ||||
| moreRed = "4.0.0.4" | ||||
| oculus = "1.2.5" | ||||
| rei = "14.0.688" | ||||
| rei = "15.0.728" | ||||
| rubidium = "0.6.1" | ||||
| sodium = "mc1.20-0.4.10" | ||||
| mixinExtra = "0.3.5" | ||||
|   | ||||
| @@ -21,4 +21,16 @@ tasks.javadoc { | ||||
| 
 | ||||
|     // Include the core-api in our javadoc export. This is wrong, but it means we can export a single javadoc dump. | ||||
|     source(project(":core-api").sourceSets.main.map { it.allJava }) | ||||
| 
 | ||||
|     options { | ||||
|         this as StandardJavadocDocletOptions | ||||
|         addBooleanOption("-allow-script-in-comments", true) | ||||
|         bottom( | ||||
|             """ | ||||
|             <script src="https://cdn.jsdelivr.net/npm/prismjs@v1.29.0/components/prism-core.min.js"></script> | ||||
|             <script src="https://cdn.jsdelivr.net/npm/prismjs@v1.29.0/plugins/autoloader/prism-autoloader.min.js"></script> | ||||
|             <link href=" https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css " rel="stylesheet"> | ||||
|             """.trimIndent(), | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -4,12 +4,14 @@ | ||||
| 
 | ||||
| package dan200.computercraft.api.pocket; | ||||
| 
 | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
| import dan200.computercraft.api.upgrades.UpgradeBase; | ||||
| import dan200.computercraft.api.upgrades.UpgradeType; | ||||
| import dan200.computercraft.impl.ComputerCraftAPIService; | ||||
| import net.minecraft.core.Registry; | ||||
| import net.minecraft.resources.ResourceKey; | ||||
| import net.minecraft.resources.ResourceLocation; | ||||
| import net.minecraft.world.level.Level; | ||||
| 
 | ||||
| import javax.annotation.Nullable; | ||||
| @@ -21,11 +23,11 @@ import javax.annotation.Nullable; | ||||
|  * {@link UpgradeType} instance, which are then registered in a registry. | ||||
|  * <p> | ||||
|  * You then write a JSON file in your mod's {@literal data/} folder. This is then parsed when the world is loaded, and | ||||
|  * the upgrade automatically registered. It is recommended this is done via {@linkplain PocketUpgradeDataProvider data | ||||
|  * generators}. | ||||
|  * the upgrade automatically registered. It is recommended this is done via | ||||
|  * <a href="../upgrades/UpgradeType.html#datagen">data generators</a>. | ||||
|  * | ||||
|  * <h2>Example</h2> | ||||
|  * <pre>{@code | ||||
|  * {@snippet lang="java" : | ||||
|  * // We use Forge's DeferredRegister to register our upgrade type. Fabric mods may register their type directly. | ||||
|  * static final DeferredRegister<UpgradeType<? extends IPocketUpgrade>> POCKET_UPGRADES = DeferredRegister.create(IPocketUpgrade.typeRegistry(), "my_mod"); | ||||
|  * | ||||
| @@ -35,19 +37,19 @@ import javax.annotation.Nullable; | ||||
|  * | ||||
|  * // Then in your constructor | ||||
|  * POCKET_UPGRADES.register(bus); | ||||
|  * }</pre> | ||||
|  * } | ||||
|  * <p> | ||||
|  * We can then define a new upgrade using JSON by placing the following in | ||||
|  * {@code data/<my_mod>/computercraft/pocket_upgrades/<my_upgrade_id>.json}. | ||||
|  * <pre>{@code | ||||
|  * {@code data/<my_mod>/computercraft/pocket_upgrade/<my_upgrade_id>.json}. | ||||
|  * {@snippet lang="json" : | ||||
|  * { | ||||
|  *     "type": my_mod:my_upgrade", | ||||
|  *     "type": "my_mod:my_upgrade" | ||||
|  * } | ||||
|  * } | ||||
|  * }</pre> | ||||
|  * <p> | ||||
|  * {@link PocketUpgradeDataProvider} provides a data provider to aid with generating these JSON files. | ||||
|  */ | ||||
| public interface IPocketUpgrade extends UpgradeBase { | ||||
|     ResourceKey<Registry<IPocketUpgrade>> REGISTRY = ResourceKey.createRegistryKey(new ResourceLocation(ComputerCraftAPI.MOD_ID, "pocket_upgrade")); | ||||
| 
 | ||||
|     /** | ||||
|      * The registry key for pocket upgrade types. | ||||
|      * | ||||
|   | ||||
| @@ -1,30 +0,0 @@ | ||||
| // SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers | ||||
| // | ||||
| // SPDX-License-Identifier: MPL-2.0 | ||||
| 
 | ||||
| package dan200.computercraft.api.pocket; | ||||
| 
 | ||||
| import dan200.computercraft.api.upgrades.UpgradeDataProvider; | ||||
| import dan200.computercraft.api.upgrades.UpgradeType; | ||||
| import dan200.computercraft.impl.ComputerCraftAPIService; | ||||
| import dan200.computercraft.impl.RegistryHelper; | ||||
| import net.minecraft.data.DataGenerator; | ||||
| import net.minecraft.data.PackOutput; | ||||
| 
 | ||||
| import java.util.function.Consumer; | ||||
| 
 | ||||
| /** | ||||
|  * A data provider to generate pocket computer upgrades. | ||||
|  * <p> | ||||
|  * This should be subclassed and registered to a {@link DataGenerator.PackGenerator}. Override the | ||||
|  * {@link #addUpgrades(Consumer)} function, construct each upgrade, and pass them off to the provided consumer to | ||||
|  * generate them. | ||||
|  * | ||||
|  * @see IPocketUpgrade | ||||
|  * @see UpgradeType | ||||
|  */ | ||||
| public abstract class PocketUpgradeDataProvider extends UpgradeDataProvider<IPocketUpgrade> { | ||||
|     public PocketUpgradeDataProvider(PackOutput output) { | ||||
|         super(output, "Pocket Computer Upgrades", RegistryHelper.POCKET_UPGRADE, ComputerCraftAPIService.get().pocketUpgradeCodec()); | ||||
|     } | ||||
| } | ||||
| @@ -4,6 +4,7 @@ | ||||
| 
 | ||||
| package dan200.computercraft.api.turtle; | ||||
| 
 | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
| import dan200.computercraft.api.upgrades.UpgradeBase; | ||||
| import dan200.computercraft.api.upgrades.UpgradeType; | ||||
| @@ -12,6 +13,7 @@ import net.minecraft.core.Direction; | ||||
| import net.minecraft.core.Registry; | ||||
| import net.minecraft.core.component.DataComponentPatch; | ||||
| import net.minecraft.resources.ResourceKey; | ||||
| import net.minecraft.resources.ResourceLocation; | ||||
| 
 | ||||
| import javax.annotation.Nullable; | ||||
| 
 | ||||
| @@ -23,11 +25,11 @@ import javax.annotation.Nullable; | ||||
|  * {@link UpgradeType} instance, which are then registered in a registry. | ||||
|  * <p> | ||||
|  * You then write a JSON file in your mod's {@literal data/} folder. This is then parsed when the world is loaded, and | ||||
|  * the upgrade automatically registered. It is recommended this is done via {@linkplain TurtleUpgradeDataProvider data | ||||
|  * generators}. | ||||
|  * the upgrade automatically registered. It is recommended this is done via | ||||
|  * <a href="../upgrades/UpgradeType.html#datagen">data generators</a>. | ||||
|  * | ||||
|  * <h2>Example</h2> | ||||
|  * <pre>{@code | ||||
|  * {@snippet lang="java" : | ||||
|  * // We use Forge's DeferredRegister to register our upgrade type. Fabric mods may register their type directly. | ||||
|  * static final DeferredRegister<UpgradeType<? extends ITurtleUpgrade>> TURTLE_UPGRADES = DeferredRegister.create(ITurtleUpgrade.typeRegistry(), "my_mod"); | ||||
|  * | ||||
| @@ -37,28 +39,38 @@ import javax.annotation.Nullable; | ||||
|  * | ||||
|  * // Then in your constructor | ||||
|  * TURTLE_UPGRADES.register(bus); | ||||
|  * }</pre> | ||||
|  * } | ||||
|  * <p> | ||||
|  * We can then define a new upgrade using JSON by placing the following in | ||||
|  * {@literal data/<my_mod>/computercraft/turtle_upgrades/<my_upgrade_id>.json}}. | ||||
|  * | ||||
|  * <pre>{@code | ||||
|  * {@code data/<my_mod>/computercraft/turtle_upgrade/<my_upgrade_id>.json}. | ||||
|  * <p> | ||||
|  * {@snippet lang="json" : | ||||
|  * { | ||||
|  *     "type": "my_mod:my_upgrade" | ||||
|  * } | ||||
|  * }</pre> | ||||
|  * <p> | ||||
|  * {@link TurtleUpgradeDataProvider} provides a data provider to aid with generating these JSON files. | ||||
|  * } | ||||
|  * <p> | ||||
|  * Finally, we need to register a model for our upgrade, see | ||||
|  * {@link dan200.computercraft.api.client.turtle.TurtleUpgradeModeller} for more information. | ||||
|  * | ||||
|  * <pre>{@code | ||||
|  * // Register our model inside FMLClientSetupEvent | ||||
|  * ComputerCraftAPIClient.registerTurtleUpgradeModeller(MY_UPGRADE.get(), TurtleUpgradeModeller.flatItem()) | ||||
|  * }</pre> | ||||
|  */ | ||||
| public interface ITurtleUpgrade extends UpgradeBase { | ||||
|     /** | ||||
|      * The registry in which turtle upgrades are stored. | ||||
|      */ | ||||
|     ResourceKey<Registry<ITurtleUpgrade>> REGISTRY = ResourceKey.createRegistryKey(new ResourceLocation(ComputerCraftAPI.MOD_ID, "turtle_upgrade")); | ||||
| 
 | ||||
|     /** | ||||
|      * Create a {@link ResourceKey} for a turtle upgrade given a {@link ResourceLocation}. | ||||
|      * <p> | ||||
|      * This should only be called from within data generation code. Do not hard code references to your upgrades! | ||||
|      * | ||||
|      * @param id The id of the turtle upgrade. | ||||
|      * @return The upgrade registry key. | ||||
|      */ | ||||
|     static ResourceKey<ITurtleUpgrade> createKey(ResourceLocation id) { | ||||
|         return ResourceKey.create(REGISTRY, id); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * The registry key for turtle upgrade types. | ||||
|      * | ||||
|   | ||||
| @@ -0,0 +1,157 @@ | ||||
| // SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers | ||||
| // | ||||
| // SPDX-License-Identifier: MPL-2.0 | ||||
| 
 | ||||
| package dan200.computercraft.api.turtle; | ||||
| 
 | ||||
| import dan200.computercraft.api.ComputerCraftTags; | ||||
| import dan200.computercraft.api.upgrades.UpgradeBase; | ||||
| import dan200.computercraft.impl.ComputerCraftAPIService; | ||||
| import dan200.computercraft.impl.upgrades.TurtleToolSpec; | ||||
| import net.minecraft.core.component.DataComponents; | ||||
| import net.minecraft.data.worldgen.BootstrapContext; | ||||
| import net.minecraft.network.chat.Component; | ||||
| import net.minecraft.resources.ResourceKey; | ||||
| import net.minecraft.resources.ResourceLocation; | ||||
| import net.minecraft.tags.TagKey; | ||||
| import net.minecraft.world.entity.ai.attributes.Attributes; | ||||
| import net.minecraft.world.item.Item; | ||||
| import net.minecraft.world.item.ItemStack; | ||||
| import net.minecraft.world.level.block.Block; | ||||
| 
 | ||||
| import javax.annotation.Nullable; | ||||
| import java.util.Optional; | ||||
| 
 | ||||
| /** | ||||
|  * A builder for custom turtle tool upgrades. | ||||
|  * <p> | ||||
|  * This can be used from your <a href="../upgrades/UpgradeType.html#datagen">data generator</a> code in order to | ||||
|  * register turtle tools for your mod's tools. | ||||
|  * | ||||
|  * <h2>Example:</h2> | ||||
|  * {@snippet lang = "java": | ||||
|  * import net.minecraft.data.worldgen.BootstrapContext; | ||||
|  * import net.minecraft.resources.ResourceLocation; | ||||
|  * import net.minecraft.world.item.Items; | ||||
|  * | ||||
|  * public void registerTool(BootstrapContext<ITurtleUpgrade> upgrades) { | ||||
|  *   TurtleToolBuilder.tool(new ResourceLocation("my_mod", "wooden_pickaxe"), Items.WOODEN_PICKAXE).register(upgrades); | ||||
|  * } | ||||
|  *} | ||||
|  */ | ||||
| public final class TurtleToolBuilder { | ||||
|     private final ResourceKey<ITurtleUpgrade> id; | ||||
|     private final Item item; | ||||
|     private Component adjective; | ||||
|     private float damageMultiplier = TurtleToolSpec.DEFAULT_DAMAGE_MULTIPLIER; | ||||
|     private @Nullable TagKey<Block> breakable; | ||||
|     private boolean allowEnchantments = false; | ||||
|     private TurtleToolDurability consumeDurability = TurtleToolDurability.NEVER; | ||||
| 
 | ||||
|     private TurtleToolBuilder(ResourceKey<ITurtleUpgrade> id, Item item) { | ||||
|         this.id = id; | ||||
|         adjective = Component.translatable(UpgradeBase.getDefaultAdjective(id.location())); | ||||
|         this.item = item; | ||||
|     } | ||||
| 
 | ||||
|     public static TurtleToolBuilder tool(ResourceLocation id, Item item) { | ||||
|         return new TurtleToolBuilder(ITurtleUpgrade.createKey(id), item); | ||||
|     } | ||||
| 
 | ||||
|     public static TurtleToolBuilder tool(ResourceKey<ITurtleUpgrade> id, Item item) { | ||||
|         return new TurtleToolBuilder(id, item); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get the id for this turtle tool. | ||||
|      * | ||||
|      * @return The upgrade id. | ||||
|      */ | ||||
|     public ResourceKey<ITurtleUpgrade> id() { | ||||
|         return id; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Specify a custom adjective for this tool. By default this takes its adjective from the upgrade id. | ||||
|      * | ||||
|      * @param adjective The new adjective to use. | ||||
|      * @return The tool builder, for further use. | ||||
|      */ | ||||
|     public TurtleToolBuilder adjective(Component adjective) { | ||||
|         this.adjective = adjective; | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * The amount of damage a swing of this tool will do. This is multiplied by {@link Attributes#ATTACK_DAMAGE} to | ||||
|      * get the final damage. | ||||
|      * | ||||
|      * @param damageMultiplier The damage multiplier. | ||||
|      * @return The tool builder, for further use. | ||||
|      */ | ||||
|     public TurtleToolBuilder damageMultiplier(float damageMultiplier) { | ||||
|         this.damageMultiplier = damageMultiplier; | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Indicate that this upgrade allows items which have been {@linkplain ItemStack#isEnchanted() enchanted} or have | ||||
|      * {@linkplain DataComponents#ATTRIBUTE_MODIFIERS custom attribute modifiers}. | ||||
|      * | ||||
|      * @return The tool builder, for further use. | ||||
|      */ | ||||
|     public TurtleToolBuilder allowEnchantments() { | ||||
|         allowEnchantments = true; | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Set when the tool will consume durability. | ||||
|      * | ||||
|      * @param durability The durability predicate. | ||||
|      * @return The tool builder, for further use. | ||||
|      */ | ||||
|     public TurtleToolBuilder consumeDurability(TurtleToolDurability durability) { | ||||
|         consumeDurability = durability; | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Provide a list of breakable blocks. If not given, the tool can break all blocks. If given, only blocks | ||||
|      * in this tag, those in {@link ComputerCraftTags.Blocks#TURTLE_ALWAYS_BREAKABLE} and "insta-mine" ones can | ||||
|      * be broken. | ||||
|      * | ||||
|      * @param breakable The tag containing all blocks breakable by this item. | ||||
|      * @return The tool builder, for further use. | ||||
|      * @see ComputerCraftTags.Blocks | ||||
|      */ | ||||
|     public TurtleToolBuilder breakable(TagKey<Block> breakable) { | ||||
|         this.breakable = breakable; | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Build the turtle tool upgrade. | ||||
|      * | ||||
|      * @return The constructed upgrade. | ||||
|      */ | ||||
|     public ITurtleUpgrade build() { | ||||
|         return ComputerCraftAPIService.get().createTurtleTool(new TurtleToolSpec( | ||||
|             adjective, | ||||
|             item, | ||||
|             damageMultiplier, | ||||
|             allowEnchantments, | ||||
|             consumeDurability, | ||||
|             Optional.ofNullable(breakable) | ||||
|         )); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Build this upgrade and register it for datagen. | ||||
|      * | ||||
|      * @param upgrades The registry this upgrade should be added to. | ||||
|      */ | ||||
|     public void register(BootstrapContext<ITurtleUpgrade> upgrades) { | ||||
|         upgrades.register(id(), build()); | ||||
|     } | ||||
| } | ||||
| @@ -11,7 +11,7 @@ import net.minecraft.world.item.ItemStack; | ||||
| /** | ||||
|  * Indicates if an equipped turtle item will consume durability. | ||||
|  * | ||||
|  * @see TurtleUpgradeDataProvider.ToolBuilder#consumeDurability(TurtleToolDurability) | ||||
|  * @see TurtleToolBuilder#consumeDurability(TurtleToolDurability) | ||||
|  */ | ||||
| public enum TurtleToolDurability implements StringRepresentable { | ||||
|     /** | ||||
|   | ||||
| @@ -1,151 +0,0 @@ | ||||
| // SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers | ||||
| // | ||||
| // SPDX-License-Identifier: MPL-2.0 | ||||
| 
 | ||||
| package dan200.computercraft.api.turtle; | ||||
| 
 | ||||
| import dan200.computercraft.api.ComputerCraftTags; | ||||
| import dan200.computercraft.api.upgrades.UpgradeBase; | ||||
| import dan200.computercraft.api.upgrades.UpgradeDataProvider; | ||||
| import dan200.computercraft.impl.ComputerCraftAPIService; | ||||
| import dan200.computercraft.impl.RegistryHelper; | ||||
| import dan200.computercraft.impl.upgrades.TurtleToolSpec; | ||||
| import net.minecraft.core.component.DataComponents; | ||||
| import net.minecraft.data.DataGenerator; | ||||
| import net.minecraft.data.PackOutput; | ||||
| import net.minecraft.network.chat.Component; | ||||
| import net.minecraft.resources.ResourceLocation; | ||||
| import net.minecraft.tags.TagKey; | ||||
| import net.minecraft.world.entity.ai.attributes.Attributes; | ||||
| import net.minecraft.world.item.Item; | ||||
| import net.minecraft.world.item.ItemStack; | ||||
| import net.minecraft.world.level.block.Block; | ||||
| 
 | ||||
| import javax.annotation.Nullable; | ||||
| import java.util.Optional; | ||||
| import java.util.function.Consumer; | ||||
| 
 | ||||
| /** | ||||
|  * A data provider to generate turtle upgrades. | ||||
|  * <p> | ||||
|  * This should be subclassed and registered to a {@link DataGenerator.PackGenerator}. Override the | ||||
|  * {@link #addUpgrades(Consumer)} function, construct each upgrade, and pass them off to the provided consumer to | ||||
|  * generate them. | ||||
|  * | ||||
|  * @see ITurtleUpgrade | ||||
|  */ | ||||
| public abstract class TurtleUpgradeDataProvider extends UpgradeDataProvider<ITurtleUpgrade> { | ||||
|     public TurtleUpgradeDataProvider(PackOutput output) { | ||||
|         super(output, "Turtle Upgrades", RegistryHelper.TURTLE_UPGRADE, ComputerCraftAPIService.get().turtleUpgradeCodec()); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Create a new turtle tool upgrade, such as a pickaxe or shovel. | ||||
|      * | ||||
|      * @param id   The ID of this tool. | ||||
|      * @param item The item used for tool actions. Note, this doesn't inherit all properties of the tool, you may need | ||||
|      *             to specify {@link ToolBuilder#damageMultiplier(float)} and {@link ToolBuilder#breakable(TagKey)}. | ||||
|      * @return A tool builder, | ||||
|      */ | ||||
|     public final ToolBuilder tool(ResourceLocation id, Item item) { | ||||
|         return new ToolBuilder(id, item); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * A builder for custom turtle tool upgrades. | ||||
|      * | ||||
|      * @see #tool(ResourceLocation, Item) | ||||
|      */ | ||||
|     public final class ToolBuilder { | ||||
|         private final ResourceLocation id; | ||||
|         private final Item item; | ||||
|         private Component adjective; | ||||
|         private @Nullable Item craftingItem; | ||||
|         private float damageMultiplier = TurtleToolSpec.DEFAULT_DAMAGE_MULTIPLIER; | ||||
|         private @Nullable TagKey<Block> breakable; | ||||
|         private boolean allowEnchantments = false; | ||||
|         private TurtleToolDurability consumeDurability = TurtleToolDurability.NEVER; | ||||
| 
 | ||||
|         ToolBuilder(ResourceLocation id, Item item) { | ||||
|             this.id = id; | ||||
|             adjective = Component.translatable(UpgradeBase.getDefaultAdjective(id)); | ||||
|             this.item = item; | ||||
|             craftingItem = null; | ||||
|         } | ||||
| 
 | ||||
|         /** | ||||
|          * Specify a custom adjective for this tool. By default this takes its adjective from the upgrade id. | ||||
|          * | ||||
|          * @param adjective The new adjective to use. | ||||
|          * @return The tool builder, for further use. | ||||
|          */ | ||||
|         public ToolBuilder adjective(Component adjective) { | ||||
|             this.adjective = adjective; | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         /** | ||||
|          * The amount of damage a swing of this tool will do. This is multiplied by {@link Attributes#ATTACK_DAMAGE} to | ||||
|          * get the final damage. | ||||
|          * | ||||
|          * @param damageMultiplier The damage multiplier. | ||||
|          * @return The tool builder, for further use. | ||||
|          */ | ||||
|         public ToolBuilder damageMultiplier(float damageMultiplier) { | ||||
|             this.damageMultiplier = damageMultiplier; | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         /** | ||||
|          * Indicate that this upgrade allows items which have been {@linkplain ItemStack#isEnchanted() enchanted} or have | ||||
|          * {@linkplain DataComponents#ATTRIBUTE_MODIFIERS custom attribute modifiers}. | ||||
|          * | ||||
|          * @return The tool builder, for further use. | ||||
|          */ | ||||
|         public ToolBuilder allowEnchantments() { | ||||
|             allowEnchantments = true; | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         /** | ||||
|          * Set when the tool will consume durability. | ||||
|          * | ||||
|          * @param durability The durability predicate. | ||||
|          * @return The tool builder, for further use. | ||||
|          */ | ||||
|         public ToolBuilder consumeDurability(TurtleToolDurability durability) { | ||||
|             consumeDurability = durability; | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         /** | ||||
|          * Provide a list of breakable blocks. If not given, the tool can break all blocks. If given, only blocks | ||||
|          * in this tag, those in {@link ComputerCraftTags.Blocks#TURTLE_ALWAYS_BREAKABLE} and "insta-mine" ones can | ||||
|          * be broken. | ||||
|          * | ||||
|          * @param breakable The tag containing all blocks breakable by this item. | ||||
|          * @return The tool builder, for further use. | ||||
|          * @see ComputerCraftTags.Blocks | ||||
|          */ | ||||
|         public ToolBuilder breakable(TagKey<Block> breakable) { | ||||
|             this.breakable = breakable; | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         /** | ||||
|          * Register this as an upgrade. | ||||
|          * | ||||
|          * @param add The callback given to {@link #addUpgrades(Consumer)}. | ||||
|          */ | ||||
|         public void add(Consumer<Upgrade<ITurtleUpgrade>> add) { | ||||
|             upgrade(id, ComputerCraftAPIService.get().createTurtleTool(new TurtleToolSpec( | ||||
|                 adjective, | ||||
|                 item, | ||||
|                 damageMultiplier, | ||||
|                 allowEnchantments, | ||||
|                 consumeDurability, | ||||
|                 Optional.ofNullable(breakable) | ||||
|             ))).add(add); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,154 +0,0 @@ | ||||
| // SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers | ||||
| // | ||||
| // SPDX-License-Identifier: MPL-2.0 | ||||
| 
 | ||||
| package dan200.computercraft.api.upgrades; | ||||
| 
 | ||||
| import com.google.gson.JsonObject; | ||||
| import com.mojang.serialization.Codec; | ||||
| import com.mojang.serialization.JsonOps; | ||||
| import dan200.computercraft.impl.PlatformHelper; | ||||
| import net.minecraft.Util; | ||||
| import net.minecraft.core.Registry; | ||||
| import net.minecraft.data.CachedOutput; | ||||
| import net.minecraft.data.DataProvider; | ||||
| import net.minecraft.data.PackOutput; | ||||
| import net.minecraft.resources.ResourceKey; | ||||
| import net.minecraft.resources.ResourceLocation; | ||||
| import org.jetbrains.annotations.ApiStatus; | ||||
| import org.jetbrains.annotations.Nullable; | ||||
| 
 | ||||
| import java.util.*; | ||||
| import java.util.concurrent.CompletableFuture; | ||||
| import java.util.function.Consumer; | ||||
| 
 | ||||
| /** | ||||
|  * A data generator/provider for turtle and pocket computer upgrades. This should not be extended directly, instead see | ||||
|  * the other subclasses. | ||||
|  * | ||||
|  * @param <T> The base class of upgrades. | ||||
|  */ | ||||
| public abstract class UpgradeDataProvider<T extends UpgradeBase> implements DataProvider { | ||||
|     private final PackOutput output; | ||||
|     private final String name; | ||||
|     private final ResourceKey<Registry<T>> registryName; | ||||
|     private final Codec<T> codec; | ||||
| 
 | ||||
|     private @Nullable Map<ResourceKey<T>, T> upgrades; | ||||
| 
 | ||||
|     @ApiStatus.Internal | ||||
|     protected UpgradeDataProvider(PackOutput output, String name, ResourceKey<Registry<T>> registryName, Codec<T> codec) { | ||||
|         this.output = output; | ||||
|         this.name = name; | ||||
|         this.registryName = registryName; | ||||
|         this.codec = codec; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Add a new upgrade. | ||||
|      * | ||||
|      * @param id      The ID of the upgrade to create. | ||||
|      * @param upgrade The upgrade to add. | ||||
|      * @return The constructed upgrade, ready to be passed off to {@link #addUpgrades(Consumer)}'s consumer. | ||||
|      */ | ||||
|     protected final Upgrade<T> upgrade(ResourceLocation id, T upgrade) { | ||||
|         return new Upgrade<>(id, upgrade, j -> { | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Add all turtle or pocket computer upgrades. | ||||
|      * <p> | ||||
|      * <strong>Example usage:</strong> | ||||
|      * <pre>{@code | ||||
|      * protected void addUpgrades(Consumer<Upgrade<ITurtleUpgrade>> addUpgrade) { | ||||
|      *     upgrade(new ResourceLocation("mymod", "speaker"), new TurtleSpeaker(new ItemStack(Items.NOTE_BLOCK))).add(addUpgrade); | ||||
|      * } | ||||
|      * }</pre> | ||||
|      * | ||||
|      * @param addUpgrade A callback used to register an upgrade. | ||||
|      */ | ||||
|     protected abstract void addUpgrades(Consumer<Upgrade<T>> addUpgrade); | ||||
| 
 | ||||
|     @Override | ||||
|     public CompletableFuture<?> run(CachedOutput cache) { | ||||
|         var base = output.createPathProvider(PackOutput.Target.DATA_PACK, registryName.location().getNamespace() + "/" + registryName.location().getPath()); | ||||
| 
 | ||||
|         Map<ResourceKey<T>, T> upgrades = new LinkedHashMap<>(); | ||||
| 
 | ||||
|         List<CompletableFuture<?>> futures = new ArrayList<>(); | ||||
|         addUpgrades(upgrade -> { | ||||
|             var id = ResourceKey.create(registryName, upgrade.id); | ||||
|             if (upgrades.containsKey(id)) throw new IllegalStateException("Duplicate upgrade " + upgrade.id); | ||||
| 
 | ||||
|             var json = (JsonObject) codec.encodeStart(JsonOps.INSTANCE, upgrade.upgrade).getOrThrow(); | ||||
|             upgrade.serialise.accept(json); | ||||
| 
 | ||||
|             futures.add(DataProvider.saveStable(cache, json, base.json(upgrade.id))); | ||||
| 
 | ||||
|             upgrades.put(id, upgrade.upgrade); | ||||
|         }); | ||||
| 
 | ||||
|         this.upgrades = Collections.unmodifiableMap(upgrades); | ||||
| 
 | ||||
|         return Util.sequenceFailFast(futures); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public final String getName() { | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get all registered upgrades. | ||||
|      * | ||||
|      * @return The map of registered upgrades. | ||||
|      */ | ||||
|     public Map<ResourceKey<T>, T> getGeneratedUpgrades() { | ||||
|         var upgrades = this.upgrades; | ||||
|         if (upgrades == null) throw new IllegalStateException("Upgrades are not available yet"); | ||||
|         return upgrades; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * A constructed upgrade instance, produced {@link #addUpgrades(Consumer)}. | ||||
|      * | ||||
|      * @param <T> The type of upgrade. | ||||
|      */ | ||||
|     public static final class Upgrade<T extends UpgradeBase> { | ||||
|         private final ResourceLocation id; | ||||
|         private final T upgrade; | ||||
|         private final Consumer<JsonObject> serialise; | ||||
| 
 | ||||
|         private Upgrade(ResourceLocation id, T upgrade, Consumer<JsonObject> serialise) { | ||||
|             this.id = id; | ||||
|             this.upgrade = upgrade; | ||||
|             this.serialise = serialise; | ||||
|         } | ||||
| 
 | ||||
|         /** | ||||
|          * Convenience method for registering an upgrade. | ||||
|          * | ||||
|          * @param add The callback given to {@link #addUpgrades(Consumer)} | ||||
|          */ | ||||
|         public void add(Consumer<Upgrade<T>> add) { | ||||
|             add.accept(this); | ||||
|         } | ||||
| 
 | ||||
|         /** | ||||
|          * Return a new {@link Upgrade} which requires the given mod to be present. | ||||
|          * <p> | ||||
|          * This uses mod-loader-specific hooks (Forge's crafting conditions and Fabric's resource conditions). If using | ||||
|          * this in a multi-loader setup, you must generate resources separately for the two loaders. | ||||
|          * | ||||
|          * @param modId The id of the mod. | ||||
|          * @return A new upgrade instance. | ||||
|          */ | ||||
|         public Upgrade<T> requireMod(String modId) { | ||||
|             return new Upgrade<>(id, upgrade, json -> { | ||||
|                 PlatformHelper.get().addRequiredModCondition(json, modId); | ||||
|                 serialise.accept(json); | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -6,11 +6,10 @@ package dan200.computercraft.api.upgrades; | ||||
| 
 | ||||
| import com.mojang.serialization.MapCodec; | ||||
| import dan200.computercraft.api.pocket.IPocketUpgrade; | ||||
| import dan200.computercraft.api.pocket.PocketUpgradeDataProvider; | ||||
| import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
| import dan200.computercraft.api.turtle.TurtleUpgradeDataProvider; | ||||
| import dan200.computercraft.impl.upgrades.UpgradeTypeImpl; | ||||
| import net.minecraft.core.registries.BuiltInRegistries; | ||||
| import net.minecraft.data.registries.RegistryPatchGenerator; | ||||
| import net.minecraft.world.item.ItemStack; | ||||
| import net.minecraft.world.item.crafting.Recipe; | ||||
| import net.minecraft.world.level.storage.loot.functions.LootItemFunction; | ||||
| @@ -33,8 +32,35 @@ import java.util.function.Function; | ||||
|  * {@link IPocketUpgrade#typeRegistry()}). | ||||
|  * <p> | ||||
|  * In order to register the actual upgrade, a JSON file referencing your upgrade type should be added to a datapack. It | ||||
|  * is recommended to do this via the data generators (see {@link TurtleUpgradeDataProvider} and | ||||
|  * {@link PocketUpgradeDataProvider}). | ||||
|  * is recommended to do this via the data generators. | ||||
|  * | ||||
|  * <h2 id="datagen">Data Generation</h2> | ||||
|  * As turtle and pocket upgrades are just loaded using vanilla's dynamic loaders, one may use the same data generation | ||||
|  * tools as you would for any other dynamic registry. | ||||
|  * <p> | ||||
|  * This can typically be done by extending vanilla's built-in registries using {@link RegistryPatchGenerator}, and then | ||||
|  * writing out the new registries using {@code net.fabricmc.fabric.api.datagen.v1.provider.FabricDynamicRegistryProvider} | ||||
|  * on Fabric or {@code net.neoforged.neoforge.common.data.DatapackBuiltinEntriesProvider} on Forge. | ||||
|  * <p> | ||||
|  * {@snippet lang="java" : | ||||
|  * import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
|  * import net.minecraft.Util; | ||||
|  * import net.minecraft.core.HolderLookup; | ||||
|  * import net.minecraft.core.RegistrySetBuilder; | ||||
|  * import net.minecraft.data.DataGenerator; | ||||
|  * import net.neoforged.neoforge.common.data.DatapackBuiltinEntriesProvider; | ||||
|  * | ||||
|  * import java.util.concurrent.CompletableFuture; | ||||
|  * | ||||
|  * public void generate(DataGenerator.PackGenerator output, CompletableFuture<HolderLookup.Provider> registries) { | ||||
|  *     var newRegistries = RegistryPatchGenerator.createLookup(registries, Util.make(new RegistrySetBuilder(), builder -> { | ||||
|  *         builder.add(ITurtleUpgrade.REGISTRY, upgrades -> { | ||||
|  *             upgrades.register(ITurtleUpgrade.createKey(new ResourceLocation("my_mod", "my_upgrade")), new MyUpgrade()); | ||||
|  *         }); | ||||
|  *     })); | ||||
|  *     output.addProvider(o -> new DatapackBuiltinEntriesProvider(o, newRegistries, Set.of("my_mod"))); | ||||
|  * } | ||||
|  * } | ||||
|  * | ||||
|  * @param <T> The upgrade subclass that this upgrade type represents. | ||||
|  * @see ITurtleUpgrade | ||||
|   | ||||
| @@ -1,54 +0,0 @@ | ||||
| // SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers | ||||
| // | ||||
| // SPDX-License-Identifier: MPL-2.0 | ||||
| 
 | ||||
| package dan200.computercraft.impl; | ||||
| 
 | ||||
| import com.google.gson.JsonObject; | ||||
| import dan200.computercraft.api.upgrades.UpgradeDataProvider; | ||||
| import org.jetbrains.annotations.ApiStatus; | ||||
| 
 | ||||
| import javax.annotation.Nullable; | ||||
| 
 | ||||
| /** | ||||
|  * Abstraction layer for Forge and Fabric. See implementations for more details. | ||||
|  * <p> | ||||
|  * Do <strong>NOT</strong> directly reference this class. It exists for internal use by the API. | ||||
|  */ | ||||
| @ApiStatus.Internal | ||||
| public interface PlatformHelper { | ||||
|     /** | ||||
|      * Get the current {@link PlatformHelper} instance. | ||||
|      * | ||||
|      * @return The current instance. | ||||
|      */ | ||||
|     static PlatformHelper get() { | ||||
|         var instance = Instance.INSTANCE; | ||||
|         return instance == null ? Services.raise(PlatformHelper.class, Instance.ERROR) : instance; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Add a resource condition which requires a mod to be loaded. This should be used by data providers such as | ||||
|      * {@link UpgradeDataProvider}. | ||||
|      * | ||||
|      * @param object The JSON object we're generating. | ||||
|      * @param modId  The mod ID that we require. | ||||
|      */ | ||||
|     void addRequiredModCondition(JsonObject object, String modId); | ||||
| 
 | ||||
|     final class Instance { | ||||
|         static final @Nullable PlatformHelper INSTANCE; | ||||
|         static final @Nullable Throwable ERROR; | ||||
| 
 | ||||
|         static { | ||||
|             // We don't want class initialisation to fail here (as that results in confusing errors). Instead, capture | ||||
|             // the error and rethrow it when accessing. This should be JITted away in the common case. | ||||
|             var helper = Services.tryLoad(PlatformHelper.class); | ||||
|             INSTANCE = helper.instance(); | ||||
|             ERROR = helper.error(); | ||||
|         } | ||||
| 
 | ||||
|         private Instance() { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -6,12 +6,15 @@ package dan200.computercraft.client.integration.emi; | ||||
| 
 | ||||
| import dan200.computercraft.api.turtle.TurtleSide; | ||||
| import dan200.computercraft.shared.ModRegistry; | ||||
| import dan200.computercraft.shared.integration.RecipeModHelpers; | ||||
| import dan200.computercraft.shared.pocket.items.PocketComputerItem; | ||||
| import dan200.computercraft.shared.turtle.items.TurtleItem; | ||||
| import dev.emi.emi.api.EmiEntrypoint; | ||||
| import dev.emi.emi.api.EmiPlugin; | ||||
| import dev.emi.emi.api.EmiRegistry; | ||||
| import dev.emi.emi.api.stack.Comparison; | ||||
| import dev.emi.emi.api.stack.EmiStack; | ||||
| import net.minecraft.client.Minecraft; | ||||
| import net.minecraft.world.item.ItemStack; | ||||
| 
 | ||||
| import java.util.function.BiPredicate; | ||||
| @@ -25,6 +28,10 @@ public class EMIComputerCraft implements EmiPlugin { | ||||
| 
 | ||||
|         registry.setDefaultComparison(ModRegistry.Items.POCKET_COMPUTER_NORMAL.get(), pocketComparison); | ||||
|         registry.setDefaultComparison(ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get(), pocketComparison); | ||||
| 
 | ||||
|         for (var stack : RecipeModHelpers.getExtraStacks(Minecraft.getInstance().level.registryAccess())) { | ||||
|             registry.addEmiStack(EmiStack.of(stack)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static final Comparison turtleComparison = compareStacks((left, right) | ||||
|   | ||||
| @@ -11,14 +11,12 @@ import dan200.computercraft.api.turtle.ITurtleAccess; | ||||
| import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
| import dan200.computercraft.api.turtle.TurtleSide; | ||||
| import dan200.computercraft.api.upgrades.UpgradeType; | ||||
| import dan200.computercraft.impl.RegistryHelper; | ||||
| import dan200.computercraft.impl.UpgradeManager; | ||||
| import dan200.computercraft.shared.util.RegistryHelper; | ||||
| import net.minecraft.client.Minecraft; | ||||
| import net.minecraft.core.component.DataComponentPatch; | ||||
| import net.minecraft.resources.ResourceLocation; | ||||
| 
 | ||||
| import java.util.Map; | ||||
| import java.util.WeakHashMap; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
| import java.util.stream.Stream; | ||||
| 
 | ||||
| @@ -32,14 +30,6 @@ public final class TurtleUpgradeModellers { | ||||
|     private static final Map<UpgradeType<? extends ITurtleUpgrade>, TurtleUpgradeModeller<?>> turtleModels = new ConcurrentHashMap<>(); | ||||
|     private static volatile boolean fetchedModels; | ||||
| 
 | ||||
|     /** | ||||
|      * In order to avoid a double lookup of {@link ITurtleUpgrade} to {@link UpgradeManager.UpgradeWrapper} to | ||||
|      * {@link TurtleUpgradeModeller}, we maintain a cache here. | ||||
|      * <p> | ||||
|      * Turtle upgrades may be removed as part of datapack reloads, so we use a weak map to avoid the memory leak. | ||||
|      */ | ||||
|     private static final WeakHashMap<ITurtleUpgrade, TurtleUpgradeModeller<?>> modelCache = new WeakHashMap<>(); | ||||
| 
 | ||||
|     private TurtleUpgradeModellers() { | ||||
|     } | ||||
| 
 | ||||
| @@ -57,20 +47,17 @@ public final class TurtleUpgradeModellers { | ||||
|     } | ||||
| 
 | ||||
|     public static TransformedModel getModel(ITurtleUpgrade upgrade, ITurtleAccess access, TurtleSide side) { | ||||
|         @SuppressWarnings("unchecked") | ||||
|         var modeller = (TurtleUpgradeModeller<ITurtleUpgrade>) modelCache.computeIfAbsent(upgrade, TurtleUpgradeModellers::getModeller); | ||||
|         return modeller.getModel(upgrade, access, side, access.getUpgradeData(side)); | ||||
|         return getModeller(upgrade).getModel(upgrade, access, side, access.getUpgradeData(side)); | ||||
|     } | ||||
| 
 | ||||
|     public static TransformedModel getModel(ITurtleUpgrade upgrade, DataComponentPatch data, TurtleSide side) { | ||||
|         @SuppressWarnings("unchecked") | ||||
|         var modeller = (TurtleUpgradeModeller<ITurtleUpgrade>) modelCache.computeIfAbsent(upgrade, TurtleUpgradeModellers::getModeller); | ||||
|         return modeller.getModel(upgrade, null, side, data); | ||||
|         return getModeller(upgrade).getModel(upgrade, null, side, data); | ||||
|     } | ||||
| 
 | ||||
|     private static TurtleUpgradeModeller<?> getModeller(ITurtleUpgrade upgrade) { | ||||
|     @SuppressWarnings("unchecked") | ||||
|     private static <T extends ITurtleUpgrade> TurtleUpgradeModeller<T> getModeller(T upgrade) { | ||||
|         var modeller = turtleModels.get(upgrade.getType()); | ||||
|         return modeller == null ? NULL_TURTLE_MODELLER : modeller; | ||||
|         return (TurtleUpgradeModeller<T>) (modeller == null ? NULL_TURTLE_MODELLER : modeller); | ||||
|     } | ||||
| 
 | ||||
|     public static Stream<ResourceLocation> getDependencies() { | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| { | ||||
|   "type": "minecraft:crafting_shaped", | ||||
|   "category": "redstone", | ||||
|   "key": {"#": {"tag": "c:stones"}, "R": {"tag": "c:dusts/redstone"}}, | ||||
|   "key": {"#": {"item": "minecraft:stone"}, "R": {"tag": "c:dusts/redstone"}}, | ||||
|   "pattern": [" # ", "#R#", " # "], | ||||
|   "result": {"count": 6, "id": "computercraft:cable"} | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| { | ||||
|   "type": "minecraft:crafting_shaped", | ||||
|   "category": "redstone", | ||||
|   "key": {"#": {"tag": "c:stones"}, "G": {"tag": "c:glass_panes"}, "R": {"tag": "c:dusts/redstone"}}, | ||||
|   "key": {"#": {"item": "minecraft:stone"}, "G": {"tag": "c:glass_panes"}, "R": {"tag": "c:dusts/redstone"}}, | ||||
|   "pattern": ["###", "#R#", "#G#"], | ||||
|   "result": {"count": 1, "id": "computercraft:computer_normal"} | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| { | ||||
|   "type": "minecraft:crafting_shaped", | ||||
|   "category": "redstone", | ||||
|   "key": {"#": {"tag": "c:stones"}, "R": {"tag": "c:dusts/redstone"}}, | ||||
|   "key": {"#": {"item": "minecraft:stone"}, "R": {"tag": "c:dusts/redstone"}}, | ||||
|   "pattern": ["###", "#R#", "#R#"], | ||||
|   "result": {"count": 1, "id": "computercraft:disk_drive"} | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| { | ||||
|   "type": "minecraft:crafting_shaped", | ||||
|   "category": "redstone", | ||||
|   "key": {"#": {"tag": "c:stones"}, "G": {"tag": "c:glass_panes"}}, | ||||
|   "key": {"#": {"item": "minecraft:stone"}, "G": {"tag": "c:glass_panes"}}, | ||||
|   "pattern": ["###", "#G#", "###"], | ||||
|   "result": {"count": 1, "id": "computercraft:monitor_normal"} | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,11 @@ | ||||
| { | ||||
|   "type": "minecraft:crafting_shaped", | ||||
|   "category": "redstone", | ||||
|   "key": {"#": {"tag": "c:stones"}, "A": {"item": "minecraft:golden_apple"}, "G": {"tag": "c:glass_panes"}}, | ||||
|   "key": { | ||||
|     "#": {"item": "minecraft:stone"}, | ||||
|     "A": {"item": "minecraft:golden_apple"}, | ||||
|     "G": {"tag": "c:glass_panes"} | ||||
|   }, | ||||
|   "pattern": ["###", "#A#", "#G#"], | ||||
|   "result": {"count": 1, "id": "computercraft:pocket_computer_normal"} | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| { | ||||
|   "type": "minecraft:crafting_shaped", | ||||
|   "category": "redstone", | ||||
|   "key": {"#": {"tag": "c:stones"}, "D": {"tag": "c:dyes"}, "R": {"tag": "c:dusts/redstone"}}, | ||||
|   "key": {"#": {"item": "minecraft:stone"}, "D": {"tag": "c:dyes"}, "R": {"tag": "c:dusts/redstone"}}, | ||||
|   "pattern": ["###", "#R#", "#D#"], | ||||
|   "result": {"count": 1, "id": "computercraft:printer"} | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,11 @@ | ||||
| { | ||||
|   "type": "minecraft:crafting_shaped", | ||||
|   "category": "redstone", | ||||
|   "key": {"#": {"tag": "c:stones"}, "N": {"item": "minecraft:note_block"}, "R": {"tag": "c:dusts/redstone"}}, | ||||
|   "key": { | ||||
|     "#": {"item": "minecraft:stone"}, | ||||
|     "N": {"item": "minecraft:note_block"}, | ||||
|     "R": {"tag": "c:dusts/redstone"} | ||||
|   }, | ||||
|   "pattern": ["###", "#N#", "#R#"], | ||||
|   "result": {"count": 1, "id": "computercraft:speaker"} | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| { | ||||
|   "type": "minecraft:crafting_shaped", | ||||
|   "category": "redstone", | ||||
|   "key": {"#": {"tag": "c:stones"}, "R": {"tag": "c:dusts/redstone"}}, | ||||
|   "key": {"#": {"item": "minecraft:stone"}, "R": {"tag": "c:dusts/redstone"}}, | ||||
|   "pattern": ["###", "#R#", "###"], | ||||
|   "result": {"count": 1, "id": "computercraft:wired_modem"} | ||||
| } | ||||
|   | ||||
| @@ -5,7 +5,9 @@ | ||||
| package dan200.computercraft.data; | ||||
| 
 | ||||
| import com.mojang.serialization.Codec; | ||||
| import dan200.computercraft.shared.ModRegistry; | ||||
| import dan200.computercraft.api.pocket.IPocketUpgrade; | ||||
| import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
| import net.minecraft.Util; | ||||
| import net.minecraft.core.HolderLookup; | ||||
| import net.minecraft.core.RegistrySetBuilder; | ||||
| import net.minecraft.data.DataProvider; | ||||
| @@ -20,7 +22,6 @@ import net.minecraft.world.level.block.Block; | ||||
| import java.util.Set; | ||||
| import java.util.concurrent.CompletableFuture; | ||||
| import java.util.function.BiConsumer; | ||||
| import java.util.function.BiFunction; | ||||
| import java.util.function.Consumer; | ||||
| 
 | ||||
| /** | ||||
| @@ -32,25 +33,25 @@ public final class DataProviders { | ||||
|     } | ||||
| 
 | ||||
|     public static void add(GeneratorSink generator) { | ||||
|         var turtleUpgrades = generator.add(TurtleUpgradeProvider::new); | ||||
|         var pocketUpgrades = generator.add(PocketUpgradeProvider::new); | ||||
|         var fullRegistryPatch = RegistryPatchGenerator.createLookup( | ||||
|             generator.registries(), | ||||
|             Util.make(new RegistrySetBuilder(), builder -> { | ||||
|                 builder.add(ITurtleUpgrade.REGISTRY, TurtleUpgradeProvider::addUpgrades); | ||||
|                 builder.add(IPocketUpgrade.REGISTRY, PocketUpgradeProvider::addUpgrades); | ||||
|             })); | ||||
|         var fullRegistries = fullRegistryPatch.thenApply(RegistrySetBuilder.PatchedRegistries::full); | ||||
| 
 | ||||
|         generator.add((out, registries) -> { | ||||
|             var builder = new RegistrySetBuilder(); | ||||
|             builder.add(ModRegistry.TURTLE_UPGRADE, bs -> turtleUpgrades.getGeneratedUpgrades().forEach(bs::register)); | ||||
|             builder.add(ModRegistry.POCKET_UPGRADE, bs -> pocketUpgrades.getGeneratedUpgrades().forEach(bs::register)); | ||||
| 
 | ||||
|             return new RecipeProvider(out, generator.createPatchedRegistries(registries, builder).thenApply(RegistrySetBuilder.PatchedRegistries::full)); | ||||
|         }); | ||||
|         generator.registries(fullRegistryPatch); | ||||
|         generator.add(out -> new RecipeProvider(out, fullRegistries)); | ||||
| 
 | ||||
|         var blockTags = generator.blockTags(TagProvider::blockTags); | ||||
|         generator.itemTags(TagProvider::itemTags, blockTags); | ||||
| 
 | ||||
|         generator.add((out, registries) -> new net.minecraft.data.loot.LootTableProvider(out, Set.of(), LootTableProvider.getTables(), registries)); | ||||
|         generator.add(out -> new net.minecraft.data.loot.LootTableProvider(out, Set.of(), LootTableProvider.getTables(), fullRegistries)); | ||||
| 
 | ||||
|         generator.add(out -> new ModelProvider(out, BlockModelProvider::addBlockModels, ItemModelProvider::addItemModels)); | ||||
| 
 | ||||
|         generator.add(out -> new LanguageProvider(out, turtleUpgrades, pocketUpgrades)); | ||||
|         generator.add(out -> new LanguageProvider(out, fullRegistries)); | ||||
| 
 | ||||
|         // Unfortunately we rely on some client-side classes in this code. We just load in the client side data provider | ||||
|         // and invoke that. | ||||
| @@ -63,9 +64,9 @@ public final class DataProviders { | ||||
|     } | ||||
| 
 | ||||
|     public interface GeneratorSink { | ||||
|         <T extends DataProvider> T add(DataProvider.Factory<T> factory); | ||||
|         CompletableFuture<HolderLookup.Provider> registries(); | ||||
| 
 | ||||
|         <T extends DataProvider> T add(BiFunction<PackOutput, CompletableFuture<HolderLookup.Provider>, T> factory); | ||||
|         <T extends DataProvider> T add(DataProvider.Factory<T> factory); | ||||
| 
 | ||||
|         <T> void addFromCodec(String name, PackType type, String directory, Codec<T> codec, Consumer<BiConsumer<ResourceLocation, T>> output); | ||||
| 
 | ||||
| @@ -74,16 +75,10 @@ public final class DataProviders { | ||||
|         TagsProvider<Item> itemTags(Consumer<TagProvider.ItemTagConsumer> tags, TagsProvider<Block> blocks); | ||||
| 
 | ||||
|         /** | ||||
|          * Extend our registries with additional entries. | ||||
|          * Build new dynamic registries and save them to a pack. | ||||
|          * | ||||
|          * @param registries The existing registries. | ||||
|          * @param patch      The new registries to apply. | ||||
|          * @return The built registries. | ||||
|          * @param registries The patched registries to write. | ||||
|          */ | ||||
|         default CompletableFuture<RegistrySetBuilder.PatchedRegistries> createPatchedRegistries( | ||||
|             CompletableFuture<HolderLookup.Provider> registries, RegistrySetBuilder patch | ||||
|         ) { | ||||
|             return RegistryPatchGenerator.createLookup(registries, patch); | ||||
|         } | ||||
|         void registries(CompletableFuture<RegistrySetBuilder.PatchedRegistries> registries); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -7,8 +7,8 @@ package dan200.computercraft.data; | ||||
| import com.google.gson.JsonObject; | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
| import dan200.computercraft.api.ComputerCraftTags; | ||||
| import dan200.computercraft.api.pocket.PocketUpgradeDataProvider; | ||||
| import dan200.computercraft.api.turtle.TurtleUpgradeDataProvider; | ||||
| import dan200.computercraft.api.pocket.IPocketUpgrade; | ||||
| import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
| import dan200.computercraft.core.metrics.Metric; | ||||
| import dan200.computercraft.core.metrics.Metrics; | ||||
| import dan200.computercraft.shared.ModRegistry; | ||||
| @@ -17,6 +17,7 @@ import dan200.computercraft.shared.computer.metrics.basic.Aggregate; | ||||
| import dan200.computercraft.shared.computer.metrics.basic.AggregatedMetric; | ||||
| import dan200.computercraft.shared.config.ConfigFile; | ||||
| import dan200.computercraft.shared.config.ConfigSpec; | ||||
| import net.minecraft.core.HolderLookup; | ||||
| import net.minecraft.core.registries.BuiltInRegistries; | ||||
| import net.minecraft.data.CachedOutput; | ||||
| import net.minecraft.data.DataProvider; | ||||
| @@ -34,27 +35,28 @@ import java.util.stream.Stream; | ||||
| 
 | ||||
| public final class LanguageProvider implements DataProvider { | ||||
|     private final PackOutput output; | ||||
|     private final TurtleUpgradeDataProvider turtleUpgrades; | ||||
|     private final PocketUpgradeDataProvider pocketUpgrades; | ||||
|     private final CompletableFuture<HolderLookup.Provider> registries; | ||||
| 
 | ||||
|     private final Map<String, String> translations = new HashMap<>(); | ||||
| 
 | ||||
|     public LanguageProvider(PackOutput output, TurtleUpgradeDataProvider turtleUpgrades, PocketUpgradeDataProvider pocketUpgrades) { | ||||
|     public LanguageProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) { | ||||
|         this.output = output; | ||||
|         this.turtleUpgrades = turtleUpgrades; | ||||
|         this.pocketUpgrades = pocketUpgrades; | ||||
|         this.registries = registries; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public CompletableFuture<?> run(CachedOutput cachedOutput) { | ||||
|         addTranslations(); | ||||
|         getExpectedKeys().forEach(x -> { | ||||
| 
 | ||||
|         return registries.thenCompose(registries -> { | ||||
|             getExpectedKeys(registries).forEach(x -> { | ||||
|                 if (!translations.containsKey(x)) throw new IllegalStateException("No translation for " + x); | ||||
|             }); | ||||
| 
 | ||||
|             var json = new JsonObject(); | ||||
|             for (var pair : translations.entrySet()) json.addProperty(pair.getKey(), pair.getValue()); | ||||
|             return DataProvider.saveStable(cachedOutput, json, output.getOutputFolder().resolve("assets/" + ComputerCraftAPI.MOD_ID + "/lang/en_us.json")); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
| @@ -280,7 +282,7 @@ public final class LanguageProvider implements DataProvider { | ||||
|         addConfigEntry(ConfigSpec.uploadNagDelay, "Upload nag delay"); | ||||
|     } | ||||
| 
 | ||||
|     private Stream<String> getExpectedKeys() { | ||||
|     private Stream<String> getExpectedKeys(HolderLookup.Provider registries) { | ||||
|         return Stream.of( | ||||
|             BuiltInRegistries.BLOCK.holders() | ||||
|                 .filter(x -> x.key().location().getNamespace().equals(ComputerCraftAPI.MOD_ID)) | ||||
| @@ -288,8 +290,8 @@ public final class LanguageProvider implements DataProvider { | ||||
|             BuiltInRegistries.ITEM.holders() | ||||
|                 .filter(x -> x.key().location().getNamespace().equals(ComputerCraftAPI.MOD_ID)) | ||||
|                 .map(x -> x.value().getDescriptionId()), | ||||
|             turtleUpgrades.getGeneratedUpgrades().values().stream().flatMap(x -> getTranslationKeys(x.getAdjective())), | ||||
|             pocketUpgrades.getGeneratedUpgrades().values().stream().flatMap(x -> getTranslationKeys(x.getAdjective())), | ||||
|             registries.lookupOrThrow(ITurtleUpgrade.REGISTRY).listElements().flatMap(x -> getTranslationKeys(x.value().getAdjective())), | ||||
|             registries.lookupOrThrow(IPocketUpgrade.REGISTRY).listElements().flatMap(x -> getTranslationKeys(x.value().getAdjective())), | ||||
|             Metric.metrics().values().stream().map(x -> AggregatedMetric.TRANSLATION_PREFIX + x.name() + ".name"), | ||||
|             ConfigSpec.serverSpec.entries().map(ConfigFile.Entry::translationKey), | ||||
|             ConfigSpec.clientSpec.entries().map(ConfigFile.Entry::translationKey), | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| package dan200.computercraft.data; | ||||
| 
 | ||||
| import com.google.gson.JsonElement; | ||||
| import dan200.computercraft.impl.RegistryHelper; | ||||
| import dan200.computercraft.shared.util.RegistryHelper; | ||||
| import net.minecraft.Util; | ||||
| import net.minecraft.core.registries.BuiltInRegistries; | ||||
| import net.minecraft.data.CachedOutput; | ||||
|   | ||||
| @@ -6,30 +6,23 @@ package dan200.computercraft.data; | ||||
| 
 | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
| import dan200.computercraft.api.pocket.IPocketUpgrade; | ||||
| import dan200.computercraft.api.pocket.PocketUpgradeDataProvider; | ||||
| import dan200.computercraft.shared.pocket.peripherals.PocketModem; | ||||
| import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker; | ||||
| import net.minecraft.data.PackOutput; | ||||
| import net.minecraft.data.worldgen.BootstrapContext; | ||||
| import net.minecraft.resources.ResourceKey; | ||||
| import net.minecraft.resources.ResourceLocation; | ||||
| import net.minecraft.world.item.ItemStack; | ||||
| 
 | ||||
| import java.util.function.Consumer; | ||||
| 
 | ||||
| import static dan200.computercraft.shared.ModRegistry.Items; | ||||
| 
 | ||||
| class PocketUpgradeProvider extends PocketUpgradeDataProvider { | ||||
|     PocketUpgradeProvider(PackOutput output) { | ||||
|         super(output); | ||||
| class PocketUpgradeProvider { | ||||
|     public static void addUpgrades(BootstrapContext<IPocketUpgrade> upgrades) { | ||||
|         upgrades.register(id("speaker"), new PocketSpeaker(new ItemStack(Items.SPEAKER.get()))); | ||||
|         upgrades.register(id("wireless_modem_normal"), new PocketModem(new ItemStack(Items.WIRELESS_MODEM_NORMAL.get()), false)); | ||||
|         upgrades.register(id("wireless_modem_advanced"), new PocketModem(new ItemStack(Items.WIRELESS_MODEM_ADVANCED.get()), true)); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void addUpgrades(Consumer<Upgrade<IPocketUpgrade>> addUpgrade) { | ||||
|         upgrade(id("speaker"), new PocketSpeaker(new ItemStack(Items.SPEAKER.get()))).add(addUpgrade); | ||||
|         upgrade(id("wireless_modem_normal"), new PocketModem(new ItemStack(Items.WIRELESS_MODEM_NORMAL.get()), false)).add(addUpgrade); | ||||
|         upgrade(id("wireless_modem_advanced"), new PocketModem(new ItemStack(Items.WIRELESS_MODEM_ADVANCED.get()), true)).add(addUpgrade); | ||||
|     } | ||||
| 
 | ||||
|     private static ResourceLocation id(String id) { | ||||
|         return new ResourceLocation(ComputerCraftAPI.MOD_ID, id); | ||||
|     private static ResourceKey<IPocketUpgrade> id(String id) { | ||||
|         return ResourceKey.create(IPocketUpgrade.REGISTRY, new ResourceLocation(ComputerCraftAPI.MOD_ID, id)); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -8,11 +8,13 @@ import com.google.gson.JsonObject; | ||||
| import com.mojang.authlib.GameProfile; | ||||
| import com.mojang.serialization.JsonOps; | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
| import dan200.computercraft.api.pocket.IPocketUpgrade; | ||||
| import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
| import dan200.computercraft.api.upgrades.UpgradeData; | ||||
| import dan200.computercraft.core.util.Colour; | ||||
| import dan200.computercraft.data.recipe.ShapedSpecBuilder; | ||||
| import dan200.computercraft.data.recipe.ShapelessSpecBuilder; | ||||
| import dan200.computercraft.impl.RegistryHelper; | ||||
| import dan200.computercraft.shared.util.RegistryHelper; | ||||
| import dan200.computercraft.shared.ModRegistry; | ||||
| import dan200.computercraft.shared.common.ClearColourRecipe; | ||||
| import dan200.computercraft.shared.common.ColourableRecipe; | ||||
| @@ -54,14 +56,12 @@ import net.minecraft.world.item.crafting.CraftingBookCategory; | ||||
| import net.minecraft.world.item.crafting.Ingredient; | ||||
| import net.minecraft.world.item.crafting.Recipe; | ||||
| import net.minecraft.world.level.ItemLike; | ||||
| import net.minecraft.world.level.block.Blocks; | ||||
| 
 | ||||
| import java.util.List; | ||||
| import java.util.UUID; | ||||
| import java.util.concurrent.CompletableFuture; | ||||
| import java.util.concurrent.ExecutionException; | ||||
| import java.util.function.Consumer; | ||||
| import java.util.stream.Stream; | ||||
| 
 | ||||
| import static dan200.computercraft.api.ComputerCraftTags.Items.COMPUTER; | ||||
| import static dan200.computercraft.api.ComputerCraftTags.Items.WIRED_MODEM; | ||||
| @@ -119,7 +119,7 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider { | ||||
|                 .requires(Items.PAPER) | ||||
|                 .requires(DyeItem.byColor(ofColour(colour))) | ||||
|                 .group("computercraft:disk") | ||||
|                 .unlockedBy("has_drive", inventoryChange(ModRegistry.Blocks.DISK_DRIVE.get())) | ||||
|                 .unlockedBy("has_drive", inventoryChange(ModRegistry.Items.DISK_DRIVE.get())) | ||||
|                 .build(ImpostorShapelessRecipe::new) | ||||
|                 .save(output, new ResourceLocation(ComputerCraftAPI.MOD_ID, "disk_" + (colour.ordinal() + 1))); | ||||
|         } | ||||
| @@ -139,7 +139,7 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider { | ||||
|         for (var turtleItem : turtleItems()) { | ||||
|             var name = RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, turtleItem); | ||||
| 
 | ||||
|             registries.lookup(ModRegistry.TURTLE_UPGRADE).map(HolderLookup::listElements).orElse(Stream.empty()).forEach(upgradeHolder -> { | ||||
|             registries.lookupOrThrow(ITurtleUpgrade.REGISTRY).listElements().forEach(upgradeHolder -> { | ||||
|                 var upgrade = upgradeHolder.value(); | ||||
|                 ShapedSpecBuilder | ||||
|                     .shaped(RecipeCategory.REDSTONE, DataComponentUtil.createStack(turtleItem, ModRegistry.DataComponents.RIGHT_TURTLE_UPGRADE.get(), UpgradeData.ofDefault(upgradeHolder))) | ||||
| @@ -171,7 +171,7 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider { | ||||
|         for (var pocket : pocketComputerItems()) { | ||||
|             var name = RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, pocket).withPath(x -> x.replace("pocket_computer_", "pocket_")); | ||||
| 
 | ||||
|             registries.lookup(ModRegistry.POCKET_UPGRADE).map(HolderLookup::listElements).orElse(Stream.empty()).forEach(upgradeHolder -> { | ||||
|             registries.lookupOrThrow(IPocketUpgrade.REGISTRY).listElements().forEach(upgradeHolder -> { | ||||
|                 var upgrade = upgradeHolder.value(); | ||||
|                 ShapedSpecBuilder | ||||
|                     .shaped(RecipeCategory.REDSTONE, DataComponentUtil.createStack(pocket, ModRegistry.DataComponents.POCKET_UPGRADE.get(), UpgradeData.ofDefault(upgradeHolder))) | ||||
| @@ -238,25 +238,25 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider { | ||||
|             .pattern(" # ") | ||||
|             .pattern("#R#") | ||||
|             .pattern(" # ") | ||||
|             .define('#', ingredients.stone()) | ||||
|             .define('#', Items.STONE) | ||||
|             .define('R', ingredients.redstone()) | ||||
|             .unlockedBy("has_computer", inventoryChange(COMPUTER)) | ||||
|             .unlockedBy("has_modem", inventoryChange(WIRED_MODEM)) | ||||
|             .save(add); | ||||
| 
 | ||||
|         ShapedRecipeBuilder | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.COMPUTER_NORMAL.get()) | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Items.COMPUTER_NORMAL.get()) | ||||
|             .pattern("###") | ||||
|             .pattern("#R#") | ||||
|             .pattern("#G#") | ||||
|             .define('#', ingredients.stone()) | ||||
|             .define('#', Items.STONE) | ||||
|             .define('R', ingredients.redstone()) | ||||
|             .define('G', ingredients.glassPane()) | ||||
|             .unlockedBy("has_redstone", inventoryChange(itemPredicate(ingredients.redstone()))) | ||||
|             .save(add); | ||||
| 
 | ||||
|         ShapedRecipeBuilder | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.COMPUTER_ADVANCED.get()) | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Items.COMPUTER_ADVANCED.get()) | ||||
|             .pattern("###") | ||||
|             .pattern("#R#") | ||||
|             .pattern("#G#") | ||||
| @@ -278,18 +278,18 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider { | ||||
|             .save(add, new ResourceLocation(ComputerCraftAPI.MOD_ID, "computer_advanced_upgrade")); | ||||
| 
 | ||||
|         ShapedRecipeBuilder | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.COMPUTER_COMMAND.get()) | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Items.COMPUTER_COMMAND.get()) | ||||
|             .pattern("###") | ||||
|             .pattern("#R#") | ||||
|             .pattern("#G#") | ||||
|             .define('#', ingredients.goldIngot()) | ||||
|             .define('R', Blocks.COMMAND_BLOCK) | ||||
|             .define('R', Items.COMMAND_BLOCK) | ||||
|             .define('G', ingredients.glassPane()) | ||||
|             .unlockedBy("has_components", inventoryChange(Blocks.COMMAND_BLOCK)) | ||||
|             .unlockedBy("has_components", inventoryChange(Items.COMMAND_BLOCK)) | ||||
|             .save(add); | ||||
| 
 | ||||
|         ShapedSpecBuilder | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.TURTLE_NORMAL.get()) | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Items.TURTLE_NORMAL.get()) | ||||
|             .pattern("###") | ||||
|             .pattern("#C#") | ||||
|             .pattern("#I#") | ||||
| @@ -301,7 +301,7 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider { | ||||
|             .save(add); | ||||
| 
 | ||||
|         ShapedSpecBuilder | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.TURTLE_ADVANCED.get()) | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Items.TURTLE_ADVANCED.get()) | ||||
|             .pattern("###") | ||||
|             .pattern("#C#") | ||||
|             .pattern("#I#") | ||||
| @@ -313,7 +313,7 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider { | ||||
|             .save(add); | ||||
| 
 | ||||
|         ShapedSpecBuilder | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.TURTLE_ADVANCED.get()) | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Items.TURTLE_ADVANCED.get()) | ||||
|             .pattern("###") | ||||
|             .pattern("#C#") | ||||
|             .pattern(" B ") | ||||
| @@ -325,27 +325,27 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider { | ||||
|             .save(add, new ResourceLocation(ComputerCraftAPI.MOD_ID, "turtle_advanced_upgrade")); | ||||
| 
 | ||||
|         ShapedRecipeBuilder | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.DISK_DRIVE.get()) | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Items.DISK_DRIVE.get()) | ||||
|             .pattern("###") | ||||
|             .pattern("#R#") | ||||
|             .pattern("#R#") | ||||
|             .define('#', ingredients.stone()) | ||||
|             .define('#', Items.STONE) | ||||
|             .define('R', ingredients.redstone()) | ||||
|             .unlockedBy("has_computer", inventoryChange(COMPUTER)) | ||||
|             .save(add); | ||||
| 
 | ||||
|         ShapedRecipeBuilder | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.MONITOR_NORMAL.get()) | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Items.MONITOR_NORMAL.get()) | ||||
|             .pattern("###") | ||||
|             .pattern("#G#") | ||||
|             .pattern("###") | ||||
|             .define('#', ingredients.stone()) | ||||
|             .define('#', Items.STONE) | ||||
|             .define('G', ingredients.glassPane()) | ||||
|             .unlockedBy("has_computer", inventoryChange(COMPUTER)) | ||||
|             .save(add); | ||||
| 
 | ||||
|         ShapedRecipeBuilder | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.MONITOR_ADVANCED.get(), 4) | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Items.MONITOR_ADVANCED.get(), 4) | ||||
|             .pattern("###") | ||||
|             .pattern("#G#") | ||||
|             .pattern("###") | ||||
| @@ -359,7 +359,7 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider { | ||||
|             .pattern("###") | ||||
|             .pattern("#A#") | ||||
|             .pattern("#G#") | ||||
|             .define('#', ingredients.stone()) | ||||
|             .define('#', Items.STONE) | ||||
|             .define('A', Items.GOLDEN_APPLE) | ||||
|             .define('G', ingredients.glassPane()) | ||||
|             .unlockedBy("has_computer", inventoryChange(COMPUTER)) | ||||
| @@ -390,23 +390,23 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider { | ||||
|             .save(add, new ResourceLocation(ComputerCraftAPI.MOD_ID, "pocket_computer_advanced_upgrade")); | ||||
| 
 | ||||
|         ShapedRecipeBuilder | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.PRINTER.get()) | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Items.PRINTER.get()) | ||||
|             .pattern("###") | ||||
|             .pattern("#R#") | ||||
|             .pattern("#D#") | ||||
|             .define('#', ingredients.stone()) | ||||
|             .define('#', Items.STONE) | ||||
|             .define('R', ingredients.redstone()) | ||||
|             .define('D', ingredients.dye()) | ||||
|             .unlockedBy("has_computer", inventoryChange(COMPUTER)) | ||||
|             .save(add); | ||||
| 
 | ||||
|         ShapedRecipeBuilder | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.SPEAKER.get()) | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Items.SPEAKER.get()) | ||||
|             .pattern("###") | ||||
|             .pattern("#N#") | ||||
|             .pattern("#R#") | ||||
|             .define('#', ingredients.stone()) | ||||
|             .define('N', Blocks.NOTE_BLOCK) | ||||
|             .define('#', Items.STONE) | ||||
|             .define('N', Items.NOTE_BLOCK) | ||||
|             .define('R', ingredients.redstone()) | ||||
|             .unlockedBy("has_computer", inventoryChange(COMPUTER)) | ||||
|             .save(add); | ||||
| @@ -416,42 +416,42 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider { | ||||
|             .pattern("###") | ||||
|             .pattern("#R#") | ||||
|             .pattern("###") | ||||
|             .define('#', ingredients.stone()) | ||||
|             .define('#', Items.STONE) | ||||
|             .define('R', ingredients.redstone()) | ||||
|             .unlockedBy("has_computer", inventoryChange(COMPUTER)) | ||||
|             .unlockedBy("has_cable", inventoryChange(ModRegistry.Items.CABLE.get())) | ||||
|             .save(add); | ||||
| 
 | ||||
|         ShapelessRecipeBuilder | ||||
|             .shapeless(RecipeCategory.REDSTONE, ModRegistry.Blocks.WIRED_MODEM_FULL.get()) | ||||
|             .shapeless(RecipeCategory.REDSTONE, ModRegistry.Items.WIRED_MODEM_FULL.get()) | ||||
|             .requires(ModRegistry.Items.WIRED_MODEM.get()) | ||||
|             .unlockedBy("has_modem", inventoryChange(WIRED_MODEM)) | ||||
|             .save(add, new ResourceLocation(ComputerCraftAPI.MOD_ID, "wired_modem_full_from")); | ||||
|         ShapelessRecipeBuilder | ||||
|             .shapeless(RecipeCategory.REDSTONE, ModRegistry.Items.WIRED_MODEM.get()) | ||||
|             .requires(ModRegistry.Blocks.WIRED_MODEM_FULL.get()) | ||||
|             .requires(ModRegistry.Items.WIRED_MODEM_FULL.get()) | ||||
|             .unlockedBy("has_modem", inventoryChange(WIRED_MODEM)) | ||||
|             .save(add, new ResourceLocation(ComputerCraftAPI.MOD_ID, "wired_modem_full_to")); | ||||
| 
 | ||||
|         ShapedRecipeBuilder | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.WIRELESS_MODEM_NORMAL.get()) | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Items.WIRELESS_MODEM_NORMAL.get()) | ||||
|             .pattern("###") | ||||
|             .pattern("#E#") | ||||
|             .pattern("###") | ||||
|             .define('#', ingredients.stone()) | ||||
|             .define('#', Items.STONE) | ||||
|             .define('E', ingredients.enderPearl()) | ||||
|             .unlockedBy("has_computer", inventoryChange(COMPUTER)) | ||||
|             .save(add); | ||||
| 
 | ||||
|         ShapedRecipeBuilder | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.WIRELESS_MODEM_ADVANCED.get()) | ||||
|             .shaped(RecipeCategory.REDSTONE, ModRegistry.Items.WIRELESS_MODEM_ADVANCED.get()) | ||||
|             .pattern("###") | ||||
|             .pattern("#E#") | ||||
|             .pattern("###") | ||||
|             .define('#', ingredients.goldIngot()) | ||||
|             .define('E', Items.ENDER_EYE) | ||||
|             .unlockedBy("has_computer", inventoryChange(COMPUTER)) | ||||
|             .unlockedBy("has_wireless", inventoryChange(ModRegistry.Blocks.WIRELESS_MODEM_NORMAL.get())) | ||||
|             .unlockedBy("has_wireless", inventoryChange(ModRegistry.Items.WIRELESS_MODEM_NORMAL.get())) | ||||
|             .save(add); | ||||
| 
 | ||||
|         ShapelessSpecBuilder | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| package dan200.computercraft.data; | ||||
| 
 | ||||
| import dan200.computercraft.api.ComputerCraftTags; | ||||
| import dan200.computercraft.impl.RegistryHelper; | ||||
| import dan200.computercraft.shared.util.RegistryHelper; | ||||
| import dan200.computercraft.shared.ModRegistry; | ||||
| import dan200.computercraft.shared.integration.ExternalModTags; | ||||
| import net.minecraft.core.Registry; | ||||
|   | ||||
| @@ -5,45 +5,40 @@ | ||||
| package dan200.computercraft.data; | ||||
| 
 | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
| import dan200.computercraft.api.ComputerCraftTags.Blocks; | ||||
| import dan200.computercraft.api.ComputerCraftTags; | ||||
| import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
| import dan200.computercraft.api.turtle.TurtleUpgradeDataProvider; | ||||
| import dan200.computercraft.shared.ModRegistry; | ||||
| import dan200.computercraft.shared.turtle.upgrades.TurtleCraftingTable; | ||||
| import dan200.computercraft.shared.turtle.upgrades.TurtleModem; | ||||
| import dan200.computercraft.shared.turtle.upgrades.TurtleSpeaker; | ||||
| import net.minecraft.data.PackOutput; | ||||
| import net.minecraft.data.worldgen.BootstrapContext; | ||||
| import net.minecraft.resources.ResourceKey; | ||||
| import net.minecraft.resources.ResourceLocation; | ||||
| import net.minecraft.world.item.ItemStack; | ||||
| import net.minecraft.world.item.Items; | ||||
| 
 | ||||
| import java.util.function.Consumer; | ||||
| import static dan200.computercraft.api.turtle.TurtleToolBuilder.tool; | ||||
| 
 | ||||
| class TurtleUpgradeProvider extends TurtleUpgradeDataProvider { | ||||
|     TurtleUpgradeProvider(PackOutput output) { | ||||
|         super(output); | ||||
| class TurtleUpgradeProvider { | ||||
|     public static void addUpgrades(BootstrapContext<ITurtleUpgrade> upgrades) { | ||||
|         upgrades.register(id("speaker"), new TurtleSpeaker(new ItemStack(ModRegistry.Items.SPEAKER.get()))); | ||||
|         upgrades.register(vanilla("crafting_table"), new TurtleCraftingTable(new ItemStack(Items.CRAFTING_TABLE))); | ||||
|         upgrades.register(id("wireless_modem_normal"), new TurtleModem(new ItemStack(ModRegistry.Items.WIRELESS_MODEM_NORMAL.get()), false)); | ||||
|         upgrades.register(id("wireless_modem_advanced"), new TurtleModem(new ItemStack(ModRegistry.Items.WIRELESS_MODEM_ADVANCED.get()), true)); | ||||
| 
 | ||||
|         tool(vanilla("diamond_axe").location(), Items.DIAMOND_AXE).damageMultiplier(6.0f).register(upgrades); | ||||
|         tool(vanilla("diamond_pickaxe"), Items.DIAMOND_PICKAXE).register(upgrades); | ||||
|         tool(vanilla("diamond_hoe"), Items.DIAMOND_HOE).breakable(ComputerCraftTags.Blocks.TURTLE_HOE_BREAKABLE).register(upgrades); | ||||
|         tool(vanilla("diamond_shovel"), Items.DIAMOND_SHOVEL).breakable(ComputerCraftTags.Blocks.TURTLE_SHOVEL_BREAKABLE).register(upgrades); | ||||
|         tool(vanilla("diamond_sword"), Items.DIAMOND_SWORD).breakable(ComputerCraftTags.Blocks.TURTLE_SWORD_BREAKABLE).damageMultiplier(9.0f).register(upgrades); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void addUpgrades(Consumer<Upgrade<ITurtleUpgrade>> addUpgrade) { | ||||
|         upgrade(id("speaker"), new TurtleSpeaker(new ItemStack(ModRegistry.Items.SPEAKER.get()))).add(addUpgrade); | ||||
|         upgrade(vanilla("crafting_table"), new TurtleCraftingTable(new ItemStack(Items.CRAFTING_TABLE))).add(addUpgrade); | ||||
|         upgrade(id("wireless_modem_normal"), new TurtleModem(new ItemStack(ModRegistry.Items.WIRELESS_MODEM_NORMAL.get()), false)).add(addUpgrade); | ||||
|         upgrade(id("wireless_modem_advanced"), new TurtleModem(new ItemStack(ModRegistry.Items.WIRELESS_MODEM_ADVANCED.get()), true)).add(addUpgrade); | ||||
| 
 | ||||
|         tool(vanilla("diamond_axe"), Items.DIAMOND_AXE).damageMultiplier(6.0f).add(addUpgrade); | ||||
|         tool(vanilla("diamond_pickaxe"), Items.DIAMOND_PICKAXE).add(addUpgrade); | ||||
|         tool(vanilla("diamond_hoe"), Items.DIAMOND_HOE).breakable(Blocks.TURTLE_HOE_BREAKABLE).add(addUpgrade); | ||||
|         tool(vanilla("diamond_shovel"), Items.DIAMOND_SHOVEL).breakable(Blocks.TURTLE_SHOVEL_BREAKABLE).add(addUpgrade); | ||||
|         tool(vanilla("diamond_sword"), Items.DIAMOND_SWORD).breakable(Blocks.TURTLE_SWORD_BREAKABLE).damageMultiplier(9.0f).add(addUpgrade); | ||||
|     private static ResourceKey<ITurtleUpgrade> id(String id) { | ||||
|         return ITurtleUpgrade.createKey(new ResourceLocation(ComputerCraftAPI.MOD_ID, id)); | ||||
|     } | ||||
| 
 | ||||
|     private static ResourceLocation id(String id) { | ||||
|         return new ResourceLocation(ComputerCraftAPI.MOD_ID, id); | ||||
|     } | ||||
| 
 | ||||
|     private static ResourceLocation vanilla(String id) { | ||||
|     private static ResourceKey<ITurtleUpgrade> vanilla(String id) { | ||||
|         // Naughty, please don't do this. Mostly here for some semblance of backwards compatibility. | ||||
|         return new ResourceLocation("minecraft", id); | ||||
|         return ITurtleUpgrade.createKey(new ResourceLocation("minecraft", id)); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -5,11 +5,10 @@ | ||||
| package dan200.computercraft.impl; | ||||
| 
 | ||||
| import dan200.computercraft.api.pocket.IPocketUpgrade; | ||||
| import dan200.computercraft.shared.ModRegistry; | ||||
| 
 | ||||
| public final class PocketUpgrades { | ||||
|     private static final UpgradeManager<IPocketUpgrade> registry = new UpgradeManager<>( | ||||
|         IPocketUpgrade.typeRegistry(), ModRegistry.POCKET_UPGRADE, IPocketUpgrade::getType | ||||
|         IPocketUpgrade.typeRegistry(), IPocketUpgrade.REGISTRY, IPocketUpgrade::getType | ||||
|     ); | ||||
| 
 | ||||
|     private PocketUpgrades() { | ||||
|   | ||||
| @@ -5,11 +5,10 @@ | ||||
| package dan200.computercraft.impl; | ||||
| 
 | ||||
| import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
| import dan200.computercraft.shared.ModRegistry; | ||||
| 
 | ||||
| public final class TurtleUpgrades { | ||||
|     private static final UpgradeManager<ITurtleUpgrade> registry = new UpgradeManager<>( | ||||
|         ITurtleUpgrade.typeRegistry(), ModRegistry.TURTLE_UPGRADE, ITurtleUpgrade::getType | ||||
|         ITurtleUpgrade.typeRegistry(), ITurtleUpgrade.REGISTRY, ITurtleUpgrade::getType | ||||
|     ); | ||||
| 
 | ||||
|     private TurtleUpgrades() { | ||||
|   | ||||
| @@ -18,7 +18,6 @@ import dan200.computercraft.api.upgrades.UpgradeData; | ||||
| import dan200.computercraft.api.upgrades.UpgradeType; | ||||
| import dan200.computercraft.core.util.Colour; | ||||
| import dan200.computercraft.impl.PocketUpgrades; | ||||
| import dan200.computercraft.impl.RegistryHelper; | ||||
| import dan200.computercraft.shared.command.UserLevel; | ||||
| import dan200.computercraft.shared.command.arguments.ComputerArgumentType; | ||||
| import dan200.computercraft.shared.command.arguments.RepeatArgumentType; | ||||
| @@ -91,7 +90,6 @@ import net.minecraft.commands.synchronization.ArgumentTypeInfo; | ||||
| import net.minecraft.commands.synchronization.SingletonArgumentInfo; | ||||
| import net.minecraft.core.Holder; | ||||
| import net.minecraft.core.HolderLookup; | ||||
| import net.minecraft.core.Registry; | ||||
| import net.minecraft.core.cauldron.CauldronInteraction; | ||||
| import net.minecraft.core.component.DataComponentType; | ||||
| import net.minecraft.core.registries.Registries; | ||||
| @@ -99,7 +97,6 @@ import net.minecraft.network.RegistryFriendlyByteBuf; | ||||
| import net.minecraft.network.chat.Component; | ||||
| import net.minecraft.network.codec.ByteBufCodecs; | ||||
| import net.minecraft.network.codec.StreamCodec; | ||||
| import net.minecraft.resources.ResourceKey; | ||||
| import net.minecraft.resources.ResourceLocation; | ||||
| import net.minecraft.world.flag.FeatureFlags; | ||||
| import net.minecraft.world.inventory.MenuType; | ||||
| @@ -130,9 +127,6 @@ public final class ModRegistry { | ||||
|     private ModRegistry() { | ||||
|     } | ||||
| 
 | ||||
|     public static final ResourceKey<Registry<ITurtleUpgrade>> TURTLE_UPGRADE = RegistryHelper.TURTLE_UPGRADE; | ||||
|     public static final ResourceKey<Registry<IPocketUpgrade>> POCKET_UPGRADE = RegistryHelper.POCKET_UPGRADE; | ||||
| 
 | ||||
|     public static final class Blocks { | ||||
|         static final RegistrationHelper<Block> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registries.BLOCK); | ||||
| 
 | ||||
| @@ -602,7 +596,7 @@ public final class ModRegistry { | ||||
| 
 | ||||
|     private static void addTurtle(CreativeModeTab.Output out, TurtleItem turtle, HolderLookup.Provider registries) { | ||||
|         out.accept(new ItemStack(turtle)); | ||||
|         registries.lookupOrThrow(TURTLE_UPGRADE).listElements() | ||||
|         registries.lookupOrThrow(ITurtleUpgrade.REGISTRY).listElements() | ||||
|             .filter(ModRegistry::isOurUpgrade) | ||||
|             .map(x -> DataComponentUtil.createStack(turtle, DataComponents.RIGHT_TURTLE_UPGRADE.get(), UpgradeData.ofDefault(x))) | ||||
|             .forEach(out::accept); | ||||
| @@ -610,7 +604,7 @@ public final class ModRegistry { | ||||
| 
 | ||||
|     private static void addPocket(CreativeModeTab.Output out, PocketComputerItem pocket, HolderLookup.Provider registries) { | ||||
|         out.accept(new ItemStack(pocket)); | ||||
|         registries.lookupOrThrow(POCKET_UPGRADE).listElements() | ||||
|         registries.lookupOrThrow(IPocketUpgrade.REGISTRY).listElements() | ||||
|             .filter(ModRegistry::isOurUpgrade) | ||||
|             .map(x -> DataComponentUtil.createStack(pocket, DataComponents.POCKET_UPGRADE.get(), UpgradeData.ofDefault(x))).forEach(out::accept); | ||||
|     } | ||||
|   | ||||
| @@ -8,7 +8,7 @@ import com.google.gson.JsonObject; | ||||
| import com.mojang.brigadier.Message; | ||||
| import com.mojang.brigadier.arguments.ArgumentType; | ||||
| import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; | ||||
| import dan200.computercraft.impl.RegistryHelper; | ||||
| import dan200.computercraft.shared.util.RegistryHelper; | ||||
| import net.minecraft.commands.synchronization.ArgumentTypeInfo; | ||||
| import net.minecraft.core.registries.BuiltInRegistries; | ||||
| import net.minecraft.network.FriendlyByteBuf; | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
| 
 | ||||
| package dan200.computercraft.shared.details; | ||||
| 
 | ||||
| import dan200.computercraft.impl.RegistryHelper; | ||||
| import dan200.computercraft.shared.util.RegistryHelper; | ||||
| import net.minecraft.core.Holder; | ||||
| import net.minecraft.core.Registry; | ||||
| import net.minecraft.tags.TagKey; | ||||
|   | ||||
| @@ -5,6 +5,8 @@ | ||||
| package dan200.computercraft.shared.integration; | ||||
| 
 | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
| import dan200.computercraft.api.pocket.IPocketUpgrade; | ||||
| import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
| import dan200.computercraft.api.upgrades.UpgradeData; | ||||
| import dan200.computercraft.shared.ModRegistry; | ||||
| import dan200.computercraft.shared.pocket.items.PocketComputerItem; | ||||
| @@ -60,14 +62,14 @@ public final class RecipeModHelpers { | ||||
|         List<ItemStack> upgradeItems = new ArrayList<>(); | ||||
|         for (var turtleSupplier : TURTLES) { | ||||
|             var turtle = turtleSupplier.get(); | ||||
|             forEachRegistry(registries, ModRegistry.TURTLE_UPGRADE, upgrade -> | ||||
|             forEachRegistry(registries, ITurtleUpgrade.REGISTRY, upgrade -> | ||||
|                 upgradeItems.add(DataComponentUtil.createStack(turtle, ModRegistry.DataComponents.RIGHT_TURTLE_UPGRADE.get(), UpgradeData.ofDefault(upgrade))) | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         for (var pocketSupplier : POCKET_COMPUTERS) { | ||||
|             var pocket = pocketSupplier.get(); | ||||
|             forEachRegistry(registries, ModRegistry.POCKET_UPGRADE, upgrade -> | ||||
|             forEachRegistry(registries, IPocketUpgrade.REGISTRY, upgrade -> | ||||
|                 upgradeItems.add(DataComponentUtil.createStack(pocket, ModRegistry.DataComponents.POCKET_UPGRADE.get(), UpgradeData.ofDefault(upgrade))) | ||||
|             ); | ||||
|         } | ||||
|   | ||||
| @@ -57,7 +57,7 @@ public class UpgradeRecipeGenerator<T> { | ||||
|         if (initialised) return; | ||||
|         initialised = true; | ||||
| 
 | ||||
|         forEachRegistry(registries, ModRegistry.TURTLE_UPGRADE, holder -> { | ||||
|         forEachRegistry(registries, ITurtleUpgrade.REGISTRY, holder -> { | ||||
|             var upgrade = holder.value(); | ||||
|             var stack = upgrade.getCraftingItem(); | ||||
|             if (stack.isEmpty()) return; | ||||
| @@ -67,7 +67,7 @@ public class UpgradeRecipeGenerator<T> { | ||||
|             turtleUpgrades.add(info); | ||||
|         }); | ||||
| 
 | ||||
|         forEachRegistry(registries, ModRegistry.POCKET_UPGRADE, holder -> { | ||||
|         forEachRegistry(registries, IPocketUpgrade.REGISTRY, holder -> { | ||||
|             var upgrade = holder.value(); | ||||
|             var stack = upgrade.getCraftingItem(); | ||||
|             if (stack.isEmpty()) return; | ||||
| @@ -223,13 +223,13 @@ public class UpgradeRecipeGenerator<T> { | ||||
|         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; | ||||
|         return newStack; | ||||
|     } | ||||
| 
 | ||||
|     private static ItemStack pocketWith(ItemStack stack, @Nullable UpgradeData<IPocketUpgrade> back) { | ||||
|         var newStack = stack.copyWithCount(1); | ||||
|         newStack.set(ModRegistry.DataComponents.POCKET_UPGRADE.get(), back); | ||||
|         return stack; | ||||
|         return newStack; | ||||
|     } | ||||
| 
 | ||||
|     private T pocket(Ingredient upgrade, Ingredient pocketComputer, ItemStack result) { | ||||
|   | ||||
| @@ -8,7 +8,9 @@ import com.mojang.serialization.Codec; | ||||
| import com.mojang.serialization.DataResult; | ||||
| import com.mojang.serialization.codecs.RecordCodecBuilder; | ||||
| import dan200.computercraft.core.terminal.Terminal; | ||||
| import dan200.computercraft.shared.ModRegistry; | ||||
| import io.netty.buffer.ByteBuf; | ||||
| import net.minecraft.core.component.DataComponentHolder; | ||||
| import net.minecraft.network.codec.ByteBufCodecs; | ||||
| import net.minecraft.network.codec.StreamCodec; | ||||
| 
 | ||||
| @@ -93,6 +95,10 @@ public record PrintoutData(String title, List<Line> lines) { | ||||
|         return DataResult.success(lines); | ||||
|     } | ||||
| 
 | ||||
|     public static PrintoutData getOrEmpty(DataComponentHolder holder) { | ||||
|         return holder.getOrDefault(ModRegistry.DataComponents.PRINTOUT.get(), EMPTY); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get the number of pages in this printout. | ||||
|      * | ||||
|   | ||||
| @@ -35,7 +35,7 @@ public class PrintoutItem extends Item { | ||||
| 
 | ||||
|     @Override | ||||
|     public void appendHoverText(ItemStack stack, TooltipContext context, List<Component> list, TooltipFlag options) { | ||||
|         var title = getTitle(stack); | ||||
|         var title = PrintoutData.getOrEmpty(stack).title(); | ||||
|         if (!title.isEmpty()) list.add(Component.literal(title)); | ||||
|     } | ||||
| 
 | ||||
| @@ -51,14 +51,4 @@ public class PrintoutItem extends Item { | ||||
|     public Type getType() { | ||||
|         return type; | ||||
|     } | ||||
| 
 | ||||
|     public static String getTitle(ItemStack stack) { | ||||
|         var nbt = stack.get(ModRegistry.DataComponents.PRINTOUT.get()); | ||||
|         return nbt == null ? "" : nbt.title(); | ||||
|     } | ||||
| 
 | ||||
|     public static int getPageCount(ItemStack stack) { | ||||
|         var nbt = stack.get(ModRegistry.DataComponents.PRINTOUT.get()); | ||||
|         return nbt == null ? 1 : nbt.pages(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -64,7 +64,7 @@ public final class PrintoutRecipe extends CustomRecipe { | ||||
|                     if (stack.getItem() instanceof PrintoutItem printout && printout.getType() != PrintoutItem.Type.BOOK) { | ||||
|                         if (printouts == null) printouts = new ItemStack[9]; | ||||
|                         printouts[numPrintouts] = stack; | ||||
|                         numPages += PrintoutItem.getPageCount(stack); | ||||
|                         numPages += PrintoutData.getOrEmpty(stack).pages(); | ||||
|                         numPrintouts++; | ||||
|                         printoutFound = true; | ||||
|                     } else if (stack.getItem() == Items.PAPER) { | ||||
| @@ -104,7 +104,7 @@ public final class PrintoutRecipe extends CustomRecipe { | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             var title = PrintoutItem.getTitle(printouts[0]); | ||||
|             var title = PrintoutData.getOrEmpty(printouts[0]).title(); | ||||
| 
 | ||||
|             return DataComponentUtil.createStack( | ||||
|                 leatherFound ? ModRegistry.Items.PRINTED_BOOK.get() : ModRegistry.Items.PRINTED_PAGES.get(), | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
| 
 | ||||
| package dan200.computercraft.shared.peripheral.modem.wired; | ||||
| 
 | ||||
| import dan200.computercraft.impl.RegistryHelper; | ||||
| import dan200.computercraft.shared.util.RegistryHelper; | ||||
| import dan200.computercraft.shared.ModRegistry; | ||||
| import net.minecraft.Util; | ||||
| import net.minecraft.core.BlockPos; | ||||
|   | ||||
| @@ -11,7 +11,6 @@ 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; | ||||
| @@ -172,8 +171,7 @@ public final class PrinterBlockEntity extends AbstractContainerBlockEntity imple | ||||
| 
 | ||||
|     static boolean isPaper(ItemStack stack) { | ||||
|         var item = stack.getItem(); | ||||
|         return item == Items.PAPER | ||||
|             || (item instanceof PrintoutItem printout && printout.getType() == PrintoutItem.Type.PAGE); | ||||
|         return item == Items.PAPER || item == ModRegistry.Items.PRINTED_PAGE.get(); | ||||
|     } | ||||
| 
 | ||||
|     private boolean canInputPage() { | ||||
|   | ||||
| @@ -4,11 +4,11 @@ | ||||
| 
 | ||||
| package dan200.computercraft.shared.platform; | ||||
| 
 | ||||
| import com.google.gson.JsonObject; | ||||
| import com.mojang.authlib.GameProfile; | ||||
| import com.mojang.brigadier.arguments.ArgumentType; | ||||
| import dan200.computercraft.api.network.wired.WiredElement; | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
| import dan200.computercraft.impl.Services; | ||||
| import dan200.computercraft.shared.config.ConfigFile; | ||||
| import dan200.computercraft.shared.network.container.ContainerData; | ||||
| import dan200.computercraft.shared.util.InventoryUtil; | ||||
| @@ -47,26 +47,19 @@ import java.util.function.Consumer; | ||||
| import java.util.function.Predicate; | ||||
| 
 | ||||
| /** | ||||
|  * This extends {@linkplain dan200.computercraft.impl.PlatformHelper the API's loader abstraction layer}, adding | ||||
|  * additional methods used by the actual mod. | ||||
|  * Abstraction layer for Forge and Fabric. See implementations for more details. | ||||
|  */ | ||||
| public interface PlatformHelper extends dan200.computercraft.impl.PlatformHelper { | ||||
| public interface PlatformHelper { | ||||
|     /** | ||||
|      * Get the current {@link PlatformHelper} instance. | ||||
|      * | ||||
|      * @return The current instance. | ||||
|      */ | ||||
|     static PlatformHelper get() { | ||||
|         return (PlatformHelper) dan200.computercraft.impl.PlatformHelper.get(); | ||||
|         var instance = Instance.INSTANCE; | ||||
|         return instance == null ? Services.raise(PlatformHelper.class, Instance.ERROR) : instance; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if we're running in a development environment. | ||||
|      * | ||||
|      * @return If we're running in a development environment. | ||||
|      */ | ||||
|     boolean isDevelopmentEnvironment(); | ||||
| 
 | ||||
|     /** | ||||
|      * Create a new config builder. | ||||
|      * | ||||
| @@ -83,16 +76,6 @@ public interface PlatformHelper extends dan200.computercraft.impl.PlatformHelper | ||||
|      */ | ||||
|     <T> RegistrationHelper<T> createRegistrationHelper(ResourceKey<Registry<T>> registry); | ||||
| 
 | ||||
|     /** | ||||
|      * Determine if this resource should be loaded, based on platform-specific loot conditions. | ||||
|      * <p> | ||||
|      * This should only be called from the {@code apply} stage of a reload listener. | ||||
|      * | ||||
|      * @param object The root JSON object of this resource. | ||||
|      * @return If this resource should be loaded. | ||||
|      */ | ||||
|     boolean shouldLoadResource(JsonObject object); | ||||
| 
 | ||||
|     /** | ||||
|      * Register a new argument type. | ||||
|      * | ||||
| @@ -328,4 +311,21 @@ public interface PlatformHelper extends dan200.computercraft.impl.PlatformHelper | ||||
|      * @see ServerPlayerGameMode#useItemOn(ServerPlayer, Level, ItemStack, InteractionHand, BlockHitResult) | ||||
|      */ | ||||
|     InteractionResult useOn(ServerPlayer player, ItemStack stack, BlockHitResult hit, Predicate<BlockState> canUseBlock); | ||||
| 
 | ||||
| 
 | ||||
|     final class Instance { | ||||
|         static final @Nullable PlatformHelper INSTANCE; | ||||
|         static final @Nullable Throwable ERROR; | ||||
| 
 | ||||
|         static { | ||||
|             // We don't want class initialisation to fail here (as that results in confusing errors). Instead, capture | ||||
|             // the error and rethrow it when accessing. This should be JITted away in the common case. | ||||
|             var helper = Services.tryLoad(PlatformHelper.class); | ||||
|             INSTANCE = helper.instance(); | ||||
|             ERROR = helper.error(); | ||||
|         } | ||||
| 
 | ||||
|         private Instance() { | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -13,7 +13,6 @@ import net.minecraft.world.item.crafting.Ingredient; | ||||
|  * @param redstone    All {@link Items#REDSTONE} items. | ||||
|  * @param string      All {@link Items#STRING} items. | ||||
|  * @param leather     All {@link Items#LEATHER} items. | ||||
|  * @param stone       All {@link Items#STONE} items. | ||||
|  * @param glassPane   All {@link Items#GLASS_PANE} items. | ||||
|  * @param goldIngot   All {@link Items#GOLD_INGOT} items. | ||||
|  * @param goldBlock   All {@link Items#GOLD_BLOCK} items. | ||||
| @@ -26,7 +25,6 @@ public record RecipeIngredients( | ||||
|     Ingredient redstone, | ||||
|     Ingredient string, | ||||
|     Ingredient leather, | ||||
|     Ingredient stone, | ||||
|     Ingredient glassPane, | ||||
|     Ingredient goldIngot, | ||||
|     Ingredient goldBlock, | ||||
|   | ||||
| @@ -6,7 +6,7 @@ package dan200.computercraft.shared.recipe; | ||||
| 
 | ||||
| import com.mojang.serialization.DataResult; | ||||
| import com.mojang.serialization.MapCodec; | ||||
| import dan200.computercraft.impl.RegistryHelper; | ||||
| import dan200.computercraft.shared.util.RegistryHelper; | ||||
| import net.minecraft.core.registries.BuiltInRegistries; | ||||
| import net.minecraft.network.RegistryFriendlyByteBuf; | ||||
| import net.minecraft.network.codec.StreamCodec; | ||||
|   | ||||
| @@ -2,11 +2,8 @@ | ||||
| // | ||||
| // SPDX-License-Identifier: MPL-2.0 | ||||
| 
 | ||||
| package dan200.computercraft.impl; | ||||
| package dan200.computercraft.shared.util; | ||||
| 
 | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
| import dan200.computercraft.api.pocket.IPocketUpgrade; | ||||
| import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
| import net.minecraft.core.Registry; | ||||
| import net.minecraft.core.registries.BuiltInRegistries; | ||||
| import net.minecraft.resources.ResourceKey; | ||||
| @@ -18,9 +15,6 @@ import org.jetbrains.annotations.ApiStatus; | ||||
|  */ | ||||
| @ApiStatus.Internal | ||||
| public final class RegistryHelper { | ||||
|     public static final ResourceKey<Registry<ITurtleUpgrade>> TURTLE_UPGRADE = ResourceKey.createRegistryKey(new ResourceLocation(ComputerCraftAPI.MOD_ID, "turtle_upgrade")); | ||||
|     public static final ResourceKey<Registry<IPocketUpgrade>> POCKET_UPGRADE = ResourceKey.createRegistryKey(new ResourceLocation(ComputerCraftAPI.MOD_ID, "pocket_upgrade")); | ||||
| 
 | ||||
|     private RegistryHelper() { | ||||
|     } | ||||
| 
 | ||||
| @@ -6,7 +6,6 @@ package dan200.computercraft.shared.util; | ||||
| 
 | ||||
| import com.mojang.serialization.*; | ||||
| import com.mojang.serialization.codecs.KeyDispatchCodec; | ||||
| import dan200.computercraft.impl.RegistryHelper; | ||||
| import net.minecraft.core.Registry; | ||||
| import net.minecraft.resources.ResourceKey; | ||||
| 
 | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
|     "uniforms": [ | ||||
|         { "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, | ||||
|         { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, | ||||
|         { "name": "IViewRotMat", "type": "matrix3x3", "count": 9, "values": [ 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 ] }, | ||||
|         { "name": "ColorModulator", "type": "float", "count": 4, "values": [ 1.0, 1.0, 1.0, 1.0 ] }, | ||||
|         { "name": "FogStart", "type": "float", "count": 1, "values": [ 0.0 ] }, | ||||
|         { "name": "FogEnd", "type": "float", "count": 1, "values": [ 1.0 ] }, | ||||
|   | ||||
| @@ -5,7 +5,6 @@ | ||||
| package dan200.computercraft; | ||||
| 
 | ||||
| import com.google.auto.service.AutoService; | ||||
| import com.google.gson.JsonObject; | ||||
| import com.mojang.authlib.GameProfile; | ||||
| import com.mojang.brigadier.arguments.ArgumentType; | ||||
| import dan200.computercraft.api.network.wired.WiredElement; | ||||
| @@ -48,13 +47,8 @@ import java.util.List; | ||||
| import java.util.function.Consumer; | ||||
| import java.util.function.Predicate; | ||||
| 
 | ||||
| @AutoService({ PlatformHelper.class, dan200.computercraft.impl.PlatformHelper.class, ComputerCraftAPIService.class }) | ||||
| @AutoService({ PlatformHelper.class, ComputerCraftAPIService.class }) | ||||
| public class TestPlatformHelper extends AbstractComputerCraftAPI implements PlatformHelper { | ||||
|     @Override | ||||
|     public boolean isDevelopmentEnvironment() { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public ConfigFile.Builder createConfigBuilder() { | ||||
|         throw new UnsupportedOperationException("Cannot create config file inside tests"); | ||||
| @@ -65,16 +59,6 @@ public class TestPlatformHelper extends AbstractComputerCraftAPI implements Plat | ||||
|         throw new UnsupportedOperationException("Cannot query registry inside tests"); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean shouldLoadResource(JsonObject object) { | ||||
|         throw new UnsupportedOperationException("Cannot use resource conditions"); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void addRequiredModCondition(JsonObject object, String modId) { | ||||
|         throw new UnsupportedOperationException("Cannot use resource conditions"); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public <A extends ArgumentType<?>, T extends ArgumentTypeInfo.Template<A>, I extends ArgumentTypeInfo<A, T>> I registerArgumentTypeInfo(Class<A> klass, I info) { | ||||
|         throw new UnsupportedOperationException("Cannot register ArgumentTypeInfo inside tests"); | ||||
|   | ||||
| @@ -17,7 +17,7 @@ import com.mojang.brigadier.builder.RequiredArgumentBuilder; | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
| import dan200.computercraft.data.PrettyJsonWriter; | ||||
| import dan200.computercraft.gametest.core.TestHooks; | ||||
| import dan200.computercraft.impl.RegistryHelper; | ||||
| import dan200.computercraft.shared.util.RegistryHelper; | ||||
| import net.minecraft.client.Minecraft; | ||||
| import net.minecraft.core.registries.BuiltInRegistries; | ||||
| import net.minecraft.network.chat.Component; | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
| 
 | ||||
| package dan200.computercraft.export; | ||||
| 
 | ||||
| import dan200.computercraft.impl.RegistryHelper; | ||||
| import dan200.computercraft.shared.util.RegistryHelper; | ||||
| import net.minecraft.core.registries.BuiltInRegistries; | ||||
| import net.minecraft.world.item.Item; | ||||
| import net.minecraft.world.item.ItemStack; | ||||
|   | ||||
| @@ -233,7 +233,7 @@ class Turtle_Test { | ||||
|             val turtle = helper.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.TURTLE_NORMAL.get()).access | ||||
|             val upgrade = turtle.getUpgrade(TurtleSide.LEFT) | ||||
|             assertEquals( | ||||
|                 helper.level.registryAccess().registryOrThrow(ModRegistry.TURTLE_UPGRADE) | ||||
|                 helper.level.registryAccess().registryOrThrow(ITurtleUpgrade.REGISTRY) | ||||
|                     .get(ResourceLocation("cctest", "wooden_pickaxe")), | ||||
|                 upgrade, | ||||
|                 "Upgrade is a wooden pickaxe", | ||||
| @@ -262,7 +262,7 @@ class Turtle_Test { | ||||
|             helper.assertUpgradeItem( | ||||
|                 ItemStack(Items.WOODEN_PICKAXE), | ||||
|                 UpgradeData.ofDefault( | ||||
|                     helper.level.registryAccess().registryOrThrow(ModRegistry.TURTLE_UPGRADE) | ||||
|                     helper.level.registryAccess().registryOrThrow(ITurtleUpgrade.REGISTRY) | ||||
|                         .getHolder(ResourceLocation("cctest", "wooden_pickaxe")).orElseThrow(), | ||||
|                 ), | ||||
|             ) | ||||
| @@ -283,7 +283,7 @@ class Turtle_Test { | ||||
|             val turtle = helper.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.TURTLE_NORMAL.get()).access | ||||
|             val upgrade = turtle.getUpgrade(TurtleSide.LEFT) | ||||
|             assertEquals( | ||||
|                 helper.level.registryAccess().registryOrThrow(ModRegistry.TURTLE_UPGRADE) | ||||
|                 helper.level.registryAccess().registryOrThrow(ITurtleUpgrade.REGISTRY) | ||||
|                     .get(ResourceLocation("cctest", "netherite_pickaxe")), | ||||
|                 upgrade, | ||||
|                 "Upgrade is a netherite pickaxe", | ||||
|   | ||||
| @@ -5,8 +5,8 @@ | ||||
| package dan200.computercraft.gametest.api | ||||
| 
 | ||||
| import dan200.computercraft.gametest.core.MinecraftExtensions | ||||
| import dan200.computercraft.impl.RegistryHelper | ||||
| import dan200.computercraft.mixin.gametest.GameTestSequenceAccessor | ||||
| import dan200.computercraft.shared.util.RegistryHelper | ||||
| import net.minecraft.client.Minecraft | ||||
| import net.minecraft.client.Screenshot | ||||
| import net.minecraft.client.gui.screens.inventory.MenuAccess | ||||
|   | ||||
| @@ -6,10 +6,10 @@ package dan200.computercraft.gametest.api | ||||
| 
 | ||||
| import dan200.computercraft.api.peripheral.IPeripheral | ||||
| import dan200.computercraft.gametest.core.ManagedComputers | ||||
| import dan200.computercraft.impl.RegistryHelper | ||||
| import dan200.computercraft.mixin.gametest.GameTestInfoAccessor | ||||
| import dan200.computercraft.mixin.gametest.GameTestSequenceAccessor | ||||
| import dan200.computercraft.shared.platform.PlatformHelper | ||||
| import dan200.computercraft.shared.util.RegistryHelper | ||||
| import dan200.computercraft.test.core.computer.LuaTaskContext | ||||
| import dan200.computercraft.test.shared.ItemStackMatcher.isStack | ||||
| import net.minecraft.commands.arguments.blocks.BlockInput | ||||
|   | ||||
| @@ -7,15 +7,22 @@ package dan200.computercraft.client.integration.rei; | ||||
| import dan200.computercraft.api.turtle.TurtleSide; | ||||
| import dan200.computercraft.shared.ModRegistry; | ||||
| import dan200.computercraft.shared.integration.RecipeModHelpers; | ||||
| import dan200.computercraft.shared.platform.RegistryEntry; | ||||
| import dan200.computercraft.shared.pocket.items.PocketComputerItem; | ||||
| import dan200.computercraft.shared.turtle.items.TurtleItem; | ||||
| import dev.architectury.event.EventResult; | ||||
| import me.shedaniel.rei.api.client.plugins.REIClientPlugin; | ||||
| import me.shedaniel.rei.api.client.registry.display.DisplayRegistry; | ||||
| import me.shedaniel.rei.api.client.registry.entry.CollapsibleEntryRegistry; | ||||
| import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; | ||||
| import me.shedaniel.rei.api.common.display.basic.BasicDisplay; | ||||
| import me.shedaniel.rei.api.common.entry.comparison.ItemComparatorRegistry; | ||||
| import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; | ||||
| import me.shedaniel.rei.api.common.util.EntryStacks; | ||||
| import me.shedaniel.rei.plugin.common.BuiltinPlugin; | ||||
| import net.minecraft.world.item.Item; | ||||
| import net.minecraft.world.item.ItemStack; | ||||
| import net.minecraft.world.item.component.DyedItemColor; | ||||
| 
 | ||||
| /** | ||||
|  * REI integration for ComputerCraft. | ||||
| @@ -40,15 +47,30 @@ public class REIComputerCraft implements REIClientPlugin { | ||||
|             var upgrade = PocketComputerItem.getUpgradeWithData(stack); | ||||
|             return upgrade == null ? 1 : upgrade.holder().key().location().hashCode(); | ||||
|         }, ModRegistry.Items.POCKET_COMPUTER_NORMAL.get(), ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get()); | ||||
| 
 | ||||
|         registry.register((context, stack) -> DyedItemColor.getOrDefault(stack, -1), ModRegistry.Items.DISK.get()); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void registerEntries(EntryRegistry registry) { | ||||
|         for (var stack : RecipeModHelpers.getExtraStacks(RecipeModHelpers.getEmptyRegistryAccess())) { | ||||
|         for (var stack : RecipeModHelpers.getExtraStacks(BasicDisplay.registryAccess())) { | ||||
|             registry.addEntry(EntryStacks.of(stack)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void registerCollapsibleEntries(CollapsibleEntryRegistry registry) { | ||||
|         addCollapsableGroup(registry, ModRegistry.Items.TURTLE_NORMAL); | ||||
|         addCollapsableGroup(registry, ModRegistry.Items.TURTLE_ADVANCED); | ||||
|         addCollapsableGroup(registry, ModRegistry.Items.POCKET_COMPUTER_NORMAL); | ||||
|         addCollapsableGroup(registry, ModRegistry.Items.POCKET_COMPUTER_ADVANCED); | ||||
|     } | ||||
| 
 | ||||
|     private static void addCollapsableGroup(CollapsibleEntryRegistry registry, RegistryEntry<? extends Item> holder) { | ||||
|         var item = holder.get(); | ||||
|         registry.group(holder.id(), new ItemStack(item).getDisplayName(), VanillaEntryTypes.ITEM, x -> x.getValue().is(item)); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void registerDisplays(DisplayRegistry registry) { | ||||
|         registry.registerDisplayGenerator(BuiltinPlugin.CRAFTING, new UpgradeDisplayGenerator()); | ||||
|   | ||||
| @@ -4,7 +4,6 @@ | ||||
| 
 | ||||
| package dan200.computercraft.client.integration.rei; | ||||
| 
 | ||||
| import dan200.computercraft.shared.integration.RecipeModHelpers; | ||||
| import dan200.computercraft.shared.integration.UpgradeRecipeGenerator; | ||||
| import me.shedaniel.rei.api.client.registry.display.DynamicDisplayGenerator; | ||||
| import me.shedaniel.rei.api.common.display.basic.BasicDisplay; | ||||
| @@ -24,7 +23,7 @@ import java.util.Optional; | ||||
|  * Provides custom recipe and usage hints for pocket/turtle upgrades. | ||||
|  */ | ||||
| class UpgradeDisplayGenerator implements DynamicDisplayGenerator<DefaultCraftingDisplay<?>> { | ||||
|     private final UpgradeRecipeGenerator<DefaultCraftingDisplay<?>> resolver = new UpgradeRecipeGenerator<>(GeneratedShapedDisplay::new, RecipeModHelpers.getEmptyRegistryAccess()); | ||||
|     private final UpgradeRecipeGenerator<DefaultCraftingDisplay<?>> resolver = new UpgradeRecipeGenerator<>(GeneratedShapedDisplay::new, BasicDisplay.registryAccess()); | ||||
| 
 | ||||
|     @Override | ||||
|     public Optional<List<DefaultCraftingDisplay<?>>> getRecipeFor(EntryStack<?> entry) { | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| { | ||||
|   "type": "minecraft:crafting_shaped", | ||||
|   "category": "redstone", | ||||
|   "key": {"#": {"tag": "c:stones"}, "E": {"item": "minecraft:ender_pearl"}}, | ||||
|   "key": {"#": {"item": "minecraft:stone"}, "E": {"item": "minecraft:ender_pearl"}}, | ||||
|   "pattern": ["###", "#E#", "###"], | ||||
|   "result": {"count": 1, "id": "computercraft:wireless_modem_normal"} | ||||
| } | ||||
|   | ||||
| @@ -5,41 +5,40 @@ | ||||
| package dan200.computercraft.data; | ||||
| 
 | ||||
| import com.mojang.serialization.Codec; | ||||
| import com.mojang.serialization.Lifecycle; | ||||
| import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint; | ||||
| import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator; | ||||
| import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; | ||||
| import net.fabricmc.fabric.api.datagen.v1.provider.FabricCodecDataProvider; | ||||
| import net.fabricmc.fabric.api.datagen.v1.provider.FabricDynamicRegistryProvider; | ||||
| import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider; | ||||
| import net.fabricmc.fabric.api.event.registry.DynamicRegistries; | ||||
| import net.minecraft.core.*; | ||||
| import net.minecraft.core.Holder; | ||||
| import net.minecraft.core.HolderLookup; | ||||
| import net.minecraft.core.RegistrySetBuilder; | ||||
| import net.minecraft.core.registries.BuiltInRegistries; | ||||
| import net.minecraft.data.DataProvider; | ||||
| import net.minecraft.data.PackOutput; | ||||
| import net.minecraft.data.tags.TagsProvider; | ||||
| import net.minecraft.resources.RegistryDataLoader; | ||||
| import net.minecraft.resources.ResourceKey; | ||||
| import net.minecraft.resources.ResourceLocation; | ||||
| import net.minecraft.server.packs.PackType; | ||||
| import net.minecraft.tags.TagKey; | ||||
| import net.minecraft.world.item.Item; | ||||
| import net.minecraft.world.level.block.Block; | ||||
| 
 | ||||
| import java.util.Optional; | ||||
| import java.util.concurrent.CompletableFuture; | ||||
| import java.util.function.BiConsumer; | ||||
| import java.util.function.BiFunction; | ||||
| import java.util.function.Consumer; | ||||
| import java.util.stream.Stream; | ||||
| 
 | ||||
| public class FabricDataGenerators implements DataGeneratorEntrypoint { | ||||
|     @Override | ||||
|     public void onInitializeDataGenerator(FabricDataGenerator generator) { | ||||
|         var pack = new PlatformGeneratorsImpl(generator.createPack()); | ||||
|         var pack = new PlatformGeneratorsImpl(generator.createPack(), generator.getRegistries()); | ||||
|         DataProviders.add(pack); | ||||
|     } | ||||
| 
 | ||||
|     private record PlatformGeneratorsImpl(FabricDataGenerator.Pack generator) implements DataProviders.GeneratorSink { | ||||
|     private record PlatformGeneratorsImpl( | ||||
|         FabricDataGenerator.Pack generator, CompletableFuture<HolderLookup.Provider> registries | ||||
|     ) implements DataProviders.GeneratorSink { | ||||
|         public <T extends DataProvider> T addWithFabricOutput(FabricDataGenerator.Pack.Factory<T> factory) { | ||||
|             return generator.addProvider((FabricDataOutput p) -> new PrettyDataProvider<>(factory.create(p))).provider(); | ||||
|         } | ||||
| @@ -53,11 +52,6 @@ public class FabricDataGenerators implements DataGeneratorEntrypoint { | ||||
|             return addWithFabricOutput(factory::create); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public <T extends DataProvider> T add(BiFunction<PackOutput, CompletableFuture<HolderLookup.Provider>, T> factory) { | ||||
|             return addWithRegistries(factory::apply); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public <T> void addFromCodec(String name, PackType type, String directory, Codec<T> codec, Consumer<BiConsumer<ResourceLocation, T>> output) { | ||||
|             addWithRegistries((out, registries) -> { | ||||
| @@ -111,61 +105,24 @@ public class FabricDataGenerators implements DataGeneratorEntrypoint { | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public CompletableFuture<RegistrySetBuilder.PatchedRegistries> createPatchedRegistries(CompletableFuture<HolderLookup.Provider> registries, RegistrySetBuilder patch) { | ||||
|             return registries.thenApply(oldRegistries -> { | ||||
|                 var factory = new Cloner.Factory(); | ||||
|                 DynamicRegistries.getDynamicRegistries().forEach(registryData -> registryData.runWithArguments(factory::addCodec)); | ||||
|                 return patch.buildPatch(RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY), new DynamicRegistryLookup(oldRegistries), factory); | ||||
|         public void registries(CompletableFuture<RegistrySetBuilder.PatchedRegistries> registries) { | ||||
|             addWithFabricOutput(out -> new FabricDynamicRegistryProvider(out, registries.thenApply(RegistrySetBuilder.PatchedRegistries::patches)) { | ||||
|                 @Override | ||||
|                 public String getName() { | ||||
|                     return "Registries"; | ||||
|                 } | ||||
| 
 | ||||
|                 @Override | ||||
|                 protected void configure(HolderLookup.Provider registries, Entries entries) { | ||||
|                     for (var reg : DynamicRegistries.getDynamicRegistries()) { | ||||
|                         registries.lookupOrThrow(reg.key()).listElements().forEach(x -> register(entries, x)); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 private static <T> void register(Entries entries, Holder.Reference<T> reference) { | ||||
|                     entries.add(reference.key(), reference.value()); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         /** | ||||
|          * A {@link HolderLookup.Provider} implementation that adds any Fabric dynamic registry, if missing. | ||||
|          * | ||||
|          * @param parent The parent registry. | ||||
|          */ | ||||
|         private record DynamicRegistryLookup(HolderLookup.Provider parent) implements HolderLookup.Provider { | ||||
|             @Override | ||||
|             public Stream<ResourceKey<? extends Registry<?>>> listRegistries() { | ||||
|                 return Stream.concat( | ||||
|                     parent.listRegistries(), | ||||
|                     DynamicRegistries.getDynamicRegistries().stream().map(RegistryDataLoader.RegistryData::key) | ||||
|                 ).distinct(); | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public <T> Optional<HolderLookup.RegistryLookup<T>> lookup(ResourceKey<? extends Registry<? extends T>> registryKey) { | ||||
|                 return parent.lookup(registryKey).or(() -> Optional.of(new EmptyRegistry<>(registryKey))); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private record EmptyRegistry<T>( | ||||
|             ResourceKey<? extends Registry<? extends T>> key | ||||
|         ) implements HolderLookup.RegistryLookup<T> { | ||||
|             @Override | ||||
|             public Lifecycle registryLifecycle() { | ||||
|                 return Lifecycle.stable(); | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public Stream<Holder.Reference<T>> listElements() { | ||||
|                 return Stream.empty(); | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public Stream<HolderSet.Named<T>> listTags() { | ||||
|                 return Stream.empty(); | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public Optional<Holder.Reference<T>> get(ResourceKey<T> resourceKey) { | ||||
|                 return Optional.empty(); | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public Optional<HolderSet.Named<T>> get(TagKey<T> tagKey) { | ||||
|                 return Optional.empty(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -8,6 +8,8 @@ import dan200.computercraft.api.ComputerCraftAPI; | ||||
| import dan200.computercraft.api.detail.FabricDetailRegistries; | ||||
| import dan200.computercraft.api.network.wired.WiredElementLookup; | ||||
| import dan200.computercraft.api.peripheral.PeripheralLookup; | ||||
| import dan200.computercraft.api.pocket.IPocketUpgrade; | ||||
| import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
| import dan200.computercraft.impl.Peripherals; | ||||
| import dan200.computercraft.impl.PocketUpgrades; | ||||
| import dan200.computercraft.impl.TurtleUpgrades; | ||||
| @@ -66,8 +68,8 @@ public class ComputerCraft { | ||||
| 
 | ||||
|         FabricRegistryBuilder.createSimple(RecipeFunction.REGISTRY).attribute(RegistryAttribute.SYNCED).buildAndRegister(); | ||||
| 
 | ||||
|         DynamicRegistries.registerSynced(ModRegistry.TURTLE_UPGRADE, TurtleUpgrades.instance().upgradeCodec()); | ||||
|         DynamicRegistries.registerSynced(ModRegistry.POCKET_UPGRADE, PocketUpgrades.instance().upgradeCodec()); | ||||
|         DynamicRegistries.registerSynced(ITurtleUpgrade.REGISTRY, TurtleUpgrades.instance().upgradeCodec()); | ||||
|         DynamicRegistries.registerSynced(IPocketUpgrade.REGISTRY, PocketUpgrades.instance().upgradeCodec()); | ||||
| 
 | ||||
|         ModRegistry.register(); | ||||
|         ModRegistry.registerMainThread(); | ||||
|   | ||||
| @@ -5,11 +5,8 @@ | ||||
| package dan200.computercraft.shared.platform; | ||||
| 
 | ||||
| import com.google.auto.service.AutoService; | ||||
| import com.google.gson.JsonArray; | ||||
| 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; | ||||
| @@ -27,14 +24,11 @@ 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.registry.FuelRegistry; | ||||
| 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.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; | ||||
| import net.minecraft.commands.synchronization.ArgumentTypeInfo; | ||||
| import net.minecraft.core.BlockPos; | ||||
| import net.minecraft.core.Direction; | ||||
| @@ -49,7 +43,6 @@ import net.minecraft.server.level.ServerLevel; | ||||
| import net.minecraft.server.level.ServerPlayer; | ||||
| import net.minecraft.tags.ItemTags; | ||||
| import net.minecraft.tags.TagKey; | ||||
| import net.minecraft.util.GsonHelper; | ||||
| import net.minecraft.world.Container; | ||||
| import net.minecraft.world.InteractionHand; | ||||
| import net.minecraft.world.InteractionResult; | ||||
| @@ -79,13 +72,8 @@ import java.util.function.Consumer; | ||||
| import java.util.function.Predicate; | ||||
| import java.util.function.Supplier; | ||||
| 
 | ||||
| @AutoService(dan200.computercraft.impl.PlatformHelper.class) | ||||
| @AutoService(PlatformHelper.class) | ||||
| public class PlatformHelperImpl implements PlatformHelper { | ||||
|     @Override | ||||
|     public boolean isDevelopmentEnvironment() { | ||||
|         return FabricLoader.getInstance().isDevelopmentEnvironment(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public ConfigFile.Builder createConfigBuilder() { | ||||
|         return new FabricConfigFile.Builder(); | ||||
| @@ -103,22 +91,6 @@ public class PlatformHelperImpl implements PlatformHelper { | ||||
|         return new RegistrationHelperImpl<>(getRegistry(registry)); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean shouldLoadResource(JsonObject object) { | ||||
|         return true; // Done by default in Fabric, so can be skipped | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void addRequiredModCondition(JsonObject object, String modId) { | ||||
|         var conditions = GsonHelper.getAsJsonArray(object, ResourceConditions.CONDITIONS_KEY, null); | ||||
|         if (conditions == null) { | ||||
|             conditions = new JsonArray(); | ||||
|             object.add(ResourceConditions.CONDITIONS_KEY, conditions); | ||||
|         } | ||||
| 
 | ||||
|         conditions.add(ResourceCondition.CODEC.encodeStart(JsonOps.INSTANCE, ResourceConditions.allModsLoaded(modId)).getOrThrow()); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public <A extends ArgumentType<?>, T extends ArgumentTypeInfo.Template<A>, I extends ArgumentTypeInfo<A, T>> I registerArgumentTypeInfo(Class<A> klass, I info) { | ||||
|         ArgumentTypeInfosAccessor.classMap().put(klass, info); | ||||
| @@ -171,7 +143,6 @@ public class PlatformHelperImpl implements PlatformHelper { | ||||
|             Ingredient.of(ConventionalItemTags.REDSTONE_DUSTS), | ||||
|             Ingredient.of(ConventionalItemTags.STRINGS), | ||||
|             Ingredient.of(Items.LEATHER), | ||||
|             Ingredient.of(ConventionalItemTags.STONES), | ||||
|             Ingredient.of(ConventionalItemTags.GLASS_PANES), | ||||
|             Ingredient.of(ConventionalItemTags.GOLD_INGOTS), | ||||
|             Ingredient.of(ConventionalItemTags.STORAGE_BLOCKS_GOLD), | ||||
|   | ||||
| @@ -47,7 +47,7 @@ | ||||
|     "depends": { | ||||
|         "fabricloader": ">=0.15.10", | ||||
|         "fabric-api": ">=0.97.3", | ||||
|         "minecraft": ">=1.20.5 <1.20.7" | ||||
|         "minecraft": "=1.20.6" | ||||
|     }, | ||||
|     "accessWidener": "computercraft.accesswidener" | ||||
| } | ||||
|   | ||||
| @@ -15,6 +15,11 @@ cct.inlineProject(":common-api") | ||||
| 
 | ||||
| dependencies { | ||||
|     api(project(":core-api")) | ||||
| 
 | ||||
|     // FIXME: This should be implementation (and in the common Forge config) | ||||
|     // but NeoGradle does weird things and we end up with two Forge deps on the | ||||
|     // classpath - https://github.com/neoforged/NeoGradle/issues/162. | ||||
|     compileOnly("net.neoforged:neoforge:${libs.versions.neoForge.get()}") | ||||
| } | ||||
| 
 | ||||
| tasks.javadoc { | ||||
|   | ||||
| @@ -89,7 +89,7 @@ runs { | ||||
|     } | ||||
| 
 | ||||
|     val gameTestClient by registering { | ||||
|         configure(runTypes.client) | ||||
|         configure(runTypes.named("client")) | ||||
| 
 | ||||
|         workingDirectory(file("run/testClient")) | ||||
|         configureForGameTest() | ||||
| @@ -121,6 +121,8 @@ dependencies { | ||||
|     compileOnly(libs.bundles.externalMods.forge.compile) | ||||
|     runtimeOnly(libs.bundles.externalMods.forge.runtime) { cct.exclude(this) } | ||||
| 
 | ||||
|     implementation("net.neoforged:neoforge:${libs.versions.neoForge.get()}") | ||||
| 
 | ||||
|     // Depend on our other projects. | ||||
|     api(commonClasses(project(":forge-api"))) { cct.exclude(this) } | ||||
|     clientApi(clientClasses(project(":forge-api"))) { cct.exclude(this) } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|   "type": "computercraft:impostor_shapeless", | ||||
|   "category": "redstone", | ||||
|   "ingredients": [{"tag": "c:leather"}, {"item": "computercraft:printed_page"}, {"tag": "c:strings"}], | ||||
|   "ingredients": [{"tag": "c:leathers"}, {"item": "computercraft:printed_page"}, {"tag": "c:strings"}], | ||||
|   "result": {"count": 1, "id": "computercraft:printed_book"} | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| { | ||||
|   "type": "minecraft:crafting_shaped", | ||||
|   "category": "redstone", | ||||
|   "key": {"#": {"tag": "c:stones"}, "E": {"tag": "c:ender_pearls"}}, | ||||
|   "key": {"#": {"item": "minecraft:stone"}, "E": {"tag": "c:ender_pearls"}}, | ||||
|   "pattern": ["###", "#E#", "###"], | ||||
|   "result": {"count": 1, "id": "computercraft:wireless_modem_normal"} | ||||
| } | ||||
|   | ||||
| @@ -90,8 +90,8 @@ public final class ComputerCraft { | ||||
| 
 | ||||
|     @SubscribeEvent | ||||
|     public static void registerDynamicRegistries(DataPackRegistryEvent.NewRegistry event) { | ||||
|         event.dataPackRegistry(ModRegistry.TURTLE_UPGRADE, TurtleUpgrades.instance().upgradeCodec(), TurtleUpgrades.instance().upgradeCodec()); | ||||
|         event.dataPackRegistry(ModRegistry.POCKET_UPGRADE, PocketUpgrades.instance().upgradeCodec(), PocketUpgrades.instance().upgradeCodec()); | ||||
|         event.dataPackRegistry(ITurtleUpgrade.REGISTRY, TurtleUpgrades.instance().upgradeCodec(), TurtleUpgrades.instance().upgradeCodec()); | ||||
|         event.dataPackRegistry(IPocketUpgrade.REGISTRY, PocketUpgrades.instance().upgradeCodec(), PocketUpgrades.instance().upgradeCodec()); | ||||
|     } | ||||
| 
 | ||||
|     @SubscribeEvent | ||||
|   | ||||
| @@ -7,6 +7,7 @@ package dan200.computercraft.data; | ||||
| import com.mojang.serialization.Codec; | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
| import net.minecraft.core.HolderLookup; | ||||
| import net.minecraft.core.RegistrySetBuilder; | ||||
| import net.minecraft.core.registries.BuiltInRegistries; | ||||
| import net.minecraft.data.DataGenerator; | ||||
| import net.minecraft.data.DataProvider; | ||||
| @@ -21,13 +22,13 @@ import net.minecraft.world.level.block.Block; | ||||
| import net.neoforged.bus.api.SubscribeEvent; | ||||
| import net.neoforged.fml.common.EventBusSubscriber; | ||||
| import net.neoforged.neoforge.common.data.BlockTagsProvider; | ||||
| import net.neoforged.neoforge.common.data.DatapackBuiltinEntriesProvider; | ||||
| import net.neoforged.neoforge.common.data.ExistingFileHelper; | ||||
| import net.neoforged.neoforge.common.data.JsonCodecProvider; | ||||
| import net.neoforged.neoforge.data.event.GatherDataEvent; | ||||
| 
 | ||||
| import java.util.concurrent.CompletableFuture; | ||||
| import java.util.function.BiConsumer; | ||||
| import java.util.function.BiFunction; | ||||
| import java.util.function.Consumer; | ||||
| 
 | ||||
| @EventBusSubscriber(bus = EventBusSubscriber.Bus.MOD) | ||||
| @@ -48,11 +49,6 @@ public class Generators { | ||||
|             return generator.addProvider(p -> new PrettyDataProvider<>(factory.create(p))).provider(); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public <T extends DataProvider> T add(BiFunction<PackOutput, CompletableFuture<HolderLookup.Provider>, T> factory) { | ||||
|             return generator.addProvider(p -> new PrettyDataProvider<>(factory.apply(p, registries))).provider(); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public <T> void addFromCodec(String name, PackType type, String directory, Codec<T> codec, Consumer<BiConsumer<ResourceLocation, T>> output) { | ||||
|             add(out -> { | ||||
| @@ -99,5 +95,10 @@ public class Generators { | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public void registries(CompletableFuture<RegistrySetBuilder.PatchedRegistries> registries) { | ||||
|             add(out -> new DatapackBuiltinEntriesProvider(out, registries, null)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -5,11 +5,8 @@ | ||||
| package dan200.computercraft.shared.platform; | ||||
| 
 | ||||
| import com.google.auto.service.AutoService; | ||||
| import com.google.gson.JsonArray; | ||||
| import com.google.gson.JsonObject; | ||||
| import com.mojang.authlib.GameProfile; | ||||
| import com.mojang.brigadier.arguments.ArgumentType; | ||||
| import com.mojang.serialization.JsonOps; | ||||
| import dan200.computercraft.ComputerCraft; | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
| import dan200.computercraft.api.network.wired.WiredElement; | ||||
| @@ -32,7 +29,6 @@ import net.minecraft.resources.ResourceLocation; | ||||
| import net.minecraft.server.level.ServerLevel; | ||||
| import net.minecraft.server.level.ServerPlayer; | ||||
| import net.minecraft.tags.TagKey; | ||||
| import net.minecraft.util.GsonHelper; | ||||
| import net.minecraft.world.Container; | ||||
| import net.minecraft.world.InteractionHand; | ||||
| import net.minecraft.world.InteractionResult; | ||||
| @@ -54,16 +50,12 @@ import net.minecraft.world.level.block.state.BlockState; | ||||
| import net.minecraft.world.phys.BlockHitResult; | ||||
| import net.minecraft.world.phys.Vec3; | ||||
| import net.neoforged.bus.api.Event; | ||||
| import net.neoforged.fml.loading.FMLLoader; | ||||
| import net.neoforged.neoforge.capabilities.BlockCapability; | ||||
| import net.neoforged.neoforge.capabilities.BlockCapabilityCache; | ||||
| import net.neoforged.neoforge.capabilities.Capabilities; | ||||
| import net.neoforged.neoforge.common.CommonHooks; | ||||
| import net.neoforged.neoforge.common.Tags; | ||||
| import net.neoforged.neoforge.common.ToolActions; | ||||
| import net.neoforged.neoforge.common.conditions.ConditionalOps; | ||||
| import net.neoforged.neoforge.common.conditions.ICondition; | ||||
| import net.neoforged.neoforge.common.conditions.ModLoadedCondition; | ||||
| import net.neoforged.neoforge.common.extensions.IMenuTypeExtension; | ||||
| import net.neoforged.neoforge.event.EventHooks; | ||||
| import net.neoforged.neoforge.items.wrapper.InvWrapper; | ||||
| @@ -78,13 +70,8 @@ import java.util.function.Consumer; | ||||
| import java.util.function.Predicate; | ||||
| import java.util.function.Supplier; | ||||
| 
 | ||||
| @AutoService(dan200.computercraft.impl.PlatformHelper.class) | ||||
| @AutoService(PlatformHelper.class) | ||||
| public class PlatformHelperImpl implements PlatformHelper { | ||||
|     @Override | ||||
|     public boolean isDevelopmentEnvironment() { | ||||
|         return !FMLLoader.isProduction(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public ConfigFile.Builder createConfigBuilder() { | ||||
|         return new ForgeConfigFile.Builder(); | ||||
| @@ -95,23 +82,6 @@ public class PlatformHelperImpl implements PlatformHelper { | ||||
|         return new RegistrationHelperImpl<>(DeferredRegister.create(registry, ComputerCraftAPI.MOD_ID)); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean shouldLoadResource(JsonObject object) { | ||||
|         return ICondition.conditionsMatched(JsonOps.INSTANCE, object); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void addRequiredModCondition(JsonObject object, String modId) { | ||||
|         // FIXME: Test this, though maybe this should be implemented a different way anyway? | ||||
|         var conditions = GsonHelper.getAsJsonArray(object, ConditionalOps.DEFAULT_CONDITIONS_KEY, null); | ||||
|         if (conditions == null) { | ||||
|             conditions = new JsonArray(); | ||||
|             object.add(ConditionalOps.DEFAULT_CONDITIONS_KEY, conditions); | ||||
|         } | ||||
| 
 | ||||
|         conditions.add(ICondition.CODEC.encodeStart(JsonOps.INSTANCE, new ModLoadedCondition(modId)).getOrThrow()); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public <A extends ArgumentType<?>, T extends ArgumentTypeInfo.Template<A>, I extends ArgumentTypeInfo<A, T>> I registerArgumentTypeInfo(Class<A> klass, I info) { | ||||
|         return ArgumentTypeInfos.registerByClass(klass, info); | ||||
| @@ -169,7 +139,6 @@ public class PlatformHelperImpl implements PlatformHelper { | ||||
|             Ingredient.of(Tags.Items.DUSTS_REDSTONE), | ||||
|             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), | ||||
|   | ||||
| @@ -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.6)" | ||||
|     versionRange="[${neoVersion},20.7)" | ||||
|     ordering="NONE" | ||||
|     side="BOTH" | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jonathan Coates
					Jonathan Coates