From a80c2ddd1731418bc710543ff999e6f5986267b2 Mon Sep 17 00:00:00 2001 From: samarthdhiman2005 Date: Sun, 3 May 2026 20:49:43 +0530 Subject: [PATCH 1/5] 5.27.7 - commit.1 - Perform config cleanup. - Fix and close https://github.com/coredex-source/ModernFix---mVUS/issues/33 --- gradle.properties | 2 +- .../core/config/ModernFixEarlyConfig.java | 16 +--------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/gradle.properties b/gradle.properties index f8c8a510c..888022a45 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ org.gradle.jvmargs=-Xmx2G # Mod properties mod_id=modernfix -version=5.27.5-build.2 +version=5.27.7-build.1 # Minecraft/Fabric minecraft_version=26.1.2 diff --git a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index 983c85347..df00865ba 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -186,28 +186,19 @@ public DefaultSettingMapBuilder put(String key, Boolean value) { .put("mixin.feature.blockentity_incorrect_thread", false) .put("mixin.perf.clear_mixin_classinfo", false) .put("mixin.perf.deduplicate_climate_parameters", 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.faster_item_rendering", false) .put("mixin.feature.spam_thread_dump", false) .put("mixin.feature.remove_chat_signing", false) - .put("mixin.bugfix.skip_redundant_saves", false) .put("mixin.feature.snapshot_easter_egg", true) - .put("mixin.feature.warn_missing_perf_mods", true) .put("mixin.feature.spark_profile_launch", false) .put("mixin.feature.spark_profile_world_join", false) - .put("mixin.feature.log_stdout_in_log_files", true) .put("mixin.devenv", isDevEnv) - .putConditionally(() -> !isFabric, "mixin.bugfix.fix_config_crashes", true) - .putConditionally(() -> !isFabric, "mixin.feature.registry_event_progress", true) - .putConditionally(() -> isFabric, "mixin.perf.clear_fabric_mapping_tables", false) // Beta (promote on next release) .put("mixin.perf.compact_entity_models", false) .put("mixin.perf.dynamic_languages", false) - .put("mixin.perf.faster_capabilities.bytecode_analysis", false) - .put("mixin.perf.ingredient_item_deduplication", false) // END .build(); @@ -234,7 +225,6 @@ private ModernFixEarlyConfig(File file) { } // Defines the default rules which can be configured by the user or other mods. // You must manually add a rule for any new mixins not covered by an existing package rule. - this.addMixinRule("launch.class_search_cache", true); /* Mod compat */ disableIfModPresent("mixin.perf.thread_priorities", "smoothboot", "threadtweak"); @@ -252,8 +242,7 @@ private ModernFixEarlyConfig(File file) { disableIfModPresent("mixin.bugfix.item_cache_flag", "lithium", "canary", "radium"); // DimThread makes changes to the server chunk manager (understandably), C2ME probably does the same disableIfModPresent("mixin.bugfix.chunk_deadlock", "c2me", "dimthread"); - disableIfModPresent("mixin.perf.release_protochunks", "c2me"); - disableIfModPresent("mixin.launch.class_search_cache", "optifine"); + disableIfModPresent("mixin.perf.release_protochunks", "c2me", "moonrise"); disableIfModPresent("mixin.perf.faster_texture_stitching", "optifine"); disableIfModPresent("mixin.bugfix.entity_pose_stack", "optifine"); disableIfModPresent("mixin.perf.datapack_reload_exceptions", "cyanide"); @@ -262,9 +251,6 @@ private ModernFixEarlyConfig(File file) { disableIfModPresent("mixin.perf.faster_texture_loading", "stitch", "optifine", "changed"); disableIfModPresent("mixin.perf.faster_ingredients", "vmp"); disableIfModPresent("mixin.perf.smart_ingredient_sync", "crafttweaker"); - if(isFabric) { - disableIfModPresent("mixin.bugfix.packet_leak", "memoryleakfix"); - } checkBlockstateCacheRebuilds(); checkModelDataManager(); From 039f2b04702fa05dac2cf35838eb887715fdb03f Mon Sep 17 00:00:00 2001 From: coredex-source Date: Sun, 3 May 2026 21:01:25 +0530 Subject: [PATCH 2/5] Revert "Merge branch 'fabric/26.2' into fabric/26.1" This reverts commit 286243649370ddfb3dc94a0a5d629988883b02bc, reversing changes made to a80c2ddd1731418bc710543ff999e6f5986267b2. --- gradle.properties | 12 ++--- .../WorldSelectionListMixin.java | 2 +- .../feature/measure_time/MinecraftMixin.java | 8 ++-- .../SurfaceRulesContextMixin.java | 46 +++---------------- .../dynresources/DynamicModelSystem.java | 6 +-- .../screen/ModernFixConfigScreen.java | 2 +- .../screen/ModernFixOptionInfoScreen.java | 2 +- .../modernfix/screen/OptionList.java | 4 +- 8 files changed, 24 insertions(+), 58 deletions(-) diff --git a/gradle.properties b/gradle.properties index 79c6eb6fc..888022a45 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,22 +4,22 @@ org.gradle.jvmargs=-Xmx2G # Mod properties mod_id=modernfix -version=5.27.5-build.3 +version=5.27.7-build.1 # Minecraft/Fabric -minecraft_version=26.2-snapshot-5 -loader_version=0.19.2 +minecraft_version=26.1.2 +loader_version=0.18.6 loom_version=1.16-SNAPSHOT # Fabric API -fabric_api_version=0.147.1+26.2 +fabric_api_version=0.145.4+26.1.2 # Dependencies mixinextras_version=0.4.1 -modmenu_version=18.0.0-alpha.8 +modmenu_version=18.0.0-alpha.5 # For mod sites -supported_minecraft_versions=~26.2- +supported_minecraft_versions=~26.1- # Build shadow_version=8.1.1 diff --git a/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/world_screen_skipped/WorldSelectionListMixin.java b/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/world_screen_skipped/WorldSelectionListMixin.java index 2f67c46ef..7d816acd2 100644 --- a/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/world_screen_skipped/WorldSelectionListMixin.java +++ b/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/world_screen_skipped/WorldSelectionListMixin.java @@ -18,7 +18,7 @@ public class WorldSelectionListMixin { @Inject(method = "*", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/worldselection/WorldSelectionList$WorldListEntry;doDeleteWorld()V", ordinal = 0, shift = At.Shift.AFTER), cancellable = true) private void preventClosingCreateScreenAfterDelete(CallbackInfo ci) { - if(minecraft.gui.screen() instanceof CreateWorldScreen) + if(minecraft.screen instanceof CreateWorldScreen) ci.cancel(); } } diff --git a/src/main/java/org/embeddedt/modernfix/common/mixin/feature/measure_time/MinecraftMixin.java b/src/main/java/org/embeddedt/modernfix/common/mixin/feature/measure_time/MinecraftMixin.java index f5b5f8514..53c3b8466 100644 --- a/src/main/java/org/embeddedt/modernfix/common/mixin/feature/measure_time/MinecraftMixin.java +++ b/src/main/java/org/embeddedt/modernfix/common/mixin/feature/measure_time/MinecraftMixin.java @@ -1,10 +1,10 @@ package org.embeddedt.modernfix.common.mixin.feature.measure_time; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.screens.Overlay; import org.embeddedt.modernfix.ModernFixClient; import org.embeddedt.modernfix.annotation.ClientOnlyMixin; -import org.spongepowered.asm.mixin.Final; +import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -16,11 +16,11 @@ @ClientOnlyMixin public class MinecraftMixin { // TODO re-add datapack reload time measurement - @Shadow @Final public Gui gui; + @Shadow @Nullable public Overlay overlay; @Inject(method = "tick", at = @At("HEAD")) private void onClientTick(CallbackInfo ci) { - if(this.gui.overlay() == null && ModernFixClient.INSTANCE != null) { + if(this.overlay == null && ModernFixClient.INSTANCE != null) { ModernFixClient.INSTANCE.onGameLaunchFinish(); } } diff --git a/src/main/java/org/embeddedt/modernfix/common/mixin/perf/worldgen_allocation/SurfaceRulesContextMixin.java b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/worldgen_allocation/SurfaceRulesContextMixin.java index 2a18c710b..c2be9c3df 100644 --- a/src/main/java/org/embeddedt/modernfix/common/mixin/perf/worldgen_allocation/SurfaceRulesContextMixin.java +++ b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/worldgen_allocation/SurfaceRulesContextMixin.java @@ -8,20 +8,14 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; import java.util.function.Function; - -// Update the file when embeddedt patches this file for 26.2 in the neoforge version to keep it conisitent with the upstream changes. +import java.util.function.Supplier; @Mixin(targets = {"net/minecraft/world/level/levelgen/SurfaceRules$Context"}, priority = 100) public class SurfaceRulesContextMixin { @Shadow private long lastUpdateY; - @Shadow private int blockX; - - @Shadow private int blockZ; - @Shadow private int blockY; @Shadow private int waterHeight; @@ -30,53 +24,27 @@ public class SurfaceRulesContextMixin { @Shadow private int stoneDepthAbove; - @Shadow private Holder biome; + @Shadow private Supplier> biome; @Shadow @Final private Function> biomeGetter; @Shadow @Final private BlockPos.MutableBlockPos pos; - @Unique - private PositionalBiomeGetter modernfix$biomeCache; - /** * @author embeddedt - * @reason Keep a reusable biome cache helper instead of rebuilding intermediate state + * @reason Reuse supplier object instead of creating new ones every time */ @Overwrite - protected void updateY(int stoneDepthAbove, int stoneDepthBelow, int waterHeight, int blockY) { + public void updateY(int stoneDepthAbove, int stoneDepthBelow, int waterHeight, int blockX, int blockY, int blockZ) { ++this.lastUpdateY; - - var getter = this.modernfix$biomeCache; + var getter = this.biome; if(getter == null) { - this.modernfix$biomeCache = getter = new PositionalBiomeGetter(this.biomeGetter, this.pos); + this.biome = getter = new PositionalBiomeGetter(this.biomeGetter, this.pos); } - - getter.update(this.blockX, blockY, this.blockZ); - this.biome = null; + ((PositionalBiomeGetter)getter).update(blockX, blockY, blockZ); this.blockY = blockY; this.waterHeight = waterHeight; this.stoneDepthBelow = stoneDepthBelow; this.stoneDepthAbove = stoneDepthAbove; } - - /** - * @author coredex - * @reason Reuse a single positional getter object for biome lookups - */ - @Overwrite - protected Holder getBiome() { - var biome = this.biome; - if(biome == null) { - var getter = this.modernfix$biomeCache; - if(getter == null) { - this.modernfix$biomeCache = getter = new PositionalBiomeGetter(this.biomeGetter, this.pos); - } - - getter.update(this.blockX, this.blockY, this.blockZ); - this.biome = biome = getter.get(); - } - - return biome; - } } diff --git a/src/main/java/org/embeddedt/modernfix/dynresources/DynamicModelSystem.java b/src/main/java/org/embeddedt/modernfix/dynresources/DynamicModelSystem.java index a21c9f422..2f45c8863 100644 --- a/src/main/java/org/embeddedt/modernfix/dynresources/DynamicModelSystem.java +++ b/src/main/java/org/embeddedt/modernfix/dynresources/DynamicModelSystem.java @@ -11,11 +11,10 @@ import it.unimi.dsi.fastutil.objects.ObjectSet; import it.unimi.dsi.fastutil.objects.ObjectSets; import it.unimi.dsi.fastutil.objects.ReferenceSets; -// import net.fabricmc.fabric.impl.client.model.loading.UnbakedModelDeserializerRegistry; // Disabled by FRAPI +import net.fabricmc.fabric.impl.client.model.loading.UnbakedModelDeserializerRegistry; import net.minecraft.client.color.block.BlockColors; import net.minecraft.client.renderer.item.ClientItem; import net.minecraft.client.renderer.block.dispatch.BlockStateModel; -import net.minecraft.client.resources.model.cuboid.CuboidModel; import net.minecraft.client.resources.model.cuboid.ItemModelGenerator; import net.minecraft.client.resources.model.BlockStateModelLoader; import net.minecraft.client.resources.model.ClientItemInfoLoader; @@ -65,8 +64,7 @@ public UnbakedModel load(Identifier key) throws Exception { ModernFix.LOGGER.info("Loading unbaked model {}", key); } try (Reader reader = resource.openAsReader()) { - // return UnbakedModelDeserializerRegistry.deserialize(reader); // Disabled by FRAPI - return CuboidModel.fromStream(reader); + return UnbakedModelDeserializerRegistry.deserialize(reader); } } }); diff --git a/src/main/java/org/embeddedt/modernfix/screen/ModernFixConfigScreen.java b/src/main/java/org/embeddedt/modernfix/screen/ModernFixConfigScreen.java index 99fa1a7c0..f5b1cd6ef 100644 --- a/src/main/java/org/embeddedt/modernfix/screen/ModernFixConfigScreen.java +++ b/src/main/java/org/embeddedt/modernfix/screen/ModernFixConfigScreen.java @@ -37,7 +37,7 @@ protected void init() { @Override public void onClose() { - this.minecraft.gui.setScreen(lastScreen); + this.minecraft.setScreen(lastScreen); } @Override diff --git a/src/main/java/org/embeddedt/modernfix/screen/ModernFixOptionInfoScreen.java b/src/main/java/org/embeddedt/modernfix/screen/ModernFixOptionInfoScreen.java index 7cf37899c..262cb1a47 100644 --- a/src/main/java/org/embeddedt/modernfix/screen/ModernFixOptionInfoScreen.java +++ b/src/main/java/org/embeddedt/modernfix/screen/ModernFixOptionInfoScreen.java @@ -35,7 +35,7 @@ protected void init() { @Override public void onClose() { - this.minecraft.gui.setScreen(lastScreen); + this.minecraft.setScreen(lastScreen); } private void drawMultilineString(GuiGraphicsExtractor guiGraphics, Font fr, Component str, int x, int y) { diff --git a/src/main/java/org/embeddedt/modernfix/screen/OptionList.java b/src/main/java/org/embeddedt/modernfix/screen/OptionList.java index aef80223b..35bedaa0a 100644 --- a/src/main/java/org/embeddedt/modernfix/screen/OptionList.java +++ b/src/main/java/org/embeddedt/modernfix/screen/OptionList.java @@ -107,7 +107,7 @@ public CategoryEntry(Component component) { public void extractContent(GuiGraphicsExtractor guiGraphics, int mouseX, int mouseY, boolean isMouseOver, float partialTicks) { Font var10000 = OptionList.this.minecraft.font; - float x = (float)(OptionList.this.minecraft.gui.screen().width / 2 - this.width / 2); + float x = (float)(OptionList.this.minecraft.screen.width / 2 - this.width / 2); int y = getY() + getHeight() - 10; guiGraphics.text(var10000, this.name, (int)x, y, -1); /* @@ -164,7 +164,7 @@ public OptionEntry(String optionName, Option option) { updateStatus(); this.helpButton = new Button.Builder(Component.literal("?"), (arg) -> { mainScreen.setLastScrollAmount(scrollAmount()); - Minecraft.getInstance().gui.setScreen(new ModernFixOptionInfoScreen(mainScreen, optionName)); + Minecraft.getInstance().setScreen(new ModernFixOptionInfoScreen(mainScreen, optionName)); }).pos(75, 0).size(20, 20).build(); String helpKey = "modernfix.option." + optionName; String helpText = I18n.get(helpKey); From 512a4f7d0202826a0afd6cb066b4723a9b9fb315 Mon Sep 17 00:00:00 2001 From: Coredex <73810221+coredex-source@users.noreply.github.com> Date: Sun, 31 May 2026 20:22:23 +0530 Subject: [PATCH 3/5] Change Discord link in issue template --- .github/ISSUE_TEMPLATE/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 2354f98d6..9bc51b439 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,6 +1,6 @@ blank_issues_enabled: true contact_links: - name: For help with other issues, join our Discord community - url: https://discord.gg/rN9Y7caguP + url: https://discord.gg/qX7uy6eERC about: This is the best option for getting help with mod installation, performance issues, and any other support inquiries # Copied from https://github.com/CaffeineMC/sodium-fabric#community From b8c90d1d93771ea5b02158b0d76011753ecc9249 Mon Sep 17 00:00:00 2001 From: coredex-source Date: Wed, 17 Jun 2026 16:24:24 +0530 Subject: [PATCH 4/5] Upsteam updates - SurfaceRule optimizations are pending. - Fixes https://github.com/coredex-source/ModernFix---mVUS/issues/40 --- gradle.properties | 2 +- .../org/embeddedt/modernfix/ModernFix.java | 3 + .../AttributeSupplierMixin.java | 10 +- .../ClientLanguageMixin.java | 12 +- .../dynamic_resources/MixinModelManager.java | 2 + .../core/config/ModernFixEarlyConfig.java | 2 +- .../dynresources/BlockStateModelMap.java | 13 +- .../dynresources/DynamicModelSystem.java | 154 ++++++++++-------- .../dynresources/DynamicRegistryMap.java | 16 +- 9 files changed, 129 insertions(+), 85 deletions(-) diff --git a/gradle.properties b/gradle.properties index 888022a45..7e2bf9f1d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ org.gradle.jvmargs=-Xmx2G # Mod properties mod_id=modernfix -version=5.27.7-build.1 +version=5.27.17-build.1 # Minecraft/Fabric minecraft_version=26.1.2 diff --git a/src/main/java/org/embeddedt/modernfix/ModernFix.java b/src/main/java/org/embeddedt/modernfix/ModernFix.java index a1fdf9b6e..ae0bd8360 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFix.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFix.java @@ -15,6 +15,7 @@ import org.embeddedt.modernfix.util.ClassInfoManager; import org.spongepowered.asm.mixin.MixinEnvironment; +import net.minecraft.client.Minecraft; import java.lang.management.ManagementFactory; // The value here should match an entry in the META-INF/mods.toml file @@ -51,6 +52,8 @@ public static void runAuditIfRequested() { if (auditAndExit || Boolean.getBoolean("modernfix.auditMixinsAtStart")) { MixinEnvironment.getCurrentEnvironment().audit(); if (auditAndExit) { + // Prevents Crash Assistant from treating mixin audit as a crash + Minecraft.getInstance().stop(); System.exit(0); } } diff --git a/src/main/java/org/embeddedt/modernfix/common/mixin/perf/attribute_supplier_dedup/AttributeSupplierMixin.java b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/attribute_supplier_dedup/AttributeSupplierMixin.java index c214cba0e..d4d0901b5 100644 --- a/src/main/java/org/embeddedt/modernfix/common/mixin/perf/attribute_supplier_dedup/AttributeSupplierMixin.java +++ b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/attribute_supplier_dedup/AttributeSupplierMixin.java @@ -1,6 +1,6 @@ package org.embeddedt.modernfix.common.mixin.perf.attribute_supplier_dedup; -import net.minecraft.core.Holder; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.minecraft.world.entity.ai.attributes.Attribute; import net.minecraft.world.entity.ai.attributes.AttributeInstance; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; @@ -19,15 +19,15 @@ public class AttributeSupplierMixin { @Shadow @Final @Mutable - private Map, AttributeInstance> instances; + private Map instances; /** * @author embeddedt - * @reason Java 9's Map.of() implementation is significantly more compact than ImmutableMap, and we do not + * @reason more compact than ImmutableMap due to less wrapper objects, and we do not * care about insertion order in this context */ @Inject(method = "", at = @At("RETURN")) - private void useCompactJavaMap(Map, AttributeInstance> instances, CallbackInfo ci) { - this.instances = Map.copyOf(this.instances); + private void useCompactJavaMap(Map instances, CallbackInfo ci) { + this.instances = new Object2ObjectOpenHashMap<>(this.instances); } } \ No newline at end of file diff --git a/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_languages/ClientLanguageMixin.java b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_languages/ClientLanguageMixin.java index 0d62a7340..97332bc14 100644 --- a/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_languages/ClientLanguageMixin.java +++ b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_languages/ClientLanguageMixin.java @@ -28,9 +28,11 @@ public class ClientLanguageMixin { * @reason collect the list of all known language resources */ @WrapOperation(method = "loadFrom", at = @At(value = "INVOKE", - target = "Lnet/minecraft/client/resources/language/ClientLanguage;appendFrom(Ljava/lang/String;Ljava/util/List;Ljava/util/Map;)V")) + target = "Lnet/minecraft/client/resources/language/ClientLanguage;appendFrom(Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/util/Map;)V")) private static void collectResources(String languageName, List resources, - Map destinationMap, Operation original, + Map destinationMap, + Map componentMap, + Operation original, @Share("usedResources") LocalRef> usedResources) { List collected = usedResources.get(); if (collected == null) { @@ -38,16 +40,16 @@ private static void collectResources(String languageName, List resourc usedResources.set(collected); } collected.addAll(resources); - original.call(languageName, resources, destinationMap); + original.call(languageName, resources, destinationMap, componentMap); } /** * @author embeddedt * @reason figure out which keys are dynamically loaded and which are injected by mixins */ - @ModifyArg(method = "loadFrom", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/language/ClientLanguage;(Ljava/util/Map;Z)V"), index = 0) + @ModifyArg(method = "loadFrom", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/language/ClientLanguage;(Ljava/util/Map;ZLjava/util/Map;)V"), index = 0) private static Map modifyLanguageMap(Map storage, @Share("usedResources") LocalRef> usedResources) { List collected = Objects.requireNonNullElse(usedResources.get(), List.of()); return DynamicLanguageMap.forVanillaData(storage, collected); } -} +} \ No newline at end of file diff --git a/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/MixinModelManager.java b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/MixinModelManager.java index b44603d97..3d0bd20bb 100644 --- a/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/MixinModelManager.java +++ b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/MixinModelManager.java @@ -22,6 +22,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.util.Map; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.function.Function; @@ -67,6 +68,7 @@ private static Object2IntMap buildModelGroups(BlockColors blockColor @Overwrite private static Map createBlockStateToModelDispatch(Map blockStateModels, BlockStateModel missingModel) { BlockStateModelMap.resetCache(); + Objects.requireNonNull(missingModel); return new BlockStateModelMap(blockStateModels, missingModel); } } diff --git a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index df00865ba..b89a988ee 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -235,7 +235,7 @@ private ModernFixEarlyConfig(File file) { disableIfModPresent("mixin.bugfix.paper_chunk_patches", "c2me"); disableIfModPresent("mixin.bugfix.preserve_early_window_pos", "better_loading_screen"); disableIfModPresent("mixin.perf.dynamic_dfu", "litematica"); - disableIfModPresent("mixin.perf.cache_strongholds", "littletiles", "c2me"); + disableIfModPresent("mixin.perf.cache_strongholds", "littletiles", "c2me", "flashback"); // content overlap disableIfModPresent("mixin.perf.deduplicate_wall_shapes", "dashloader"); disableIfModPresent("mixin.perf.nbt_memory_usage", "c2me"); diff --git a/src/main/java/org/embeddedt/modernfix/dynresources/BlockStateModelMap.java b/src/main/java/org/embeddedt/modernfix/dynresources/BlockStateModelMap.java index 35398a0dd..5542f319f 100644 --- a/src/main/java/org/embeddedt/modernfix/dynresources/BlockStateModelMap.java +++ b/src/main/java/org/embeddedt/modernfix/dynresources/BlockStateModelMap.java @@ -9,6 +9,7 @@ import java.util.Collection; import java.util.Map; +import java.util.Objects; import java.util.Set; /** @@ -18,6 +19,10 @@ public record BlockStateModelMap(Map modelMap, BlockStateModel fallbackModel) implements Map { + public BlockStateModelMap { + Objects.requireNonNull(fallbackModel); + } + @Override public int size() { return Block.BLOCK_STATE_REGISTRY.size(); @@ -55,6 +60,12 @@ public BlockStateModel get(Object o) { } } + @Override + public BlockStateModel getOrDefault(Object key, BlockStateModel defaultValue) { + var value = get(key); + return value != fallbackModel ? value : defaultValue; + } + @Override public @Nullable BlockStateModel put(BlockState blockState, BlockStateModel blockStateModel) { var oldModel = modelMap.put(blockState, blockStateModel); @@ -102,4 +113,4 @@ public static void resetCache() { ((IModelHoldingBlockState) state).mfix$setModel(null); } } -} +} \ No newline at end of file diff --git a/src/main/java/org/embeddedt/modernfix/dynresources/DynamicModelSystem.java b/src/main/java/org/embeddedt/modernfix/dynresources/DynamicModelSystem.java index 2f45c8863..2bd14431c 100644 --- a/src/main/java/org/embeddedt/modernfix/dynresources/DynamicModelSystem.java +++ b/src/main/java/org/embeddedt/modernfix/dynresources/DynamicModelSystem.java @@ -4,27 +4,24 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.Maps; -import com.google.common.collect.Sets; import it.unimi.dsi.fastutil.objects.AbstractObject2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectSet; import it.unimi.dsi.fastutil.objects.ObjectSets; -import it.unimi.dsi.fastutil.objects.ReferenceSets; import net.fabricmc.fabric.impl.client.model.loading.UnbakedModelDeserializerRegistry; import net.minecraft.client.color.block.BlockColors; import net.minecraft.client.renderer.item.ClientItem; -import net.minecraft.client.renderer.block.dispatch.BlockStateModel; -import net.minecraft.client.resources.model.cuboid.ItemModelGenerator; import net.minecraft.client.resources.model.BlockStateModelLoader; import net.minecraft.client.resources.model.ClientItemInfoLoader; -import net.minecraft.client.resources.model.cuboid.MissingCuboidModel; import net.minecraft.client.resources.model.ModelDiscovery; import net.minecraft.client.resources.model.ModelManager; import net.minecraft.client.resources.model.ResolvedModel; import net.minecraft.client.resources.model.UnbakedModel; -import net.minecraft.resources.FileToIdConverter; +import net.minecraft.client.resources.model.cuboid.ItemModelGenerator; +import net.minecraft.client.resources.model.cuboid.MissingCuboidModel; import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.FileToIdConverter; import net.minecraft.resources.Identifier; import net.minecraft.server.packs.resources.Resource; import net.minecraft.world.level.block.Block; @@ -40,6 +37,8 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.function.BiFunction; import java.util.function.Function; @@ -51,46 +50,77 @@ public class DynamicModelSystem { private static final FileToIdConverter ITEM_LISTER = FileToIdConverter.json("items"); public static final boolean DEBUG_DYNAMIC_MODEL_LOADING = Boolean.getBoolean("modernfix.debugDynamicModelLoading"); - - public static Map createDynamicUnbakedModelMap(Map resourceMap) { - LoadingCache unbakedModelCache = CacheBuilder.newBuilder().softValues().maximumSize(1000).build(new CacheLoader<>() { + + private interface ResultLoader { + RESULT load(Identifier file, @Nullable RESOURCE resource) throws Exception; + } + + private static Map createCachedResourceBackedMap(Map resourceMap, + FileToIdConverter converter, + String debugName, + ResultLoader loader) { + LoadingCache> resultCache = CacheBuilder.newBuilder().softValues().maximumSize(1000).build(new CacheLoader<>() { @Override - public UnbakedModel load(Identifier key) throws Exception { - var resource = resourceMap.get(MODEL_LISTER.idToFile(key)); + public Optional load(Identifier id) throws Exception { + var file = converter.idToFile(id); + var resource = resourceMap.get(file); if (resource == null) { - throw new IllegalArgumentException("Model " + key + " does not exist in map"); + return Optional.empty(); } if (DEBUG_DYNAMIC_MODEL_LOADING) { - ModernFix.LOGGER.info("Loading unbaked model {}", key); - } - try (Reader reader = resource.openAsReader()) { - return UnbakedModelDeserializerRegistry.deserialize(reader); + ModernFix.LOGGER.info("Loading {} {}", debugName, id); } + return Optional.of(loader.load(file, resource)); + } + }); + Set idSet = resourceMap.keySet().stream().map(converter::fileToId).collect(Collectors.toUnmodifiableSet()); + return new DynamicRegistryMap<>(idSet, key -> { + if (key == null) { + return null; + } + try { + return resultCache.getUnchecked(key).orElse(null); + } catch (RuntimeException e) { + ModernFix.LOGGER.error("Error loading {} {} from cache", debugName, key); + throw e; + } + }); + } + + public static Map createDynamicUnbakedModelMap(Map resourceMap) { + return createCachedResourceBackedMap(resourceMap, MODEL_LISTER, "unbaked model", (id, resource) -> { + Objects.requireNonNull(resource, "unbaked model not present"); + try (Reader reader = resource.openAsReader()) { + return UnbakedModelDeserializerRegistry.deserialize(reader); } }); - Set unbakedIdSet = resourceMap.keySet().stream().map(MODEL_LISTER::fileToId).collect(Collectors.toUnmodifiableSet()); - return Maps.asMap(unbakedIdSet, key -> key != null ? unbakedModelCache.getUnchecked(key) : null); } public interface SingleBlockStateEntryLoader { BlockStateModelLoader.LoadedModels loadEntry(Identifier identifier, List blockstateResources); } - private static Set getAllBlockStates() { - return ((IdMapperAccessor) Block.BLOCK_STATE_REGISTRY).getReferenceMap().keySet(); - } - public static BlockStateModelLoader.LoadedModels createDynamicBlockStateLoadedModels(Map> resourceMap, SingleBlockStateEntryLoader entryLoader) { - LoadingCache definitionCache = CacheBuilder.newBuilder().softValues().maximumSize(1000).build(new CacheLoader<>() { + public static Set getAllBlockStates() { + var blockStateSet = ((IdMapperAccessor) Block.BLOCK_STATE_REGISTRY).getReferenceMap().keySet(); + return new AbstractSet<>() { @Override - public BlockStateModelLoader.LoadedModels load(Identifier key) throws Exception { - if (DEBUG_DYNAMIC_MODEL_LOADING) { - ModernFix.LOGGER.info("Loading blockstate definition for {}", key); - } - var file = BLOCKSTATE_LISTER.idToFile(key); - var resources = resourceMap.getOrDefault(file, List.of()); - return entryLoader.loadEntry(file, resources); + public Iterator iterator() { + // We explicitly override iterator() and handle it differently so that mods iterating the maps + // are likely to work with the same block many times in a row, which hits our caches better + return BuiltInRegistries.BLOCK.stream().flatMap(b -> b.getStateDefinition().getPossibleStates().stream()).iterator(); } - }); + @Override + public boolean contains(Object o) { + return blockStateSet.contains(o); + } + @Override + public int size() { + return blockStateSet.size(); + } + }; + } + public static BlockStateModelLoader.LoadedModels createDynamicBlockStateLoadedModels(Map> resourceMap, SingleBlockStateEntryLoader entryLoader) { + var blockStateDefinitions = createCachedResourceBackedMap(resourceMap, BLOCKSTATE_LISTER, "blockstate definition", entryLoader::loadEntry); var staticDefinitions = BlockStateDefinitionsAccessor.getStaticDefinitions(); var staticIdentifiers = staticDefinitions.entrySet() .stream() @@ -102,8 +132,12 @@ public BlockStateModelLoader.LoadedModels load(Identifier key) throws Exception if (identifier == null) { identifier = BuiltInRegistries.BLOCK.getKey(state.getBlock()); } - var loadedModels = definitionCache.getUnchecked(identifier); - return loadedModels.models().get(state); + var loadedModels = blockStateDefinitions.get(identifier); + if (loadedModels != null) { + return loadedModels.models().get(state); + } else { + return null; + } })); } @@ -112,34 +146,8 @@ public interface SingleClientItemEntryLoader { } public static ClientItemInfoLoader.LoadedClientInfos createDynamicClientInfos(Map resourceMap, SingleClientItemEntryLoader entryLoader) { - Set itemIdSet = resourceMap.keySet().stream().map(ITEM_LISTER::fileToId).collect(Collectors.toUnmodifiableSet()); - LoadingCache clientItemCache = CacheBuilder.newBuilder().softValues().maximumSize(1000).build(new CacheLoader<>() { - @Override - public Object load(Identifier key) { - Identifier fileId = ITEM_LISTER.idToFile(key); - Resource resource = resourceMap.get(fileId); - if (resource == null) { - return NULL_SENTINEL; - } - if (DEBUG_DYNAMIC_MODEL_LOADING) { - ModernFix.LOGGER.info("Loading client item info {}", key); - } - try { - ClientItem result = entryLoader.loadEntry(fileId, resource); - return result != null ? result : NULL_SENTINEL; - } catch (RuntimeException e) { - ModernFix.LOGGER.warn("Failed to build dynamic client item info for {}", key, e); - return NULL_SENTINEL; - } - } - }); - return new ClientItemInfoLoader.LoadedClientInfos(Maps.asMap(itemIdSet, key -> { - if (key == null) { - return null; - } - Object value = clientItemCache.getUnchecked(key); - return value == NULL_SENTINEL ? null : (ClientItem) value; - })); + var clientItems = createCachedResourceBackedMap(resourceMap, ITEM_LISTER, "client item info", entryLoader::loadEntry); + return new ClientItemInfoLoader.LoadedClientInfos(clientItems); } public record DynamicResolver(Map inputModels, @@ -205,7 +213,7 @@ public int getInt(Object key) { } } - private static final Object NULL_SENTINEL = new Object(); + private static final Object NULL_BAKED = new Object(); public static Map createDynamicBakedRegistry(Map input, BiFunction baker) { // TODO: support persistence of overrides @@ -213,20 +221,24 @@ public static Map createDynamicBakedRegistry(Map input, Bi @Override public Object load(K key) throws Exception { var unbaked = input.get(key); - if (unbaked != null) { - if (DEBUG_DYNAMIC_MODEL_LOADING) { - ModernFix.LOGGER.info("Baking {}", key); - } - return baker.apply(key, unbaked); - } else { - return NULL_SENTINEL; + if (unbaked == null) { + return NULL_BAKED; + } + if (DEBUG_DYNAMIC_MODEL_LOADING) { + ModernFix.LOGGER.info("Baking {}", key); + } + var bakerResult = baker.apply(key, unbaked); + if (bakerResult == null) { + ModernFix.LOGGER.warn("Baker has returned null for {}", key); + return NULL_BAKED; } + return bakerResult; } }); return new DynamicRegistryMap<>(input.keySet(), k -> { if (k != null) { Object value = bakedCache.getUnchecked(k); - if (value == NULL_SENTINEL) { + if (value == NULL_BAKED) { value = null; } return (V) value; @@ -235,4 +247,4 @@ public Object load(K key) throws Exception { } }); } -} \ No newline at end of file +} diff --git a/src/main/java/org/embeddedt/modernfix/dynresources/DynamicRegistryMap.java b/src/main/java/org/embeddedt/modernfix/dynresources/DynamicRegistryMap.java index 65c8e6efd..5f9f6722a 100644 --- a/src/main/java/org/embeddedt/modernfix/dynresources/DynamicRegistryMap.java +++ b/src/main/java/org/embeddedt/modernfix/dynresources/DynamicRegistryMap.java @@ -9,6 +9,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; @@ -73,6 +74,19 @@ public V get(Object o) { } } + @Override + public V getOrDefault(Object o, V defaultValue) { + Object value = overrides.get(o); + if (value == NULL_OVERRIDE) { + return null; + } else if (value != null) { + return (V) value; + } else { + var fallback = fallbackGetter.apply((K)o); + return fallback != null ? fallback : defaultValue; + } + } + @Override public @Nullable V put(K k, V v) { if (v == null) { @@ -158,4 +172,4 @@ public int size() { return DynamicRegistryMap.this.size(); } } -} +} \ No newline at end of file From 3c173a4fbb91c2c43d157f95fb1e79eede5c1759 Mon Sep 17 00:00:00 2001 From: coredex-source Date: Wed, 17 Jun 2026 16:49:49 +0530 Subject: [PATCH 5/5] 5.27.17 - commit.2 - Fix https://github.com/coredex-source/ModernFix---mVUS/issues/36 - Close https://github.com/coredex-source/ModernFix---mVUS/issues/39 --- .../dynamic_resources/MixinTextureSlots.java | 23 +++ .../dynresources/DynamicModelSystem.java | 3 + .../assets/modernfix/lang/pt_br.json | 139 ++++++++++++++++++ .../resources/modernfix-common.mixins.json | 1 + 4 files changed, 166 insertions(+) create mode 100644 src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/MixinTextureSlots.java create mode 100644 src/main/resources/assets/modernfix/lang/pt_br.json diff --git a/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/MixinTextureSlots.java b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/MixinTextureSlots.java new file mode 100644 index 000000000..1bc85f29f --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/MixinTextureSlots.java @@ -0,0 +1,23 @@ +package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources; + +import net.minecraft.client.resources.model.sprite.TextureSlots; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; +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.CallbackInfoReturnable; + +@Mixin(TextureSlots.class) +@ClientOnlyMixin +public class MixinTextureSlots { + /** + * @author coredex-source + * @reason Return false instead of throwing StringIndexOutOfBoundsException to prevent resource reload from crashing when model points to empty texture string. + */ + @Inject(method = "isTextureReference", at = @At("HEAD"), cancellable = true) + private static void mfix$handleEmptyTextureReference(String string, CallbackInfoReturnable cir) { + if (string == null || string.isEmpty()) { + cir.setReturnValue(false); + } + } +} diff --git a/src/main/java/org/embeddedt/modernfix/dynresources/DynamicModelSystem.java b/src/main/java/org/embeddedt/modernfix/dynresources/DynamicModelSystem.java index 2bd14431c..e8f0fba5c 100644 --- a/src/main/java/org/embeddedt/modernfix/dynresources/DynamicModelSystem.java +++ b/src/main/java/org/embeddedt/modernfix/dynresources/DynamicModelSystem.java @@ -92,6 +92,9 @@ public static Map createDynamicUnbakedModelMap(Map