Make Datapack Registries support ICondition(s) (#9113)

This commit is contained in:
Brennan Ward authored and GitHub committed 2022-11-30 14:45:00 -08:00
1 parent c1c619a109
commit bdddc8c5d4
8 files changed
+115 -2

No files matched your search

@@ -8,6 +8,7 @@ package net.minecraftforge.common;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
@@ -27,6 +28,7 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.mojang.serialization.Codec;
import com.mojang.serialization.JsonOps;
import com.mojang.serialization.Lifecycle;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
@@ -107,6 +109,7 @@ import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSpecialEffects;
import net.minecraft.world.level.biome.BiomeGenerationSettings;
import net.minecraft.world.level.biome.MobSpawnSettings;
import net.minecraftforge.common.crafting.conditions.ICondition;
import net.minecraftforge.common.loot.IGlobalLootModifier;
import net.minecraftforge.common.loot.LootModifierManager;
import net.minecraftforge.common.loot.LootTableIdCondition;
@@ -171,8 +174,10 @@ import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import net.minecraft.ChatFormatting;
import net.minecraft.resources.RegistryResourceAccess;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.resources.RegistryResourceAccess.EntryThunk;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.Level;
@@ -1660,4 +1665,12 @@ public class ForgeHooks
}
return false;
}
}
@SuppressWarnings("unchecked")
public static <E> Collection<Entry<ResourceKey<E>, EntryThunk<E>>> filterThunks(Map<ResourceKey<E>, RegistryResourceAccess.EntryThunk<E>> map)
{
return map.entrySet().stream().filter(e ->
((EntryThunk<Boolean>)e.getValue()).parseElement(JsonOps.INSTANCE, ICondition.DECODER)
.get().left().get().value()).toList(); // Validity of this .get() call is enforced by the above Decoder object, which only returns DataResult.success.
}
}
@@ -234,4 +234,14 @@ public class CraftingHelper
throw new JsonSyntaxException("Unknown condition type: " + condition.getID().toString());
return serializer.getJson(condition);
}
public static JsonArray serialize(ICondition... conditions)
{
JsonArray arr = new JsonArray();
for(ICondition iCond : conditions)
{
arr.add(serialize(iCond));
}
return arr;
}
}
@@ -5,11 +5,17 @@
package net.minecraftforge.common.crafting.conditions;
import com.google.gson.JsonObject;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.Decoder;
import com.mojang.serialization.DynamicOps;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraftforge.common.crafting.CraftingHelper;
import java.util.Collection;
import java.util.Collections;
@@ -18,6 +24,28 @@ import java.util.Set;
public interface ICondition
{
Decoder<Boolean> DECODER = new Decoder<>() {
@Override
public <T> DataResult<Pair<Boolean, T>> decode(DynamicOps<T> ops, T input)
{
if(input instanceof JsonObject obj && obj.has("forge:conditions"))
{
try
{
boolean result = CraftingHelper.processConditions(obj, "forge:conditions", IContext.TAGS_INVALID);
return DataResult.success(Pair.of(result, input));
}
catch(Exception ex)
{
ex.printStackTrace();
return DataResult.success(Pair.of(false, input)); // Print stacktrace and do not load errored conditions.
}
}
return DataResult.success(Pair.of(true, input));
}
};
ResourceLocation getID();
boolean test(IContext context);
@@ -33,6 +61,15 @@ public interface ICondition
}
};
IContext TAGS_INVALID = new IContext()
{
@Override
public <T> Map<ResourceLocation, Collection<Holder<T>>> getAllTags(ResourceKey<? extends Registry<T>> registry)
{
throw new UnsupportedOperationException("Usage of tag-based conditions is not permitted in this context!");
}
};
/**
* Return the requested tag if available, or an empty tag otherwise.
*/
@@ -8,9 +8,11 @@ package net.minecraftforge.common.data;
import com.mojang.logging.LogUtils;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.Map;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.JsonOps;
@@ -26,6 +28,8 @@ import net.minecraft.resources.RegistryOps;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.PackType;
import net.minecraftforge.common.crafting.CraftingHelper;
import net.minecraftforge.common.crafting.conditions.ICondition;
import net.minecraftforge.common.data.ExistingFileHelper.ResourceType;
import org.slf4j.Logger;
@@ -49,6 +53,7 @@ public class JsonCodecProvider<T> implements DataProvider
protected final String directory;
protected final Codec<T> codec;
protected final Map<ResourceLocation, T> entries;
protected Map<ResourceLocation, ICondition[]> conditions = Collections.emptyMap();
/**
* @param dataGenerator DataGenerator provided by {@link GatherDataEvent}.
@@ -112,6 +117,18 @@ public class JsonCodecProvider<T> implements DataProvider
final Path path = outputFolder.resolve(String.join("/", dataFolder, id.getNamespace(), this.directory, id.getPath() + ".json"));
JsonElement encoded = this.codec.encodeStart(this.dynamicOps, value)
.getOrThrow(false, msg -> LOGGER.error("Failed to encode {}: {}", path, msg));
ICondition[] conditions = this.conditions.get(id);
if (conditions != null && conditions.length > 0)
{
if(encoded instanceof JsonObject obj)
{
obj.add("forge:conditions", CraftingHelper.serialize(conditions));
}
else
{
LOGGER.error("Attempted to apply conditions to a type that is not a JsonObject! - Path: {}", path);
}
}
DataProvider.saveStable(cache, encoded, path);
}));
}
@@ -126,4 +143,16 @@ public class JsonCodecProvider<T> implements DataProvider
{
return String.format("%s generator for %s", this.directory, this.modid);
}
/**
* Applies a condition map to this provider.
* These conditions will be applied to the created JsonElements with the matching names.
* Null or empty arrays will not be written, and if the top-level json type is not JsonObject, attempting to add conditions will error.
* @param conditions The name->condition map to apply.
*/
public JsonCodecProvider<T> setConditions(Map<ResourceLocation, ICondition[]> conditions)
{
this.conditions = conditions;
return this;
}
}