mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-10-25 20:22:22 +00:00
Speed up boot (#2190)
This commit is contained in:
1 parent
12fa08ab46
commit
38b1d9a0c3
17 files changed
+937
-23
No files matched your search
@@ -49,11 +49,11 @@ public class GlslTransformUtils {
|
||||
private static final Map<Integer, List<ReservedWordRename>> VERSIONED_RESERVED_WORDS = Map.of(
|
||||
// Some reserved words to always rename
|
||||
0, List.of(
|
||||
new ReservedWordRename(Pattern.compile("\\bsample\\b"), RENAMED_PREFIX + "sample"),
|
||||
new ReservedWordRename(Pattern.compile("\\bnew\\b"), RENAMED_PREFIX + "new")
|
||||
new ReservedWordRename(Pattern.compile("sample(?<=\\bsample)\\b"), RENAMED_PREFIX + "sample"),
|
||||
new ReservedWordRename(Pattern.compile("new(?<=\\bnew)\\b"), RENAMED_PREFIX + "new")
|
||||
),
|
||||
400, List.of(
|
||||
new ReservedWordRename(Pattern.compile("\\bsampler\\b(?!\\d)"), RENAMED_PREFIX + "sampler")
|
||||
new ReservedWordRename(Pattern.compile("sampler(?<=\\bsampler)\\b(?!\\d)"), RENAMED_PREFIX + "sampler")
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ public final class GLSMHooks {
|
||||
public static ShaderTransformPostProcessor postTransformProcessor;
|
||||
public static PerFrameUniformBlock perFrameUniformBlock;
|
||||
public static PerFrameUniformBlock perPassUniformBlock;
|
||||
public static Runnable uniformBlockBarrier;
|
||||
public static PendingProgramSelection pendingProgramSelection;
|
||||
|
||||
public static void resolvePendingProgram() {
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class ReservedWordRenameTest {
|
||||
|
||||
private static final List<Pattern> LEGACY_ALWAYS = List.of(Pattern.compile("\\bsample\\b"), Pattern.compile("\\bnew\\b"));
|
||||
private static final Pattern LEGACY_400 = Pattern.compile("\\bsampler\\b(?!\\d)");
|
||||
private static final String[] WORDS = { "sample", "sampler", "new" };
|
||||
|
||||
private static String legacyRename(String source, int targetVersion) {
|
||||
String out = source;
|
||||
for (Pattern p : LEGACY_ALWAYS) {
|
||||
final String word = p.pattern().substring(2, p.pattern().length() - 2);
|
||||
out = p.matcher(out).replaceAll("angelica_renamed_" + word);
|
||||
}
|
||||
if (targetVersion >= 400) out = LEGACY_400.matcher(out).replaceAll("angelica_renamed_sampler");
|
||||
return out;
|
||||
}
|
||||
|
||||
private static void assertSameAsLegacy(String source) {
|
||||
for (int version : new int[] { 120, 330, 400, 460 }) {
|
||||
assertEquals(legacyRename(source, version), GlslTransformUtils.renameReservedWords(source, version), "version " + version + " source: " + source);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void edgeCasesMatchLegacy() {
|
||||
final String[] cases = {
|
||||
"", "sample", "new", "sampler", " sample ", "sample;", "(sample)", "_sample", "sample_", "sample2", "2sample",
|
||||
"samples", "resample", "sampler2D", "samplerX", "sampler_", "sampler;", "uniform sampler s;", "sampler2DShadow",
|
||||
"new_", "renew", "news", "new;new new", "sample sample sample", "samplesampler", "sampler sample new",
|
||||
"ésample", "sampleé", "ßnewß", "中sampler", "sampler中", "samplé",
|
||||
"// sample in a comment\nfloat sample = 1.0;\n", "#define new sample\n", "vec4 c = texture(sampler, uv) * sample;",
|
||||
"float x = sample.x + new_value + newValue + sample1;", "sample\nnew\nsampler\n", "\tsample\t", "sample-new+sampler*",
|
||||
};
|
||||
for (String c : cases) assertSameAsLegacy(c);
|
||||
}
|
||||
|
||||
@Test
|
||||
void randomizedInputsMatchLegacy() {
|
||||
final Random random = new Random(0x5A3D1E);
|
||||
final String[] fragments = { "sample", "sampler", "new", "s", "a", "_", "1", "2", "D", "x", " ", "\n", ";", "(", ")", ".", "é", "中", "́", "//", "#" };
|
||||
for (int i = 0; i < 5000; i++) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final int n = 1 + random.nextInt(24);
|
||||
for (int j = 0; j < n; j++) sb.append(fragments[random.nextInt(fragments.length)]);
|
||||
assertSameAsLegacy(sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void literalWordsAreTheOnlyCandidates() {
|
||||
for (String w : WORDS) {
|
||||
assertEquals("angelica_renamed_" + w, GlslTransformUtils.renameReservedWords(w, 460));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,6 +146,8 @@ public final class ShaderManager {
|
||||
public void shaderSource(int shader, CharSequence source) {
|
||||
final ShaderObject obj = shaderObjects.get(shader);
|
||||
if (obj == null) return;
|
||||
final Runnable barrier = GLSMHooks.uniformBlockBarrier;
|
||||
if (barrier != null && !AngelicaWorkers.isWorkerThread()) barrier.run();
|
||||
discardSpirvFuture(obj);
|
||||
|
||||
String raw = source.toString();
|
||||
|
||||
@@ -1012,8 +1012,8 @@ public enum Mixins implements IMixins {
|
||||
MCPATCHER_FORGE_CTM_OR_CC(new MixinBuilder("MCP:F Connected Textures or Custom Colors")
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableMCPatcherForgeFeatures
|
||||
&& MCPatcherForgeConfig.ConnectedTextures.enabled
|
||||
|| MCPatcherForgeConfig.CustomColors.enabled)
|
||||
&& (MCPatcherForgeConfig.ConnectedTextures.enabled
|
||||
|| MCPatcherForgeConfig.CustomColors.enabled))
|
||||
.addClientMixins("mcpatcherforge.ctm_cc.MixinTextureMap")
|
||||
),
|
||||
//End from NotFine
|
||||
|
||||
@@ -56,7 +56,7 @@ public class CITUtils {
|
||||
private static final List<Enchantment> allItemEnchantments = new ArrayList<>();
|
||||
private static final Map<Item, List<ArmorOverride>> armors = new IdentityHashMap<>();
|
||||
|
||||
static boolean useGlint;
|
||||
static boolean useGlint = true;
|
||||
|
||||
private static EnchantmentList armorMatches;
|
||||
private static int armorMatchIndex;
|
||||
|
||||
@@ -353,6 +353,7 @@ public class CTMUtils {
|
||||
}
|
||||
|
||||
private static void setBlankResourceWithoutLock() {
|
||||
if (tileLoader == null) return;
|
||||
RenderBlocksUtils.blankIcon = tileLoader.getIcon(RenderPassAPI.instance.getBlankResource());
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,12 @@ import java.util.Set;
|
||||
|
||||
import net.minecraft.client.resources.IResourcePack;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.prupe.mcpatcher.MCLogger;
|
||||
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.LoaderState;
|
||||
|
||||
abstract public class TexturePackChangeHandler implements Comparable<TexturePackChangeHandler> {
|
||||
|
||||
private static final MCLogger logger = MCLogger.getLogger(MCLogger.Category.TEXTURE_PACK);
|
||||
@@ -18,6 +22,8 @@ abstract public class TexturePackChangeHandler implements Comparable<TexturePack
|
||||
private static boolean initialized;
|
||||
private static long startTime;
|
||||
private static long startMem;
|
||||
private static boolean loaderAvailable;
|
||||
private static int deferredDepth;
|
||||
|
||||
private boolean updateNeeded;
|
||||
|
||||
@@ -50,14 +56,29 @@ abstract public class TexturePackChangeHandler implements Comparable<TexturePack
|
||||
return this.order - that.order;
|
||||
}
|
||||
|
||||
public static boolean isBootDeferred() {
|
||||
if (loaderAvailable) {
|
||||
return false;
|
||||
}
|
||||
if (!AngelicaConfig.enableMCPatcherForgeFeatures || Loader.instance().hasReachedState(LoaderState.AVAILABLE)) {
|
||||
loaderAvailable = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void register(TexturePackChangeHandler handler) {
|
||||
if (handler != null) {
|
||||
try {
|
||||
logger.info("initializing %s...", handler.name);
|
||||
handler.initialize();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
logger.severe("%s initialization failed", handler.name);
|
||||
if (isBootDeferred()) {
|
||||
logger.fine("deferring %s initialization until mod loading completes", handler.name);
|
||||
} else {
|
||||
try {
|
||||
logger.info("initializing %s...", handler.name);
|
||||
handler.initialize();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
logger.severe("%s initialization failed", handler.name);
|
||||
}
|
||||
}
|
||||
handlers.add(handler);
|
||||
logger.fine("registered texture pack handler %s, priority %d", handler.name, handler.order);
|
||||
@@ -81,6 +102,10 @@ abstract public class TexturePackChangeHandler implements Comparable<TexturePack
|
||||
}
|
||||
|
||||
public static void beforeChange1() {
|
||||
if (deferredDepth > 0 || isBootDeferred()) {
|
||||
deferredDepth++;
|
||||
return;
|
||||
}
|
||||
logger.finer("beforeChange1 depth %d", recurseDepth);
|
||||
if (recurseDepth++ > 0) {
|
||||
return;
|
||||
@@ -115,6 +140,10 @@ abstract public class TexturePackChangeHandler implements Comparable<TexturePack
|
||||
}
|
||||
|
||||
public static void afterChange1() {
|
||||
if (deferredDepth > 0) {
|
||||
deferredDepth--;
|
||||
return;
|
||||
}
|
||||
logger.finer("afterChange1 depth %d", recurseDepth - 1);
|
||||
if (--recurseDepth > 0) {
|
||||
return;
|
||||
|
||||
@@ -92,6 +92,9 @@ public class TileLoader {
|
||||
}
|
||||
|
||||
public static void registerIcons(TextureMap textureMap, String mapName, Map<String, TextureAtlasSprite> map) {
|
||||
if (TexturePackChangeHandler.isBootDeferred()) {
|
||||
return;
|
||||
}
|
||||
mapName = mapName.replaceFirst("/$", "");
|
||||
logger.fine("before registerIcons(%s) %d icons", mapName, map.size());
|
||||
if (!changeHandlerCalled) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.gtnewhorizons.angelica.Tags;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMHooks;
|
||||
import com.gtnewhorizons.angelica.glsm.shader.GlslVulkanPreprocess;
|
||||
import com.gtnewhorizons.angelica.glsm.shader.SpirvCompiler;
|
||||
import com.gtnewhorizons.angelica.glsm.threading.AngelicaWorkers;
|
||||
@@ -97,6 +98,7 @@ public class Iris {
|
||||
private static ShaderpackDirectoryManager shaderpacksDirectoryManager;
|
||||
|
||||
private static ShaderPack currentPack;
|
||||
private static CompletableFuture<Void> programSetWarmup;
|
||||
@Getter
|
||||
private static String currentPackName;
|
||||
@Getter
|
||||
@@ -164,14 +166,13 @@ public class Iris {
|
||||
public static void warmup() {
|
||||
final String vertexShader = "#version 120\nvoid main() { gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; }";
|
||||
final String fragmentShader = "#version 120\nvoid main() { gl_FragColor = vec4(1.0); }";
|
||||
try {
|
||||
submitTracked(() -> {
|
||||
TransformPatcher.patchComposite(vertexShader, null, fragmentShader);
|
||||
TransformPatcher.patchAttributes(vertexShader, null, fragmentShader, InputAvailability.of(true, true));
|
||||
}).get();
|
||||
} catch (Exception e) {
|
||||
submitTracked(() -> {
|
||||
TransformPatcher.patchComposite(vertexShader, null, fragmentShader);
|
||||
TransformPatcher.patchAttributes(vertexShader, null, fragmentShader, InputAvailability.of(true, true));
|
||||
}).exceptionally(e -> {
|
||||
logger.warn("Warmup failed", e);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public static <T> CompletableFuture<T> submitTracked(Supplier<T> supplier) {
|
||||
@@ -394,19 +395,35 @@ public class Iris {
|
||||
}
|
||||
|
||||
public static void warmupShaderTransforms() {
|
||||
if (currentPack == null) return;
|
||||
final ShaderPack pack = currentPack;
|
||||
if (pack == null) return;
|
||||
try {
|
||||
if (BackendManager.RENDER_BACKEND.isSDLGPU()) {
|
||||
IrisGLSMBridge.installPostTransformHook();
|
||||
}
|
||||
final ProgramSet programs = currentPack.getProgramSet(lastDimensionName != null ? lastDimensionName : "Overworld");
|
||||
PerFrameUniformBlockHarvester.harvest(programs);
|
||||
DeferredWorldRenderingPipeline.warmupTransforms(programs);
|
||||
final String dimensionName = lastDimensionName != null ? lastDimensionName : "Overworld";
|
||||
GLSMHooks.uniformBlockBarrier = Iris::awaitProgramSetWarmup;
|
||||
programSetWarmup = ShaderTransformExecutor.submitTracked(() -> {
|
||||
final ProgramSet programs = pack.getProgramSet(dimensionName);
|
||||
PerFrameUniformBlockHarvester.harvest(programs);
|
||||
DeferredWorldRenderingPipeline.warmupTransforms(programs);
|
||||
});
|
||||
} catch (Throwable t) {
|
||||
logger.warn("Early shader transform warmup failed; transforms will run at pipeline creation", t);
|
||||
}
|
||||
}
|
||||
|
||||
private static void awaitProgramSetWarmup() {
|
||||
final CompletableFuture<Void> warmup = programSetWarmup;
|
||||
if (warmup == null) return;
|
||||
programSetWarmup = null;
|
||||
try {
|
||||
warmup.join();
|
||||
} catch (RuntimeException e) {
|
||||
logger.warn("Early shader transform warmup failed; transforms will run at pipeline creation", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean loadExternalShaderpack(String name) {
|
||||
final Path shaderPackRoot;
|
||||
final Path shaderPackConfigTxt;
|
||||
@@ -682,6 +699,7 @@ public class Iris {
|
||||
* Destroys and deallocates all created OpenGL resources. Useful as part of a reload.
|
||||
*/
|
||||
private static void destroyEverything() {
|
||||
awaitProgramSetWarmup();
|
||||
currentPack = null;
|
||||
|
||||
getPipelineManager().destroyPipeline();
|
||||
@@ -746,6 +764,7 @@ public class Iris {
|
||||
* Supports dimension.properties mappings with wildcard fallback.
|
||||
*/
|
||||
private static WorldRenderingPipeline createPipeline(String dimensionName) {
|
||||
awaitProgramSetWarmup();
|
||||
if (currentPack == null) {
|
||||
// Completely disables shader-based rendering
|
||||
PerFrameUniformBlockHarvester.clear();
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
package net.coderbot.iris.texture.pbr;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.threading.AngelicaWorkers;
|
||||
import cpw.mods.fml.client.FMLFileResourcePack;
|
||||
import cpw.mods.fml.client.FMLFolderResourcePack;
|
||||
import net.minecraft.client.resources.AbstractResourcePack;
|
||||
import net.minecraft.client.resources.FallbackResourceManager;
|
||||
import net.minecraft.client.resources.FileResourcePack;
|
||||
import net.minecraft.client.resources.FolderResourcePack;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.client.resources.IResourcePack;
|
||||
import net.minecraft.client.resources.SimpleReloadableResourceManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileVisitOption;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
public final class PBRResourceIndex {
|
||||
private static final Logger LOGGER = LogManager.getLogger("Angelica");
|
||||
private static final String ASSETS = "assets";
|
||||
private static final String NORMAL_NAME = PBRType.NORMAL.getSuffix() + ".png";
|
||||
private static final String SPECULAR_NAME = PBRType.SPECULAR.getSuffix() + ".png";
|
||||
|
||||
private static IResourceManager owner;
|
||||
private static CompletableFuture<Map<IResourcePack, PackIndex>> pending;
|
||||
private static Map<IResourcePack, PackIndex> built;
|
||||
private static boolean disabled;
|
||||
private static boolean warned;
|
||||
|
||||
private PBRResourceIndex() {
|
||||
}
|
||||
|
||||
private record PackIndex(Set<String> names, boolean lowerCase) {}
|
||||
|
||||
private record ScanTarget(IResourcePack pack, ZipFile zip, File folder) {}
|
||||
|
||||
public static synchronized void start(IResourceManager resourceManager) {
|
||||
drop();
|
||||
owner = resourceManager;
|
||||
disabled = false;
|
||||
if (!(resourceManager instanceof SimpleReloadableResourceManager manager)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final List<ScanTarget> targets = collectTargets(manager);
|
||||
pending = AngelicaWorkers.submit(() -> scan(targets));
|
||||
} catch (RuntimeException e) {
|
||||
disable(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static synchronized void drop() {
|
||||
owner = null;
|
||||
pending = null;
|
||||
built = null;
|
||||
}
|
||||
|
||||
public static synchronized boolean mayExist(IResourceManager resourceManager, ResourceLocation location) {
|
||||
if (!(resourceManager instanceof SimpleReloadableResourceManager manager)) {
|
||||
return true;
|
||||
}
|
||||
final String path = location.getResourcePath();
|
||||
if (!path.endsWith(NORMAL_NAME) && !path.endsWith(SPECULAR_NAME)) {
|
||||
return true;
|
||||
}
|
||||
if (owner != resourceManager) {
|
||||
start(resourceManager);
|
||||
}
|
||||
if (disabled) {
|
||||
return true;
|
||||
}
|
||||
if (built == null) {
|
||||
try {
|
||||
built = pending.join();
|
||||
} catch (RuntimeException e) {
|
||||
disable(e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
final Object domain = manager.domainResourceManagers.get(location.getResourceDomain());
|
||||
if (domain == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(domain instanceof FallbackResourceManager fallback)) {
|
||||
return true;
|
||||
}
|
||||
final String name = ASSETS + "/" + location.getResourceDomain() + "/" + path;
|
||||
String lower = null;
|
||||
final List<IResourcePack> packs = fallback.resourcePacks;
|
||||
for (int i = packs.size() - 1; i >= 0; i--) {
|
||||
final IResourcePack pack = packs.get(i);
|
||||
final PackIndex index = built.get(pack);
|
||||
final boolean present;
|
||||
if (index == null) {
|
||||
present = pack.resourceExists(location);
|
||||
} else if (index.lowerCase()) {
|
||||
if (lower == null) lower = name.toLowerCase(Locale.ROOT);
|
||||
present = index.names().contains(lower);
|
||||
} else {
|
||||
present = index.names().contains(name);
|
||||
}
|
||||
if (present) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void disable(RuntimeException e) {
|
||||
disabled = true;
|
||||
built = null;
|
||||
pending = null;
|
||||
if (!warned) {
|
||||
warned = true;
|
||||
LOGGER.warn("PBR resource index disabled, falling back to direct lookups", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<ScanTarget> collectTargets(SimpleReloadableResourceManager manager) {
|
||||
final Set<IResourcePack> seen = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||
final List<ScanTarget> targets = new ArrayList<>();
|
||||
for (Object domain : manager.domainResourceManagers.values()) {
|
||||
if (domain instanceof FallbackResourceManager fallback) {
|
||||
for (IResourcePack pack : fallback.resourcePacks) {
|
||||
if (seen.add(pack)) {
|
||||
final ScanTarget target = target(pack);
|
||||
if (target != null) {
|
||||
targets.add(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return targets;
|
||||
}
|
||||
|
||||
private static ScanTarget target(IResourcePack pack) {
|
||||
final Class<?> type = pack.getClass();
|
||||
if (type == FileResourcePack.class || type == FMLFileResourcePack.class) {
|
||||
final FileResourcePack zipPack = (FileResourcePack) pack;
|
||||
try {
|
||||
return new ScanTarget(pack, zipPack.getResourcePackZipFile(), null);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Unable to index " + zipPack.resourcePackFile, e);
|
||||
}
|
||||
}
|
||||
if (type == FolderResourcePack.class || type == FMLFolderResourcePack.class) {
|
||||
return new ScanTarget(pack, null, ((AbstractResourcePack) pack).resourcePackFile);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Map<IResourcePack, PackIndex> scan(List<ScanTarget> targets) {
|
||||
final Map<IResourcePack, PackIndex> result = new IdentityHashMap<>();
|
||||
for (ScanTarget t : targets) {
|
||||
result.put(t.pack(), t.zip() != null ? scanZip(t.zip()) : scanFolder(t.folder()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean isPbrName(String name) {
|
||||
return name.endsWith(NORMAL_NAME) || name.endsWith(SPECULAR_NAME);
|
||||
}
|
||||
|
||||
private static PackIndex scanZip(ZipFile zip) {
|
||||
final Set<String> names = new HashSet<>();
|
||||
final Enumeration<? extends ZipEntry> entries = zip.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
final String name = entries.nextElement().getName();
|
||||
final String key = name.endsWith("/") ? name.substring(0, name.length() - 1) : name;
|
||||
if (isPbrName(key)) {
|
||||
names.add(key);
|
||||
}
|
||||
}
|
||||
return new PackIndex(names, false);
|
||||
}
|
||||
|
||||
private static PackIndex scanFolder(File file) {
|
||||
final Set<String> names = new HashSet<>();
|
||||
final Path root = file.toPath();
|
||||
final Path assets = root.resolve(ASSETS);
|
||||
final boolean caseInsensitive = Files.exists(root.resolve(ASSETS.toUpperCase(Locale.ROOT)));
|
||||
if (Files.isDirectory(assets)) {
|
||||
try {
|
||||
Files.walkFileTree(assets, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new SimpleFileVisitor<>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) {
|
||||
final String relative = root.relativize(path).toString().replace(File.separatorChar, '/');
|
||||
final String name = caseInsensitive ? relative.toLowerCase(Locale.ROOT) : relative;
|
||||
if (isPbrName(name)) {
|
||||
names.add(name);
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFileFailed(Path path, IOException e) throws IOException {
|
||||
if (e instanceof NoSuchFileException) {
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Unable to index " + file, e);
|
||||
}
|
||||
}
|
||||
return new PackIndex(names, caseInsensitive);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import net.coderbot.iris.texture.mipmap.ChannelMipmapGenerator;
|
||||
import net.coderbot.iris.texture.mipmap.CustomMipmapGenerator;
|
||||
import net.coderbot.iris.texture.mipmap.LinearBlendFunction;
|
||||
import net.coderbot.iris.texture.pbr.PBRAtlasTexture;
|
||||
import net.coderbot.iris.texture.pbr.PBRResourceIndex;
|
||||
import net.coderbot.iris.texture.pbr.PBRSpriteHolder;
|
||||
import net.coderbot.iris.texture.pbr.PBRType;
|
||||
import net.coderbot.iris.texture.pbr.TextureAtlasSpriteExtension;
|
||||
@@ -119,6 +120,10 @@ public class AtlasPBRLoader implements PBRTextureLoader<TextureMap> {
|
||||
final ResourceLocation imageLocation = texMap.completeResourceLocation(spriteName, 0);
|
||||
final ResourceLocation pbrImageLocation = pbrType.appendToFileLocation(imageLocation);
|
||||
|
||||
if (!PBRResourceIndex.mayExist(resourceManager, pbrImageLocation)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TextureAtlasSprite pbrSprite = null;
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.coderbot.iris.texture.pbr.loader;
|
||||
|
||||
import net.coderbot.iris.texture.pbr.PBRResourceIndex;
|
||||
import net.coderbot.iris.texture.pbr.PBRType;
|
||||
import net.minecraft.client.renderer.texture.AbstractTexture;
|
||||
import net.minecraft.client.renderer.texture.SimpleTexture;
|
||||
@@ -29,6 +30,10 @@ public class SimplePBRLoader implements PBRTextureLoader<SimpleTexture> {
|
||||
protected AbstractTexture createPBRTexture(ResourceLocation imageLocation, IResourceManager resourceManager, PBRType pbrType) {
|
||||
ResourceLocation pbrImageLocation = pbrType.appendToFileLocation(imageLocation);
|
||||
|
||||
if (!PBRResourceIndex.mayExist(resourceManager, pbrImageLocation)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SimpleTexture pbrTexture = new SimpleTexture(pbrImageLocation);
|
||||
try {
|
||||
pbrTexture.loadTexture(resourceManager);
|
||||
|
||||
+2
@@ -2,6 +2,7 @@ package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.texture.format.TextureFormatLoader;
|
||||
import net.coderbot.iris.texture.pbr.PBRResourceIndex;
|
||||
import net.coderbot.iris.texture.pbr.PBRTextureManager;
|
||||
import net.coderbot.iris.uniforms.CapturedRenderingState;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
@@ -25,6 +26,7 @@ public class MixinTextureManager_ReloadCount {
|
||||
Iris.logger.error("Failed to reload the shader pipeline for a texture format change", e);
|
||||
}
|
||||
PBRTextureManager.INSTANCE.clear();
|
||||
PBRResourceIndex.start(resourceManager);
|
||||
CapturedRenderingState.INSTANCE.incrementTextureReloadCount();
|
||||
}
|
||||
}
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
package com.prupe.mcpatcher.mal.resource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.testutil.Reflect;
|
||||
|
||||
import cpw.mods.fml.common.LoadController;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.LoaderState;
|
||||
|
||||
class TexturePackChangeHandlerDeferralTest {
|
||||
|
||||
private static final class CountingHandler extends TexturePackChangeHandler {
|
||||
|
||||
int before;
|
||||
int after;
|
||||
int after2;
|
||||
|
||||
CountingHandler() {
|
||||
super("counting", 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeChange() {
|
||||
before++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterChange() {
|
||||
after++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterChange2() {
|
||||
after2++;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean savedFeatures;
|
||||
private Object savedLoader;
|
||||
private Object savedMinecraft;
|
||||
private Object savedResourceList;
|
||||
private List<TexturePackChangeHandler> savedHandlers;
|
||||
private LoadController controller;
|
||||
|
||||
@BeforeEach
|
||||
void stubLoader() {
|
||||
savedFeatures = AngelicaConfig.enableMCPatcherForgeFeatures;
|
||||
savedLoader = Reflect.getStatic(Loader.class, "instance");
|
||||
savedMinecraft = Reflect.getStatic(Minecraft.class, "theMinecraft");
|
||||
savedResourceList = Reflect.getStatic(ResourceList.class, "instance");
|
||||
final List<TexturePackChangeHandler> handlers = Reflect.getStatic(TexturePackChangeHandler.class, "handlers");
|
||||
savedHandlers = new ArrayList<>(handlers);
|
||||
handlers.clear();
|
||||
|
||||
AngelicaConfig.enableMCPatcherForgeFeatures = true;
|
||||
controller = Reflect.allocate(LoadController.class);
|
||||
setState(LoaderState.PREINITIALIZATION);
|
||||
final Loader loader = Reflect.allocate(Loader.class);
|
||||
Reflect.setDeclared(Loader.class, loader, "modController", controller);
|
||||
Reflect.setStatic(Loader.class, "instance", loader);
|
||||
|
||||
final Minecraft minecraft = mock(Minecraft.class);
|
||||
when(minecraft.getResourceManager()).thenReturn(mock(IResourceManager.class));
|
||||
Reflect.setStatic(Minecraft.class, "theMinecraft", minecraft);
|
||||
|
||||
resetGate();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void restore() {
|
||||
final List<TexturePackChangeHandler> handlers = Reflect.getStatic(TexturePackChangeHandler.class, "handlers");
|
||||
handlers.clear();
|
||||
handlers.addAll(savedHandlers);
|
||||
resetGate();
|
||||
Reflect.setStatic(ResourceList.class, "instance", savedResourceList);
|
||||
Reflect.setStatic(Minecraft.class, "theMinecraft", savedMinecraft);
|
||||
Reflect.setStatic(Loader.class, "instance", savedLoader);
|
||||
AngelicaConfig.enableMCPatcherForgeFeatures = savedFeatures;
|
||||
}
|
||||
|
||||
private void setState(LoaderState state) {
|
||||
Reflect.setDeclared(LoadController.class, controller, "state", state);
|
||||
}
|
||||
|
||||
private static void resetGate() {
|
||||
Reflect.setStatic(TexturePackChangeHandler.class, "loaderAvailable", false);
|
||||
Reflect.setStatic(TexturePackChangeHandler.class, "deferredDepth", 0);
|
||||
Reflect.setStatic(TexturePackChangeHandler.class, "recurseDepth", 0);
|
||||
}
|
||||
|
||||
private static int recurseDepth() {
|
||||
return Reflect.getStatic(TexturePackChangeHandler.class, "recurseDepth");
|
||||
}
|
||||
|
||||
private static int deferredDepth() {
|
||||
return Reflect.getStatic(TexturePackChangeHandler.class, "deferredDepth");
|
||||
}
|
||||
|
||||
private static void reload() {
|
||||
TexturePackChangeHandler.beforeChange1();
|
||||
TexturePackChangeHandler.afterChange1();
|
||||
}
|
||||
|
||||
@Test
|
||||
void beforeAvailableRegistrationAndReloadsDoNothing() {
|
||||
final ResourceList sentinel = Reflect.allocate(ResourceList.class);
|
||||
Reflect.setStatic(ResourceList.class, "instance", sentinel);
|
||||
final CountingHandler handler = new CountingHandler();
|
||||
|
||||
TexturePackChangeHandler.register(handler);
|
||||
reload();
|
||||
TexturePackChangeHandler.beforeChange1();
|
||||
reload();
|
||||
TexturePackChangeHandler.afterChange1();
|
||||
|
||||
assertTrue(TexturePackChangeHandler.isBootDeferred());
|
||||
assertEquals(0, handler.before);
|
||||
assertEquals(0, handler.after);
|
||||
assertEquals(0, handler.after2);
|
||||
assertEquals(0, recurseDepth());
|
||||
assertEquals(0, deferredDepth());
|
||||
assertSame(sentinel, Reflect.getStatic(ResourceList.class, "instance"));
|
||||
assertTrue(Reflect.<List<TexturePackChangeHandler>>getStatic(TexturePackChangeHandler.class, "handlers").contains(handler));
|
||||
}
|
||||
|
||||
@Test
|
||||
void firstReloadAfterAvailableRunsDeferredHandlersOnce() {
|
||||
final CountingHandler handler = new CountingHandler();
|
||||
TexturePackChangeHandler.register(handler);
|
||||
setState(LoaderState.AVAILABLE);
|
||||
|
||||
reload();
|
||||
|
||||
assertEquals(1, handler.before);
|
||||
assertEquals(1, handler.after);
|
||||
assertEquals(1, handler.after2);
|
||||
assertEquals(0, recurseDepth());
|
||||
assertNull(Reflect.getStatic(ResourceList.class, "instance"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void availableLatchesThroughLaterStates() {
|
||||
setState(LoaderState.AVAILABLE);
|
||||
assertFalse(TexturePackChangeHandler.isBootDeferred());
|
||||
setState(LoaderState.ERRORED);
|
||||
assertFalse(TexturePackChangeHandler.isBootDeferred());
|
||||
final CountingHandler handler = new CountingHandler();
|
||||
reload();
|
||||
TexturePackChangeHandler.register(handler);
|
||||
reload();
|
||||
assertEquals(2, handler.before);
|
||||
assertEquals(2, handler.after);
|
||||
}
|
||||
|
||||
@Test
|
||||
void registrationAfterAvailableInitializesImmediately() {
|
||||
setState(LoaderState.AVAILABLE);
|
||||
final CountingHandler handler = new CountingHandler();
|
||||
TexturePackChangeHandler.register(handler);
|
||||
assertEquals(1, handler.before);
|
||||
assertEquals(1, handler.after);
|
||||
assertEquals(0, handler.after2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void disabledFeaturesNeverDefer() {
|
||||
AngelicaConfig.enableMCPatcherForgeFeatures = false;
|
||||
final CountingHandler handler = new CountingHandler();
|
||||
TexturePackChangeHandler.register(handler);
|
||||
assertFalse(TexturePackChangeHandler.isBootDeferred());
|
||||
assertEquals(1, handler.before);
|
||||
assertEquals(1, handler.after);
|
||||
}
|
||||
|
||||
@Test
|
||||
void bracketOpenedDeferredStaysDeferredAcrossAvailable() {
|
||||
final CountingHandler handler = new CountingHandler();
|
||||
TexturePackChangeHandler.register(handler);
|
||||
TexturePackChangeHandler.beforeChange1();
|
||||
setState(LoaderState.AVAILABLE);
|
||||
reload();
|
||||
TexturePackChangeHandler.afterChange1();
|
||||
|
||||
assertEquals(0, handler.before);
|
||||
assertEquals(0, handler.after);
|
||||
assertEquals(0, deferredDepth());
|
||||
assertEquals(0, recurseDepth());
|
||||
|
||||
reload();
|
||||
assertEquals(1, handler.before);
|
||||
assertEquals(1, handler.after);
|
||||
assertEquals(0, recurseDepth());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package net.coderbot.iris;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.testutil.Reflect;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class IrisProgramSetWarmupTest {
|
||||
@AfterEach
|
||||
void reset() {
|
||||
Reflect.setStatic(Iris.class, "programSetWarmup", null);
|
||||
}
|
||||
|
||||
private static void await() {
|
||||
Reflect.invokeStatic(Iris.class, "awaitProgramSetWarmup", new Class<?>[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
void noPendingWarmupIsNoOp() {
|
||||
Reflect.setStatic(Iris.class, "programSetWarmup", null);
|
||||
await();
|
||||
assertNull(Reflect.getStatic(Iris.class, "programSetWarmup"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void blocksUntilWarmupCompletes() throws Exception {
|
||||
final CompletableFuture<Void> warmup = new CompletableFuture<>();
|
||||
Reflect.setStatic(Iris.class, "programSetWarmup", warmup);
|
||||
final CountDownLatch done = new CountDownLatch(1);
|
||||
final Thread joiner = new Thread(() -> {
|
||||
await();
|
||||
done.countDown();
|
||||
});
|
||||
joiner.start();
|
||||
assertFalse(done.await(200, TimeUnit.MILLISECONDS));
|
||||
warmup.complete(null);
|
||||
assertTrue(done.await(5, TimeUnit.SECONDS));
|
||||
joiner.join();
|
||||
assertNull(Reflect.getStatic(Iris.class, "programSetWarmup"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void failedWarmupIsSwallowedAndCleared() {
|
||||
final CompletableFuture<Void> warmup = new CompletableFuture<>();
|
||||
warmup.completeExceptionally(new IllegalStateException("boom"));
|
||||
Reflect.setStatic(Iris.class, "programSetWarmup", warmup);
|
||||
await();
|
||||
assertNull(Reflect.getStatic(Iris.class, "programSetWarmup"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
package net.coderbot.iris.texture.pbr;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.testutil.Reflect;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import net.minecraft.client.resources.FallbackResourceManager;
|
||||
import net.minecraft.client.resources.FileResourcePack;
|
||||
import net.minecraft.client.resources.FolderResourcePack;
|
||||
import net.minecraft.client.resources.IResourcePack;
|
||||
import net.minecraft.client.resources.SimpleReloadableResourceManager;
|
||||
import net.minecraft.client.resources.data.IMetadataSection;
|
||||
import net.minecraft.client.resources.data.IMetadataSerializer;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
class PBRResourceIndexTest {
|
||||
|
||||
@TempDir
|
||||
Path tmp;
|
||||
|
||||
private final List<FileResourcePack> zipPacks = new ArrayList<>();
|
||||
|
||||
@AfterEach
|
||||
void cleanup() throws IOException {
|
||||
Reflect.invokeStatic(PBRResourceIndex.class, "drop", new Class<?>[0]);
|
||||
for (FileResourcePack pack : zipPacks) {
|
||||
pack.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class StubPack implements IResourcePack {
|
||||
|
||||
private final Set<ResourceLocation> claims = new HashSet<>();
|
||||
|
||||
StubPack(ResourceLocation... locations) {
|
||||
Collections.addAll(claims, locations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream(ResourceLocation location) throws IOException {
|
||||
return new ByteArrayInputStream("stub".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean resourceExists(ResourceLocation location) {
|
||||
return claims.contains(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getResourceDomains() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMetadataSection getPackMetadata(IMetadataSerializer serializer, String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage getPackImage() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPackName() {
|
||||
return "stub";
|
||||
}
|
||||
}
|
||||
|
||||
private FileResourcePack zip(String name, String... entries) throws IOException {
|
||||
final File file = tmp.resolve(name).toFile();
|
||||
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(file))) {
|
||||
for (String entry : entries) {
|
||||
zos.putNextEntry(new ZipEntry(entry));
|
||||
if (!entry.endsWith("/")) {
|
||||
zos.write(entry.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
final FileResourcePack pack = new FileResourcePack(file);
|
||||
zipPacks.add(pack);
|
||||
return pack;
|
||||
}
|
||||
|
||||
private FolderResourcePack folder(String name, String... files) throws IOException {
|
||||
final Path root = tmp.resolve(name);
|
||||
for (String file : files) {
|
||||
final Path target = root.resolve(file);
|
||||
Files.createDirectories(target.getParent());
|
||||
Files.write(target, file.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
Files.createDirectories(root);
|
||||
return new FolderResourcePack(root.toFile());
|
||||
}
|
||||
|
||||
private static FallbackResourceManager domain(IMetadataSerializer serializer, IResourcePack... packs) {
|
||||
final FallbackResourceManager manager = new FallbackResourceManager(serializer);
|
||||
for (IResourcePack pack : packs) {
|
||||
manager.resourcePacks.add(pack);
|
||||
}
|
||||
return manager;
|
||||
}
|
||||
|
||||
private static boolean loads(SimpleReloadableResourceManager manager, ResourceLocation location) {
|
||||
try {
|
||||
manager.getResource(location).getInputStream().close();
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertAgrees(SimpleReloadableResourceManager manager, ResourceLocation location) {
|
||||
final boolean loaded = loads(manager, location);
|
||||
assertEquals(loaded, PBRResourceIndex.mayExist(manager, location), location.toString());
|
||||
}
|
||||
|
||||
private SimpleReloadableResourceManager build(IMetadataSerializer serializer) throws IOException {
|
||||
final ResourceLocation stubbed = new ResourceLocation("minecraft", "textures/blocks/stub_n.png");
|
||||
final ResourceLocation stubbedShadowed = new ResourceLocation("minecraft", "textures/blocks/lowzip_s.png");
|
||||
final FileResourcePack low = zip(
|
||||
"low.zip",
|
||||
"assets/minecraft/textures/blocks/lowzip_n.png",
|
||||
"assets/minecraft/textures/blocks/lowzip_s.png",
|
||||
"assets/minecraft/textures/blocks/both_n.png",
|
||||
"assets/minecraft/textures/blocks/dirlike_n.png/",
|
||||
"assets/minecraft/textures/blocks/plain.png",
|
||||
"assets/minecraft/textures/blocks/notpbr_x.png",
|
||||
"assets/minecraft/textures/blocks/tail_n.png.bak",
|
||||
"assets/other/textures/blocks/other_n.png",
|
||||
"pack.mcmeta");
|
||||
final FolderResourcePack mid = folder(
|
||||
"mid",
|
||||
"assets/minecraft/textures/blocks/folder_s.png",
|
||||
"assets/minecraft/textures/blocks/both_n.png",
|
||||
"assets/minecraft/textures/blocks/Mixed_n.png",
|
||||
"assets/minecraft/textures/blocks/deep/er/nested_n.png",
|
||||
"assets/other/textures/blocks/otherfolder_s.png");
|
||||
final StubPack high = new StubPack(stubbed, stubbedShadowed);
|
||||
|
||||
final SimpleReloadableResourceManager manager = new SimpleReloadableResourceManager(serializer);
|
||||
manager.domainResourceManagers.put("minecraft", domain(serializer, low, mid, high));
|
||||
manager.domainResourceManagers.put("other", domain(serializer, low, mid));
|
||||
manager.domainResourceManagers.put("stubonly", domain(serializer, new StubPack(new ResourceLocation("stubonly", "textures/x_n.png"))));
|
||||
return manager;
|
||||
}
|
||||
|
||||
@Test
|
||||
void agreesWithGetResourceAcrossPackTypesAndDomains() throws Exception {
|
||||
final IMetadataSerializer serializer = new IMetadataSerializer();
|
||||
final SimpleReloadableResourceManager manager = build(serializer);
|
||||
PBRResourceIndex.start(manager);
|
||||
|
||||
final String[][] locations = {
|
||||
{ "minecraft", "textures/blocks/lowzip_n.png" },
|
||||
{ "minecraft", "textures/blocks/lowzip_s.png" },
|
||||
{ "minecraft", "textures/blocks/both_n.png" },
|
||||
{ "minecraft", "textures/blocks/both_s.png" },
|
||||
{ "minecraft", "textures/blocks/dirlike_n.png" },
|
||||
{ "minecraft", "textures/blocks/folder_s.png" },
|
||||
{ "minecraft", "textures/blocks/folder_n.png" },
|
||||
{ "minecraft", "textures/blocks/Mixed_n.png" },
|
||||
{ "minecraft", "textures/blocks/mixed_n.png" },
|
||||
{ "minecraft", "textures/blocks/MIXED_n.png" },
|
||||
{ "minecraft", "textures/blocks/deep/er/nested_n.png" },
|
||||
{ "minecraft", "textures/blocks/deep/nested_n.png" },
|
||||
{ "minecraft", "textures/blocks/stub_n.png" },
|
||||
{ "minecraft", "textures/blocks/stub_s.png" },
|
||||
{ "minecraft", "textures/blocks/absent_n.png" },
|
||||
{ "minecraft", "textures/blocks/absent_s.png" },
|
||||
{ "minecraft", "textures/blocks/tail_n.png" },
|
||||
{ "other", "textures/blocks/other_n.png" },
|
||||
{ "other", "textures/blocks/otherfolder_s.png" },
|
||||
{ "other", "textures/blocks/stub_n.png" },
|
||||
{ "other", "textures/blocks/lowzip_n.png" },
|
||||
{ "stubonly", "textures/x_n.png" },
|
||||
{ "stubonly", "textures/y_n.png" },
|
||||
{ "ghost", "textures/blocks/lowzip_n.png" },
|
||||
};
|
||||
for (String[] location : locations) {
|
||||
assertAgrees(manager, new ResourceLocation(location[0], location[1]));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void presentLocationsAreReportedPresent() throws Exception {
|
||||
final SimpleReloadableResourceManager manager = build(new IMetadataSerializer());
|
||||
PBRResourceIndex.start(manager);
|
||||
|
||||
assertTrue(PBRResourceIndex.mayExist(manager, new ResourceLocation("minecraft", "textures/blocks/lowzip_n.png")));
|
||||
assertTrue(PBRResourceIndex.mayExist(manager, new ResourceLocation("minecraft", "textures/blocks/folder_s.png")));
|
||||
assertTrue(PBRResourceIndex.mayExist(manager, new ResourceLocation("minecraft", "textures/blocks/stub_n.png")));
|
||||
assertTrue(PBRResourceIndex.mayExist(manager, new ResourceLocation("other", "textures/blocks/otherfolder_s.png")));
|
||||
assertFalse(PBRResourceIndex.mayExist(manager, new ResourceLocation("minecraft", "textures/blocks/absent_n.png")));
|
||||
assertFalse(PBRResourceIndex.mayExist(manager, new ResourceLocation("other", "textures/blocks/stub_n.png")));
|
||||
assertFalse(PBRResourceIndex.mayExist(manager, new ResourceLocation("ghost", "textures/blocks/lowzip_n.png")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nonPbrLocationsAreNeverRuledOut() throws Exception {
|
||||
final SimpleReloadableResourceManager manager = build(new IMetadataSerializer());
|
||||
PBRResourceIndex.start(manager);
|
||||
|
||||
assertTrue(PBRResourceIndex.mayExist(manager, new ResourceLocation("minecraft", "textures/blocks/plain.png")));
|
||||
assertTrue(PBRResourceIndex.mayExist(manager, new ResourceLocation("minecraft", "textures/blocks/nothing.png")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void lazyBuildWithoutStartAgrees() throws Exception {
|
||||
final SimpleReloadableResourceManager manager = build(new IMetadataSerializer());
|
||||
|
||||
assertAgrees(manager, new ResourceLocation("minecraft", "textures/blocks/lowzip_n.png"));
|
||||
assertAgrees(manager, new ResourceLocation("minecraft", "textures/blocks/absent_n.png"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void startAfterReloadSeesNewPacks() throws Exception {
|
||||
final IMetadataSerializer serializer = new IMetadataSerializer();
|
||||
final SimpleReloadableResourceManager manager = build(serializer);
|
||||
PBRResourceIndex.start(manager);
|
||||
final ResourceLocation added = new ResourceLocation("minecraft", "textures/blocks/added_n.png");
|
||||
assertFalse(PBRResourceIndex.mayExist(manager, added));
|
||||
|
||||
manager.domainResourceManagers.get("minecraft").resourcePacks.add(zip("added.zip", "assets/minecraft/textures/blocks/added_n.png"));
|
||||
PBRResourceIndex.start(manager);
|
||||
|
||||
assertTrue(PBRResourceIndex.mayExist(manager, added));
|
||||
assertAgrees(manager, added);
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildFailureDisablesIndex() throws Exception {
|
||||
final IMetadataSerializer serializer = new IMetadataSerializer();
|
||||
final SimpleReloadableResourceManager manager = new SimpleReloadableResourceManager(serializer);
|
||||
final FileResourcePack missing = new FileResourcePack(tmp.resolve("missing.zip").toFile());
|
||||
manager.domainResourceManagers.put("minecraft", domain(serializer, missing));
|
||||
PBRResourceIndex.start(manager);
|
||||
|
||||
assertTrue(PBRResourceIndex.mayExist(manager, new ResourceLocation("minecraft", "textures/blocks/absent_n.png")));
|
||||
assertTrue(PBRResourceIndex.mayExist(manager, new ResourceLocation("ghost", "textures/blocks/absent_n.png")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void zipScanSharesThePacksOpenJar() throws Exception {
|
||||
final IMetadataSerializer serializer = new IMetadataSerializer();
|
||||
final SimpleReloadableResourceManager manager = new SimpleReloadableResourceManager(serializer);
|
||||
final FileResourcePack pack = zip("shared.zip", "assets/minecraft/textures/blocks/shared_n.png");
|
||||
manager.domainResourceManagers.put("minecraft", domain(serializer, pack));
|
||||
PBRResourceIndex.start(manager);
|
||||
|
||||
assertTrue(PBRResourceIndex.mayExist(manager, new ResourceLocation("minecraft", "textures/blocks/shared_n.png")));
|
||||
final ZipFile jar = pack.getResourcePackZipFile();
|
||||
assertSame(jar, pack.getResourcePackZipFile());
|
||||
assertNotNull(jar.getEntry("assets/minecraft/textures/blocks/shared_n.png"));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user