From c30574c3d071936f49076432aeab9c5636f250fc Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 6 May 2023 16:40:49 -0400 Subject: [PATCH 01/36] Only apply item rendering optimization outside of level rendering --- .../GameRendererMixin.java | 21 +++++++++++++++++++ .../ItemRendererMixin.java | 3 ++- .../modernfix/render/RenderState.java | 5 +++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/GameRendererMixin.java create mode 100644 common/src/main/java/org/embeddedt/modernfix/render/RenderState.java diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/GameRendererMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/GameRendererMixin.java new file mode 100644 index 00000000..ee3a0f9d --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/GameRendererMixin.java @@ -0,0 +1,21 @@ +package org.embeddedt.modernfix.common.mixin.perf.faster_item_rendering; + +import net.minecraft.client.renderer.GameRenderer; +import org.embeddedt.modernfix.render.RenderState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(GameRenderer.class) +public class GameRendererMixin { + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;renderLevel(FJLcom/mojang/blaze3d/vertex/PoseStack;)V", shift = At.Shift.BEFORE)) + private void markRenderingLevel(CallbackInfo ci) { + RenderState.IS_RENDERING_LEVEL = true; + } + + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;renderLevel(FJLcom/mojang/blaze3d/vertex/PoseStack;)V", shift = At.Shift.AFTER)) + private void markNotRenderingLevel(CallbackInfo ci) { + RenderState.IS_RENDERING_LEVEL = false; + } +} diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/ItemRendererMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/ItemRendererMixin.java index 630cef82..987f0235 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/ItemRendererMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/ItemRendererMixin.java @@ -12,6 +12,7 @@ import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.SimpleBakedModel; import net.minecraft.core.Direction; import net.minecraft.world.item.ItemStack; +import org.embeddedt.modernfix.render.RenderState; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -47,7 +48,7 @@ public abstract class ItemRendererMixin { */ @Inject(method = "renderModelLists", at = @At("HEAD"), cancellable = true) private void fasterItemRender(BakedModel model, ItemStack stack, int combinedLight, int combinedOverlay, PoseStack matrixStack, VertexConsumer buffer, CallbackInfo ci) { - if(!stack.isEmpty() && model.getClass() == SimpleBakedModel.class && transformType == ItemTransforms.TransformType.GUI && model.getTransforms().gui == ItemTransform.NO_TRANSFORM) { + if(!RenderState.IS_RENDERING_LEVEL && !stack.isEmpty() && model.getClass() == SimpleBakedModel.class && transformType == ItemTransforms.TransformType.GUI && model.getTransforms().gui == ItemTransform.NO_TRANSFORM) { ci.cancel(); PoseStack.Pose pose = matrixStack.last(); int[] combinedLights = new int[] {combinedLight, combinedLight, combinedLight, combinedLight}; diff --git a/common/src/main/java/org/embeddedt/modernfix/render/RenderState.java b/common/src/main/java/org/embeddedt/modernfix/render/RenderState.java new file mode 100644 index 00000000..e869e383 --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/render/RenderState.java @@ -0,0 +1,5 @@ +package org.embeddedt.modernfix.render; + +public class RenderState { + public static boolean IS_RENDERING_LEVEL = false; +} From 3ba38b602ae4cc93f817ef36a9a1f02e77e70cfc Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 7 May 2023 13:57:52 -0400 Subject: [PATCH 02/36] Remove nonexistent mixin configs --- .../embeddedt/modernfix/core/config/ModernFixEarlyConfig.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index 28733531..70e3833a 100644 --- a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -139,15 +139,12 @@ public class ModernFixEarlyConfig { private static final ImmutableMap DEFAULT_SETTING_OVERRIDES = ImmutableMap.builder() .put("mixin.perf.dynamic_resources", false) - .put("mixin.feature.reduce_loading_screen_freezes", false) .put("mixin.feature.direct_stack_trace", false) .put("mixin.perf.rewrite_registry", false) .put("mixin.perf.clear_mixin_classinfo", false) .put("mixin.perf.compress_blockstate", false) .put("mixin.bugfix.packet_leak", false) .put("mixin.perf.deduplicate_location", false) - .put("mixin.perf.preload_block_classes", false) - .put("mixin.perf.faster_singleplayer_load", false) .put("mixin.perf.blast_search_trees", shouldReplaceSearchTrees) .put("mixin.devenv", isDevEnv) .put("mixin.perf.remove_spawn_chunks", isDevEnv) From 65e12016b60524ee00aeca10fafebe1cfead4842 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 7 May 2023 14:07:17 -0400 Subject: [PATCH 03/36] Add config for integrated server watchdog --- .../src/main/java/org/embeddedt/modernfix/ModernFixClient.java | 2 ++ .../embeddedt/modernfix/core/config/ModernFixEarlyConfig.java | 1 + 2 files changed, 3 insertions(+) diff --git a/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java b/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java index 3c1cf8be..bf15ca24 100644 --- a/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java +++ b/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java @@ -173,6 +173,8 @@ public class ModernFixClient { } public void onServerStarted(MinecraftServer server) { + if(!ModernFixMixinPlugin.instance.isOptionEnabled("feature.integrated_server_watchdog.IntegratedWatchdog")) + return; IntegratedWatchdog watchdog = new IntegratedWatchdog(server); watchdog.start(); } diff --git a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index 70e3833a..d37bbdb5 100644 --- a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -145,6 +145,7 @@ public class ModernFixEarlyConfig { .put("mixin.perf.compress_blockstate", false) .put("mixin.bugfix.packet_leak", false) .put("mixin.perf.deduplicate_location", false) + .put("mixin.feature.integrated_server_watchdog", true) .put("mixin.perf.blast_search_trees", shouldReplaceSearchTrees) .put("mixin.devenv", isDevEnv) .put("mixin.perf.remove_spawn_chunks", isDevEnv) From 321c676fd08c27056187923ebca7383a1dd51a94 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 7 May 2023 14:39:55 -0400 Subject: [PATCH 04/36] Disable dynamic entity renderers by default due to incompatible mods --- .../embeddedt/modernfix/core/config/ModernFixEarlyConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index d37bbdb5..25adb46b 100644 --- a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -145,6 +145,7 @@ public class ModernFixEarlyConfig { .put("mixin.perf.compress_blockstate", false) .put("mixin.bugfix.packet_leak", false) .put("mixin.perf.deduplicate_location", false) + .put("mixin.perf.dynamic_entity_renderers", false) .put("mixin.feature.integrated_server_watchdog", true) .put("mixin.perf.blast_search_trees", shouldReplaceSearchTrees) .put("mixin.devenv", isDevEnv) From b55129a8cada0aaee4b1b012078fb0cfdcebe00a Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 7 May 2023 18:08:00 -0400 Subject: [PATCH 05/36] Generate resource cache using resource reload workers --- .../resources/PackResourcesCacheEngine.java | 73 +++++++++++++------ 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java b/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java index 8e2ced85..6c0d2235 100644 --- a/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java +++ b/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java @@ -1,16 +1,19 @@ package org.embeddedt.modernfix.resources; +import com.google.common.base.Stopwatch; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.PackType; +import org.embeddedt.modernfix.ModernFix; import org.embeddedt.modernfix.util.PackTypeHelper; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; @@ -26,6 +29,7 @@ public class PackResourcesCacheEngine { private final Map> namespacesByType; private final Set containedPaths; private final EnumMap>> resourceListings; + private CompletableFuture cacheFuture; public PackResourcesCacheEngine(Function> namespacesRetriever, BiFunction basePathRetriever) { this.namespacesByType = new EnumMap<>(PackType.class); @@ -36,32 +40,50 @@ public class PackResourcesCacheEngine { } this.containedPaths = new ObjectOpenHashSet<>(); this.resourceListings = new EnumMap<>(PackType.class); + CompletableFuture future = CompletableFuture.completedFuture(null); + Stopwatch watch = Stopwatch.createStarted(); + // used for log message + Path debugPath = basePathRetriever.apply(PackType.CLIENT_RESOURCES, "minecraft").toAbsolutePath(); for(PackType type : PackType.values()) { Collection namespaces = PackTypeHelper.isVanillaPackType(type) ? this.namespacesByType.get(type) : namespacesRetriever.apply(type); - ImmutableMap.Builder> packTypedMap = ImmutableMap.builder(); - for(String namespace : namespaces) { - try { - ImmutableList.Builder namespacedList = ImmutableList.builder(); - Path root = basePathRetriever.apply(type, namespace).toAbsolutePath(); - String[] prefix = new String[] { type.getDirectory(), namespace }; - try (Stream stream = Files.walk(root)) { - stream - .map(path -> root.relativize(path.toAbsolutePath())) - .filter(PackResourcesCacheEngine::isValidCachedResourcePath) - .forEach(path -> { - CachedResourcePath cachedPath = new CachedResourcePath(prefix, path); - this.containedPaths.add(cachedPath); - if(!cachedPath.getFileName().endsWith(".mcmeta")) - namespacedList.add(cachedPath); - }); + future = future.thenRunAsync(() -> { + ImmutableMap.Builder> packTypedMap = ImmutableMap.builder(); + for(String namespace : namespaces) { + try { + ImmutableList.Builder namespacedList = ImmutableList.builder(); + Path root = basePathRetriever.apply(type, namespace).toAbsolutePath(); + String[] prefix = new String[] { type.getDirectory(), namespace }; + try (Stream stream = Files.walk(root)) { + stream + .map(path -> root.relativize(path.toAbsolutePath())) + .filter(PackResourcesCacheEngine::isValidCachedResourcePath) + .forEach(path -> { + CachedResourcePath cachedPath = new CachedResourcePath(prefix, path); + synchronized (this.containedPaths) { + this.containedPaths.add(cachedPath); + } + if(!cachedPath.getFileName().endsWith(".mcmeta")) + namespacedList.add(cachedPath); + }); + } + packTypedMap.put(namespace, namespacedList.build()); + } catch(IOException ignored) { } - packTypedMap.put(namespace, namespacedList.build()); - } catch(IOException ignored) { } - } - this.resourceListings.put(type, packTypedMap.build()); + synchronized (this.resourceListings) { + this.resourceListings.put(type, packTypedMap.build()); + } + }, ModernFix.resourceReloadExecutor()); } - ((ObjectOpenHashSet)this.containedPaths).trim(); + future = future.thenRunAsync(() -> { + ((ObjectOpenHashSet)this.containedPaths).trim(); + watch.stop(); + }, ModernFix.resourceReloadExecutor()); + this.cacheFuture = future; + // print debug message in separate task to prevent slowing down rest of load + future.thenRunAsync(() -> { + ModernFix.LOGGER.debug("Generated cache for {} in {}", debugPath, watch); + }, ModernFix.resourceReloadExecutor()); } private static boolean isValidCachedResourcePath(Path path) { @@ -86,13 +108,22 @@ public class PackResourcesCacheEngine { return null; } + private void awaitLoad() { + if(this.cacheFuture != null) { + this.cacheFuture.join(); + this.cacheFuture = null; + } + } + public boolean hasResource(String path) { + awaitLoad(); return this.containedPaths.contains(new CachedResourcePath(path)); } public Collection getResources(PackType type, String resourceNamespace, String pathIn, int maxDepth, Predicate filter) { if(!PackTypeHelper.isVanillaPackType(type)) throw new IllegalArgumentException("Only vanilla PackTypes are supported"); + awaitLoad(); List paths = resourceListings.get(type).getOrDefault(resourceNamespace, Collections.emptyList()); if(paths.isEmpty()) return Collections.emptyList(); From 604c3687ef26ec1d33fbacc6a1466ad08b8a96b2 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 7 May 2023 21:07:56 -0400 Subject: [PATCH 06/36] Optimize block item rendering as well --- .../ItemRendererMixin.java | 46 +++++++++++++++---- .../modernfix/render/FastItemRenderType.java | 6 +++ 2 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 common/src/main/java/org/embeddedt/modernfix/render/FastItemRenderType.java diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/ItemRendererMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/ItemRendererMixin.java index 987f0235..9f936496 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/ItemRendererMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/ItemRendererMixin.java @@ -11,7 +11,9 @@ import net.minecraft.client.renderer.entity.ItemRenderer; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.SimpleBakedModel; import net.minecraft.core.Direction; +import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.ItemStack; +import org.embeddedt.modernfix.render.FastItemRenderType; import org.embeddedt.modernfix.render.RenderState; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -38,6 +40,17 @@ public abstract class ItemRendererMixin { this.transformType = transformType; } + private static final Direction[] ITEM_DIRECTIONS = new Direction[] { Direction.SOUTH }; + private static final Direction[] BLOCK_DIRECTIONS = new Direction[] { Direction.UP, Direction.EAST, Direction.NORTH }; + + private boolean isCorrectDirectionForType(FastItemRenderType type, Direction direction) { + if(type == FastItemRenderType.SIMPLE_ITEM) + return direction == Direction.SOUTH; + else { + return direction == Direction.UP || direction == Direction.EAST || direction == Direction.NORTH; + } + } + /** * If a model * - is a vanilla item model (SimpleBakedModel), @@ -48,25 +61,42 @@ public abstract class ItemRendererMixin { */ @Inject(method = "renderModelLists", at = @At("HEAD"), cancellable = true) private void fasterItemRender(BakedModel model, ItemStack stack, int combinedLight, int combinedOverlay, PoseStack matrixStack, VertexConsumer buffer, CallbackInfo ci) { - if(!RenderState.IS_RENDERING_LEVEL && !stack.isEmpty() && model.getClass() == SimpleBakedModel.class && transformType == ItemTransforms.TransformType.GUI && model.getTransforms().gui == ItemTransform.NO_TRANSFORM) { + if(!RenderState.IS_RENDERING_LEVEL && !stack.isEmpty() && model.getClass() == SimpleBakedModel.class && transformType == ItemTransforms.TransformType.GUI) { + FastItemRenderType type; + ItemTransform transform = model.getTransforms().gui; + if(transform == ItemTransform.NO_TRANSFORM) + type = FastItemRenderType.SIMPLE_ITEM; + else if(stack.getItem() instanceof BlockItem && isBlockTransforms(transform)) + type = FastItemRenderType.SIMPLE_BLOCK; + else + return; ci.cancel(); PoseStack.Pose pose = matrixStack.last(); int[] combinedLights = new int[] {combinedLight, combinedLight, combinedLight, combinedLight}; - List culledFaces = model.getQuads(null, Direction.SOUTH, dummyRandom); - List unculledFaces = model.getQuads(null, null, dummyRandom); - /* check size to avoid instantiating iterator when the list is empty */ - if(culledFaces.size() > 0) { - for(BakedQuad quad : culledFaces) { - render2dItemFace(quad, stack, buffer, pose, combinedLights, combinedOverlay); + Direction[] directions = type == FastItemRenderType.SIMPLE_ITEM ? ITEM_DIRECTIONS : BLOCK_DIRECTIONS; + for(Direction direction : directions) { + List culledFaces = model.getQuads(null, direction, dummyRandom); + /* check size to avoid instantiating iterator when the list is empty */ + if(culledFaces.size() > 0) { + for(BakedQuad quad : culledFaces) { + render2dItemFace(quad, stack, buffer, pose, combinedLights, combinedOverlay); + } } } + List unculledFaces = model.getQuads(null, null, dummyRandom); for(BakedQuad quad : unculledFaces) { - if(quad.getDirection() == Direction.SOUTH) + if(isCorrectDirectionForType(type, quad.getDirection())) render2dItemFace(quad, stack, buffer, pose, combinedLights, combinedOverlay); } } } + private boolean isBlockTransforms(ItemTransform transform) { + return transform.rotation.x() == 30f + && transform.rotation.y() == 225f + && transform.rotation.z() == 0f; + } + private void render2dItemFace(BakedQuad quad, ItemStack stack, VertexConsumer buffer, PoseStack.Pose pose, int[] combinedLights, int combinedOverlay) { int i = -1; if (quad.isTinted()) { diff --git a/common/src/main/java/org/embeddedt/modernfix/render/FastItemRenderType.java b/common/src/main/java/org/embeddedt/modernfix/render/FastItemRenderType.java new file mode 100644 index 00000000..31b02d27 --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/render/FastItemRenderType.java @@ -0,0 +1,6 @@ +package org.embeddedt.modernfix.render; + +public enum FastItemRenderType { + SIMPLE_ITEM, + SIMPLE_BLOCK +} From 43c1ed70299d38b87990c2150bbdac90aca7d050 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 7 May 2023 21:39:25 -0400 Subject: [PATCH 07/36] Disable faster item rendering by default until its tested more --- .../embeddedt/modernfix/core/config/ModernFixEarlyConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index d37bbdb5..b88082ab 100644 --- a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -146,6 +146,7 @@ public class ModernFixEarlyConfig { .put("mixin.bugfix.packet_leak", false) .put("mixin.perf.deduplicate_location", false) .put("mixin.feature.integrated_server_watchdog", true) + .put("mixin.perf.faster_item_rendering", false) .put("mixin.perf.blast_search_trees", shouldReplaceSearchTrees) .put("mixin.devenv", isDevEnv) .put("mixin.perf.remove_spawn_chunks", isDevEnv) From 530fb5f796e8ba8684a254cd001988a496719ab0 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 09:04:43 -0400 Subject: [PATCH 08/36] Hotfix for potential resource reload race condition --- .../modernfix/resources/PackResourcesCacheEngine.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java b/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java index 6c0d2235..d02c55d8 100644 --- a/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java +++ b/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java @@ -3,6 +3,7 @@ package org.embeddedt.modernfix.resources; import com.google.common.base.Stopwatch; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.mojang.datafixers.util.Pair; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.PackType; @@ -17,6 +18,7 @@ import java.util.concurrent.CompletableFuture; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; +import java.util.stream.Collectors; import java.util.stream.Stream; /** @@ -46,12 +48,14 @@ public class PackResourcesCacheEngine { Path debugPath = basePathRetriever.apply(PackType.CLIENT_RESOURCES, "minecraft").toAbsolutePath(); for(PackType type : PackType.values()) { Collection namespaces = PackTypeHelper.isVanillaPackType(type) ? this.namespacesByType.get(type) : namespacesRetriever.apply(type); + Collection> namespacedRoots = namespaces.stream().map(s -> Pair.of(s, basePathRetriever.apply(type, s).toAbsolutePath())).collect(Collectors.toList()); future = future.thenRunAsync(() -> { ImmutableMap.Builder> packTypedMap = ImmutableMap.builder(); - for(String namespace : namespaces) { + for(Pair pair : namespacedRoots) { try { ImmutableList.Builder namespacedList = ImmutableList.builder(); - Path root = basePathRetriever.apply(type, namespace).toAbsolutePath(); + String namespace = pair.getFirst(); + Path root = pair.getSecond(); String[] prefix = new String[] { type.getDirectory(), namespace }; try (Stream stream = Files.walk(root)) { stream From d8d76c00c77ac344fbeed1bbc044ac59cde7e406 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 09:25:40 -0400 Subject: [PATCH 09/36] Hotfix for another potential race condition --- .../modernfix/resources/PackResourcesCacheEngine.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java b/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java index d02c55d8..577e1c50 100644 --- a/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java +++ b/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java @@ -31,7 +31,7 @@ public class PackResourcesCacheEngine { private final Map> namespacesByType; private final Set containedPaths; private final EnumMap>> resourceListings; - private CompletableFuture cacheFuture; + private volatile CompletableFuture cacheFuture; public PackResourcesCacheEngine(Function> namespacesRetriever, BiFunction basePathRetriever) { this.namespacesByType = new EnumMap<>(PackType.class); @@ -114,8 +114,12 @@ public class PackResourcesCacheEngine { private void awaitLoad() { if(this.cacheFuture != null) { - this.cacheFuture.join(); - this.cacheFuture = null; + synchronized (this) { + if(this.cacheFuture != null) { + this.cacheFuture.join(); + this.cacheFuture = null; + } + } } } From c63252946ab8d01e9513b345f0bc5937657b9b80 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 09:44:44 -0400 Subject: [PATCH 10/36] Fix JEI creative search tree replacement not working Fixes #86 --- .../perf/blast_search_trees/MinecraftMixin.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/blast_search_trees/MinecraftMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/blast_search_trees/MinecraftMixin.java index b0e3955c..4d5c5b75 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/blast_search_trees/MinecraftMixin.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/blast_search_trees/MinecraftMixin.java @@ -4,6 +4,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.searchtree.SearchRegistry; import net.minecraftforge.fml.ModContainer; import net.minecraftforge.fml.ModList; +import org.embeddedt.modernfix.ModernFix; import org.embeddedt.modernfix.annotation.ClientOnlyMixin; import org.embeddedt.modernfix.searchtree.DummySearchTree; import org.embeddedt.modernfix.searchtree.REIBackedSearchTree; @@ -24,18 +25,26 @@ public class MinecraftMixin { @Inject(method = "createSearchTrees", at = @At("HEAD"), cancellable = true) private void replaceSearchTrees(CallbackInfo ci) { - ci.cancel(); Optional jeiContainer = ModList.get().getModContainerById("jei"); if(ModList.get().isLoaded("roughlyenoughitems")) { + ModernFix.LOGGER.info("Replaced creative search logic with REI"); this.searchRegistry.register(SearchRegistry.CREATIVE_NAMES, new REIBackedSearchTree(false)); this.searchRegistry.register(SearchRegistry.CREATIVE_TAGS, new REIBackedSearchTree(true)); - } else if(jeiContainer.isPresent() && jeiContainer.get().getModInfo().getVersion().getMajorVersion() >= 10) { + } else if(jeiContainer.isPresent()) { + /* ugly hack since getMajorVersion() returns 0 */ + if(jeiContainer.get().getModInfo().getVersion().toString().startsWith("9.")) { + ModernFix.LOGGER.warn("Not disabling creative search as JEI 9 is in use"); + return; + } + ModernFix.LOGGER.info("Replaced creative search logic with JEI"); this.searchRegistry.register(SearchRegistry.CREATIVE_NAMES, new JEIBackedSearchTree(false)); this.searchRegistry.register(SearchRegistry.CREATIVE_TAGS, new JEIBackedSearchTree(true)); } else { + ModernFix.LOGGER.info("Completely removed creative search logic"); this.searchRegistry.register(SearchRegistry.CREATIVE_NAMES, new DummySearchTree<>()); this.searchRegistry.register(SearchRegistry.CREATIVE_TAGS, new DummySearchTree<>()); } this.searchRegistry.register(SearchRegistry.RECIPE_COLLECTIONS, new DummySearchTree<>()); + ci.cancel(); } } From 2f8f47ae3efcb9bc5b03db406afc9f7940c1661d Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 09:57:53 -0400 Subject: [PATCH 11/36] Ensure the context class loader is set for the resource reload executors --- .../org/embeddedt/modernfix/ModernFix.java | 10 ++-- .../modernfix/resources/ReloadExecutor.java | 48 +++++++++++++++++++ 2 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 common/src/main/java/org/embeddedt/modernfix/resources/ReloadExecutor.java diff --git a/common/src/main/java/org/embeddedt/modernfix/ModernFix.java b/common/src/main/java/org/embeddedt/modernfix/ModernFix.java index 18f99171..cbd44bf4 100644 --- a/common/src/main/java/org/embeddedt/modernfix/ModernFix.java +++ b/common/src/main/java/org/embeddedt/modernfix/ModernFix.java @@ -9,10 +9,11 @@ import org.apache.logging.log4j.Logger; import org.embeddedt.modernfix.command.ModernFixCommands; import org.embeddedt.modernfix.core.ModernFixMixinPlugin; import org.embeddedt.modernfix.platform.ModernFixPlatformHooks; +import org.embeddedt.modernfix.resources.ReloadExecutor; import org.embeddedt.modernfix.util.ClassInfoManager; import java.lang.management.ManagementFactory; -import java.util.concurrent.*; +import java.util.concurrent.Executor; // The value here should match an entry in the META-INF/mods.toml file public class ModernFix { @@ -31,12 +32,7 @@ public class ModernFix { static { if(ModernFixMixinPlugin.instance.isOptionEnabled("perf.dedicated_reload_executor.ReloadExecutor")) { - try { - resourceReloadService = Util.makeExecutor("ResourceReload"); - } catch(Throwable e) { - LOGGER.error("Error creating resource reload service, using fallback", e); - resourceReloadService = Util.backgroundExecutor(); - } + resourceReloadService = ReloadExecutor.createCustomResourceReloadExecutor(); } else { resourceReloadService = Util.backgroundExecutor(); } diff --git a/common/src/main/java/org/embeddedt/modernfix/resources/ReloadExecutor.java b/common/src/main/java/org/embeddedt/modernfix/resources/ReloadExecutor.java new file mode 100644 index 00000000..ec35c84a --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/resources/ReloadExecutor.java @@ -0,0 +1,48 @@ +package org.embeddedt.modernfix.resources; + +import net.minecraft.ReportedException; +import net.minecraft.server.Bootstrap; +import org.embeddedt.modernfix.ModernFix; + +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinWorkerThread; +import java.util.concurrent.atomic.AtomicInteger; + +public class ReloadExecutor { + public static ExecutorService createCustomResourceReloadExecutor() { + ClassLoader loader = ReloadExecutor.class.getClassLoader(); + AtomicInteger workerCount = new AtomicInteger(0); + return new ForkJoinPool(ForkJoinPool.getCommonPoolParallelism(), (forkJoinPool) -> { + ForkJoinWorkerThread forkJoinWorkerThread = new ForkJoinWorkerThread(forkJoinPool) { + protected void onTermination(Throwable throwOnTermination) { + if (throwOnTermination != null) { + ModernFix.LOGGER.warn("{} died", this.getName(), throwOnTermination); + } else { + ModernFix.LOGGER.debug("{} shutdown", this.getName()); + } + + super.onTermination(throwOnTermination); + } + }; + // needed to prevent weirdness on some systems + forkJoinWorkerThread.setContextClassLoader(loader); + forkJoinWorkerThread.setName("Worker-ResourceReload-" + workerCount.getAndIncrement()); + return forkJoinWorkerThread; + }, ReloadExecutor::handleException, true); + } + + private static void handleException(Thread thread, Throwable throwable) { + if (throwable instanceof CompletionException) { + throwable = throwable.getCause(); + } + + if (throwable instanceof ReportedException) { + Bootstrap.realStdoutPrintln(((ReportedException)throwable).getReport().getFriendlyReport()); + System.exit(-1); + } + + ModernFix.LOGGER.error(String.format("Caught exception in thread %s", thread), throwable); + } +} From cc9e7289c661fea170118428b5015dad4b0cb57b Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 09:59:05 -0400 Subject: [PATCH 12/36] Fix compile error --- common/src/main/java/org/embeddedt/modernfix/ModernFix.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/ModernFix.java b/common/src/main/java/org/embeddedt/modernfix/ModernFix.java index cc43248d..b571b718 100644 --- a/common/src/main/java/org/embeddedt/modernfix/ModernFix.java +++ b/common/src/main/java/org/embeddedt/modernfix/ModernFix.java @@ -13,7 +13,7 @@ import org.embeddedt.modernfix.resources.ReloadExecutor; import org.embeddedt.modernfix.util.ClassInfoManager; import java.lang.management.ManagementFactory; -import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; // The value here should match an entry in the META-INF/mods.toml file public class ModernFix { From b955f17fbda5f5343586d833e46d5be0e3145e49 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 10:17:24 -0400 Subject: [PATCH 13/36] Do resource cache generation on-thread, but lazily Apparently ForkJoinPools can deadlock even though they are not supposed to --- .../resources/PackResourcesCacheEngine.java | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java b/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java index 577e1c50..a8333fa3 100644 --- a/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java +++ b/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java @@ -14,7 +14,6 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; -import java.util.concurrent.CompletableFuture; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; @@ -31,7 +30,9 @@ public class PackResourcesCacheEngine { private final Map> namespacesByType; private final Set containedPaths; private final EnumMap>> resourceListings; - private volatile CompletableFuture cacheFuture; + private volatile boolean cacheGenerationFlag = false; + private List cacheGenerationTasks = new ArrayList<>(); + private Path debugPath; public PackResourcesCacheEngine(Function> namespacesRetriever, BiFunction basePathRetriever) { this.namespacesByType = new EnumMap<>(PackType.class); @@ -42,14 +43,12 @@ public class PackResourcesCacheEngine { } this.containedPaths = new ObjectOpenHashSet<>(); this.resourceListings = new EnumMap<>(PackType.class); - CompletableFuture future = CompletableFuture.completedFuture(null); - Stopwatch watch = Stopwatch.createStarted(); // used for log message - Path debugPath = basePathRetriever.apply(PackType.CLIENT_RESOURCES, "minecraft").toAbsolutePath(); + this.debugPath = basePathRetriever.apply(PackType.CLIENT_RESOURCES, "minecraft").toAbsolutePath(); for(PackType type : PackType.values()) { Collection namespaces = PackTypeHelper.isVanillaPackType(type) ? this.namespacesByType.get(type) : namespacesRetriever.apply(type); Collection> namespacedRoots = namespaces.stream().map(s -> Pair.of(s, basePathRetriever.apply(type, s).toAbsolutePath())).collect(Collectors.toList()); - future = future.thenRunAsync(() -> { + cacheGenerationTasks.add(() -> { ImmutableMap.Builder> packTypedMap = ImmutableMap.builder(); for(Pair pair : namespacedRoots) { try { @@ -77,17 +76,11 @@ public class PackResourcesCacheEngine { synchronized (this.resourceListings) { this.resourceListings.put(type, packTypedMap.build()); } - }, ModernFix.resourceReloadExecutor()); + }); } - future = future.thenRunAsync(() -> { + cacheGenerationTasks.add(() -> { ((ObjectOpenHashSet)this.containedPaths).trim(); - watch.stop(); - }, ModernFix.resourceReloadExecutor()); - this.cacheFuture = future; - // print debug message in separate task to prevent slowing down rest of load - future.thenRunAsync(() -> { - ModernFix.LOGGER.debug("Generated cache for {} in {}", debugPath, watch); - }, ModernFix.resourceReloadExecutor()); + }); } private static boolean isValidCachedResourcePath(Path path) { @@ -112,12 +105,23 @@ public class PackResourcesCacheEngine { return null; } + private void doGenerateCache() { + Stopwatch watch = Stopwatch.createStarted(); + for(Runnable r : this.cacheGenerationTasks) { + r.run(); + } + watch.stop(); + ModernFix.LOGGER.debug("Generated cache for {} in {}", debugPath, watch); + debugPath = null; + cacheGenerationTasks = ImmutableList.of(); + } + private void awaitLoad() { - if(this.cacheFuture != null) { + if(!this.cacheGenerationFlag) { synchronized (this) { - if(this.cacheFuture != null) { - this.cacheFuture.join(); - this.cacheFuture = null; + if(!this.cacheGenerationFlag) { + this.doGenerateCache(); + this.cacheGenerationFlag = true; } } } From 9e7c82a30381a99a0bcecc0ab67af011aacd9f07 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 10:41:53 -0400 Subject: [PATCH 14/36] Disable datapack_reload_exceptions if Cyanide is installed as it overlaps --- .../embeddedt/modernfix/core/config/ModernFixEarlyConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index b88082ab..b0372155 100644 --- a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -186,6 +186,7 @@ public class ModernFixEarlyConfig { disableIfModPresent("mixin.bugfix.mc218112", "performant"); disableIfModPresent("mixin.perf.reuse_datapacks", "tac"); disableIfModPresent("mixin.launch.class_search_cache", "optifine"); + disableIfModPresent("mixin.perf.datapack_reload_exceptions", "cyanide"); } private void disableIfModPresent(String configName, String... ids) { From 992269034d9397b35b713cbb2a41c4367fe2d7df Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 14:10:54 -0400 Subject: [PATCH 15/36] Rewrite Fabric dynamic model loader to not load all models at startup --- .../dynamicresources/ModelBakeryHelpers.java | 7 +- .../dynamic_resources/ModelBakeryMixin.java | 158 ++++++++++++++++-- 2 files changed, 152 insertions(+), 13 deletions(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelBakeryHelpers.java b/common/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelBakeryHelpers.java index e0df2a26..0f993e12 100644 --- a/common/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelBakeryHelpers.java +++ b/common/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelBakeryHelpers.java @@ -268,6 +268,7 @@ public class ModelBakeryHelpers { ModernFix.LOGGER.error("Suppressed additional {} model errors for domain {}", entry.getIntValue(), entry.getKey()); } }); + blockstateErrors.clear(); modelFiles = null; Function modelGetter = loc -> { UnbakedModel m = basicModels.get(loc); @@ -275,7 +276,11 @@ public class ModelBakeryHelpers { return m != null ? m : bakeryModelGetter.apply(loc); }; for(BlockModel model : basicModels.values()) { - materialSet.addAll(model.getMaterials(modelGetter, errorSet)); + try { + materialSet.addAll(model.getMaterials(modelGetter, errorSet)); + } catch(Throwable e) { + ModernFix.LOGGER.error("Model {} threw error while getting materials", model.name, e); + } } //errorSet.stream().filter(pair -> !pair.getSecond().equals(MISSING_MODEL_LOCATION_STRING)).forEach(pair -> LOGGER.warn("Unable to resolve texture reference: {} in {}", pair.getFirst(), pair.getSecond())); stopwatch.stop(); diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java index 185bb732..6a47edba 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -1,23 +1,33 @@ package org.embeddedt.modernfix.fabric.mixin.perf.dynamic_resources; +import com.google.common.base.Stopwatch; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.cache.RemovalNotification; import com.google.common.collect.ForwardingMap; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.mojang.datafixers.util.Pair; import com.mojang.math.Transformation; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.client.renderer.block.model.BlockModelDefinition; import net.minecraft.client.renderer.block.model.ItemModelGenerator; import net.minecraft.client.renderer.block.model.MultiVariant; import net.minecraft.client.renderer.block.model.multipart.MultiPart; -import net.minecraft.client.renderer.texture.AtlasSet; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.client.renderer.texture.*; +import net.minecraft.client.resources.ClientPackSource; import net.minecraft.client.resources.model.*; +import net.minecraft.core.Registry; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.FilePackResources; +import net.minecraft.server.packs.FolderPackResources; +import net.minecraft.server.packs.PackResources; +import net.minecraft.server.packs.VanillaPackResources; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; import org.apache.commons.lang3.tuple.Triple; @@ -34,6 +44,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.util.*; @@ -41,6 +52,9 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.function.Predicate; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import java.util.stream.Stream; /* high priority so that our injectors are added before other mods' */ @Mixin(value = ModelBakery.class, priority = 600) @@ -75,6 +89,12 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { @Shadow @Nullable public abstract BakedModel bake(ResourceLocation location, ModelState transform); @Shadow @Final private Map topLevelModels; + @Shadow @Final private static String MISSING_MODEL_LOCATION_STRING; + + @Shadow protected abstract void cacheAndQueueDependencies(ResourceLocation location, UnbakedModel model); + + @Shadow @Final private BlockModelDefinition.Context context; + @Shadow @Final private static Map> STATIC_DEFINITIONS; private Cache, BakedModel> loadedBakedModels; private Cache loadedModels; @@ -141,6 +161,103 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { return this.missingModel; } + private Set blockStateFiles = new ObjectOpenHashSet<>(); + private Set modelFiles = new ObjectOpenHashSet<>(); + + private boolean forceLoadModel = false; + + @Inject(method = "loadModel", at = @At(value = "HEAD", shift = At.Shift.AFTER), cancellable = true) + private void ignoreNonFabricModel(ResourceLocation modelLocation, CallbackInfo ci) throws Exception { + if(this.inTextureGatheringPass && !this.forceLoadModel) { + // Custom model processor, try to avoid loading unwrapped models + // First add this to the list of models to scan for textures + ResourceLocation blockStateLocation = null; + if(modelLocation instanceof ModelResourceLocation) { + ModelResourceLocation location = (ModelResourceLocation)modelLocation; + if(Objects.equals(location.getVariant(), "inventory")) { + modelFiles.add(new ResourceLocation(location.getNamespace(), "item/" + location.getPath())); + } else { + blockStateLocation = new ResourceLocation(location.getNamespace(), location.getPath()); + blockStateFiles.add(blockStateLocation); + } + } else + modelFiles.add(modelLocation); + // Now check if it's a wrapped model + boolean isWrappedModel = false; + Set oldLoadingStack = this.loadingStack.size() > 0 ? new ObjectOpenHashSet<>(this.loadingStack) : ImmutableSet.of(); + // Set the correct blockstate context + StateDefinition statecontainer; + if(blockStateLocation != null) { + statecontainer = STATIC_DEFINITIONS.get(blockStateLocation); + if(statecontainer == null) + statecontainer = Registry.BLOCK.get(blockStateLocation).getStateDefinition(); + } else + statecontainer = Blocks.AIR.getStateDefinition(); + this.context.setDefinition(statecontainer); + // Pretend to be caching the model by caching the missing model, if the actually cached model isn't + // the exact same instance we know a mixin tampered with it + this.forceLoadModel = true; + this.cacheAndQueueDependencies(modelLocation, this.missingModel); + this.forceLoadModel = false; + this.loadingStack.clear(); + this.loadingStack.addAll(oldLoadingStack); + if(this.smallLoadingCache.get(modelLocation) != this.missingModel) { + /* probably a wrapped model, allow it to load normally */ + isWrappedModel = true; + } + this.smallLoadingCache.clear(); + this.unbakedCache.remove(modelLocation); + // Load the model through the normal code path + if(isWrappedModel) { + ModernFix.LOGGER.warn("Model {} appears to be replaced by another mod and will load at startup", modelLocation); + this.forceLoadModel = true; + this.loadModel(modelLocation); + this.forceLoadModel = false; + } + ci.cancel(); + } + } + + private boolean trustedResourcePack(PackResources pack) { + return pack instanceof VanillaPackResources || + pack instanceof ClientPackSource || + pack instanceof FolderPackResources || + pack instanceof FilePackResources; + } + + @Redirect(method = "", at = @At(value = "INVOKE", target = "Ljava/util/stream/Stream;collect(Ljava/util/stream/Collector;)Ljava/lang/Object;", ordinal = 0)) + private Object collectExtraTextures(Stream instance, Collector arCollector) { + Set materialsSet = new ObjectOpenHashSet<>(instance.collect(Collectors.toSet())); + ModelBakeryHelpers.gatherModelMaterials(this.resourceManager, this::trustedResourcePack, materialsSet, + blockStateFiles, modelFiles, this.missingModel, json -> BlockModel.GSON.fromJson(json, BlockModel.class), + this::getModel); + /* take every texture from these folders (1.19.3+ emulation) */ + String[] extraFolders = new String[] { + "block", + "blocks", + "item", + "items", + "bettergrass" + }; + for(String folder : extraFolders) { + Collection textureLocations = this.resourceManager.listResources("textures/" + folder, p -> p.endsWith(".png")); + for(ResourceLocation rl : textureLocations) { + if(rl.getNamespace().equals("assets")) { + /* buggy pack, correct path */ + int slashIndex = rl.getPath().indexOf('/'); + String actualNamespace = rl.getPath().substring(0, slashIndex); + String actualPath = rl.getPath().substring(slashIndex + 1); + rl = new ResourceLocation(actualNamespace, actualPath); + } + ResourceLocation texLoc = new ResourceLocation(rl.getNamespace(), rl.getPath().substring(9, rl.getPath().length() - 4)); + materialsSet.add(new Material(TextureAtlas.LOCATION_BLOCKS, texLoc)); + } + } + blockStateFiles = null; + modelFiles = null; + return materialsSet; + } + @Inject(method = "uploadTextures", at = @At(value = "FIELD", target = "Lnet/minecraft/client/resources/model/ModelBakery;topLevelModels:Ljava/util/Map;", ordinal = 0), cancellable = true) private void skipBake(TextureManager resourceManager, ProfilerFiller profiler, CallbackInfoReturnable cir) { profiler.pop(); @@ -162,15 +279,21 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { } }; // discard unwrapped models - int oldSize = this.unbakedCache.size(); Predicate> isVanillaModel = entry -> entry.getValue() instanceof BlockModel || entry.getValue() instanceof MultiVariant || entry.getValue() instanceof MultiPart; - // bake indigo models - this.topLevelModels.entrySet().forEach((entry) -> { - if(!isVanillaModel.test(entry)) - this.bake(entry.getKey(), BlockModelRotation.X0_Y0); - }); this.unbakedCache.entrySet().removeIf(isVanillaModel); - ModernFix.LOGGER.info("{} models evicted, {} custom models loaded permanently", oldSize - this.unbakedCache.size(), this.unbakedCache.size()); + this.topLevelModels.entrySet().removeIf(isVanillaModel); + // bake indigo models + Stopwatch watch = Stopwatch.createStarted(); + this.topLevelModels.forEach((key, value) -> { + try { + this.bake(key, BlockModelRotation.X0_Y0); + } catch(RuntimeException e) { + ModernFix.LOGGER.error("Model {} failed to bake", key, e); + } + }); + watch.stop(); + ModernFix.LOGGER.info("Early model bake took {}", watch); + ModernFix.LOGGER.info("{} unbaked models, {} baked models loaded permanently", this.unbakedCache.size(), this.bakedCache.size()); this.unbakedCache = new LayeredForwardingMap<>(new Map[] { this.unbakedCache, mutableBackingMap }); this.bakedTopLevelModels = new DynamicBakedModelProvider((ModelBakery)(Object)this, bakedCache); @@ -194,7 +317,6 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { return unbakedCache.get(rl); } - /** * @author embeddedt * @reason synchronize @@ -281,7 +403,19 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { if(debugDynamicModelLoading) LOGGER.info("Baking {}", arg); UnbakedModel iunbakedmodel = this.getModel(arg); - iunbakedmodel.getMaterials(this::getModel, new HashSet<>()); + Set> errorSet = new HashSet<>(); + Collection theMaterials = iunbakedmodel.getMaterials(this::getModel, errorSet); + /* check if sprites are actually present */ + TextureAtlasSprite missingSprite = this.atlasSet.getAtlas(TextureAtlas.LOCATION_BLOCKS).getSprite(MissingTextureAtlasSprite.getLocation()); + for(Material m : theMaterials) { + if(m.atlasLocation().equals(TextureAtlas.LOCATION_BLOCKS)) { + TextureAtlasSprite sprite = this.atlasSet.getAtlas(TextureAtlas.LOCATION_BLOCKS).getSprite(m.texture()); + if(sprite == missingSprite && !m.texture().equals(MissingTextureAtlasSprite.getLocation())) + ModernFix.LOGGER.warn("Texture {} is not present in blocks atlas", m.texture()); + } + } + errorSet.stream().filter(pair -> !pair.getSecond().equals(MISSING_MODEL_LOCATION_STRING)).forEach(pair -> LOGGER.warn("Unable to resolve texture reference: {} in {}", pair.getFirst(), pair.getSecond())); + if(iunbakedmodel == missingModel && debugDynamicModelLoading) LOGGER.warn("Model {} not present", arg); BakedModel ibakedmodel = null; From c420c63ab1bf953a4248cda9a5b3edfb3e338862 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 14:14:20 -0400 Subject: [PATCH 16/36] Handle bakedTopLevelModels not being a dynamic provider yet --- .../fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java index 6a47edba..264c2b6c 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -430,8 +430,9 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { // use a shared baked missing model if(bakedMissingModel == null) { bakedMissingModel = iunbakedmodel.bake((ModelBakery) (Object) this, textureGetter, arg2, arg); - ((DynamicBakedModelProvider)this.bakedTopLevelModels).setMissingModel(bakedMissingModel); } + if(this.bakedTopLevelModels instanceof DynamicBakedModelProvider) + ((DynamicBakedModelProvider)this.bakedTopLevelModels).setMissingModel(bakedMissingModel); ibakedmodel = bakedMissingModel; } else ibakedmodel = iunbakedmodel.bake((ModelBakery) (Object) this, textureGetter, arg2, arg); From 85025b77fb9a30f81d8365a06b2710cbf780fb4b Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 14:15:22 -0400 Subject: [PATCH 17/36] Set the missing model early if needed --- .../fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java index 264c2b6c..8ce9e128 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -296,6 +296,8 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { ModernFix.LOGGER.info("{} unbaked models, {} baked models loaded permanently", this.unbakedCache.size(), this.bakedCache.size()); this.unbakedCache = new LayeredForwardingMap<>(new Map[] { this.unbakedCache, mutableBackingMap }); this.bakedTopLevelModels = new DynamicBakedModelProvider((ModelBakery)(Object)this, bakedCache); + if(this.bakedMissingModel != null) + ((DynamicBakedModelProvider)this.bakedTopLevelModels).setMissingModel(this.bakedMissingModel); // ensure missing model is a permanent override this.bakedTopLevelModels.put(MISSING_MODEL_LOCATION, this.bake(MISSING_MODEL_LOCATION, BlockModelRotation.X0_Y0)); From 833fdc9ae515ed2275da33b35431659dbf141c89 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 14:22:50 -0400 Subject: [PATCH 18/36] Minor optimization when turning MRL into blockstate list --- .../modernfix/dynamicresources/ModelBakeryHelpers.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelBakeryHelpers.java b/common/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelBakeryHelpers.java index 0f993e12..49b01c78 100644 --- a/common/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelBakeryHelpers.java +++ b/common/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelBakeryHelpers.java @@ -321,6 +321,10 @@ public class ModelBakeryHelpers { } } } + // check if there is only one possible state + if(fixedProperties.size() == stateDefinition.getProperties().size()) { + return ImmutableList.of(fixedState); + } // generate all possible blockstates from the remaining properties ArrayList> anyProperties = new ArrayList<>(stateDefinition.getProperties()); anyProperties.removeAll(fixedProperties); From 656f3924dad641905d824d0a3810387cac3052c7 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 14:53:23 -0400 Subject: [PATCH 19/36] Avoid running Fabric loading hook except for extra models --- fabric/build.gradle | 1 + .../dynamic_resources/ModelBakeryMixin.java | 23 +++++++++++-------- fabric/src/main/resources/fabric.mod.json | 1 + 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/fabric/build.gradle b/fabric/build.gradle index 5aa002d4..a68aea14 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -33,6 +33,7 @@ dependencies { modIncludeImplementation(fabricApi.module("fabric-lifecycle-events-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' } modIncludeImplementation(fabricApi.module("fabric-screen-api-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' } modIncludeImplementation(fabricApi.module("fabric-command-api-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' } + modIncludeImplementation(fabricApi.module("fabric-models-v0", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' } modImplementation(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' } modCompileOnly("com.terraformersmc:modmenu:${rootProject.modmenu_version}") { transitive false } // Remove the next line if you don't want to depend on the API diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java index 8ce9e128..a3b88dd7 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -6,10 +6,9 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.RemovalNotification; import com.google.common.collect.ForwardingMap; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.mojang.datafixers.util.Pair; import com.mojang.math.Transformation; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import net.fabricmc.fabric.impl.client.model.ModelLoadingRegistryImpl; import net.minecraft.client.renderer.block.model.BlockModel; import net.minecraft.client.renderer.block.model.BlockModelDefinition; import net.minecraft.client.renderer.block.model.ItemModelGenerator; @@ -102,6 +101,8 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { private boolean inTextureGatheringPass; + private Set injectedModels; + @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiling/ProfilerFiller;push(Ljava/lang/String;)V", ordinal = 0)) private void replaceTopLevelBakedModels(ProfilerFiller filler, String s) { this.inTextureGatheringPass = true; @@ -134,6 +135,10 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { } }; filler.push(s); + this.injectedModels = new ObjectOpenHashSet<>(); + ModelLoadingRegistryImpl.LoaderInstance instance = ModelLoadingRegistryImpl.begin((ModelBakery)(Object)this, this.resourceManager); + instance.onModelPopulation(this.injectedModels::add); + instance.finish(); } private void onModelRemoved(RemovalNotification notification) { @@ -166,9 +171,9 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { private boolean forceLoadModel = false; - @Inject(method = "loadModel", at = @At(value = "HEAD", shift = At.Shift.AFTER), cancellable = true) + @Inject(method = "loadModel", at = @At(value = "HEAD"), cancellable = true) private void ignoreNonFabricModel(ResourceLocation modelLocation, CallbackInfo ci) throws Exception { - if(this.inTextureGatheringPass && !this.forceLoadModel) { + if(this.inTextureGatheringPass && !this.forceLoadModel && !this.injectedModels.contains(modelLocation)) { // Custom model processor, try to avoid loading unwrapped models // First add this to the list of models to scan for textures ResourceLocation blockStateLocation = null; @@ -184,7 +189,6 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { modelFiles.add(modelLocation); // Now check if it's a wrapped model boolean isWrappedModel = false; - Set oldLoadingStack = this.loadingStack.size() > 0 ? new ObjectOpenHashSet<>(this.loadingStack) : ImmutableSet.of(); // Set the correct blockstate context StateDefinition statecontainer; if(blockStateLocation != null) { @@ -199,8 +203,6 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { this.forceLoadModel = true; this.cacheAndQueueDependencies(modelLocation, this.missingModel); this.forceLoadModel = false; - this.loadingStack.clear(); - this.loadingStack.addAll(oldLoadingStack); if(this.smallLoadingCache.get(modelLocation) != this.missingModel) { /* probably a wrapped model, allow it to load normally */ isWrappedModel = true; @@ -262,6 +264,7 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { private void skipBake(TextureManager resourceManager, ProfilerFiller profiler, CallbackInfoReturnable cir) { profiler.pop(); this.inTextureGatheringPass = false; + this.injectedModels = null; // hand off to the dynamic model system this.loadedModels.put(MISSING_MODEL_LOCATION, this.missingModel); this.bakedCache = loadedBakedModels.asMap(); @@ -391,6 +394,8 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { private BakedModel bakedMissingModel = null; + private Set bakeStack = new LinkedHashSet<>(); + @Inject(method = "bake", at = @At("HEAD"), cancellable = true) public void getOrLoadBakedModelDynamic(ResourceLocation arg, ModelState arg2, CallbackInfoReturnable cir) { Function textureGetter = mat -> this.atlasSet.getSprite(mat); @@ -405,8 +410,7 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { if(debugDynamicModelLoading) LOGGER.info("Baking {}", arg); UnbakedModel iunbakedmodel = this.getModel(arg); - Set> errorSet = new HashSet<>(); - Collection theMaterials = iunbakedmodel.getMaterials(this::getModel, errorSet); + Collection theMaterials = iunbakedmodel.getMaterials(this::getModel, new HashSet<>()); /* check if sprites are actually present */ TextureAtlasSprite missingSprite = this.atlasSet.getAtlas(TextureAtlas.LOCATION_BLOCKS).getSprite(MissingTextureAtlasSprite.getLocation()); for(Material m : theMaterials) { @@ -416,7 +420,6 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { ModernFix.LOGGER.warn("Texture {} is not present in blocks atlas", m.texture()); } } - errorSet.stream().filter(pair -> !pair.getSecond().equals(MISSING_MODEL_LOCATION_STRING)).forEach(pair -> LOGGER.warn("Unable to resolve texture reference: {} in {}", pair.getFirst(), pair.getSecond())); if(iunbakedmodel == missingModel && debugDynamicModelLoading) LOGGER.warn("Model {} not present", arg); diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 2b241674..40277be7 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -32,6 +32,7 @@ "fabric-lifecycle-events-v1": "*", "fabric-screen-api-v1": "*", "fabric-command-api-v1": "*", + "fabric-models-v0": "*", "minecraft": ">=1.16.5" }, "breaks": { From 21a9266c8fa298949c4f68c45897ef729e218ee5 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 14:54:31 -0400 Subject: [PATCH 20/36] Update patch for 1.19 --- .../fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java index 687ed64f..01cc5dce 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -243,7 +243,7 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { "bettergrass" }; for(String folder : extraFolders) { - Collection textureLocations = this.resourceManager.listResources("textures/" + folder, p -> p.endsWith(".png")); + Collection textureLocations = this.resourceManager.listResources("textures/" + folder, p -> p.getPath().endsWith(".png")).keySet(); for(ResourceLocation rl : textureLocations) { if(rl.getNamespace().equals("assets")) { /* buggy pack, correct path */ From c4ee1dd5221ad18cffb374295787b3d35aa19a39 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 15:06:15 -0400 Subject: [PATCH 21/36] Update incompatible mod disabling list --- .../embeddedt/modernfix/core/config/ModernFixEarlyConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index b0372155..d46f0ffa 100644 --- a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -184,6 +184,8 @@ public class ModernFixEarlyConfig { disableIfModPresent("mixin.perf.async_jei", "modernui"); disableIfModPresent("mixin.perf.compress_biome_container", "chocolate", "betterendforge"); disableIfModPresent("mixin.bugfix.mc218112", "performant"); + disableIfModPresent("mixin.bugfix.remove_block_chunkloading", "performant"); + disableIfModPresent("mixin.bugfix.paper_chunk_patches", "c2me"); disableIfModPresent("mixin.perf.reuse_datapacks", "tac"); disableIfModPresent("mixin.launch.class_search_cache", "optifine"); disableIfModPresent("mixin.perf.datapack_reload_exceptions", "cyanide"); @@ -195,8 +197,6 @@ public class ModernFixEarlyConfig { Option option = this.options.get(configName); if(option != null) option.addModOverride(false, id); - else - LOGGER.warn("Can't disable missing option {}", configName); } } } From 5ee4c636e79f32117d0d9dab476a3312ba9cc2a1 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 15:38:16 -0400 Subject: [PATCH 22/36] Adjust faster texture loading for FAPI compat --- .../TextureAtlasMixin.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_texture_loading/TextureAtlasMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_texture_loading/TextureAtlasMixin.java index 0c9e7199..2a749f5c 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_texture_loading/TextureAtlasMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_texture_loading/TextureAtlasMixin.java @@ -34,16 +34,17 @@ public abstract class TextureAtlasMixin { private Map> loadedImages; private boolean usingFasterLoad; + private Collection storedResults; /** * @author embeddedt * @reason simplify texture loading by loading whole image once, avoid slow PngInfo code */ - @Redirect(method = "prepareToStitch", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/texture/TextureAtlas;getBasicSpriteInfos(Lnet/minecraft/server/packs/resources/ResourceManager;Ljava/util/Set;)Ljava/util/Collection;")) - private Collection loadImages(TextureAtlas atlas, ResourceManager manager, Set imageLocations) { + @Inject(method = "getBasicSpriteInfos", at = @At("HEAD")) + private void loadImages(ResourceManager manager, Set imageLocations, CallbackInfoReturnable> cir) { usingFasterLoad = ModernFixPlatformHooks.isLoadingNormally(); // bail if Forge is erroring to avoid AT crashes if(!usingFasterLoad) { - return getBasicSpriteInfos(manager, imageLocations); + return; } List> futures = new ArrayList<>(); ConcurrentLinkedQueue results = new ConcurrentLinkedQueue<>(); @@ -71,12 +72,24 @@ public abstract class TextureAtlasMixin { }, ModernFix.resourceReloadExecutor())); } CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); - return results; + storedResults = results; + } + + @Redirect(method = "getBasicSpriteInfos", at = @At(value = "INVOKE", target = "Ljava/util/Set;iterator()Ljava/util/Iterator;", ordinal = 0)) + private Iterator skipIteration(Set instance) { + return usingFasterLoad ? Collections.emptyIterator() : instance.iterator(); + } + + @Inject(method = "getBasicSpriteInfos", at = @At("RETURN")) + private void injectFastSprites(ResourceManager resourceManager, Set spriteLocations, CallbackInfoReturnable> cir) { + if(usingFasterLoad) + cir.getReturnValue().addAll(storedResults); } @Inject(method = "prepareToStitch", at = @At("RETURN")) private void clearLoadedImages(CallbackInfoReturnable cir) { loadedImages = Collections.emptyMap(); + storedResults = null; } @Inject(method = "load(Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite$Info;IIIII)Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;", From cd2f289ea8ba10dbaab1b448e4981e2ea2971b62 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 15:49:47 -0400 Subject: [PATCH 23/36] Disable faster texture loading when Stitch is present --- .../embeddedt/modernfix/core/config/ModernFixEarlyConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index d46f0ffa..a7688484 100644 --- a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -189,6 +189,7 @@ public class ModernFixEarlyConfig { disableIfModPresent("mixin.perf.reuse_datapacks", "tac"); disableIfModPresent("mixin.launch.class_search_cache", "optifine"); disableIfModPresent("mixin.perf.datapack_reload_exceptions", "cyanide"); + disableIfModPresent("mixin.perf.faster_texture_loading", "stitch"); } private void disableIfModPresent(String configName, String... ids) { From 33f689ba9aa56b2b5e533b8473b55308497006db Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 16:15:15 -0400 Subject: [PATCH 24/36] Make RenderType EqualsStrategy more predictable --- .../RenderTypeEqualsStrategyMixin.java | 17 +++++++++++++++++ .../src/main/resources/modernfix.accesswidener | 3 ++- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 common/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/concurrency/RenderTypeEqualsStrategyMixin.java diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/concurrency/RenderTypeEqualsStrategyMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/concurrency/RenderTypeEqualsStrategyMixin.java new file mode 100644 index 00000000..c3afbe3d --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/concurrency/RenderTypeEqualsStrategyMixin.java @@ -0,0 +1,17 @@ +package org.embeddedt.modernfix.common.mixin.bugfix.concurrency; + +import net.minecraft.client.renderer.RenderType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.Objects; + +@Mixin(targets = { "net/minecraft/client/renderer/RenderType$CompositeRenderType$EqualsStrategy"}) +public class RenderTypeEqualsStrategyMixin { + @Redirect(method = "equals(Lnet/minecraft/client/renderer/RenderType$CompositeRenderType;Lnet/minecraft/client/renderer/RenderType$CompositeRenderType;)Z", at = @At(value = "INVOKE", target = "Ljava/util/Objects;equals(Ljava/lang/Object;Ljava/lang/Object;)Z", ordinal = 0)) + private boolean alsoCheckName(Object a, Object b, RenderType.CompositeRenderType type1, RenderType.CompositeRenderType type2) { + boolean supposedlyEqual = Objects.equals(a, b); + return supposedlyEqual && Objects.equals(type1.name, type2.name); + } +} diff --git a/common/src/main/resources/modernfix.accesswidener b/common/src/main/resources/modernfix.accesswidener index 5081dfe7..bf157c09 100644 --- a/common/src/main/resources/modernfix.accesswidener +++ b/common/src/main/resources/modernfix.accesswidener @@ -36,4 +36,5 @@ accessible field net/minecraft/client/Minecraft reserve [B accessible method net/minecraft/resources/ResourceKey (Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/resources/ResourceLocation;)V accessible method net/minecraft/client/renderer/texture/TextureAtlasSprite (Lnet/minecraft/client/renderer/texture/TextureAtlas;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite$Info;IIIIILcom/mojang/blaze3d/platform/NativeImage;)V accessible field net/minecraft/client/renderer/block/model/BlockModel GSON Lcom/google/gson/Gson; -accessible field net/minecraft/server/MinecraftServer resources Lnet/minecraft/server/ServerResources; \ No newline at end of file +accessible field net/minecraft/server/MinecraftServer resources Lnet/minecraft/server/ServerResources; +accessible field net/minecraft/client/renderer/RenderStateShard name Ljava/lang/String; \ No newline at end of file From 9e44e00e70c17fb73a94ed5f9c63664d45891365 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 16:39:01 -0400 Subject: [PATCH 25/36] Fix Continuity emissives --- .../mixin/perf/faster_texture_loading/TextureAtlasMixin.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_texture_loading/TextureAtlasMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_texture_loading/TextureAtlasMixin.java index 2a749f5c..f24add16 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_texture_loading/TextureAtlasMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_texture_loading/TextureAtlasMixin.java @@ -25,14 +25,14 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; -@Mixin(value = TextureAtlas.class, priority = 1500) +@Mixin(value = TextureAtlas.class, priority = 600) @ClientOnlyMixin public abstract class TextureAtlasMixin { @Shadow protected abstract ResourceLocation getResourceLocation(ResourceLocation location); @Shadow protected abstract Collection getBasicSpriteInfos(ResourceManager resourceManager, Set spriteLocations); - private Map> loadedImages; + private Map> loadedImages = new ConcurrentHashMap<>(); private boolean usingFasterLoad; private Collection storedResults; /** @@ -48,7 +48,6 @@ public abstract class TextureAtlasMixin { } List> futures = new ArrayList<>(); ConcurrentLinkedQueue results = new ConcurrentLinkedQueue<>(); - loadedImages = new ConcurrentHashMap<>(); for(ResourceLocation location : imageLocations) { if(MissingTextureAtlasSprite.getLocation().equals(location)) continue; From fc9aff621724d342064351cd37e217f833d5834c Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 17:59:28 -0400 Subject: [PATCH 26/36] Enable GitHub Gradle cache --- .github/workflows/gradle.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index e14c3237..561195c2 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -16,6 +16,7 @@ jobs: with: distribution: 'temurin' java-version: '17' + cache: 'gradle' - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build the mod From 9d4d1cc9b447eba9199deac192574ccac9319613 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 18:04:23 -0400 Subject: [PATCH 27/36] Add more paths to texture search --- .../mixin/perf/dynamic_resources/ModelBakeryMixin.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java index a3b88dd7..88384316 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -235,11 +235,14 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { this::getModel); /* take every texture from these folders (1.19.3+ emulation) */ String[] extraFolders = new String[] { + "attachment", + "bettergrass", "block", "blocks", + "cape", "item", "items", - "bettergrass" + "pipe" }; for(String folder : extraFolders) { Collection textureLocations = this.resourceManager.listResources("textures/" + folder, p -> p.endsWith(".png")); From d33ebd69e877c5f71c5b6be5187c8463b4757bff Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 19:17:00 -0400 Subject: [PATCH 28/36] Fix texture reload failing on second try --- .../mixin/perf/faster_texture_loading/TextureAtlasMixin.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_texture_loading/TextureAtlasMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_texture_loading/TextureAtlasMixin.java index f24add16..b605365b 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_texture_loading/TextureAtlasMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_texture_loading/TextureAtlasMixin.java @@ -85,6 +85,11 @@ public abstract class TextureAtlasMixin { cir.getReturnValue().addAll(storedResults); } + @Inject(method = "prepareToStitch", at = @At("HEAD")) + private void initMap(CallbackInfoReturnable cir) { + loadedImages = new ConcurrentHashMap<>(); + } + @Inject(method = "prepareToStitch", at = @At("RETURN")) private void clearLoadedImages(CallbackInfoReturnable cir) { loadedImages = Collections.emptyMap(); From d70480eb175440b2995d9e1283f5fcb70f202fad Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 8 May 2023 20:16:24 -0400 Subject: [PATCH 29/36] More Fabric dynamic model loading improvements --- .../LoaderInstanceMixin.java | 19 +++++++++++++++++++ .../dynamic_resources/ModelBakeryMixin.java | 5 ++++- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/LoaderInstanceMixin.java diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/LoaderInstanceMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/LoaderInstanceMixin.java new file mode 100644 index 00000000..5ab99015 --- /dev/null +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/LoaderInstanceMixin.java @@ -0,0 +1,19 @@ +package org.embeddedt.modernfix.fabric.mixin.perf.dynamic_resources; + +import net.fabricmc.fabric.impl.client.model.ModelLoadingRegistryImpl; +import net.minecraft.client.resources.model.ModelBakery; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; +import org.embeddedt.modernfix.annotation.RequiresMod; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(ModelLoadingRegistryImpl.LoaderInstance.class) +@RequiresMod("fabric-models-v0") +@ClientOnlyMixin +public class LoaderInstanceMixin { + @Redirect(method = "finish", at = @At(value = "FIELD", target = "Lnet/fabricmc/fabric/impl/client/model/ModelLoadingRegistryImpl$LoaderInstance;loader:Lnet/minecraft/client/resources/model/ModelBakery;")) + private void keepLoader(ModelLoadingRegistryImpl.LoaderInstance instance, ModelBakery value) { + /* allow loading models to happen later */ + } +} \ No newline at end of file diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java index 88384316..82b7ae6e 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -240,9 +240,12 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { "block", "blocks", "cape", + "entity/bed", + "entity/chest", "item", "items", - "pipe" + "pipe", + "ropebridge" }; for(String folder : extraFolders) { Collection textureLocations = this.resourceManager.listResources("textures/" + folder, p -> p.endsWith(".png")); From 03abdfdc498965bb387588162a2c7de7555f74a2 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Tue, 9 May 2023 16:52:10 -0400 Subject: [PATCH 30/36] Optimize server thread aliveness check --- .../mixin/bugfix/chunk_deadlock/ServerChunkCacheMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/chunk_deadlock/ServerChunkCacheMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/chunk_deadlock/ServerChunkCacheMixin.java index 682577bd..baf84759 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/chunk_deadlock/ServerChunkCacheMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/chunk_deadlock/ServerChunkCacheMixin.java @@ -29,7 +29,7 @@ public abstract class ServerChunkCacheMixin { @Inject(method = "getChunk", at = @At("HEAD"), cancellable = true) private void bailIfServerDead(int chunkX, int chunkZ, ChunkStatus requiredStatus, boolean load, CallbackInfoReturnable cir) { - if(!this.mainThread.isAlive()) { + if(!this.level.getServer().isRunning() && !this.mainThread.isAlive()) { ModernFix.LOGGER.fatal("A mod is accessing chunks from a stopped server (this will also cause memory leaks)"); if(debugDeadServerAccess) { new Exception().printStackTrace(); From bcb33a1018a7c58056d5fc91add49c9838b948e6 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 10 May 2023 09:54:14 -0400 Subject: [PATCH 31/36] Shorten structure hashes to fix issues on Windows --- .../structure/CachingStructureManager.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/structure/CachingStructureManager.java b/common/src/main/java/org/embeddedt/modernfix/structure/CachingStructureManager.java index b5ed3b88..365fb4d7 100644 --- a/common/src/main/java/org/embeddedt/modernfix/structure/CachingStructureManager.java +++ b/common/src/main/java/org/embeddedt/modernfix/structure/CachingStructureManager.java @@ -49,6 +49,12 @@ public class CachingStructureManager { private static final Set laggyStructureMods = new ObjectOpenHashSet<>(); + private static final int MAX_HASH_LENGTH = 9; + + private static String truncateHash(String hash) { + return hash.substring(0, MAX_HASH_LENGTH + 1); + } + public static CompoundTag readStructureTag(ResourceLocation location, DataFixer datafixer, InputStream stream) throws IOException { byte[] structureBytes = toBytes(stream); CompoundTag currentTag = NbtIo.readCompressed(new ByteArrayInputStream(structureBytes)); @@ -57,20 +63,22 @@ public class CachingStructureManager { } int currentDataVersion = currentTag.getInt("DataVersion"); if(currentDataVersion < SharedConstants.getCurrentVersion().getWorldVersion()) { - synchronized (laggyStructureMods) { - if(laggyStructureMods.add(location.getNamespace())) { - ModernFix.LOGGER.warn("Mod {} is shipping outdated structure files, which can cause worldgen lag; please report this to them.", location.getNamespace()); - } - } /* Needs upgrade, try looking up from cache */ MessageDigest hasher = digestThreadLocal.get(); hasher.reset(); String hash = encodeHex(hasher.digest(structureBytes)); - CompoundTag cachedUpgraded = getCachedUpgraded(location, hash); + CompoundTag cachedUpgraded = getCachedUpgraded(location, truncateHash(hash)); + if(cachedUpgraded == null) + cachedUpgraded = getCachedUpgraded(location, hash); /* pick up old cache */ if(cachedUpgraded != null && cachedUpgraded.getInt("DataVersion") == SharedConstants.getCurrentVersion().getWorldVersion()) { ModernFix.LOGGER.debug("Using cached upgraded version of {}", location); currentTag = cachedUpgraded; } else { + synchronized (laggyStructureMods) { + if(laggyStructureMods.add(location.getNamespace())) { + ModernFix.LOGGER.warn("Mod {} is shipping outdated structure files, which can cause worldgen lag; please report this to them.", location.getNamespace()); + } + } ModernFix.LOGGER.debug("Structure {} is being run through DFU (hash {}), this will cause launch time delays", location, hash); currentTag = NbtUtils.update(datafixer, DataFixTypes.STRUCTURE, currentTag, currentDataVersion, SharedConstants.getCurrentVersion().getWorldVersion()); @@ -99,7 +107,7 @@ public class CachingStructureManager { } private static synchronized void saveCachedUpgraded(ResourceLocation location, String hash, CompoundTag tagToSave) { - File theFile = getCachePath(location, hash); + File theFile = getCachePath(location, truncateHash(hash)); try { NbtIo.writeCompressed(tagToSave, theFile); } catch(IOException e) { From 1f16fc020406ff3234e38ff80ffa4a0f51cd33dd Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 10 May 2023 11:42:16 -0400 Subject: [PATCH 32/36] Move iteration later in texture atlas patch --- .../faster_texture_loading/TextureAtlasMixin.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_texture_loading/TextureAtlasMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_texture_loading/TextureAtlasMixin.java index b605365b..e32640ad 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_texture_loading/TextureAtlasMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_texture_loading/TextureAtlasMixin.java @@ -42,10 +42,13 @@ public abstract class TextureAtlasMixin { @Inject(method = "getBasicSpriteInfos", at = @At("HEAD")) private void loadImages(ResourceManager manager, Set imageLocations, CallbackInfoReturnable> cir) { usingFasterLoad = ModernFixPlatformHooks.isLoadingNormally(); + } + + @Redirect(method = "getBasicSpriteInfos", at = @At(value = "INVOKE", target = "Ljava/util/Set;iterator()Ljava/util/Iterator;", ordinal = 0)) + private Iterator skipIteration(Set instance, ResourceManager manager, Set imageLocations) { // bail if Forge is erroring to avoid AT crashes - if(!usingFasterLoad) { - return; - } + if(!usingFasterLoad) + return instance.iterator(); List> futures = new ArrayList<>(); ConcurrentLinkedQueue results = new ConcurrentLinkedQueue<>(); for(ResourceLocation location : imageLocations) { @@ -72,11 +75,7 @@ public abstract class TextureAtlasMixin { } CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); storedResults = results; - } - - @Redirect(method = "getBasicSpriteInfos", at = @At(value = "INVOKE", target = "Ljava/util/Set;iterator()Ljava/util/Iterator;", ordinal = 0)) - private Iterator skipIteration(Set instance) { - return usingFasterLoad ? Collections.emptyIterator() : instance.iterator(); + return Collections.emptyIterator(); } @Inject(method = "getBasicSpriteInfos", at = @At("RETURN")) From b5c08b996f335ebbe5b1bff58a811f8579fbda5d Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 10 May 2023 15:29:46 -0400 Subject: [PATCH 33/36] Add button to title screen for datagenning inside runClient --- .../main/resources/modernfix.accesswidener | 3 +- .../forge/datagen/RuntimeDatagen.java | 78 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 forge/src/main/java/org/embeddedt/modernfix/forge/datagen/RuntimeDatagen.java diff --git a/common/src/main/resources/modernfix.accesswidener b/common/src/main/resources/modernfix.accesswidener index bf157c09..4f571127 100644 --- a/common/src/main/resources/modernfix.accesswidener +++ b/common/src/main/resources/modernfix.accesswidener @@ -37,4 +37,5 @@ accessible method net/minecraft/resources/ResourceKey (Lnet/minecraft/res accessible method net/minecraft/client/renderer/texture/TextureAtlasSprite (Lnet/minecraft/client/renderer/texture/TextureAtlas;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite$Info;IIIIILcom/mojang/blaze3d/platform/NativeImage;)V accessible field net/minecraft/client/renderer/block/model/BlockModel GSON Lcom/google/gson/Gson; accessible field net/minecraft/server/MinecraftServer resources Lnet/minecraft/server/ServerResources; -accessible field net/minecraft/client/renderer/RenderStateShard name Ljava/lang/String; \ No newline at end of file +accessible field net/minecraft/client/renderer/RenderStateShard name Ljava/lang/String; +accessible method net/minecraft/client/gui/screens/Screen addButton (Lnet/minecraft/client/gui/components/AbstractWidget;)Lnet/minecraft/client/gui/components/AbstractWidget; \ No newline at end of file diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/datagen/RuntimeDatagen.java b/forge/src/main/java/org/embeddedt/modernfix/forge/datagen/RuntimeDatagen.java new file mode 100644 index 00000000..b3ea5c59 --- /dev/null +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/datagen/RuntimeDatagen.java @@ -0,0 +1,78 @@ +package org.embeddedt.modernfix.forge.datagen; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.screens.TitleScreen; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.server.packs.resources.SimpleReloadableResourceManager; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.DatagenModLoader; +import net.minecraftforge.fml.ModLoader; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraftforge.fml.event.lifecycle.GatherDataEvent; +import org.embeddedt.modernfix.ModernFix; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +@Mod.EventBusSubscriber(value = Dist.CLIENT) +public class RuntimeDatagen { + private static final String RESOURCES_OUT_DIR = getPropertyOrBlank("modernfix.datagen.output"); + private static final String RESOURCES_IN_DIR = getPropertyOrBlank("modernfix.datagen.existing"); + private static final String MODS_LIST = getPropertyOrBlank("modernfix.datagen.mods"); + private static final String EXISTING_MODS_LIST = getPropertyOrBlank("modernfix.datagen.existing_mods"); + private static final boolean IS_FLAT = Boolean.getBoolean("modernfix.datagen.flat"); + + private static String getPropertyOrBlank(String name) { + String val = System.getProperty(name); + if(val == null || val.length() == 0) + return ""; + else + return val; + } + + public static boolean isDatagenAvailable() { + return RESOURCES_OUT_DIR.length() > 0; + } + + public static void runRuntimeDatagen() { + ObfuscationReflectionHelper.setPrivateValue(DatagenModLoader.class, null, true, "runningDataGen"); + Set mods = new HashSet<>(Arrays.stream(MODS_LIST.split(",")).collect(Collectors.toSet())); + ModernFix.LOGGER.info("Beginning runtime datagen for " + mods.size() + " mods..."); + Set existingMods = new HashSet<>(Arrays.stream(EXISTING_MODS_LIST.split(",")).collect(Collectors.toSet())); + Set existingPacks = new HashSet<>(Arrays.stream(RESOURCES_IN_DIR.split(",")).map(Paths::get).collect(Collectors.toSet())); + Path path = Paths.get(RESOURCES_OUT_DIR); + GatherDataEvent.DataGeneratorConfig dataGeneratorConfig = new GatherDataEvent.DataGeneratorConfig(mods, path, Collections.emptyList(), + true, true, true, true, true, mods.isEmpty() || IS_FLAT); + if (!mods.contains("forge")) { + //If we aren't generating data for forge, automatically add forge as an existing so mods can access forge's data + existingMods.add("forge"); + } + ExistingFileHelper existingFileHelper = new ExistingFileHelper(existingPacks, existingMods, true, null, null); + /* Inject the client pack resources from us */ + ((SimpleReloadableResourceManager)ObfuscationReflectionHelper.getPrivateValue(ExistingFileHelper.class, existingFileHelper, "clientResources")).add(Minecraft.getInstance().getClientPackSource().getVanillaPack()); + ModLoader.get().runEventGenerator(mc->new GatherDataEvent(mc, dataGeneratorConfig.makeGenerator(p->dataGeneratorConfig.isFlat() ? p : p.resolve(mc.getModId()), dataGeneratorConfig.getMods().contains(mc.getModId())), dataGeneratorConfig, existingFileHelper)); + dataGeneratorConfig.runAll(); + ObfuscationReflectionHelper.setPrivateValue(DatagenModLoader.class, null, false, "runningDataGen"); + ModernFix.LOGGER.info("Finished runtime datagen."); + } + + @SubscribeEvent + public static void onInitTitleScreen(GuiScreenEvent.InitGuiEvent.Post event) { + if(isDatagenAvailable() && event.getGui() instanceof TitleScreen) { + TitleScreen screen = (TitleScreen)event.getGui(); + screen.addButton(new Button(screen.width / 2 - 100 - 50, screen.height / 4 + 48, 50, 20, new TextComponent("DG"), (arg) -> { + runRuntimeDatagen(); + })); + } + } +} From 74dae9316efb7932a0e2941df12f22a3c479b77b Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 10 May 2023 15:41:38 -0400 Subject: [PATCH 34/36] Update patch for 1.19 --- .../embeddedt/modernfix/forge/datagen/RuntimeDatagen.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/datagen/RuntimeDatagen.java b/forge/src/main/java/org/embeddedt/modernfix/forge/datagen/RuntimeDatagen.java index d2e32a28..a13036f2 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/datagen/RuntimeDatagen.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/datagen/RuntimeDatagen.java @@ -3,19 +3,19 @@ package org.embeddedt.modernfix.forge.datagen; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.screens.TitleScreen; -import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.Component; import net.minecraft.server.packs.PackResources; import net.minecraft.server.packs.PackType; import net.minecraft.server.packs.resources.MultiPackResourceManager; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.ScreenEvent; import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.data.event.GatherDataEvent; import net.minecraftforge.data.loading.DatagenModLoader; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.ModLoader; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.util.ObfuscationReflectionHelper; -import net.minecraftforge.forge.event.lifecycle.GatherDataEvent; import org.embeddedt.modernfix.ModernFix; import java.nio.file.Path; @@ -69,10 +69,10 @@ public class RuntimeDatagen { } @SubscribeEvent - public static void onInitTitleScreen(ScreenEvent.InitScreenEvent.Post event) { + public static void onInitTitleScreen(ScreenEvent.Init.Post event) { if(isDatagenAvailable() && event.getScreen() instanceof TitleScreen) { TitleScreen screen = (TitleScreen)event.getScreen(); - screen.addRenderableWidget(new Button(screen.width / 2 - 100 - 50, screen.height / 4 + 48, 50, 20, new TextComponent("DG"), (arg) -> { + screen.addRenderableWidget(new Button(screen.width / 2 - 100 - 50, screen.height / 4 + 48, 50, 20, Component.literal("DG"), (arg) -> { runRuntimeDatagen(); })); } From d97da8fe4c9999ac6dcd308d7ca4fb4bd0bae8d0 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 10 May 2023 17:02:15 -0400 Subject: [PATCH 35/36] Fix resource pack cache not invalidating on F3+T --- .../ReloadableResourceManagerMixin.java | 28 +++++++++++++++++++ .../resources/ICachingResourcePack.java | 5 ++++ .../ModNioResourcePackMixin.java | 11 ++++++-- .../ModFileResourcePackMixin.java | 10 ++++++- 4 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/resourcepacks/ReloadableResourceManagerMixin.java create mode 100644 common/src/main/java/org/embeddedt/modernfix/resources/ICachingResourcePack.java rename fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/{fabric_resourcepacks => resourcepacks}/ModNioResourcePackMixin.java (88%) diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/resourcepacks/ReloadableResourceManagerMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/resourcepacks/ReloadableResourceManagerMixin.java new file mode 100644 index 00000000..9250fcbc --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/resourcepacks/ReloadableResourceManagerMixin.java @@ -0,0 +1,28 @@ +package org.embeddedt.modernfix.common.mixin.perf.resourcepacks; + +import net.minecraft.server.packs.PackResources; +import net.minecraft.server.packs.resources.SimpleReloadableResourceManager; +import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.resources.ICachingResourcePack; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.List; + +@Mixin(SimpleReloadableResourceManager.class) +public class ReloadableResourceManagerMixin { + @Shadow @Final private List packs; + + @Inject(method = "createReload", at = @At("HEAD")) + private void invalidateResourceCaches(CallbackInfoReturnable cir) { + ModernFix.LOGGER.info("Invalidating pack caches"); + for(PackResources pack : this.packs) { + if(pack instanceof ICachingResourcePack) + ((ICachingResourcePack)pack).invalidateCache(); + } + } +} diff --git a/common/src/main/java/org/embeddedt/modernfix/resources/ICachingResourcePack.java b/common/src/main/java/org/embeddedt/modernfix/resources/ICachingResourcePack.java new file mode 100644 index 00000000..a9e42bde --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/resources/ICachingResourcePack.java @@ -0,0 +1,5 @@ +package org.embeddedt.modernfix.resources; + +public interface ICachingResourcePack { + void invalidateCache(); +} diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/fabric_resourcepacks/ModNioResourcePackMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/resourcepacks/ModNioResourcePackMixin.java similarity index 88% rename from fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/fabric_resourcepacks/ModNioResourcePackMixin.java rename to fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/resourcepacks/ModNioResourcePackMixin.java index 1ff34cd7..c839cdd6 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/fabric_resourcepacks/ModNioResourcePackMixin.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/resourcepacks/ModNioResourcePackMixin.java @@ -1,8 +1,9 @@ -package org.embeddedt.modernfix.fabric.mixin.perf.fabric_resourcepacks; +package org.embeddedt.modernfix.fabric.mixin.perf.resourcepacks; import net.fabricmc.fabric.impl.resource.loader.ModNioResourcePack; import net.minecraft.server.packs.PackType; import org.embeddedt.modernfix.annotation.RequiresMod; +import org.embeddedt.modernfix.resources.ICachingResourcePack; import org.embeddedt.modernfix.resources.PackResourcesCacheEngine; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -19,7 +20,7 @@ import java.util.Set; @Mixin(ModNioResourcePack.class) @RequiresMod("fabric-resource-loader-v0") -public abstract class ModNioResourcePackMixin { +public abstract class ModNioResourcePackMixin implements ICachingResourcePack { @Shadow public abstract Set getNamespaces(PackType type); @Shadow @Final private Path basePath; @@ -27,6 +28,12 @@ public abstract class ModNioResourcePackMixin { @Inject(method = "", at = @At("RETURN")) private void cacheResources(CallbackInfo ci) { + invalidateCache(); + } + + @Override + public void invalidateCache() { + this.cacheEngine = null; this.cacheEngine = new PackResourcesCacheEngine(this::getNamespaces, (type, namespace) -> { return basePath.resolve(type.getDirectory()).resolve(namespace); }); diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/resourcepacks/ModFileResourcePackMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/resourcepacks/ModFileResourcePackMixin.java index d8cc1e46..8f7bf461 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/resourcepacks/ModFileResourcePackMixin.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/resourcepacks/ModFileResourcePackMixin.java @@ -5,6 +5,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.ResourcePackFileNotFoundException; import net.minecraftforge.fml.loading.moddiscovery.ModFile; import net.minecraftforge.fml.packs.ModFileResourcePack; +import org.embeddedt.modernfix.resources.ICachingResourcePack; import org.embeddedt.modernfix.resources.PackResourcesCacheEngine; import org.embeddedt.modernfix.util.PackTypeHelper; import org.spongepowered.asm.mixin.Final; @@ -23,7 +24,7 @@ import java.util.*; import java.util.function.Predicate; @Mixin(ModFileResourcePack.class) -public abstract class ModFileResourcePackMixin { +public abstract class ModFileResourcePackMixin implements ICachingResourcePack { @Shadow public abstract Set getNamespaces(PackType type); @Shadow(remap = false) @Final private ModFile modFile; @@ -32,10 +33,17 @@ public abstract class ModFileResourcePackMixin { @Inject(method = "", at = @At("TAIL")) private void cacheResources(ModFile modFile, CallbackInfo ci) { + invalidateCache(); + } + + @Override + public void invalidateCache() { + this.cacheEngine = null; this.cacheEngine = new PackResourcesCacheEngine(this::getNamespaces, (type, namespace) -> { return modFile.getLocator().findPath(modFile, type.getDirectory(), namespace); }); } + @Inject(method = "getNamespaces", at = @At("HEAD"), cancellable = true) private void useCacheForNamespaces(PackType type, CallbackInfoReturnable> cir) { if(cacheEngine != null) { From d427c5e05005b9ac1ce5453203fb9d591de44e44 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 10 May 2023 18:12:32 -0400 Subject: [PATCH 36/36] Invalidate pack caches directly instead of iterating resource manager pack list --- .../ReloadableResourceManagerMixin.java | 14 ++------------ .../resources/PackResourcesCacheEngine.java | 16 ++++++++++++++++ .../resourcepacks/ModNioResourcePackMixin.java | 1 + .../resourcepacks/ModFileResourcePackMixin.java | 1 + 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/resourcepacks/ReloadableResourceManagerMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/resourcepacks/ReloadableResourceManagerMixin.java index 9250fcbc..04fb2d8a 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/resourcepacks/ReloadableResourceManagerMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/resourcepacks/ReloadableResourceManagerMixin.java @@ -1,28 +1,18 @@ package org.embeddedt.modernfix.common.mixin.perf.resourcepacks; -import net.minecraft.server.packs.PackResources; import net.minecraft.server.packs.resources.SimpleReloadableResourceManager; import org.embeddedt.modernfix.ModernFix; -import org.embeddedt.modernfix.resources.ICachingResourcePack; -import org.spongepowered.asm.mixin.Final; +import org.embeddedt.modernfix.resources.PackResourcesCacheEngine; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import java.util.List; - @Mixin(SimpleReloadableResourceManager.class) public class ReloadableResourceManagerMixin { - @Shadow @Final private List packs; - @Inject(method = "createReload", at = @At("HEAD")) private void invalidateResourceCaches(CallbackInfoReturnable cir) { ModernFix.LOGGER.info("Invalidating pack caches"); - for(PackResources pack : this.packs) { - if(pack instanceof ICachingResourcePack) - ((ICachingResourcePack)pack).invalidateCache(); - } + PackResourcesCacheEngine.invalidate(); } } diff --git a/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java b/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java index a8333fa3..8c592cdf 100644 --- a/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java +++ b/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java @@ -154,4 +154,20 @@ public class PackResourcesCacheEngine { } return resources; } + + private static final WeakHashMap cachingPacks = new WeakHashMap<>(); + public static void track(ICachingResourcePack pack) { + synchronized (cachingPacks) { + cachingPacks.put(pack, Boolean.TRUE); + } + } + + public static void invalidate() { + synchronized (cachingPacks) { + cachingPacks.keySet().forEach(pack -> { + if(pack != null) + pack.invalidateCache(); + }); + } + } } diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/resourcepacks/ModNioResourcePackMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/resourcepacks/ModNioResourcePackMixin.java index c839cdd6..89d0681e 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/resourcepacks/ModNioResourcePackMixin.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/resourcepacks/ModNioResourcePackMixin.java @@ -29,6 +29,7 @@ public abstract class ModNioResourcePackMixin implements ICachingResourcePack { @Inject(method = "", at = @At("RETURN")) private void cacheResources(CallbackInfo ci) { invalidateCache(); + PackResourcesCacheEngine.track(this); } @Override diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/resourcepacks/ModFileResourcePackMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/resourcepacks/ModFileResourcePackMixin.java index 8f7bf461..55173bc5 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/resourcepacks/ModFileResourcePackMixin.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/resourcepacks/ModFileResourcePackMixin.java @@ -34,6 +34,7 @@ public abstract class ModFileResourcePackMixin implements ICachingResourcePack { @Inject(method = "", at = @At("TAIL")) private void cacheResources(ModFile modFile, CallbackInfo ci) { invalidateCache(); + PackResourcesCacheEngine.track(this); } @Override