From ab19c89fa22b053c0ef0055cf6eca5d0d3947ded Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 18 Feb 2023 12:53:25 -0500 Subject: [PATCH 01/31] use Java 17 in Action --- .github/workflows/gradle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 9e5672dd..873cb766 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -15,7 +15,7 @@ jobs: - uses: actions/setup-java@v3 with: distribution: 'temurin' - java-version: '8' + java-version: '17' - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build the mod From 30bcf66c355214994043af8bf06c3df207253aaf Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 18 Feb 2023 13:12:33 -0500 Subject: [PATCH 02/31] Mark structure manager field as immutable --- .../bugfix/structure_manager_crash/StructureManagerMixin.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/bugfix/structure_manager_crash/StructureManagerMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/structure_manager_crash/StructureManagerMixin.java index 5aacf946..8ee6dd8d 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/bugfix/structure_manager_crash/StructureManagerMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/structure_manager_crash/StructureManagerMixin.java @@ -8,6 +8,7 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp import net.minecraft.world.level.storage.LevelStorageSource; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -18,7 +19,8 @@ import java.util.Map; @Mixin(StructureManager.class) public class StructureManagerMixin { - @Shadow @Final private Map structureRepository; + @Shadow @Final @Mutable + private Map structureRepository; @Inject(method = "", at = @At("RETURN")) private void makeStructuresSafe(ResourceManager arg, LevelStorageSource.LevelStorageAccess arg2, DataFixer dataFixer, CallbackInfo ci) { From 2e50b995d8d0fee94d4e4f837d7ad2a6e9168e23 Mon Sep 17 00:00:00 2001 From: ZZZank <47418975+ZZZank@users.noreply.github.com> Date: Mon, 20 Feb 2023 03:25:46 +0800 Subject: [PATCH 03/31] Improve translations (#21) --- src/main/resources/assets/modernfix/lang/en_us.json | 4 ++-- src/main/resources/assets/modernfix/lang/zh_cn.json | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 src/main/resources/assets/modernfix/lang/zh_cn.json diff --git a/src/main/resources/assets/modernfix/lang/en_us.json b/src/main/resources/assets/modernfix/lang/en_us.json index d12ff605..8b1b7ad4 100644 --- a/src/main/resources/assets/modernfix/lang/en_us.json +++ b/src/main/resources/assets/modernfix/lang/en_us.json @@ -1,5 +1,5 @@ { - "modernfix.jei_load": "Loading JEI...", + "modernfix.jei_load": "Loading JEI, this may take a while", "asynclocator.map.locating": "Map (Locating...)", "asynclocator.map.none": "Map (No nearby feature found)" -} \ No newline at end of file +} diff --git a/src/main/resources/assets/modernfix/lang/zh_cn.json b/src/main/resources/assets/modernfix/lang/zh_cn.json new file mode 100644 index 00000000..0c9c92a5 --- /dev/null +++ b/src/main/resources/assets/modernfix/lang/zh_cn.json @@ -0,0 +1,5 @@ +{ + "modernfix.jei_load": "正在加载JEI,这需要一点时间", + "asynclocator.map.locating": "地图(正在定位...)", + "asynclocator.map.none": "地图(未能找到相关地物)" +} From 5194089c7897d6242cf1d735ce1e929f2c51f813 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 19 Feb 2023 16:27:03 -0500 Subject: [PATCH 04/31] Use remapped JAR for CurseForge artifact --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 36682f45..2b86fad7 100644 --- a/build.gradle +++ b/build.gradle @@ -144,6 +144,7 @@ curseforge { releaseType = "release" addGameVersion "Forge" addGameVersion minecraft_version + mainArtifact remapJar } } } From 19018699a08bf48b8326ad449916a85f4b788335 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 19 Feb 2023 16:27:31 -0500 Subject: [PATCH 05/31] 1.6.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2b86fad7..fe434c26 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ plugins { sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8 group = 'org.embeddedt' -version = '1.6.0-beta3' +version = '1.6.0' java { archivesBaseName = 'modernfix-mc' + minecraft_version From d2d29f14cb556a86ebd93941d6aa7df105a9e462 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 19 Feb 2023 18:44:21 -0500 Subject: [PATCH 06/31] Prevent Nashorn from defining anonymous classes if Java is too new Solar Flux Reborn now works on Java 17 --- .../embeddedt/modernfix/core/ModernFixMixinPlugin.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java b/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java index c9157924..ea3b018d 100644 --- a/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java +++ b/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java @@ -39,6 +39,14 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin { this.logger.info("Loaded configuration file for ModernFix: {} options available, {} override(s) found", config.getOptionCount(), config.getOptionOverrideCount()); + try { + Class.forName("sun.misc.Unsafe").getDeclaredMethod("defineAnonymousClass", Class.class, byte[].class, Object[].class); + } catch(ReflectiveOperationException | NullPointerException e) { + this.logger.info("Applying Nashorn fix"); + Properties properties = System.getProperties(); + properties.setProperty("nashorn.args", properties.getProperty("nashorn.args", "") + " --anonymous-classes=false"); + } + /* We abuse the constructor of a mixin plugin as a safe location to start modifying the classloader */ /* Swap the transformer for ours */ ClassLoader loader = Thread.currentThread().getContextClassLoader(); From 74a727d335c9a0cf798f3128528023cf2eba443c Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 19 Feb 2023 20:05:09 -0500 Subject: [PATCH 07/31] Add ability to use vanilla resource reload profiler --- .../modernfix/core/ModernFixMixinPlugin.java | 2 +- .../core/config/ModernFixConfig.java | 5 +++- .../ProfiledReloadInstanceMixin.java | 24 ++++++++++++++++++ .../SimpleReloadableResourceManagerMixin.java | 23 +++++++++++++++++ .../util/NamedPreparableResourceListener.java | 25 +++++++++++++++++++ src/main/resources/modernfix.mixins.json | 4 ++- 6 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/feature/measure_time/ProfiledReloadInstanceMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/feature/measure_time/SimpleReloadableResourceManagerMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/util/NamedPreparableResourceListener.java diff --git a/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java b/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java index ea3b018d..bbc4dcc0 100644 --- a/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java +++ b/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java @@ -9,7 +9,7 @@ import org.apache.logging.log4j.Logger; import org.embeddedt.modernfix.classloading.ModernFixResourceFinder; import org.embeddedt.modernfix.core.config.ModernFixEarlyConfig; import org.embeddedt.modernfix.core.config.Option; -import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.*; import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; import org.spongepowered.asm.mixin.extensibility.IMixinInfo; diff --git a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixConfig.java b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixConfig.java index c4e6d610..1963ad9a 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixConfig.java @@ -23,7 +23,7 @@ public class ModernFixConfig { public static ForgeConfigSpec.ConfigValue> BLACKLIST_ASYNC_JEI_PLUGINS; public static ForgeConfigSpec.IntValue INTEGRATED_SERVER_PRIORITY; - public static ForgeConfigSpec.IntValue BACKGROUND_WORKER_PRIORITY; + public static ForgeConfigSpec.BooleanValue ENABLE_DEBUG_RELOADER; public static ForgeConfigSpec.BooleanValue REBUILD_BLOCKSTATES_ASYNC; @@ -39,6 +39,9 @@ public class ModernFixConfig { "jepb:jei_plugin" ), locationValidator); INTEGRATED_SERVER_PRIORITY = COMMON_BUILDER.comment("Thread priority to use for the integrated server. By default this is one less than the client thread, to help prevent the server from lowering FPS.").defineInRange("integratedServerPriority", 4, 1, 10); + ENABLE_DEBUG_RELOADER = COMMON_BUILDER + .comment("Whether Minecraft's built-in profiling logic should be enabled for resource reloading. Can help with diagnosing world load times.") + .define("enable_debug_reloader", false); REBUILD_BLOCKSTATES_ASYNC = COMMON_BUILDER .comment("Rebuild blockstate cache asynchronously. Should work with most mods, but can be disabled.") .define("rebuild_blockstate_cache_async", true); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/feature/measure_time/ProfiledReloadInstanceMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/feature/measure_time/ProfiledReloadInstanceMixin.java new file mode 100644 index 00000000..9d93fc83 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/feature/measure_time/ProfiledReloadInstanceMixin.java @@ -0,0 +1,24 @@ +package org.embeddedt.modernfix.mixin.feature.measure_time; + +import net.minecraft.server.packs.resources.PreparableReloadListener; +import net.minecraft.server.packs.resources.ProfiledReloadInstance; +import org.embeddedt.modernfix.util.NamedPreparableResourceListener; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +import java.util.ArrayList; +import java.util.List; + +@Mixin(ProfiledReloadInstance.class) +public class ProfiledReloadInstanceMixin { + @ModifyVariable(method = "", at = @At("HEAD"), argsOnly = true, ordinal = 0) + private static List getWrappedListeners(List listeners) { + List newList = new ArrayList<>(listeners.size()); + for(PreparableReloadListener listener : listeners) { + newList.add(new NamedPreparableResourceListener(listener)); + } + return newList; + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/feature/measure_time/SimpleReloadableResourceManagerMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/feature/measure_time/SimpleReloadableResourceManagerMixin.java new file mode 100644 index 00000000..26c2a67f --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/feature/measure_time/SimpleReloadableResourceManagerMixin.java @@ -0,0 +1,23 @@ +package org.embeddedt.modernfix.mixin.feature.measure_time; + +import net.minecraft.server.packs.resources.SimpleReloadableResourceManager; +import org.apache.logging.log4j.Logger; +import org.embeddedt.modernfix.core.config.ModernFixConfig; +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.Redirect; + +@Mixin(SimpleReloadableResourceManager.class) +public class SimpleReloadableResourceManagerMixin { + + /** + * @author embeddedt + * @reason add ability to use this feature in modpacks + */ + @Redirect(method = "createReload", at = @At(value = "INVOKE", target = "Lorg/apache/logging/log4j/Logger;isDebugEnabled()Z", remap = false)) + private boolean enableDebugReloader(Logger logger) { + return logger.isDebugEnabled() || ModernFixConfig.ENABLE_DEBUG_RELOADER.get(); + } +} diff --git a/src/main/java/org/embeddedt/modernfix/util/NamedPreparableResourceListener.java b/src/main/java/org/embeddedt/modernfix/util/NamedPreparableResourceListener.java new file mode 100644 index 00000000..a8729114 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/util/NamedPreparableResourceListener.java @@ -0,0 +1,25 @@ +package org.embeddedt.modernfix.util; + +import net.minecraft.server.packs.resources.PreparableReloadListener; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.util.profiling.ProfilerFiller; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +public class NamedPreparableResourceListener implements PreparableReloadListener { + private final PreparableReloadListener delegate; + public NamedPreparableResourceListener(PreparableReloadListener delegate) { + this.delegate = delegate; + } + + @Override + public CompletableFuture reload(PreparationBarrier stage, ResourceManager resourceManager, ProfilerFiller preparationsProfiler, ProfilerFiller reloadProfiler, Executor backgroundExecutor, Executor gameExecutor) { + return this.delegate.reload(stage, resourceManager, preparationsProfiler, reloadProfiler, backgroundExecutor, gameExecutor); + } + + @Override + public String getName() { + return this.delegate.getName() + " [" + this.delegate.getClass().getName() + "]"; + } +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 909005af..59a193dd 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -39,7 +39,9 @@ "perf.async_locator.MapItemAccess", "perf.async_locator.MerchantOfferAccess", "perf.async_locator.TreasureMapForEmeraldsMixin", - "feature.measure_time.BootstrapMixin" + "feature.measure_time.BootstrapMixin", + "feature.measure_time.SimpleReloadableResourceManagerMixin", + "feature.measure_time.ProfiledReloadInstanceMixin" ], "client": [ "feature.measure_time.MinecraftMixin", From 1f1bf4a4428094d9003350c74089a260f27dcd5b Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 19 Feb 2023 20:12:49 -0500 Subject: [PATCH 08/31] Guard against mods that don't support concurrency on resource packs Should fix #22 --- .../perf/parallelize_model_loading/ModelBakeryMixin.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/ModelBakeryMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/ModelBakeryMixin.java index 9e3c73a6..e696f92f 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/ModelBakeryMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/ModelBakeryMixin.java @@ -54,7 +54,10 @@ public abstract class ModelBakeryMixin { ResourceLocation blockStateJSON = new ResourceLocation(blockLocation.getNamespace(), "blockstates/" + blockLocation.getPath() + ".json"); List blockStates; try { - blockStates = this.resourceManager.getResources(blockStateJSON); + /* Some mods' custom resource pack implementations don't seem to like concurrency here */ + synchronized(this.resourceManager) { + blockStates = this.resourceManager.getResources(blockStateJSON); + } } catch(IOException e) { ModernFix.LOGGER.warn("Exception loading blockstate definition: {}: {}", blockLocation, e); return; From 36217fe479854ea6b69632cfc9954a6054bfcd37 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 19 Feb 2023 20:13:14 -0500 Subject: [PATCH 09/31] 1.6.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index fe434c26..86ef5518 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ plugins { sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8 group = 'org.embeddedt' -version = '1.6.0' +version = '1.6.1' java { archivesBaseName = 'modernfix-mc' + minecraft_version From 9b9b13d24b450116bc4325e8b5b2e3f4498f52ff Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 19 Feb 2023 22:19:20 -0500 Subject: [PATCH 10/31] Add KubeJS optimizations --- build.gradle | 17 ++++ gradle.properties | 3 +- .../core/config/ModernFixEarlyConfig.java | 1 + .../perf/kubejs/TagIngredientJSMixin.java | 28 +++++++ .../mixin/perf/kubejs/TagWrapperMixin.java | 82 +++++++++++++++++++ .../embeddedt/modernfix/util/KubeUtil.java | 20 +++++ src/main/resources/modernfix.mixins.json | 4 +- 7 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagIngredientJSMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagWrapperMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/util/KubeUtil.java diff --git a/build.gradle b/build.gradle index 86ef5518..cc0a8c08 100644 --- a/build.gradle +++ b/build.gradle @@ -43,6 +43,21 @@ repositories { name = 'ParchmentMC' url = 'https://maven.parchmentmc.org' } + maven { + // Shedaniel's maven (Architectury API) + url = "https://maven.architectury.dev" + content { + includeGroup "me.shedaniel" + } + } + + maven { + // saps.dev Maven (KubeJS and Rhino) + url = "https://maven.saps.dev/minecraft" + content { + includeGroup "dev.latvian.mods" + } + } } dependencies { @@ -70,6 +85,8 @@ dependencies { modRuntimeOnly("mezz.jei:jei-${minecraft_version}:${jei_version}") modCompileOnly("curse.maven:refinedstorage-243076:${refined_storage_version}") + + modImplementation("dev.latvian.mods:kubejs-forge:${kubejs_version}") } tasks.withType(JavaCompile) { diff --git a/gradle.properties b/gradle.properties index 2dcde3cd..6361e3d5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,4 +14,5 @@ lazydfu_version=3249059 mekanism_version=1.16.5-10.1.2.457 parchment_version=2022.03.06 jei_version=7.7.1.153 -refined_storage_version=3807951 \ No newline at end of file +refined_storage_version=3807951 +kubejs_version=1605.3.19-build.299 \ No newline at end of file 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 d4c8e106..7add26e8 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -44,6 +44,7 @@ public class ModernFixEarlyConfig { this.addMixinRule("perf.cache_model_materials", true); this.addMixinRule("perf.datapack_reload_exceptions", true); this.addMixinRule("perf.async_locator", true); + this.addMixinRule("perf.kubejs", true); /* Keep this off if JEI isn't installed to prevent breaking vanilla gameplay */ this.addMixinRule("perf.blast_search_trees", FMLLoader.getLoadingModList().getModFileById("jei") != null); this.addMixinRule("safety", true); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagIngredientJSMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagIngredientJSMixin.java new file mode 100644 index 00000000..080ef036 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagIngredientJSMixin.java @@ -0,0 +1,28 @@ +package org.embeddedt.modernfix.mixin.perf.kubejs; + +import dev.latvian.kubejs.item.ItemStackJS; +import dev.latvian.kubejs.item.ingredient.IngredientJS; +import dev.latvian.kubejs.item.ingredient.TagIngredientJS; +import net.minecraft.tags.Tag; +import net.minecraft.world.item.Item; +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; + +@Mixin(TagIngredientJS.class) +public abstract class TagIngredientJSMixin { + @Shadow public abstract Tag getActualTag(); + + /** + * @author embeddedt + * @reason avoid pointless construction of many ItemStack objects + */ + @Inject(method = "anyStackMatches", at = @At("HEAD"), cancellable = true, remap = false) + private void checkItemOnly(IngredientJS ingredient, CallbackInfoReturnable cir) { + if(ingredient instanceof ItemStackJS) { + cir.setReturnValue(((ItemStackJS)ingredient).getItem().is(this.getActualTag())); + } + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagWrapperMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagWrapperMixin.java new file mode 100644 index 00000000..aea5eb05 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagWrapperMixin.java @@ -0,0 +1,82 @@ +package org.embeddedt.modernfix.mixin.perf.kubejs; + +import dev.latvian.kubejs.server.TagEventJS; +import dev.latvian.kubejs.util.ConsoleJS; +import dev.latvian.kubejs.util.ListJS; +import dev.latvian.kubejs.util.UtilsJS; +import it.unimi.dsi.fastutil.chars.CharOpenHashSet; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import me.shedaniel.architectury.registry.Registry; +import net.minecraft.resources.ResourceLocation; +import org.embeddedt.modernfix.util.KubeUtil; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +@Mixin(TagEventJS.TagWrapper.class) +public class TagWrapperMixin { + private static final CharOpenHashSet REGEX_SPECIAL_CHARS = new CharOpenHashSet(new char[] { + '.', '+', '*','?','^','$','(',')','[',']','{','}','|','\\', '/' + }); + + /** + * @author embeddedt + * @reason only iterate over the whole registry if a regex is given, otherwise use the given registry name as-is + */ + @Redirect(method = "add", at = @At(value = "INVOKE", target = "Ldev/latvian/kubejs/util/UtilsJS;parseRegex(Ljava/lang/Object;)Ljava/util/regex/Pattern;"), remap = false) + private Pattern skipRegex(Object o) { + String inputStr = (String)o; + boolean regexCharFound = false; + for(int i = 0; i < inputStr.length(); i++) { + if(REGEX_SPECIAL_CHARS.contains(inputStr.charAt(i))) { + System.out.println(inputStr); + regexCharFound = true; + break; + } + } + if(regexCharFound) + return UtilsJS.parseRegex(inputStr); + else + return null; + } + + private String currentPatternStr = null; + @Inject(method = "add", at = @At(value = "INVOKE", target = "Lme/shedaniel/architectury/registry/Registry;getIds()Ljava/util/Set;", ordinal = 0), locals = LocalCapture.CAPTURE_FAILHARD, remap = false) + private void saveCurrentPattern(Object ids, CallbackInfoReturnable> cir, Iterator iterator, Object o, String patternStr) { + currentPatternStr = patternStr; + } + + @Redirect(method = "add", at = @At(value = "INVOKE", target = "Lme/shedaniel/architectury/registry/Registry;getIds()Ljava/util/Set;", ordinal = 0), remap = false) + private Set getCachedIds(Registry registryIn) { + if(currentPatternStr == null) + throw new AssertionError(); + Set cachedSet = KubeUtil.matchedIdsForRegex.get(currentPatternStr); + if(cachedSet == null) { + Pattern thePattern = UtilsJS.parseRegex(currentPatternStr); + ArrayList locations = new ArrayList<>(registryIn.getIds()); + cachedSet = locations.parallelStream() + .filter(rLoc -> thePattern.matcher(rLoc.toString()).find()) + .collect(Collectors.toSet()); + KubeUtil.matchedIdsForRegex.put(currentPatternStr, cachedSet); + } + return cachedSet; + } + + /** + * @author embeddedt + * @reason we handle pattern-matching ourselves to build the cache + */ + @Redirect(method = "add", at = @At(value = "INVOKE", target = "Ljava/util/regex/Matcher;find()Z"), remap = false) + private boolean isMatchedStr(Matcher matcher) { + return true; + } +} diff --git a/src/main/java/org/embeddedt/modernfix/util/KubeUtil.java b/src/main/java/org/embeddedt/modernfix/util/KubeUtil.java new file mode 100644 index 00000000..1f453d47 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/util/KubeUtil.java @@ -0,0 +1,20 @@ +package org.embeddedt.modernfix.util; + +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.event.AddReloadListenerEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import org.embeddedt.modernfix.ModernFix; + +import java.util.HashMap; +import java.util.Set; + +@Mod.EventBusSubscriber(modid = ModernFix.MODID) +public class KubeUtil { + public static final HashMap> matchedIdsForRegex = new HashMap<>(); + + @SubscribeEvent + public static void clearRegexCache(AddReloadListenerEvent event) { + matchedIdsForRegex.clear(); + } +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 59a193dd..f0df6b32 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -41,7 +41,9 @@ "perf.async_locator.TreasureMapForEmeraldsMixin", "feature.measure_time.BootstrapMixin", "feature.measure_time.SimpleReloadableResourceManagerMixin", - "feature.measure_time.ProfiledReloadInstanceMixin" + "feature.measure_time.ProfiledReloadInstanceMixin", + "perf.kubejs.TagIngredientJSMixin", + "perf.kubejs.TagWrapperMixin" ], "client": [ "feature.measure_time.MinecraftMixin", From 4d397361e20651f3c0ad5aac68b342501bde7c89 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 19 Feb 2023 22:19:55 -0500 Subject: [PATCH 11/31] Remove special sauce in blockstate handling Now that the cache is rebuilt off-thread, there is little to gain from parallelizing these few blocks --- .../blockstate/BlockStateCacheHandler.java | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java b/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java index 2076f136..ce1b407a 100644 --- a/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java +++ b/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java @@ -1,13 +1,8 @@ package org.embeddedt.modernfix.blockstate; import com.google.common.base.Stopwatch; -import com.google.common.collect.ImmutableSet; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.Util; -import net.minecraft.core.BlockPos; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.level.EmptyBlockGetter; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.fml.loading.FMLLoader; import org.embeddedt.modernfix.ModernFix; @@ -17,18 +12,9 @@ import org.embeddedt.modernfix.util.BakeReason; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.Set; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; public class BlockStateCacheHandler { - private static final Set PRECACHED_COLLISION_SHAPES = ImmutableSet.builder() - .add("refinedstorage") - .add("cabletiers") - .add("extrastorage") - .build(); - private static RebuildThread currentRebuildThread = null; private static boolean needToBake() { @@ -93,20 +79,8 @@ public class BlockStateCacheHandler { } @Override - @SuppressWarnings("deprecation") public void run() { Stopwatch realtimeStopwatch = Stopwatch.createStarted(); - /* Run some special sauce for Refined Storage since it has very slow collision shapes */ - List specialStates = blockStateList.stream() - .filter(state -> PRECACHED_COLLISION_SHAPES.contains(state.getBlock().getRegistryName().getNamespace())).collect(Collectors.toList()); - CompletableFuture.runAsync(() -> { - specialStates.parallelStream() - .forEach(state -> { - /* Force these blocks to compute their shapes ahead of time on worker threads */ - state.getBlock().getCollisionShape(state, EmptyBlockGetter.INSTANCE, BlockPos.ZERO, CollisionContext.empty()); - state.getBlock().getOcclusionShape(state, EmptyBlockGetter.INSTANCE, BlockPos.ZERO); - }); - }, Util.backgroundExecutor()).join(); rebuildCache(); realtimeStopwatch.stop(); if(!stopRebuild) From 613364ce917ea51faa348da99880301eeba3856c Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 19 Feb 2023 22:40:59 -0500 Subject: [PATCH 12/31] Further KubeJS optimization --- .../mixin/perf/kubejs/RecipeEventJSMixin.java | 32 +++++++++++++++++++ .../mixin/perf/kubejs/RecipeJSMixin.java | 22 +++++++++++++ src/main/resources/modernfix.mixins.json | 4 ++- 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeEventJSMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeJSMixin.java diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeEventJSMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeEventJSMixin.java new file mode 100644 index 00000000..30ebd578 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeEventJSMixin.java @@ -0,0 +1,32 @@ +package org.embeddedt.modernfix.mixin.perf.kubejs; + +import dev.latvian.kubejs.recipe.RecipeEventJS; +import dev.latvian.kubejs.recipe.RecipeJS; +import dev.latvian.kubejs.recipe.filter.RecipeFilter; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +@Mixin(RecipeEventJS.class) +public class RecipeEventJSMixin { + @Shadow @Final private List originalRecipes; + + /** + * @author embeddedt + * @reason parallelize filtering, then run the consumer on one thread + */ + @Overwrite(remap = false) + public void forEachRecipe(RecipeFilter filter, Consumer consumer) { + if (filter == RecipeFilter.ALWAYS_TRUE) { + this.originalRecipes.forEach(consumer); + } else if (filter != RecipeFilter.ALWAYS_FALSE) { + List filtered = this.originalRecipes.parallelStream().filter(filter).collect(Collectors.toList()); + filtered.forEach(consumer); + } + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeJSMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeJSMixin.java new file mode 100644 index 00000000..9b04fa90 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeJSMixin.java @@ -0,0 +1,22 @@ +package org.embeddedt.modernfix.mixin.perf.kubejs; + +import dev.latvian.kubejs.recipe.RecipeJS; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Recipe; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(RecipeJS.class) +public class RecipeJSMixin { + /** + * @author embeddedt + * @reason some mods seem to not like this being called concurrently, not sure why this doesn't crash in other scripts + */ + @Redirect(method = "hasOutput", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/crafting/Recipe;getResultItem()Lnet/minecraft/world/item/ItemStack;")) + private ItemStack syncResultItem(Recipe recipe) { + synchronized (RecipeJS.class) { + return recipe.getResultItem(); + } + } +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index f0df6b32..eb6d129c 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -43,7 +43,9 @@ "feature.measure_time.SimpleReloadableResourceManagerMixin", "feature.measure_time.ProfiledReloadInstanceMixin", "perf.kubejs.TagIngredientJSMixin", - "perf.kubejs.TagWrapperMixin" + "perf.kubejs.TagWrapperMixin", + "perf.kubejs.RecipeEventJSMixin", + "perf.kubejs.RecipeJSMixin" ], "client": [ "feature.measure_time.MinecraftMixin", From 5b852f95316d6bbb10404508525ddeb442a9e8ee Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 19 Feb 2023 22:44:35 -0500 Subject: [PATCH 13/31] Remove debug logging --- .../embeddedt/modernfix/mixin/perf/kubejs/TagWrapperMixin.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagWrapperMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagWrapperMixin.java index aea5eb05..cebfff56 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagWrapperMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagWrapperMixin.java @@ -38,7 +38,6 @@ public class TagWrapperMixin { boolean regexCharFound = false; for(int i = 0; i < inputStr.length(); i++) { if(REGEX_SPECIAL_CHARS.contains(inputStr.charAt(i))) { - System.out.println(inputStr); regexCharFound = true; break; } From a6e736e8afc30fdb16fdcaf6c4bd5de11186d4c0 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 20 Feb 2023 09:57:15 -0500 Subject: [PATCH 14/31] Remove redundant optimization --- .../mixin/perf/kubejs/TagWrapperMixin.java | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagWrapperMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagWrapperMixin.java index cebfff56..c867b5a7 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagWrapperMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagWrapperMixin.java @@ -24,30 +24,6 @@ import java.util.stream.Collectors; @Mixin(TagEventJS.TagWrapper.class) public class TagWrapperMixin { - private static final CharOpenHashSet REGEX_SPECIAL_CHARS = new CharOpenHashSet(new char[] { - '.', '+', '*','?','^','$','(',')','[',']','{','}','|','\\', '/' - }); - - /** - * @author embeddedt - * @reason only iterate over the whole registry if a regex is given, otherwise use the given registry name as-is - */ - @Redirect(method = "add", at = @At(value = "INVOKE", target = "Ldev/latvian/kubejs/util/UtilsJS;parseRegex(Ljava/lang/Object;)Ljava/util/regex/Pattern;"), remap = false) - private Pattern skipRegex(Object o) { - String inputStr = (String)o; - boolean regexCharFound = false; - for(int i = 0; i < inputStr.length(); i++) { - if(REGEX_SPECIAL_CHARS.contains(inputStr.charAt(i))) { - regexCharFound = true; - break; - } - } - if(regexCharFound) - return UtilsJS.parseRegex(inputStr); - else - return null; - } - private String currentPatternStr = null; @Inject(method = "add", at = @At(value = "INVOKE", target = "Lme/shedaniel/architectury/registry/Registry;getIds()Ljava/util/Set;", ordinal = 0), locals = LocalCapture.CAPTURE_FAILHARD, remap = false) private void saveCurrentPattern(Object ids, CallbackInfoReturnable> cir, Iterator iterator, Object o, String patternStr) { From df7cd20e59ef3490ffe34ac5899b576f26ea991e Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 20 Feb 2023 09:57:34 -0500 Subject: [PATCH 15/31] Clean up imports --- .../modernfix/mixin/perf/kubejs/TagWrapperMixin.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagWrapperMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagWrapperMixin.java index c867b5a7..7207d9bd 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagWrapperMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagWrapperMixin.java @@ -1,16 +1,11 @@ package org.embeddedt.modernfix.mixin.perf.kubejs; import dev.latvian.kubejs.server.TagEventJS; -import dev.latvian.kubejs.util.ConsoleJS; -import dev.latvian.kubejs.util.ListJS; import dev.latvian.kubejs.util.UtilsJS; -import it.unimi.dsi.fastutil.chars.CharOpenHashSet; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import me.shedaniel.architectury.registry.Registry; import net.minecraft.resources.ResourceLocation; import org.embeddedt.modernfix.util.KubeUtil; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; From 5cd80ebd27a455eca02b3bd1be90227e188d238e Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 20 Feb 2023 10:23:46 -0500 Subject: [PATCH 16/31] Use a custom ForkJoinPool so that mod classes load correctly --- .../mixin/perf/kubejs/RecipeEventJSMixin.java | 4 +++- .../org/embeddedt/modernfix/util/ModUtil.java | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeEventJSMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeEventJSMixin.java index 30ebd578..d6b49c95 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeEventJSMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeEventJSMixin.java @@ -1,8 +1,10 @@ package org.embeddedt.modernfix.mixin.perf.kubejs; +import cpw.mods.modlauncher.api.LamdbaExceptionUtils; import dev.latvian.kubejs.recipe.RecipeEventJS; import dev.latvian.kubejs.recipe.RecipeJS; import dev.latvian.kubejs.recipe.filter.RecipeFilter; +import org.embeddedt.modernfix.util.ModUtil; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; @@ -25,7 +27,7 @@ public class RecipeEventJSMixin { if (filter == RecipeFilter.ALWAYS_TRUE) { this.originalRecipes.forEach(consumer); } else if (filter != RecipeFilter.ALWAYS_FALSE) { - List filtered = this.originalRecipes.parallelStream().filter(filter).collect(Collectors.toList()); + List filtered = LamdbaExceptionUtils.uncheck(() -> ModUtil.commonPool.submit(() -> this.originalRecipes.parallelStream().filter(filter).collect(Collectors.toList())).get()); filtered.forEach(consumer); } } diff --git a/src/main/java/org/embeddedt/modernfix/util/ModUtil.java b/src/main/java/org/embeddedt/modernfix/util/ModUtil.java index e82d0982..90618d22 100644 --- a/src/main/java/org/embeddedt/modernfix/util/ModUtil.java +++ b/src/main/java/org/embeddedt/modernfix/util/ModUtil.java @@ -14,6 +14,8 @@ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import org.embeddedt.modernfix.ModernFix; import java.util.*; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinWorkerThread; import java.util.function.Supplier; public class ModUtil { @@ -49,4 +51,21 @@ public class ModUtil { }); return modsListening; } + + private static final ClassLoader targetClassLoader = Thread.currentThread().getContextClassLoader(); + + private static class ModernFixForkJoinWorkerThread extends ForkJoinWorkerThread { + ModernFixForkJoinWorkerThread(ForkJoinPool pool) { + super(pool); + /* Ensure that the context class loader is set correctly */ + this.setContextClassLoader(targetClassLoader); + } + } + + public static ForkJoinPool commonPool = new ForkJoinPool( + ForkJoinPool.getCommonPoolParallelism(), + ModernFixForkJoinWorkerThread::new, + null, + false + ); } From 02230095b78c5d40cb27ac15f9bb431671754613 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 20 Feb 2023 11:25:22 -0500 Subject: [PATCH 17/31] Ignore exceptions while building blockstate cache --- .../modernfix/blockstate/BlockStateCacheHandler.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java b/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java index ce1b407a..4128d2d9 100644 --- a/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java +++ b/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java @@ -74,7 +74,12 @@ public class BlockStateCacheHandler { private void rebuildCache() { Iterator stateIterator = blockStateList.iterator(); while(!stopRebuild && stateIterator.hasNext()) { - stateIterator.next().initCache(); + BlockState state = stateIterator.next(); + try { + state.initCache(); + } catch(Exception e) { + ModernFix.LOGGER.warn("Exception encountered while initializing cache", e); + } } } From c7f2d41695a7840a4254b8ae79a90b7565ebae0d Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 20 Feb 2023 11:25:39 -0500 Subject: [PATCH 18/31] More KubeJS optimizations --- .../org/embeddedt/modernfix/ModernFix.java | 4 +++ .../modernfix/duck/ICachedIngredientJS.java | 14 +++++++++ .../perf/kubejs/CustomIngredientMixin.java | 28 +++++++++++++++++ .../mixin/perf/kubejs/IDFilterMixin.java | 30 +++++++++++++++++++ .../mixin/perf/kubejs/RecipeEventJSMixin.java | 22 +++++++++++++- .../mixin/perf/kubejs/RecipeJSMixin.java | 21 +++++++++++++ .../perf/kubejs/TagIngredientJSMixin.java | 19 +++++++++++- .../embeddedt/modernfix/util/KubeUtil.java | 17 +++++++---- src/main/resources/modernfix.mixins.json | 4 ++- 9 files changed, 151 insertions(+), 8 deletions(-) create mode 100644 src/main/java/org/embeddedt/modernfix/duck/ICachedIngredientJS.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/CustomIngredientMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/IDFilterMixin.java diff --git a/src/main/java/org/embeddedt/modernfix/ModernFix.java b/src/main/java/org/embeddedt/modernfix/ModernFix.java index 7e5a53fd..3e4ee13a 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFix.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFix.java @@ -5,6 +5,7 @@ import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.ExtensionPoint; +import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; @@ -17,6 +18,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.embeddedt.modernfix.core.config.ModernFixConfig; import org.embeddedt.modernfix.structure.AsyncLocator; +import org.embeddedt.modernfix.util.KubeUtil; import java.lang.management.ManagementFactory; @@ -42,6 +44,8 @@ public class ModernFix { DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> MinecraftForge.EVENT_BUS.register(new ModernFixClient())); ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true)); ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModernFixConfig.COMMON_CONFIG); + if(ModList.get().isLoaded("kubejs")) + MinecraftForge.EVENT_BUS.register(KubeUtil.class); } @SubscribeEvent diff --git a/src/main/java/org/embeddedt/modernfix/duck/ICachedIngredientJS.java b/src/main/java/org/embeddedt/modernfix/duck/ICachedIngredientJS.java new file mode 100644 index 00000000..31519af6 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/duck/ICachedIngredientJS.java @@ -0,0 +1,14 @@ +package org.embeddedt.modernfix.duck; + +import dev.latvian.kubejs.item.ItemStackJS; + +import java.util.Set; + +public interface ICachedIngredientJS { + /** + * Returns a cached list of item stacks for the given ingredient. The user must not attempt to modify any contents + * of these stacks. + * @return cached set of stacks + */ + Set getCachedStacks(); +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/CustomIngredientMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/CustomIngredientMixin.java new file mode 100644 index 00000000..8257fa5e --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/CustomIngredientMixin.java @@ -0,0 +1,28 @@ +package org.embeddedt.modernfix.mixin.perf.kubejs; + +import dev.latvian.kubejs.item.ItemStackJS; +import dev.latvian.kubejs.item.ingredient.CustomIngredient; +import net.minecraft.world.item.crafting.Ingredient; +import org.embeddedt.modernfix.duck.ICachedIngredientJS; +import org.embeddedt.modernfix.util.KubeUtil; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import java.util.Set; + +@Mixin(CustomIngredient.class) +public abstract class CustomIngredientMixin implements ICachedIngredientJS { + @Shadow @Final private Ingredient ingredient; + + @Shadow public abstract Set getStacks(); + + @Override + public Set getCachedStacks() { + Set itemSet = KubeUtil.ingredientItemCache.get(this.ingredient); + if(itemSet == null) { + itemSet = this.getStacks(); + KubeUtil.ingredientItemCache.put(this.ingredient, itemSet); + } + return itemSet; + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/IDFilterMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/IDFilterMixin.java new file mode 100644 index 00000000..c3a962ef --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/IDFilterMixin.java @@ -0,0 +1,30 @@ +package org.embeddedt.modernfix.mixin.perf.kubejs; + +import dev.latvian.kubejs.recipe.RecipeJS; +import dev.latvian.kubejs.recipe.filter.IDFilter; +import net.minecraft.resources.ResourceLocation; +import org.embeddedt.modernfix.util.KubeUtil; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(IDFilter.class) +public class IDFilterMixin { + @Shadow @Final private ResourceLocation id; + private RecipeJS _target; + private boolean _targetSearched = false; + + /** + * @author embeddedt + * @reason avoid scanning every recipe + */ + @Overwrite(remap = false) + public boolean test(RecipeJS recipe) { + if(!_targetSearched) { + _target = KubeUtil.originalRecipesByHash.get(this.id); + _targetSearched = true; + } + return recipe == _target; + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeEventJSMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeEventJSMixin.java index d6b49c95..45fe65cd 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeEventJSMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeEventJSMixin.java @@ -1,22 +1,30 @@ package org.embeddedt.modernfix.mixin.perf.kubejs; +import com.google.gson.JsonObject; import cpw.mods.modlauncher.api.LamdbaExceptionUtils; import dev.latvian.kubejs.recipe.RecipeEventJS; import dev.latvian.kubejs.recipe.RecipeJS; import dev.latvian.kubejs.recipe.filter.RecipeFilter; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.crafting.RecipeManager; +import org.embeddedt.modernfix.util.KubeUtil; import org.embeddedt.modernfix.util.ModUtil; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; 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.CallbackInfo; import java.util.List; +import java.util.Map; import java.util.function.Consumer; import java.util.stream.Collectors; @Mixin(RecipeEventJS.class) public class RecipeEventJSMixin { - @Shadow @Final private List originalRecipes; + @Shadow(remap = false) @Final private List originalRecipes; /** * @author embeddedt @@ -31,4 +39,16 @@ public class RecipeEventJSMixin { filtered.forEach(consumer); } } + + @Inject(method = "post(Lnet/minecraft/world/item/crafting/RecipeManager;Ljava/util/Map;)V", at = @At(value = "INVOKE", target = "Ldev/latvian/kubejs/recipe/RecipeEventJS;post(Ldev/latvian/kubejs/script/ScriptType;Ljava/lang/String;)Z", remap = false)) + private void buildRecipeRegistry(RecipeManager manager, Map jsonMap, CallbackInfo ci) { + for(RecipeJS recipe : this.originalRecipes) { + KubeUtil.originalRecipesByHash.put(recipe.getOrCreateId(), recipe); + } + } + + @Inject(method = "post(Lnet/minecraft/world/item/crafting/RecipeManager;Ljava/util/Map;)V", at = @At("RETURN")) + private void clearRecipeRegistry(RecipeManager manager, Map jsonMap, CallbackInfo ci) { + KubeUtil.originalRecipesByHash.clear(); + } } diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeJSMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeJSMixin.java index 9b04fa90..e15b7b54 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeJSMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeJSMixin.java @@ -1,12 +1,18 @@ package org.embeddedt.modernfix.mixin.perf.kubejs; +import dev.latvian.kubejs.item.ItemStackJS; +import dev.latvian.kubejs.item.ingredient.IngredientJS; +import dev.latvian.kubejs.item.ingredient.TagIngredientJS; import dev.latvian.kubejs.recipe.RecipeJS; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Recipe; +import org.embeddedt.modernfix.duck.ICachedIngredientJS; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; +import java.util.Set; + @Mixin(RecipeJS.class) public class RecipeJSMixin { /** @@ -19,4 +25,19 @@ public class RecipeJSMixin { return recipe.getResultItem(); } } + + @Redirect(method = "*", at = @At(value = "INVOKE", target = "Ldev/latvian/kubejs/item/ingredient/IngredientJS;anyStackMatches(Ldev/latvian/kubejs/item/ingredient/IngredientJS;)Z", remap = false)) + private boolean optimizeMatching(IngredientJS target, IngredientJS given) { + if((target instanceof TagIngredientJS && given instanceof ItemStackJS) || !(target instanceof ICachedIngredientJS)) { + /* we already have an optimized code path for this */ + return target.anyStackMatches(given); + } else { + Set givenStacks = ((ICachedIngredientJS)target).getCachedStacks(); + for(ItemStackJS stack : givenStacks) { + if(given.test(stack)) + return true; + } + return false; + } + } } diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagIngredientJSMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagIngredientJSMixin.java index 080ef036..88a75047 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagIngredientJSMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagIngredientJSMixin.java @@ -5,16 +5,22 @@ import dev.latvian.kubejs.item.ingredient.IngredientJS; import dev.latvian.kubejs.item.ingredient.TagIngredientJS; import net.minecraft.tags.Tag; import net.minecraft.world.item.Item; +import org.embeddedt.modernfix.duck.ICachedIngredientJS; +import org.embeddedt.modernfix.util.KubeUtil; 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.Set; + @Mixin(TagIngredientJS.class) -public abstract class TagIngredientJSMixin { +public abstract class TagIngredientJSMixin implements ICachedIngredientJS { @Shadow public abstract Tag getActualTag(); + @Shadow public abstract Set getStacks(); + /** * @author embeddedt * @reason avoid pointless construction of many ItemStack objects @@ -25,4 +31,15 @@ public abstract class TagIngredientJSMixin { cir.setReturnValue(((ItemStackJS)ingredient).getItem().is(this.getActualTag())); } } + + @Override + public Set getCachedStacks() { + Tag ourTag = this.getActualTag(); + Set itemSet = KubeUtil.tagItemCache.get(ourTag); + if(itemSet == null) { + itemSet = this.getStacks(); + KubeUtil.tagItemCache.put(ourTag, itemSet); + } + return itemSet; + } } diff --git a/src/main/java/org/embeddedt/modernfix/util/KubeUtil.java b/src/main/java/org/embeddedt/modernfix/util/KubeUtil.java index 1f453d47..2df2f735 100644 --- a/src/main/java/org/embeddedt/modernfix/util/KubeUtil.java +++ b/src/main/java/org/embeddedt/modernfix/util/KubeUtil.java @@ -1,20 +1,27 @@ package org.embeddedt.modernfix.util; +import dev.latvian.kubejs.item.ItemStackJS; +import dev.latvian.kubejs.recipe.RecipeJS; import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.Tag; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.crafting.Ingredient; import net.minecraftforge.event.AddReloadListenerEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import org.embeddedt.modernfix.ModernFix; -import java.util.HashMap; -import java.util.Set; +import java.util.*; -@Mod.EventBusSubscriber(modid = ModernFix.MODID) public class KubeUtil { public static final HashMap> matchedIdsForRegex = new HashMap<>(); + public static final HashMap originalRecipesByHash = new HashMap<>(); + public static Map> ingredientItemCache = Collections.synchronizedMap(new WeakHashMap<>()); + public static Map, Set> tagItemCache = Collections.synchronizedMap(new WeakHashMap<>()); + @SubscribeEvent public static void clearRegexCache(AddReloadListenerEvent event) { matchedIdsForRegex.clear(); + ingredientItemCache.clear(); + tagItemCache.clear(); } } diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index eb6d129c..06b9688f 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -45,7 +45,9 @@ "perf.kubejs.TagIngredientJSMixin", "perf.kubejs.TagWrapperMixin", "perf.kubejs.RecipeEventJSMixin", - "perf.kubejs.RecipeJSMixin" + "perf.kubejs.RecipeJSMixin", + "perf.kubejs.IDFilterMixin", + "perf.kubejs.CustomIngredientMixin" ], "client": [ "feature.measure_time.MinecraftMixin", From aa963f4d1ab38b3195b9c3af6e30467e8c02e348 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 20 Feb 2023 11:43:26 -0500 Subject: [PATCH 19/31] Allow COW in StaticTagHelper Seems that some mods bind tags at runtime. This is a hack but it should fix the persistent CME I get when launching ATM6 --- .../concurrency/StaticTagHelperMixin.java | 28 +++++++++++++++++++ src/main/resources/modernfix.mixins.json | 1 + 2 files changed, 29 insertions(+) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/bugfix/concurrency/StaticTagHelperMixin.java diff --git a/src/main/java/org/embeddedt/modernfix/mixin/bugfix/concurrency/StaticTagHelperMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/concurrency/StaticTagHelperMixin.java new file mode 100644 index 00000000..17d1d698 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/concurrency/StaticTagHelperMixin.java @@ -0,0 +1,28 @@ +package org.embeddedt.modernfix.mixin.bugfix.concurrency; + +import net.minecraft.tags.StaticTagHelper; +import net.minecraft.tags.TagCollection; +import net.minecraft.tags.TagContainer; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +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.CallbackInfo; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Function; + +@Mixin(StaticTagHelper.class) +public class StaticTagHelperMixin { + @SuppressWarnings("rawtypes") + @Shadow @Mutable + @Final private List wrappers; + + @Inject(method = "", at = @At("RETURN")) + private void useCOWArrayList(Function> function, CallbackInfo ci) { + this.wrappers = new CopyOnWriteArrayList<>(); + } +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 06b9688f..452ed23a 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -55,6 +55,7 @@ "perf.skip_first_datapack_reload.MinecraftMixin", "bugfix.concurrency.RenderTypeMixin", "bugfix.concurrency.MinecraftMixin", + "bugfix.concurrency.StaticTagHelperMixin", "perf.parallelize_model_loading.ModelBakeryMixin", "perf.parallelize_model_loading.OBJLoaderMixin", "perf.parallelize_model_loading.multipart.MultipartMixin", From d7d1ba0993d1176a29f9cfab6fd75406a181e00b Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 20 Feb 2023 12:11:46 -0500 Subject: [PATCH 20/31] Make client-only injection not required Fixes #23 --- .../perf/compress_biome_container/MixinBiomeContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/compress_biome_container/MixinBiomeContainer.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/compress_biome_container/MixinBiomeContainer.java index 857e593c..d9abc9ab 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/compress_biome_container/MixinBiomeContainer.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/compress_biome_container/MixinBiomeContainer.java @@ -32,7 +32,7 @@ public class MixinBiomeContainer { private Biome[] palette; private BitStorage intArray; - @Inject(method = "(Lnet/minecraft/core/IdMap;[I)V", at = @At("RETURN")) + @Inject(method = "(Lnet/minecraft/core/IdMap;[I)V", at = @At("RETURN"), require = 0) private void reinit1(IdMap p_i241970_1_, int[] p_i241970_2_, CallbackInfo ci) { this.createCompact(); } From b57799ceddfc93c54de319b24d9434cf6fa28200 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 20 Feb 2023 12:12:08 -0500 Subject: [PATCH 21/31] 1.7.0 - KubeJS optimizations + minor bugfixes --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index cc0a8c08..bc597436 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ plugins { sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8 group = 'org.embeddedt' -version = '1.6.1' +version = '1.7.0' java { archivesBaseName = 'modernfix-mc' + minecraft_version From 749c4e1d9deca20971bf7084d5a909f6f4998616 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Tue, 21 Feb 2023 09:38:17 -0500 Subject: [PATCH 22/31] Add CTM to dev env --- build.gradle | 4 ++++ gradle.properties | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index bc597436..912043b0 100644 --- a/build.gradle +++ b/build.gradle @@ -58,6 +58,9 @@ repositories { includeGroup "dev.latvian.mods" } } + maven { // CTM + url "https://maven.tterrag.com/" + } } dependencies { @@ -87,6 +90,7 @@ dependencies { modCompileOnly("curse.maven:refinedstorage-243076:${refined_storage_version}") modImplementation("dev.latvian.mods:kubejs-forge:${kubejs_version}") + modImplementation("team.chisel.ctm:CTM:${ctm_version}") } tasks.withType(JavaCompile) { diff --git a/gradle.properties b/gradle.properties index 6361e3d5..80b27551 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,4 +15,5 @@ mekanism_version=1.16.5-10.1.2.457 parchment_version=2022.03.06 jei_version=7.7.1.153 refined_storage_version=3807951 -kubejs_version=1605.3.19-build.299 \ No newline at end of file +kubejs_version=1605.3.19-build.299 +ctm_version=MC1.16.1-1.1.2.6 \ No newline at end of file From cb6399e820eb9828a69bfcabaf7ab900fd86520f Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Tue, 21 Feb 2023 11:26:46 -0500 Subject: [PATCH 23/31] Port faster texture stitching by SuperCoder79 --- .../core/config/ModernFixEarlyConfig.java | 1 + .../StitcherMixin.java | 54 +++++++++++ .../modernfix/textures/StbStitcher.java | 90 +++++++++++++++++++ .../resources/META-INF/accesstransformer.cfg | 3 +- src/main/resources/modernfix.mixins.json | 1 + 5 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/faster_texture_stitching/StitcherMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java 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 7add26e8..d1a1ceb3 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -44,6 +44,7 @@ public class ModernFixEarlyConfig { this.addMixinRule("perf.cache_model_materials", true); this.addMixinRule("perf.datapack_reload_exceptions", true); this.addMixinRule("perf.async_locator", true); + this.addMixinRule("perf.faster_texture_stitching", true); this.addMixinRule("perf.kubejs", true); /* Keep this off if JEI isn't installed to prevent breaking vanilla gameplay */ this.addMixinRule("perf.blast_search_trees", FMLLoader.getLoadingModList().getModFileById("jei") != null); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_texture_stitching/StitcherMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_texture_stitching/StitcherMixin.java new file mode 100644 index 00000000..247f96ce --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_texture_stitching/StitcherMixin.java @@ -0,0 +1,54 @@ +package org.embeddedt.modernfix.mixin.perf.faster_texture_stitching; + +import com.mojang.datafixers.util.Pair; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.client.renderer.texture.Stitcher; +import org.embeddedt.modernfix.textures.StbStitcher; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.Set; + +@Mixin(Stitcher.class) +public class StitcherMixin { + @Shadow @Final private Set texturesToBeStitched; + + @Shadow private int storageX; + + @Shadow private int storageY; + + @Shadow @Final private static Comparator HOLDER_COMPARATOR; + private List loadableSpriteInfos; + + /** + * @author embeddedt, SuperCoder79 + * @reason Use improved STB stitcher instead of the vanilla implementation, for performance + */ + @Overwrite + public void stitch() { + ObjectArrayList holderList = new ObjectArrayList<>(this.texturesToBeStitched); + holderList.sort(HOLDER_COMPARATOR); + Stitcher.Holder[] aholder = holderList.toArray(new Stitcher.Holder[0]); + + Pair, List> packingInfo = StbStitcher.packRects(aholder); + this.storageX = packingInfo.getFirst().getFirst(); + this.storageY = packingInfo.getFirst().getSecond(); + this.loadableSpriteInfos = packingInfo.getSecond(); + } + + /** + * @author embeddedt, SuperCoder79 + * @reason We setup the image ourselves in the StbStitcher, so we just feed this information back into the vanilla code + */ + @Overwrite + public void gatherSprites(Stitcher.SpriteLoader spriteLoader) { + for(StbStitcher.LoadableSpriteInfo info : loadableSpriteInfos) { + spriteLoader.load(info.info, info.width, info.height, info.x, info.y); + } + } +} diff --git a/src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java b/src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java new file mode 100644 index 00000000..cc386233 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java @@ -0,0 +1,90 @@ +package org.embeddedt.modernfix.textures; + +import com.google.common.collect.ImmutableList; +import com.mojang.datafixers.util.Pair; +import net.minecraft.client.renderer.texture.Stitcher; +import net.minecraft.client.renderer.texture.StitcherException; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.util.Mth; +import org.lwjgl.stb.STBRPContext; +import org.lwjgl.stb.STBRPNode; +import org.lwjgl.stb.STBRPRect; +import org.lwjgl.stb.STBRectPack; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +/* Source: https://github.com/GTNewHorizons/lwjgl3ify/blob/f21364cd3d178aef863458a2faa1f5718a4e350d/src/main/java/me/eigenraven/lwjgl3ify/textures/StbStitcher.java */ +public class StbStitcher { + public static Pair, List> packRects(Stitcher.Holder[] holders) { + int holderSize = holders.length; + + List infoList = new ArrayList<>(); + + // Allocate memory for the rectangles and the context + try (STBRPRect.Buffer rectBuf = STBRPRect.malloc(holderSize); + STBRPContext ctx = STBRPContext.malloc(); ) { + + // Initialize the rectangles that we'll be using in the calculation + // While that's happening, sum up the area needed to fit all of the images + int sqSize = 0; + for (int j = 0; j < holderSize; ++j) { + Stitcher.Holder holder = holders[j]; + + int width = holder.width; + int height = holder.height; + + // The ID here is just the array index, for easy lookup later + rectBuf.get(j).set(j, (short)width, (short)height, (short)0, (short)0, false); + + sqSize += (width * height); + } + + int size = Mth.smallestEncompassingPowerOfTwo((int) Math.sqrt(sqSize)); + int width = size * 2; // needed to fix weirdness in 1.16 + int height = size; + + // Internal node structure needed for STB + try (STBRPNode.Buffer nodes = STBRPNode.malloc(width + 10)) { + // Initialize the rect packer + STBRectPack.stbrp_init_target(ctx, width, height, nodes); + + // Perform rectangle packing + STBRectPack.stbrp_pack_rects(ctx, rectBuf); + + for (STBRPRect rect : rectBuf) { + Stitcher.Holder holder = holders[rect.id()]; + + // Ensure that everything is properly packed! + if (!rect.was_packed()) { + throw new StitcherException(holder.spriteInfo, + Stream.of(holders).map(arg -> arg.spriteInfo).collect(ImmutableList.toImmutableList())); + } + + // Initialize the sprite now with the position and size that we've calculated so far + infoList.add(new LoadableSpriteInfo(holder.spriteInfo, width, height, rect.x(), rect.y())); + //holder.spriteInfo.initSprite(size, size, rect.x(), rect.y(), false); + } + + return Pair.of(Pair.of(width, height), infoList); + } + } + } + + public static class LoadableSpriteInfo { + public final TextureAtlasSprite.Info info; + public final int width; + public final int height; + public final int x; + public final int y; + + LoadableSpriteInfo(TextureAtlasSprite.Info info, int width, int height, int x, int y) { + this.info = info; + this.width = width; + this.height = height; + this.x = x; + this.y = y; + } + } +} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index aa68abed..0d376b05 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -4,4 +4,5 @@ public net.minecraft.client.renderer.RenderType$CompositeRenderType (Ljava public net.minecraft.world.level.block.state.BlockBehaviour$BlockStateBase$Cache public net.minecraft.world.phys.shapes.VoxelShape (Lnet/minecraft/util/math/shapes/VoxelShapePart;)V # public net.minecraft.client.resources.model.ModelBakery$BlockStateDefinitionException -public net.minecraft.client.renderer.model.ModelBakery field_217849_F # unbakedCache \ No newline at end of file +public net.minecraft.client.renderer.model.ModelBakery field_217849_F # unbakedCache +public net.minecraft.client.renderer.texture.Stitcher$Holder \ No newline at end of file diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 452ed23a..80a036d6 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -81,6 +81,7 @@ "perf.faster_baking.ModelManagerMixin", "perf.cache_model_materials.VanillaModelMixin", "perf.cache_model_materials.MultipartMixin", + "perf.faster_texture_stitching.StitcherMixin", "bugfix.packet_leak.ClientPlayNetHandlerMixin", "bugfix.packet_leak.SCustomPayloadPlayPacketMixin" ], From bc5b85efcca5460bcfa3a9020b0314ed364c3ec5 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Tue, 21 Feb 2023 22:24:50 -0500 Subject: [PATCH 24/31] Move 441 chunk loading to after join game packets are sent on integrated server --- .../embeddedt/modernfix/ModernFixClient.java | 93 +++++++++++++++++++ .../core/config/ModernFixEarlyConfig.java | 1 + .../MinecraftServerMixin.java | 40 ++++++++ .../screen/DeferredLevelLoadingScreen.java | 27 ++++++ .../resources/META-INF/accesstransformer.cfg | 5 +- src/main/resources/modernfix.mixins.json | 3 +- 6 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/faster_singleplayer_load/MinecraftServerMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/screen/DeferredLevelLoadingScreen.java diff --git a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java index 33974e37..9f8db69f 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java @@ -1,14 +1,33 @@ package org.embeddedt.modernfix; +import it.unimi.dsi.fastutil.longs.LongIterator; +import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.ConnectScreen; +import net.minecraft.client.gui.screens.LevelLoadingScreen; +import net.minecraft.client.gui.screens.ProgressScreen; import net.minecraft.client.gui.screens.TitleScreen; +import net.minecraft.client.server.IntegratedServer; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.*; +import net.minecraft.server.level.progress.ChunkProgressListener; +import net.minecraft.util.Unit; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.ForcedChunksSavedData; import net.minecraftforge.client.event.GuiOpenEvent; +import net.minecraftforge.common.world.ForgeChunkManager; import net.minecraftforge.event.TickEvent; +import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent; +import net.minecraftforge.fml.server.ServerLifecycleHooks; +import org.embeddedt.modernfix.screen.DeferredLevelLoadingScreen; import java.lang.management.ManagementFactory; +import java.util.concurrent.locks.LockSupport; +import java.util.function.BooleanSupplier; public class ModernFixClient { @@ -42,4 +61,78 @@ public class ModernFixClient { } } + private boolean hasFirstPlayerJoined = false; + + @SubscribeEvent + public void serverWillStart(FMLServerAboutToStartEvent event) { + hasFirstPlayerJoined = false; + } + + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) { + if(!hasFirstPlayerJoined && integratedWorldLoadListener != null) { + hasFirstPlayerJoined = true; + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + if(server instanceof IntegratedServer) { + handleInitialChunkLoad(); + } + } + } + + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onWorldShow(GuiOpenEvent event) { + if(ServerLifecycleHooks.getCurrentServer() instanceof IntegratedServer && integratedWorldLoadListener != null) { + if(event.getGui() == null && Minecraft.getInstance().level != null) { + /* this means the world is being displayed, check if 441 initialized */ + ServerChunkCache provider = ServerLifecycleHooks.getCurrentServer().overworld().getChunkSource(); + BooleanSupplier worldLoadDone = () -> provider.getTickingGenerated() >= 441; + if(!worldLoadDone.getAsBoolean()) { + DeferredLevelLoadingScreen newScreen = new DeferredLevelLoadingScreen(Minecraft.getInstance().progressListener.get(), worldLoadDone); + event.setGui(newScreen); + } + } else if(event.getGui() instanceof LevelLoadingScreen && Minecraft.getInstance().level == null) { + ProgressScreen loadscreen = new ProgressScreen(); + loadscreen.progressStartNoAbort(new TranslatableComponent("connect.joining")); + event.setGui(loadscreen); + } + } + } + + public static ChunkProgressListener integratedWorldLoadListener; + + private void handleInitialChunkLoad() { + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + ServerLevel overworld = server.overworld(); + ServerChunkCache provider = overworld.getChunkSource(); + provider.getLightEngine().setTaskPerBatch(500); + provider.addRegionTicket(TicketType.START, new ChunkPos(overworld.getSharedSpawnPos()), 11, Unit.INSTANCE); + while(provider.getTickingGenerated() < 441) { + server.runAllTasks(); + Thread.yield(); + LockSupport.parkNanos("waiting for world load", 100000L); + server.nextTickTime = Util.getMillis() + 10; + } + for(ServerLevel serverworld1 : server.getAllLevels()) { + ForcedChunksSavedData forcedchunkssavedata = serverworld1.getDataStorage().get(ForcedChunksSavedData::new, "chunks"); + if (forcedchunkssavedata != null) { + LongIterator longiterator = forcedchunkssavedata.getChunks().iterator(); + + while(longiterator.hasNext()) { + long i = longiterator.nextLong(); + ChunkPos chunkpos = new ChunkPos(i); + serverworld1.getChunkSource().updateChunkForced(chunkpos, true); + } + + ForgeChunkManager.reinstatePersistentChunks(serverworld1, forcedchunkssavedata); + } + } + server.runAllTasks(); + server.nextTickTime = Util.getMillis() + 10; + provider.getLightEngine().setTaskPerBatch(5); + if(integratedWorldLoadListener != null) { + integratedWorldLoadListener.stop(); + integratedWorldLoadListener = null; + } + } + } 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 d1a1ceb3..c94b8b24 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -46,6 +46,7 @@ public class ModernFixEarlyConfig { this.addMixinRule("perf.async_locator", true); this.addMixinRule("perf.faster_texture_stitching", true); this.addMixinRule("perf.kubejs", true); + this.addMixinRule("perf.faster_singleplayer_load", true); /* Keep this off if JEI isn't installed to prevent breaking vanilla gameplay */ this.addMixinRule("perf.blast_search_trees", FMLLoader.getLoadingModList().getModFileById("jei") != null); this.addMixinRule("safety", true); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_singleplayer_load/MinecraftServerMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_singleplayer_load/MinecraftServerMixin.java new file mode 100644 index 00000000..2596c9ce --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_singleplayer_load/MinecraftServerMixin.java @@ -0,0 +1,40 @@ +package org.embeddedt.modernfix.mixin.perf.faster_singleplayer_load; + +import net.minecraft.Util; +import net.minecraft.client.server.IntegratedServer; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.progress.ChunkProgressListener; +import org.embeddedt.modernfix.ModernFixClient; +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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(MinecraftServer.class) +public abstract class MinecraftServerMixin { + @Shadow protected long nextTickTime; + + @Shadow public abstract ServerLevel overworld(); + + @Shadow protected abstract void updateMobSpawningFlags(); + + /** + * @author embeddedt + * @reason defer the 441 chunk load until *after* join game packets are sent to the client, in order to allow + * mods that process advancements, etc. to work on that at the same time + */ + @Inject(method = "prepareLevels", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;getChunkSource()Lnet/minecraft/server/level/ServerChunkCache;", ordinal = 0), cancellable = true) + private void skipInitialChunkLoad(ChunkProgressListener arg, CallbackInfo ci) { + if(((Object)this) instanceof IntegratedServer) { + ci.cancel(); + ModernFixClient.integratedWorldLoadListener = arg; + this.nextTickTime = Util.getMillis(); + this.overworld().getChunkSource().getLightEngine().setTaskPerBatch(5); + this.updateMobSpawningFlags(); + } + } +} diff --git a/src/main/java/org/embeddedt/modernfix/screen/DeferredLevelLoadingScreen.java b/src/main/java/org/embeddedt/modernfix/screen/DeferredLevelLoadingScreen.java new file mode 100644 index 00000000..cd49687a --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/screen/DeferredLevelLoadingScreen.java @@ -0,0 +1,27 @@ +package org.embeddedt.modernfix.screen; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.gui.screens.LevelLoadingScreen; +import net.minecraft.server.level.progress.StoringChunkProgressListener; + +import java.util.function.BooleanSupplier; + +public class DeferredLevelLoadingScreen extends LevelLoadingScreen { + private final BooleanSupplier worldLoadFinished; + public DeferredLevelLoadingScreen(StoringChunkProgressListener arg, BooleanSupplier worldLoadFinished) { + super(arg); + this.worldLoadFinished = worldLoadFinished; + } + + @Override + public void tick() { + super.tick(); + if(this.worldLoadFinished.getAsBoolean()) + this.onClose(); + } + + @Override + public void renderBackground(PoseStack matrixStack, int vOffset) { + renderDirtBackground(vOffset); + } +} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 0d376b05..47aa894e 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -5,4 +5,7 @@ public net.minecraft.world.level.block.state.BlockBehaviour$BlockStateBase$Cache public net.minecraft.world.phys.shapes.VoxelShape (Lnet/minecraft/util/math/shapes/VoxelShapePart;)V # public net.minecraft.client.resources.model.ModelBakery$BlockStateDefinitionException public net.minecraft.client.renderer.model.ModelBakery field_217849_F # unbakedCache -public net.minecraft.client.renderer.texture.Stitcher$Holder \ No newline at end of file +public net.minecraft.client.renderer.texture.Stitcher$Holder +public net.minecraft.util.concurrent.ThreadTaskExecutor func_213160_bf()V # runAllTasks +public net.minecraft.server.MinecraftServer field_211151_aa # nextTickTime +public net.minecraft.client.Minecraft field_213277_ad # progressListener \ No newline at end of file diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 80a036d6..f7a43a5a 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -83,7 +83,8 @@ "perf.cache_model_materials.MultipartMixin", "perf.faster_texture_stitching.StitcherMixin", "bugfix.packet_leak.ClientPlayNetHandlerMixin", - "bugfix.packet_leak.SCustomPayloadPlayPacketMixin" + "bugfix.packet_leak.SCustomPayloadPlayPacketMixin", + "perf.faster_singleplayer_load.MinecraftServerMixin" ], "injectors": { "defaultRequire": 1 From a4ce490963605bc3fb3bb5013a9c6431f1196957 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Tue, 21 Feb 2023 22:35:29 -0500 Subject: [PATCH 25/31] Fix main thread not actually blocking until JEI thread finishes --- .../mixin/perf/async_jei/ClientLifecycleHandlerMixin.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/async_jei/ClientLifecycleHandlerMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/async_jei/ClientLifecycleHandlerMixin.java index 329b0018..6a1d664b 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/async_jei/ClientLifecycleHandlerMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/async_jei/ClientLifecycleHandlerMixin.java @@ -66,7 +66,10 @@ public class ClientLifecycleHandlerMixin { JEIReloadThread currentReloadThread = reloadThread; if(currentReloadThread != null) { currentReloadThread.requestStop(); - Minecraft.getInstance().managedBlock(currentReloadThread::isAlive); + if(currentReloadThread.isAlive()) { + ModernFix.LOGGER.warn("Blocking until JEI thread terminates"); + Minecraft.getInstance().managedBlock(() -> !currentReloadThread.isAlive()); + } reloadThread = null; } } @@ -74,7 +77,6 @@ public class ClientLifecycleHandlerMixin { private static int numReloads = 1; private void startJEIAsync(Runnable whenFinishedCb) { - ModernFix.LOGGER.info("JEI restart triggered. Waiting for previous thread to die."); cancelPreviousStart(); ModernFix.LOGGER.info("Starting new JEI thread."); JEIReloadThread newThread = new JEIReloadThread(() -> { From 2b7d79f4a7058467249c7c1ca6ea8fb6f04b179a Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Tue, 21 Feb 2023 22:35:45 -0500 Subject: [PATCH 26/31] Ensure configurability of faster singleplayer load works --- src/main/java/org/embeddedt/modernfix/ModernFixClient.java | 6 ++++-- .../org/embeddedt/modernfix/core/ModernFixMixinPlugin.java | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java index 9f8db69f..27b1df1b 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java @@ -23,6 +23,8 @@ import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent; import net.minecraftforge.fml.server.ServerLifecycleHooks; +import org.embeddedt.modernfix.core.ModernFixMixinPlugin; +import org.embeddedt.modernfix.core.config.ModernFixEarlyConfig; import org.embeddedt.modernfix.screen.DeferredLevelLoadingScreen; import java.lang.management.ManagementFactory; @@ -70,7 +72,7 @@ public class ModernFixClient { @SubscribeEvent(priority = EventPriority.LOWEST) public void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) { - if(!hasFirstPlayerJoined && integratedWorldLoadListener != null) { + if(!hasFirstPlayerJoined && ModernFixMixinPlugin.instance.isOptionEnabled("perf.faster_singleplayer_load.ClientEvents")) { hasFirstPlayerJoined = true; MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); if(server instanceof IntegratedServer) { @@ -81,7 +83,7 @@ public class ModernFixClient { @SubscribeEvent(priority = EventPriority.LOWEST) public void onWorldShow(GuiOpenEvent event) { - if(ServerLifecycleHooks.getCurrentServer() instanceof IntegratedServer && integratedWorldLoadListener != null) { + if(ServerLifecycleHooks.getCurrentServer() instanceof IntegratedServer && ModernFixMixinPlugin.instance.isOptionEnabled("perf.faster_singleplayer_load.ClientEvents")) { if(event.getGui() == null && Minecraft.getInstance().level != null) { /* this means the world is being displayed, check if 441 initialized */ ServerChunkCache provider = ServerLifecycleHooks.getCurrentServer().overworld().getChunkSource(); diff --git a/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java b/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java index bbc4dcc0..31ccf154 100644 --- a/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java +++ b/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java @@ -28,8 +28,10 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin { private final Logger logger = LogManager.getLogger("ModernFix"); public static ModernFixEarlyConfig config = null; + public static ModernFixMixinPlugin instance; public ModernFixMixinPlugin() { + instance = this; try { config = ModernFixEarlyConfig.load(new File("./config/modernfix-mixins.properties")); } catch (Exception e) { From 145213afa8e68e512146fcf5afea9044895095a5 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Tue, 21 Feb 2023 22:51:38 -0500 Subject: [PATCH 27/31] Minor bugfixes to faster singleplayer load --- src/main/java/org/embeddedt/modernfix/ModernFixClient.java | 2 +- src/main/java/org/embeddedt/modernfix/util/JEIUtil.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java index 27b1df1b..4d1a3ce4 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java @@ -55,7 +55,7 @@ public class ModernFixClient { @SubscribeEvent public void onRenderTickEnd(TickEvent.RenderTickEvent event) { - if(event.phase == TickEvent.Phase.END && worldLoadStartTime != -1 && Minecraft.getInstance().player != null && numRenderTicks++ >= 10) { + if(event.phase == TickEvent.Phase.END && !(Minecraft.getInstance().screen instanceof DeferredLevelLoadingScreen) && worldLoadStartTime != -1 && Minecraft.getInstance().player != null && numRenderTicks++ >= 10) { float timeSpentLoading = ((float)(System.nanoTime() - worldLoadStartTime) / 1000000000f); ModernFix.LOGGER.warn("Time from main menu to in-game was " + timeSpentLoading + " seconds"); ModernFix.LOGGER.warn("Total time to load game and open world was " + (timeSpentLoading + gameStartTimeSeconds) + " seconds"); diff --git a/src/main/java/org/embeddedt/modernfix/util/JEIUtil.java b/src/main/java/org/embeddedt/modernfix/util/JEIUtil.java index 230045ea..59e6b244 100644 --- a/src/main/java/org/embeddedt/modernfix/util/JEIUtil.java +++ b/src/main/java/org/embeddedt/modernfix/util/JEIUtil.java @@ -10,6 +10,7 @@ import net.minecraft.network.chat.TranslatableComponent; import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.SubscribeEvent; +import org.embeddedt.modernfix.screen.DeferredLevelLoadingScreen; import java.util.function.Supplier; @@ -23,7 +24,8 @@ public class JEIUtil { @SubscribeEvent public static void renderLoad(GuiScreenEvent.DrawScreenEvent.Post event) { - if(isLoading.get()) { + /* Don't show the JEI indicator on the level loading screen, that looks weird */ + if(isLoading.get() && !(event.getGui() instanceof DeferredLevelLoadingScreen)) { Gui.drawString(new PoseStack(), Minecraft.getInstance().font, new TranslatableComponent("modernfix.jei_load"), 0, 0, 0xffffff); } } From c258bba5ec8b301c347c3b384ff298deefbf2beb Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 22 Feb 2023 11:44:56 -0500 Subject: [PATCH 28/31] Minor code cleanup --- .../embeddedt/modernfix/ModernFixClient.java | 103 ++-------------- .../embeddedt/modernfix/load/LoadEvents.java | 113 ++++++++++++++++++ .../MinecraftServerMixin.java | 3 +- 3 files changed, 123 insertions(+), 96 deletions(-) create mode 100644 src/main/java/org/embeddedt/modernfix/load/LoadEvents.java diff --git a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java index 4d1a3ce4..1ce231d7 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java @@ -1,43 +1,31 @@ package org.embeddedt.modernfix; -import it.unimi.dsi.fastutil.longs.LongIterator; -import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.ConnectScreen; -import net.minecraft.client.gui.screens.LevelLoadingScreen; -import net.minecraft.client.gui.screens.ProgressScreen; import net.minecraft.client.gui.screens.TitleScreen; -import net.minecraft.client.server.IntegratedServer; -import net.minecraft.network.chat.TranslatableComponent; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.*; -import net.minecraft.server.level.progress.ChunkProgressListener; -import net.minecraft.util.Unit; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.ForcedChunksSavedData; import net.minecraftforge.client.event.GuiOpenEvent; -import net.minecraftforge.common.world.ForgeChunkManager; +import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.TickEvent; -import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent; -import net.minecraftforge.fml.server.ServerLifecycleHooks; import org.embeddedt.modernfix.core.ModernFixMixinPlugin; -import org.embeddedt.modernfix.core.config.ModernFixEarlyConfig; +import org.embeddedt.modernfix.load.LoadEvents; import org.embeddedt.modernfix.screen.DeferredLevelLoadingScreen; import java.lang.management.ManagementFactory; -import java.util.concurrent.locks.LockSupport; -import java.util.function.BooleanSupplier; public class ModernFixClient { - public static long worldLoadStartTime; private static int numRenderTicks; public static float gameStartTimeSeconds = -1; + public ModernFixClient() { + if(ModernFixMixinPlugin.instance.isOptionEnabled("perf.faster_singleplayer_load.ClientEvents")) { + MinecraftForge.EVENT_BUS.register(new LoadEvents()); + } + } + public void resetWorldLoadStateMachine() { numRenderTicks = 0; worldLoadStartTime = -1; @@ -62,79 +50,4 @@ public class ModernFixClient { resetWorldLoadStateMachine(); } } - - private boolean hasFirstPlayerJoined = false; - - @SubscribeEvent - public void serverWillStart(FMLServerAboutToStartEvent event) { - hasFirstPlayerJoined = false; - } - - @SubscribeEvent(priority = EventPriority.LOWEST) - public void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) { - if(!hasFirstPlayerJoined && ModernFixMixinPlugin.instance.isOptionEnabled("perf.faster_singleplayer_load.ClientEvents")) { - hasFirstPlayerJoined = true; - MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); - if(server instanceof IntegratedServer) { - handleInitialChunkLoad(); - } - } - } - - @SubscribeEvent(priority = EventPriority.LOWEST) - public void onWorldShow(GuiOpenEvent event) { - if(ServerLifecycleHooks.getCurrentServer() instanceof IntegratedServer && ModernFixMixinPlugin.instance.isOptionEnabled("perf.faster_singleplayer_load.ClientEvents")) { - if(event.getGui() == null && Minecraft.getInstance().level != null) { - /* this means the world is being displayed, check if 441 initialized */ - ServerChunkCache provider = ServerLifecycleHooks.getCurrentServer().overworld().getChunkSource(); - BooleanSupplier worldLoadDone = () -> provider.getTickingGenerated() >= 441; - if(!worldLoadDone.getAsBoolean()) { - DeferredLevelLoadingScreen newScreen = new DeferredLevelLoadingScreen(Minecraft.getInstance().progressListener.get(), worldLoadDone); - event.setGui(newScreen); - } - } else if(event.getGui() instanceof LevelLoadingScreen && Minecraft.getInstance().level == null) { - ProgressScreen loadscreen = new ProgressScreen(); - loadscreen.progressStartNoAbort(new TranslatableComponent("connect.joining")); - event.setGui(loadscreen); - } - } - } - - public static ChunkProgressListener integratedWorldLoadListener; - - private void handleInitialChunkLoad() { - MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); - ServerLevel overworld = server.overworld(); - ServerChunkCache provider = overworld.getChunkSource(); - provider.getLightEngine().setTaskPerBatch(500); - provider.addRegionTicket(TicketType.START, new ChunkPos(overworld.getSharedSpawnPos()), 11, Unit.INSTANCE); - while(provider.getTickingGenerated() < 441) { - server.runAllTasks(); - Thread.yield(); - LockSupport.parkNanos("waiting for world load", 100000L); - server.nextTickTime = Util.getMillis() + 10; - } - for(ServerLevel serverworld1 : server.getAllLevels()) { - ForcedChunksSavedData forcedchunkssavedata = serverworld1.getDataStorage().get(ForcedChunksSavedData::new, "chunks"); - if (forcedchunkssavedata != null) { - LongIterator longiterator = forcedchunkssavedata.getChunks().iterator(); - - while(longiterator.hasNext()) { - long i = longiterator.nextLong(); - ChunkPos chunkpos = new ChunkPos(i); - serverworld1.getChunkSource().updateChunkForced(chunkpos, true); - } - - ForgeChunkManager.reinstatePersistentChunks(serverworld1, forcedchunkssavedata); - } - } - server.runAllTasks(); - server.nextTickTime = Util.getMillis() + 10; - provider.getLightEngine().setTaskPerBatch(5); - if(integratedWorldLoadListener != null) { - integratedWorldLoadListener.stop(); - integratedWorldLoadListener = null; - } - } - } diff --git a/src/main/java/org/embeddedt/modernfix/load/LoadEvents.java b/src/main/java/org/embeddedt/modernfix/load/LoadEvents.java new file mode 100644 index 00000000..a7f6e158 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/load/LoadEvents.java @@ -0,0 +1,113 @@ +package org.embeddedt.modernfix.load; + +import it.unimi.dsi.fastutil.longs.LongIterator; +import net.minecraft.Util; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.LevelLoadingScreen; +import net.minecraft.client.gui.screens.ProgressScreen; +import net.minecraft.client.server.IntegratedServer; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.TicketType; +import net.minecraft.server.level.progress.ChunkProgressListener; +import net.minecraft.util.Unit; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.ForcedChunksSavedData; +import net.minecraftforge.client.event.GuiOpenEvent; +import net.minecraftforge.common.world.ForgeChunkManager; +import net.minecraftforge.event.entity.player.PlayerEvent; +import net.minecraftforge.eventbus.api.EventPriority; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent; +import net.minecraftforge.fml.server.ServerLifecycleHooks; +import org.embeddedt.modernfix.core.ModernFixMixinPlugin; +import org.embeddedt.modernfix.screen.DeferredLevelLoadingScreen; + +import java.util.concurrent.locks.LockSupport; +import java.util.function.BooleanSupplier; + +/** + * Handles deferring the world load screen. + *

+ * TODO: The vanilla check that at least 441 chunks have been loaded does not check whether they are spawn chunks + * or chunks loaded by the player. Consequently it is possible for loading to finish before every spawn chunk has + * been loaded. However the chunk system has at least been warmed up by this point so the remaining chunks load + * reasonably quickly. + */ +public class LoadEvents { + private boolean hasFirstPlayerJoined = false; + + @SubscribeEvent + public void serverWillStart(FMLServerAboutToStartEvent event) { + hasFirstPlayerJoined = false; + } + + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) { + if(!hasFirstPlayerJoined && ModernFixMixinPlugin.instance.isOptionEnabled("perf.faster_singleplayer_load.ClientEvents")) { + hasFirstPlayerJoined = true; + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + if(server instanceof IntegratedServer) { + handleInitialChunkLoad(); + } + } + } + + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onWorldShow(GuiOpenEvent event) { + if(ServerLifecycleHooks.getCurrentServer() instanceof IntegratedServer) { + if(event.getGui() == null && Minecraft.getInstance().level != null && integratedWorldLoadListener != null) { + /* this means the world is about to be displayed, check if 441 initialized */ + ServerChunkCache provider = ServerLifecycleHooks.getCurrentServer().overworld().getChunkSource(); + BooleanSupplier worldLoadDone = () -> provider.getTickingGenerated() >= 441; + if(!worldLoadDone.getAsBoolean()) { + DeferredLevelLoadingScreen newScreen = new DeferredLevelLoadingScreen(Minecraft.getInstance().progressListener.get(), worldLoadDone); + event.setGui(newScreen); + } + } else if(event.getGui() instanceof LevelLoadingScreen && Minecraft.getInstance().level == null && ModernFixMixinPlugin.instance.isOptionEnabled("perf.faster_singleplayer_load.ClientEvents")) { + ProgressScreen loadscreen = new ProgressScreen(); + loadscreen.progressStartNoAbort(new TranslatableComponent("connect.joining")); + event.setGui(loadscreen); + } + } + } + + public static ChunkProgressListener integratedWorldLoadListener; + + private void handleInitialChunkLoad() { + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + ServerLevel overworld = server.overworld(); + ServerChunkCache provider = overworld.getChunkSource(); + provider.getLightEngine().setTaskPerBatch(500); + provider.addRegionTicket(TicketType.START, new ChunkPos(overworld.getSharedSpawnPos()), 11, Unit.INSTANCE); + while(provider.getTickingGenerated() < 441) { + server.runAllTasks(); + Thread.yield(); + LockSupport.parkNanos("waiting for world load", 100000L); + server.nextTickTime = Util.getMillis() + 10; + } + for(ServerLevel serverworld1 : server.getAllLevels()) { + ForcedChunksSavedData forcedchunkssavedata = serverworld1.getDataStorage().get(ForcedChunksSavedData::new, "chunks"); + if (forcedchunkssavedata != null) { + LongIterator longiterator = forcedchunkssavedata.getChunks().iterator(); + + while(longiterator.hasNext()) { + long i = longiterator.nextLong(); + ChunkPos chunkpos = new ChunkPos(i); + serverworld1.getChunkSource().updateChunkForced(chunkpos, true); + } + + ForgeChunkManager.reinstatePersistentChunks(serverworld1, forcedchunkssavedata); + } + } + server.runAllTasks(); + server.nextTickTime = Util.getMillis() + 10; + provider.getLightEngine().setTaskPerBatch(5); + if(integratedWorldLoadListener != null) { + integratedWorldLoadListener.stop(); + integratedWorldLoadListener = null; + } + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_singleplayer_load/MinecraftServerMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_singleplayer_load/MinecraftServerMixin.java index 2596c9ce..ad0b11a0 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_singleplayer_load/MinecraftServerMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_singleplayer_load/MinecraftServerMixin.java @@ -7,6 +7,7 @@ import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.progress.ChunkProgressListener; import org.embeddedt.modernfix.ModernFixClient; +import org.embeddedt.modernfix.load.LoadEvents; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -31,7 +32,7 @@ public abstract class MinecraftServerMixin { private void skipInitialChunkLoad(ChunkProgressListener arg, CallbackInfo ci) { if(((Object)this) instanceof IntegratedServer) { ci.cancel(); - ModernFixClient.integratedWorldLoadListener = arg; + LoadEvents.integratedWorldLoadListener = arg; this.nextTickTime = Util.getMillis(); this.overworld().getChunkSource().getLightEngine().setTaskPerBatch(5); this.updateMobSpawningFlags(); From 3baace55a8dbae3934821f054bd5b44c3a2ade34 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 22 Feb 2023 12:34:47 -0500 Subject: [PATCH 29/31] Avoid lazily baking multiparts and multivariants Some mods use instanceof checks and so the correct class needs to be present. Fixes #24 --- .../perf/faster_baking/ModelBakeryMixin.java | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/ModelBakeryMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/ModelBakeryMixin.java index 6fb48308..01b80092 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/ModelBakeryMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/ModelBakeryMixin.java @@ -3,6 +3,8 @@ package org.embeddedt.modernfix.mixin.perf.faster_baking; import com.google.common.collect.ImmutableSet; import com.mojang.datafixers.util.Pair; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.model.MultiVariant; +import net.minecraft.client.renderer.block.model.multipart.MultiPart; import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.AtlasSet; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -107,22 +109,32 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { this.bakeIfPossible(location); } }); + List multiparts = new ArrayList<>(); /* Then store them as top-level models if needed, and set up the lazy models */ this.topLevelModels.forEach((location, value) -> { - if (incompatibleLazyBakedModels.contains(location.getNamespace()) || requiresBake(value)) { + if (requiresBake(value) || incompatibleLazyBakedModels.contains(location.getNamespace())) { BakedModel model = this.bakeIfPossible(location); if (model != null) this.bakedTopLevelModels.put(location, model); } else { - this.bakedTopLevelModels.put(location, new LazyBakedModel(() -> { - synchronized (this.bakedCache) { - BakedModel ibakedmodel = this.bakeIfPossible(location); + if(value instanceof MultiPart || value instanceof MultiVariant) { + multiparts.add(location); + } else { + this.bakedTopLevelModels.put(location, new LazyBakedModel(() -> { + synchronized (this.bakedCache) { + BakedModel ibakedmodel = this.bakeIfPossible(location); - return ibakedmodel != null ? ibakedmodel : missingModel; - } - })); + return ibakedmodel != null ? ibakedmodel : missingModel; + } + })); + } } }); + multiparts.forEach(location -> { + BakedModel model = this.bakeIfPossible(location); + if (model != null) + this.bakedTopLevelModels.put(location, model); + }); } /** From 084b30e089ae9d1ab893078a1f94e456d568e030 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 22 Feb 2023 13:07:38 -0500 Subject: [PATCH 30/31] Latch JEI and blockstate threads until the world finishes loading These processes are not necessary to get into the game, and so we want to devote all CPU time to essential tasks like logging in and loading chunks. --- .../org/embeddedt/modernfix/ModernFix.java | 24 ++++++++++++++++++ .../embeddedt/modernfix/ModernFixClient.java | 2 ++ .../blockstate/BlockStateCacheHandler.java | 3 +++ .../modernfix/mixin/core/MinecraftMixin.java | 25 +++++++++++++++++++ .../ClientLifecycleHandlerMixin.java | 3 +++ src/main/resources/modernfix.mixins.json | 1 + 6 files changed, 58 insertions(+) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/core/MinecraftMixin.java diff --git a/src/main/java/org/embeddedt/modernfix/ModernFix.java b/src/main/java/org/embeddedt/modernfix/ModernFix.java index 3e4ee13a..5c455d43 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFix.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFix.java @@ -21,6 +21,10 @@ import org.embeddedt.modernfix.structure.AsyncLocator; import org.embeddedt.modernfix.util.KubeUtil; import java.lang.management.ManagementFactory; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.function.BooleanSupplier; // The value here should match an entry in the META-INF/mods.toml file @Mod(ModernFix.MODID) @@ -36,6 +40,26 @@ public class ModernFix { // Used to skip computing the blockstate caches twice public static boolean runningFirstInjection = false; + public static CountDownLatch worldLoadSemaphore = null; + + /** + * Simple mechanism used to delay some background processes until the client is actually in-game, to reduce + * launch time. + */ + public static void waitForWorldLoad(BooleanSupplier exitEarly) { + CountDownLatch latch = worldLoadSemaphore; + if(latch != null) { + try { + while(!latch.await(100, TimeUnit.MILLISECONDS)) { + if(exitEarly.getAsBoolean()) + return; + } + } catch(InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + public ModernFix() { INSTANCE = this; diff --git a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java index 1ce231d7..2ed3b0c3 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java @@ -48,6 +48,8 @@ public class ModernFixClient { ModernFix.LOGGER.warn("Time from main menu to in-game was " + timeSpentLoading + " seconds"); ModernFix.LOGGER.warn("Total time to load game and open world was " + (timeSpentLoading + gameStartTimeSeconds) + " seconds"); resetWorldLoadStateMachine(); + if(ModernFix.worldLoadSemaphore != null) + ModernFix.worldLoadSemaphore.countDown(); } } } diff --git a/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java b/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java index 4128d2d9..e9bd7c9f 100644 --- a/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java +++ b/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java @@ -85,6 +85,9 @@ public class BlockStateCacheHandler { @Override public void run() { + ModernFix.waitForWorldLoad(() -> stopRebuild); + if(stopRebuild) + return; Stopwatch realtimeStopwatch = Stopwatch.createStarted(); rebuildCache(); realtimeStopwatch.stop(); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/core/MinecraftMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/core/MinecraftMixin.java new file mode 100644 index 00000000..7665941d --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/core/MinecraftMixin.java @@ -0,0 +1,25 @@ +package org.embeddedt.modernfix.mixin.core; + +import com.mojang.datafixers.util.Function4; +import net.minecraft.client.Minecraft; +import net.minecraft.core.RegistryAccess; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.world.level.DataPackConfig; +import net.minecraft.world.level.storage.LevelStorageSource; +import net.minecraft.world.level.storage.WorldData; +import org.embeddedt.modernfix.ModernFix; +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; + +import java.util.concurrent.CountDownLatch; +import java.util.function.Function; + +@Mixin(Minecraft.class) +public class MinecraftMixin { + @Inject(method = "loadWorld", at = @At("HEAD")) + private void setLatch(String string, RegistryAccess.RegistryHolder arg, Function function, Function4 function4, boolean bl, Minecraft.ExperimentalDialogType arg2, boolean creating, CallbackInfo ci) { + ModernFix.worldLoadSemaphore = new CountDownLatch(1); + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/async_jei/ClientLifecycleHandlerMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/async_jei/ClientLifecycleHandlerMixin.java index 6a1d664b..d7708b98 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/async_jei/ClientLifecycleHandlerMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/async_jei/ClientLifecycleHandlerMixin.java @@ -80,6 +80,9 @@ public class ClientLifecycleHandlerMixin { cancelPreviousStart(); ModernFix.LOGGER.info("Starting new JEI thread."); JEIReloadThread newThread = new JEIReloadThread(() -> { + ModernFix.waitForWorldLoad(() -> ((JEIReloadThread)Thread.currentThread()).isStopRequested()); + if(((JEIReloadThread)Thread.currentThread()).isStopRequested()) + return; try { starter.start( plugins, diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index f7a43a5a..5dd2746e 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -50,6 +50,7 @@ "perf.kubejs.CustomIngredientMixin" ], "client": [ + "core.MinecraftMixin", "feature.measure_time.MinecraftMixin", "feature.reduce_loading_screen_freezes.ModelBakeryMixin", "perf.skip_first_datapack_reload.MinecraftMixin", From 7868bd90ee1238ed42beaaee8158e199c51871ea Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 22 Feb 2023 15:39:16 -0500 Subject: [PATCH 31/31] Fix exception thrown in dev --- .../modernfix/classloading/ModernFixResourceFinder.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java b/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java index eaca9b5f..58ddf9d6 100644 --- a/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java +++ b/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java @@ -43,6 +43,8 @@ public class ModernFixResourceFinder { IModLocator locator = file.getLocator(); Iterable rootPath = getRootPathForLocator(locator, file); for(Path root : rootPath) { + if(!Files.exists(root)) + continue; try(Stream stream = Files.walk(root)) { stream .map(root::relativize)