From 2d9a1bc6f9d92d54cf5dc17cd3f390c722b428e2 Mon Sep 17 00:00:00 2001 From: tterrag Date: Thu, 10 Dec 2020 22:22:09 -0500 Subject: [PATCH] Add generated resource tracking to ExistingFileHelper --- .../minecraft/data/TagsProvider.java.patch | 16 +- .../client/model/generators/ModelBuilder.java | 15 +- .../client/model/generators/ModelFile.java | 5 +- .../model/generators/ModelProvider.java | 55 +------ .../common/data/ExistingFileHelper.java | 143 +++++++++++++++--- 5 files changed, 154 insertions(+), 80 deletions(-) diff --git a/patches/minecraft/net/minecraft/data/TagsProvider.java.patch b/patches/minecraft/net/minecraft/data/TagsProvider.java.patch index 5c7683c1c..98e115745 100644 --- a/patches/minecraft/net/minecraft/data/TagsProvider.java.patch +++ b/patches/minecraft/net/minecraft/data/TagsProvider.java.patch @@ -1,11 +1,12 @@ --- a/net/minecraft/data/TagsProvider.java +++ b/net/minecraft/data/TagsProvider.java -@@ -28,10 +28,18 @@ +@@ -28,10 +28,20 @@ protected final DataGenerator field_200433_a; protected final Registry field_200435_c; protected final Map field_200434_b = Maps.newLinkedHashMap(); + protected final String modId; + protected final net.minecraftforge.common.data.ExistingFileHelper existingFileHelper; ++ private final net.minecraftforge.common.data.ExistingFileHelper.IResourceType resourceType; + @Deprecated//Forge, Use ModID version. protected TagsProvider(DataGenerator p_i49827_1_, Registry p_i49827_2_) { @@ -16,10 +17,11 @@ this.field_200435_c = p_i49827_2_; + this.modId = modId; + this.existingFileHelper = existingFileHelper; ++ this.resourceType = new net.minecraftforge.common.data.ExistingFileHelper.ResourceType(net.minecraft.resources.ResourcePackType.SERVER_DATA, ".json", "tags/" + getTagFolder()); } protected abstract void func_200432_c(); -@@ -47,12 +55,14 @@ +@@ -47,12 +57,14 @@ return this.field_200435_c.func_241873_b(p_240527_1_).orElse((T)null); }; this.field_200434_b.forEach((p_240524_4_, p_240524_5_) -> { @@ -35,7 +37,7 @@ try { String s = field_200437_e.toJson((JsonElement)jsonobject); -@@ -74,11 +84,26 @@ +@@ -74,20 +86,36 @@ }); } @@ -44,7 +46,7 @@ + // We only care about non-optional tag entries, this is the only type that can reference a resource and needs validation + // Optional tags should not be validated + if (entry instanceof ITag.TagEntry) { -+ return existingFileHelper == null || !existingFileHelper.exists(((ITag.TagEntry)entry).getId(), net.minecraft.resources.ResourcePackType.SERVER_DATA, ".json", "tags/" + getTagFolder()); ++ return existingFileHelper == null || !existingFileHelper.exists(((ITag.TagEntry)entry).getId(), resourceType); + } + return false; + } @@ -63,7 +65,9 @@ } protected ITag.Builder func_240525_b_(ITag.INamedTag p_240525_1_) { -@@ -87,7 +112,7 @@ + return this.field_200434_b.computeIfAbsent(p_240525_1_.func_230234_a_(), (p_240526_0_) -> { ++ existingFileHelper.trackGenerated(p_240526_0_, resourceType); + return new ITag.Builder(); }); } @@ -72,7 +76,7 @@ private final ITag.Builder field_240528_a_; private final Registry field_240529_b_; private final String field_240530_c_; -@@ -115,5 +140,18 @@ +@@ -115,5 +143,18 @@ }); return this; } diff --git a/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java b/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java index 6d5be7549..6d10dc07c 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java +++ b/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java @@ -19,7 +19,11 @@ package net.minecraftforge.client.model.generators; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -33,20 +37,19 @@ import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonObject; -import net.minecraft.util.math.vector.Vector3f; -import net.minecraftforge.common.data.ExistingFileHelper; import net.minecraft.client.renderer.model.BlockFaceUV; +import net.minecraft.client.renderer.model.BlockModel.GuiLight; import net.minecraft.client.renderer.model.BlockPart; import net.minecraft.client.renderer.model.BlockPartFace; import net.minecraft.client.renderer.model.BlockPartRotation; import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; import net.minecraft.client.renderer.model.ItemTransformVec3f; -import net.minecraft.client.renderer.model.BlockModel.GuiLight; import net.minecraft.client.renderer.texture.MissingTextureSprite; -import net.minecraft.resources.ResourcePackType; import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.vector.Vector3f; +import net.minecraftforge.common.data.ExistingFileHelper; /** * General purpose model builder, contains all the commonalities between item @@ -146,7 +149,7 @@ public class ModelBuilder> extends ModelFile { public T texture(String key, ResourceLocation texture) { Preconditions.checkNotNull(key, "Key must not be null"); Preconditions.checkNotNull(texture, "Texture must not be null"); - Preconditions.checkArgument(existingFileHelper.exists(texture, ResourcePackType.CLIENT_RESOURCES, ".png", "textures"), + Preconditions.checkArgument(existingFileHelper.exists(texture, ModelProvider.TEXTURE), "Texture %s does not exist in any known resource pack", texture); this.textures.put(key, texture.toString()); return self(); diff --git a/src/main/java/net/minecraftforge/client/model/generators/ModelFile.java b/src/main/java/net/minecraftforge/client/model/generators/ModelFile.java index 6e5016dda..d3099cbaf 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/ModelFile.java +++ b/src/main/java/net/minecraftforge/client/model/generators/ModelFile.java @@ -21,7 +21,6 @@ package net.minecraftforge.client.model.generators; import com.google.common.base.Preconditions; -import net.minecraft.resources.ResourcePackType; import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.data.ExistingFileHelper; @@ -78,9 +77,9 @@ public abstract class ModelFile { @Override protected boolean exists() { if (getUncheckedLocation().getPath().contains(".")) - return existingHelper.exists(getUncheckedLocation(), ResourcePackType.CLIENT_RESOURCES, "", "models"); + return existingHelper.exists(getUncheckedLocation(), ModelProvider.MODEL_WITH_EXTENSION); else - return existingHelper.exists(getUncheckedLocation(), ResourcePackType.CLIENT_RESOURCES, ".json", "models"); + return existingHelper.exists(getUncheckedLocation(), ModelProvider.MODEL); } } } diff --git a/src/main/java/net/minecraftforge/client/model/generators/ModelProvider.java b/src/main/java/net/minecraftforge/client/model/generators/ModelProvider.java index 28cd1743c..b1bedb809 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/ModelProvider.java +++ b/src/main/java/net/minecraftforge/client/model/generators/ModelProvider.java @@ -21,7 +21,6 @@ package net.minecraftforge.client.model.generators; import java.io.IOException; import java.nio.file.Path; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.function.BiFunction; @@ -35,61 +34,20 @@ import com.google.gson.GsonBuilder; import net.minecraft.data.DataGenerator; import net.minecraft.data.DirectoryCache; import net.minecraft.data.IDataProvider; -import net.minecraft.resources.IResource; import net.minecraft.resources.ResourcePackType; import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.common.data.ExistingFileHelper.ResourceType; public abstract class ModelProvider> implements IDataProvider { - private class ExistingFileHelperIncludingGenerated extends ExistingFileHelper { - - private final ExistingFileHelper delegate; - - public ExistingFileHelperIncludingGenerated(ExistingFileHelper delegate) { - super(Collections.emptyList(), Collections.emptySet(), true); - this.delegate = delegate; - } - - @Override - public boolean exists(ResourceLocation loc, ResourcePackType type, String pathSuffix, String pathPrefix) - { - if (pathPrefix.equals("models") && pathSuffix.equals(".json")) - { - if (generatedModels.containsKey(loc)) - { - return true; - } - } - return delegate.exists(loc, type, pathSuffix, pathPrefix); - } - - @Override - public boolean exists(ResourceLocation loc, ResourcePackType type) { - if (loc.getPath().startsWith("models/") && loc.getPath().endsWith(".json")) - { - ResourceLocation modelLoc = new ResourceLocation( - loc.getNamespace(), - loc.getPath().substring("models/".length(), loc.getPath().length() - ".json".length()) - ); - if (generatedModels.containsKey(modelLoc)) - { - return true; - } - } - return delegate.exists(loc, type); - } - - @Override - public IResource getResource(ResourceLocation loc, ResourcePackType type) throws IOException - { - return delegate.getResource(loc, type); - } - } - public static final String BLOCK_FOLDER = "block"; public static final String ITEM_FOLDER = "item"; + protected static final ResourceType TEXTURE = new ResourceType(ResourcePackType.CLIENT_RESOURCES, ".png", "textures"); + protected static final ResourceType MODEL = new ResourceType(ResourcePackType.CLIENT_RESOURCES, ".json", "models"); + protected static final ResourceType MODEL_WITH_EXTENSION = new ResourceType(ResourcePackType.CLIENT_RESOURCES, "", "models"); + private static final Gson GSON = (new GsonBuilder()).setPrettyPrinting().create(); protected final DataGenerator generator; protected final String modid; @@ -112,7 +70,7 @@ public abstract class ModelProvider> implements IDataP Preconditions.checkNotNull(factory); this.factory = factory; Preconditions.checkNotNull(existingFileHelper); - this.existingFileHelper = new ExistingFileHelperIncludingGenerated(existingFileHelper); + this.existingFileHelper = existingFileHelper; } public ModelProvider(DataGenerator generator, String modid, String folder, BiFunction builderFromModId, ExistingFileHelper existingFileHelper) { @@ -122,6 +80,7 @@ public abstract class ModelProvider> implements IDataP public T getBuilder(String path) { Preconditions.checkNotNull(path, "Path must not be null"); ResourceLocation outputLoc = extendWithFolder(path.contains(":") ? new ResourceLocation(path) : new ResourceLocation(modid, path)); + this.existingFileHelper.trackGenerated(outputLoc, MODEL); return generatedModels.computeIfAbsent(outputLoc, factory); } diff --git a/src/main/java/net/minecraftforge/common/data/ExistingFileHelper.java b/src/main/java/net/minecraftforge/common/data/ExistingFileHelper.java index d69028eca..2d9fc063f 100644 --- a/src/main/java/net/minecraftforge/common/data/ExistingFileHelper.java +++ b/src/main/java/net/minecraftforge/common/data/ExistingFileHelper.java @@ -23,11 +23,14 @@ import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.util.Collection; - -import com.google.common.annotations.VisibleForTesting; - import java.util.Collections; import java.util.Set; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; + +import net.minecraft.data.IDataProvider; import net.minecraft.resources.FilePack; import net.minecraft.resources.FolderPack; import net.minecraft.resources.IResource; @@ -37,6 +40,7 @@ import net.minecraft.resources.ResourcePackType; import net.minecraft.resources.SimpleReloadableResourceManager; import net.minecraft.resources.VanillaPack; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.model.generators.ModelBuilder; import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.event.lifecycle.GatherDataEvent; import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo; @@ -51,14 +55,56 @@ import net.minecraftforge.fml.packs.ModFileResourcePack; */ public class ExistingFileHelper { + public interface IResourceType { + + ResourcePackType getPackType(); + + String getSuffix(); + + String getPrefix(); + } + + public static class ResourceType implements IResourceType { + + final ResourcePackType packType; + final String suffix, prefix; + public ResourceType(ResourcePackType type, String suffix, String prefix) { + this.packType = type; + this.suffix = suffix; + this.prefix = prefix; + } + + @Override + public ResourcePackType getPackType() { return packType; } + + @Override + public String getSuffix() { return suffix; } + + @Override + public String getPrefix() { return prefix; } + } + private final SimpleReloadableResourceManager clientResources, serverData; private final boolean enable; + private final Multimap generated = HashMultimap.create(); @Deprecated//TODO: Remove in 1.17 public ExistingFileHelper(Collection existingPacks, boolean enable) { this(existingPacks, Collections.emptySet(), enable); } + /** + * Create a new helper. This should probably NOT be used by mods, as + * the instance provided by forge is designed to be a central instance that + * tracks existence of generated data. + *

+ * Only create a new helper if you intentionally want to ignore the existence of + * other generated files. + * + * @param existingPacks + * @param existingMods + * @param enable + */ public ExistingFileHelper(Collection existingPacks, Set existingMods, boolean enable) { this.clientResources = new SimpleReloadableResourceManager(ResourcePackType.CLIENT_RESOURCES); this.serverData = new SimpleReloadableResourceManager(ResourcePackType.SERVER_DATA); @@ -81,8 +127,8 @@ public class ExistingFileHelper { this.enable = enable; } - private IResourceManager getManager(ResourcePackType type) { - return type == ResourcePackType.CLIENT_RESOURCES ? clientResources : serverData; + private IResourceManager getManager(ResourcePackType packType) { + return packType == ResourcePackType.CLIENT_RESOURCES ? clientResources : serverData; } private ResourceLocation getLocation(ResourceLocation base, String suffix, String prefix) { @@ -92,17 +138,34 @@ public class ExistingFileHelper { /** * Check if a given resource exists in the known resource packs. * - * @param loc the base location of the resource, e.g. - * {@code "minecraft:block/stone"} - * @param type the type of resources to check + * @param loc the complete location of the resource, e.g. + * {@code "minecraft:textures/block/stone.png"} + * @param packType the type of resources to check * @return {@code true} if the resource exists in any pack, {@code false} * otherwise */ - public boolean exists(ResourceLocation loc, ResourcePackType type) { + public boolean exists(ResourceLocation loc, ResourcePackType packType) { if (!enable) { return true; } - return getManager(type).hasResource(loc); + return generated.get(packType).contains(loc) || getManager(packType).hasResource(loc); + } + + /** + * Check if a given resource exists in the known resource packs. This is a + * convenience method to avoid repeating type/prefix/suffix and instead use the + * common definitions in {@link ResourceType}, or a custom {@link IResourceType} + * definition. + * + * @param loc the base location of the resource, e.g. + * {@code "minecraft:block/stone"} + * @param type a {@link IResourceType} describing how to form the path to the + * resource + * @return {@code true} if the resource exists in any pack, {@code false} + * otherwise + */ + public boolean exists(ResourceLocation loc, IResourceType type) { + return exists(getLocation(loc, type.getSuffix(), type.getPrefix()), type.getPackType()); } /** @@ -110,25 +173,71 @@ public class ExistingFileHelper { * * @param loc the base location of the resource, e.g. * {@code "minecraft:block/stone"} - * @param type the type of resources to check + * @param packType the type of resources to check * @param pathSuffix a string to append after the path, e.g. {@code ".json"} * @param pathPrefix a string to append before the path, before a slash, e.g. * {@code "models"} * @return {@code true} if the resource exists in any pack, {@code false} * otherwise */ - public boolean exists(ResourceLocation loc, ResourcePackType type, String pathSuffix, String pathPrefix) { - return exists(getLocation(loc, pathSuffix, pathPrefix), type); + public boolean exists(ResourceLocation loc, ResourcePackType packType, String pathSuffix, String pathPrefix) { + return exists(getLocation(loc, pathSuffix, pathPrefix), packType); + } + + /** + * Track the existence of a generated file. This is a convenience method to + * avoid repeating type/prefix/suffix and instead use the common definitions in + * {@link ResourceType}, or a custom {@link IResourceType} definition. + *

+ * This should be called by data providers immediately when a new data object is + * created, i.e. not during + * {@link IDataProvider#act(net.minecraft.data.DirectoryCache) act} but instead + * when the "builder" (or whatever intermediate object) is created, such as a + * {@link ModelBuilder}. + *

+ * This represents a promise to generate the file later, since other + * datagen may rely on this file existing. + * + * @param loc the base location of the resource, e.g. + * {@code "minecraft:block/stone"} + * @param type a {@link IResourceType} describing how to form the path to the + * resource + */ + public void trackGenerated(ResourceLocation loc, IResourceType type) { + this.generated.put(type.getPackType(), getLocation(loc, type.getSuffix(), type.getPrefix())); + } + + /** + * Track the existence of a generated file. + *

+ * This should be called by data providers immediately when a new data object is + * created, i.e. not during + * {@link IDataProvider#act(net.minecraft.data.DirectoryCache) act} but instead + * when the "builder" (or whatever intermediate object) is created, such as a + * {@link ModelBuilder}. + *

+ * This represents a promise to generate the file later, since other + * datagen may rely on this file existing. + * + * @param loc the base location of the resource, e.g. + * {@code "minecraft:block/stone"} + * @param packType the type of resources to check + * @param pathSuffix a string to append after the path, e.g. {@code ".json"} + * @param pathPrefix a string to append before the path, before a slash, e.g. + * {@code "models"} + */ + public void trackGenerated(ResourceLocation loc, ResourcePackType packType, String pathSuffix, String pathPrefix) { + this.generated.put(packType, getLocation(loc, pathSuffix, pathPrefix)); } @VisibleForTesting - public IResource getResource(ResourceLocation loc, ResourcePackType type, String pathSuffix, String pathPrefix) throws IOException { - return getResource(getLocation(loc, pathSuffix, pathPrefix), type); + public IResource getResource(ResourceLocation loc, ResourcePackType packType, String pathSuffix, String pathPrefix) throws IOException { + return getResource(getLocation(loc, pathSuffix, pathPrefix), packType); } @VisibleForTesting - public IResource getResource(ResourceLocation loc, ResourcePackType type) throws IOException { - return getManager(type).getResource(loc); + public IResource getResource(ResourceLocation loc, ResourcePackType packType) throws IOException { + return getManager(packType).getResource(loc); } /**