From 9ca3efff3c8ad29272cfec2e9dc9cee3ef2f3fa8 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sun, 9 Jul 2023 14:09:44 +0100 Subject: [PATCH] Add data generator support for required mods We've supported resource conditions in the upgrade JSON for an age, but don't expose it in our data generators at all. Indeed, using these hooks is a bit of a pain to do in multi-loader setups, as the JSON is different between the two loaders. We could generate the JSON for all loaders at once, but it feels nicer to use the per-loader APIs to add the conditions. For now, we just support generating a single condition - whether a mod is loaded not, via the requireMod(...) method. --- .../api/upgrades/UpgradeDataProvider.java | 22 ++++++++++++++----- .../computercraft/impl/PlatformHelper.java | 11 ++++++++++ .../computercraft/TestPlatformHelper.java | 7 +++++- .../shared/platform/PlatformHelperImpl.java | 14 ++++++++++++ .../shared/platform/PlatformHelperImpl.java | 15 +++++++++++++ 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeDataProvider.java b/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeDataProvider.java index 7178e8a3a..8e634239e 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeDataProvider.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeDataProvider.java @@ -23,11 +23,7 @@ import org.apache.logging.log4j.Logger; import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; import java.util.function.Function; @@ -167,5 +163,21 @@ public record Upgrade>( public void add(Consumer> add) { add.accept(this); } + + /** + * Return a new {@link Upgrade} which requires the given mod to be present. + *

+ * 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 requireMod(String modId) { + return new Upgrade<>(id, serialiser, json -> { + PlatformHelper.get().addRequiredModCondition(json, modId); + serialise.accept(json); + }); + } } } diff --git a/projects/common-api/src/main/java/dan200/computercraft/impl/PlatformHelper.java b/projects/common-api/src/main/java/dan200/computercraft/impl/PlatformHelper.java index 2ed4b230b..a7ab333d4 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/impl/PlatformHelper.java +++ b/projects/common-api/src/main/java/dan200/computercraft/impl/PlatformHelper.java @@ -4,6 +4,8 @@ package dan200.computercraft.impl; +import com.google.gson.JsonObject; +import dan200.computercraft.api.upgrades.UpgradeDataProvider; import net.minecraft.core.Registry; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceKey; @@ -63,6 +65,15 @@ default CompoundTag getShareTag(ItemStack item) { return item.getTag(); } + /** + * 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; diff --git a/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java b/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java index d898d5928..60b75ce13 100644 --- a/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java +++ b/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java @@ -96,7 +96,12 @@ public T tryGetRegistryObject(ResourceKey> registry, ResourceLoc @Override public boolean shouldLoadResource(JsonObject object) { - throw new UnsupportedOperationException("Cannot use loot conditions"); + throw new UnsupportedOperationException("Cannot use resource conditions"); + } + + @Override + public void addRequiredModCondition(JsonObject object, String modId) { + throw new UnsupportedOperationException("Cannot use resource conditions"); } @Override diff --git a/projects/fabric/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java b/projects/fabric/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java index 7f0f5fb30..3c0ee5318 100644 --- a/projects/fabric/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java +++ b/projects/fabric/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java @@ -5,6 +5,7 @@ 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; @@ -27,6 +28,7 @@ import net.fabricmc.fabric.api.lookup.v1.block.BlockApiLookup; import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; import net.fabricmc.fabric.api.registry.FuelRegistry; +import net.fabricmc.fabric.api.resource.conditions.v1.DefaultResourceConditions; import net.fabricmc.fabric.api.resource.conditions.v1.ResourceConditions; import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerType; @@ -49,6 +51,7 @@ 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; @@ -134,6 +137,17 @@ public boolean shouldLoadResource(JsonObject object) { return ResourceConditions.objectMatchesConditions(object); } + @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(DefaultResourceConditions.allModsLoaded(modId).toJson()); + } + @Override public BlockEntityType createBlockEntityType(BiFunction factory, Block block) { return FabricBlockEntityTypeBuilder.create(factory::apply).addBlock(block).build(); diff --git a/projects/forge/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java b/projects/forge/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java index 02a644bb1..d7f3a74b3 100644 --- a/projects/forge/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java +++ b/projects/forge/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java @@ -5,6 +5,7 @@ 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; @@ -32,6 +33,7 @@ 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.*; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; @@ -56,7 +58,9 @@ import net.minecraftforge.common.ToolActions; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.ForgeCapabilities; +import net.minecraftforge.common.crafting.CraftingHelper; import net.minecraftforge.common.crafting.conditions.ICondition; +import net.minecraftforge.common.crafting.conditions.ModLoadedCondition; import net.minecraftforge.common.extensions.IForgeMenuType; import net.minecraftforge.common.util.NonNullConsumer; import net.minecraftforge.event.ForgeEventFactory; @@ -122,6 +126,17 @@ public boolean shouldLoadResource(JsonObject object) { return ICondition.shouldRegisterEntry(object); } + @Override + public void addRequiredModCondition(JsonObject object, String modId) { + var conditions = GsonHelper.getAsJsonArray(object, "forge:conditions", null); + if (conditions == null) { + conditions = new JsonArray(); + object.add("forge:conditions", conditions); + } + + conditions.add(CraftingHelper.serialize(new ModLoadedCondition(modId))); + } + @Override public BlockEntityType createBlockEntityType(BiFunction factory, Block block) { return new BlockEntityType<>(factory::apply, Set.of(block), null);