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);