From 90adb1c6275223dea92d94f9f2d2dcf7e82b8333 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 1 Jul 2023 19:00:37 -0400 Subject: [PATCH 1/5] Reduce Twilight Forest structure lag Related: #147 --- forge/build.gradle | 1 + .../TFStructureStartMixin.java | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/twilightforest/structure_spawn_fix/TFStructureStartMixin.java diff --git a/forge/build.gradle b/forge/build.gradle index 8f05d6a4..898c04c1 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -43,6 +43,7 @@ dependencies { modCompileOnly("curse.maven:supermartijncore-454372:4455384") modCompileOnly("vazkii.patchouli:Patchouli:1.18.2-71.1") + modCompileOnly("curse.maven:twilightforest-227639:4337390") common(project(path: ":common", configuration: "namedElements")) { transitive false } shadowCommon(project(path: ":common", configuration: "transformProductionForge")) { transitive = false } diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/twilightforest/structure_spawn_fix/TFStructureStartMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/twilightforest/structure_spawn_fix/TFStructureStartMixin.java new file mode 100644 index 00000000..d1591fc3 --- /dev/null +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/twilightforest/structure_spawn_fix/TFStructureStartMixin.java @@ -0,0 +1,35 @@ +package org.embeddedt.modernfix.forge.mixin.perf.twilightforest.structure_spawn_fix; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.StructureFeatureManager; +import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature; +import org.embeddedt.modernfix.annotation.RequiresMod; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; +import twilightforest.world.components.structures.start.TFStructureStart; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Mixin(TFStructureStart.class) +@RequiresMod("twilightforest") +public class TFStructureStartMixin { + private static List legacyStructureNames; + @Redirect(method = "gatherPotentialSpawns", at = @At(value = "INVOKE", target = "Ljava/util/stream/Stream;toList()Ljava/util/List;"), remap = false) + private static List> getTFStructureFeatures(Stream> stream, StructureFeatureManager structureManager, MobCategory classification, BlockPos pos) { + if(legacyStructureNames == null) { + legacyStructureNames = stream.map(feature -> feature.feature.getRegistryName()).collect(Collectors.toList()); + } + var registry = structureManager.registryAccess().ownedRegistryOrThrow(Registry.CONFIGURED_STRUCTURE_FEATURE_REGISTRY); + return legacyStructureNames.stream() + .map(registry::get) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } +} From dc8d727bdb241b87876d48062e4a5a52827738d2 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 2 Jul 2023 13:30:43 -0400 Subject: [PATCH 2/5] Update Diagonal Fences mixin --- .../diagonalfences/MultipartAppenderMixin.java | 7 +++++-- gradle.properties | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/diagonalfences/MultipartAppenderMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/diagonalfences/MultipartAppenderMixin.java index 5be40715..a990c434 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/diagonalfences/MultipartAppenderMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/diagonalfences/MultipartAppenderMixin.java @@ -2,12 +2,15 @@ package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources.diagonalfenc import fuzs.diagonalfences.api.world.level.block.DiagonalBlock; import fuzs.diagonalfences.client.model.MultipartAppender; +import fuzs.diagonalfences.mixin.client.accessor.ModelBakeryAccessor; import net.minecraft.client.renderer.block.model.multipart.MultiPart; import net.minecraft.client.resources.model.ModelBakery; import net.minecraft.client.resources.model.UnbakedModel; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.FenceBlock; +import net.minecraft.world.level.block.IronBarsBlock; +import org.apache.logging.log4j.util.BiConsumer; import org.embeddedt.modernfix.ModernFixClient; import org.embeddedt.modernfix.annotation.RequiresMod; import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration; @@ -21,7 +24,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @RequiresMod("diagonalfences") public abstract class MultipartAppenderMixin { @Shadow(remap = false) - public static void appendDiagonalSelectors(ModelBakery modelBakery, MultiPart multiPart) { + public static void appendDiagonalSelectors(BiConsumer modelBakery, MultiPart multiPart, boolean rotateCenter) { throw new AssertionError(); } @@ -38,7 +41,7 @@ public abstract class MultipartAppenderMixin { if(originalModel instanceof MultiPart multipart) { Block block = multipart.definition.getOwner(); if(block instanceof FenceBlock && block instanceof DiagonalBlock diagonalBlock && diagonalBlock.hasProperties()) { - appendDiagonalSelectors(bakery, multipart); + appendDiagonalSelectors(((ModelBakeryAccessor)bakery)::diagonalfences$callCacheAndQueueDependencies, multipart, block instanceof IronBarsBlock); } } return originalModel; diff --git a/gradle.properties b/gradle.properties index 15e325f8..b87ebd91 100644 --- a/gradle.properties +++ b/gradle.properties @@ -20,6 +20,6 @@ fabric_api_version=0.80.0+1.19.4 continuity_version=3.0.0-beta.2+1.19.3 modmenu_version=6.2.2 -diagonal_fences_version=4545943 +diagonal_fences_version=4558828 spark_version=4505310 From 6f07cbdc704687077e6ba69e9a982c535ec722fc Mon Sep 17 00:00:00 2001 From: notlin4 <121224522+notlin4@users.noreply.github.com> Date: Mon, 3 Jul 2023 01:34:23 +0800 Subject: [PATCH 3/5] Add Traditional Chinese translation (#148) --- .../main/resources/assets/modernfix/lang/zh_tw.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 common/src/main/resources/assets/modernfix/lang/zh_tw.json diff --git a/common/src/main/resources/assets/modernfix/lang/zh_tw.json b/common/src/main/resources/assets/modernfix/lang/zh_tw.json new file mode 100644 index 00000000..27e5f5d8 --- /dev/null +++ b/common/src/main/resources/assets/modernfix/lang/zh_tw.json @@ -0,0 +1,13 @@ +{ + "key.modernfix": "ModernFix", + "key.modernfix.config": "開啟設定介面", + "modernfix.jei_load": "正在載入 JEI,這可能需要一點時間", + "modernfix.no_lazydfu": "沒有安裝 LazyDFU。如果 Minecraft 需要從舊版本更新遊戲資料,可能會出現明顯的延遲。", + "modernfix.config": "ModernFix 注入設定", + "modernfix.config.done_restart": "完成(需要重新啟動遊戲)", + "modernfix.option.on": "開啟", + "modernfix.option.off": "關閉", + "modernfix.config.not_default": "(已修改)", + "asynclocator.map.locating": "地圖(定位中...)", + "asynclocator.map.none": "地圖(未找到附近的特徵)" +} From ace397515692580cef9b121ec296814da328f40f Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 2 Jul 2023 18:57:37 -0400 Subject: [PATCH 4/5] Make datapack reload exception silencers not required --- .../perf/datapack_reload_exceptions/LootTableManagerMixin.java | 2 +- .../perf/datapack_reload_exceptions/RecipeManagerMixin.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/datapack_reload_exceptions/LootTableManagerMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/datapack_reload_exceptions/LootTableManagerMixin.java index 2631f448..3f66f805 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/datapack_reload_exceptions/LootTableManagerMixin.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/datapack_reload_exceptions/LootTableManagerMixin.java @@ -9,7 +9,7 @@ import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(LootTables.class) public class LootTableManagerMixin { @Redirect(method = "*(Lnet/minecraft/resources/IResourceManager;Lcom/google/common/collect/ImmutableMap$Builder;Lnet/minecraft/util/ResourceLocation;Lcom/google/gson/JsonElement;)V", - at = @At(value = "INVOKE", target = "Lorg/apache/logging/log4j/Logger;error(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V", remap = false)) + at = @At(value = "INVOKE", target = "Lorg/apache/logging/log4j/Logger;error(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V", remap = false), require = 0) private void logWithoutStacktrace(Logger instance, String s, Object location, Object exc) { instance.error(s + ": {}", location, exc.toString()); } diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/datapack_reload_exceptions/RecipeManagerMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/datapack_reload_exceptions/RecipeManagerMixin.java index 1a79f963..08555300 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/datapack_reload_exceptions/RecipeManagerMixin.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/datapack_reload_exceptions/RecipeManagerMixin.java @@ -8,7 +8,7 @@ import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(RecipeManager.class) public class RecipeManagerMixin { - @Redirect(method = "apply(Ljava/util/Map;Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/util/profiling/ProfilerFiller;)V", at = @At(value = "INVOKE", target = "Lorg/apache/logging/log4j/Logger;error(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V", remap = false)) + @Redirect(method = "apply(Ljava/util/Map;Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/util/profiling/ProfilerFiller;)V", at = @At(value = "INVOKE", target = "Lorg/apache/logging/log4j/Logger;error(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V", remap = false), require = 0) private void silenceException(Logger instance, String s, Object location, Object exc) { instance.error(s + ": {}", location, exc.toString()); } From 3541019ee0f8f88217ba40218963d39478daf0d5 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 3 Jul 2023 12:26:57 -0400 Subject: [PATCH 5/5] Modify entity loading semantics on Forge to allow EntityJoinWorldEvent handlers to load chunks --- .../modernfix/forge/ducks/ILevelChunk.java | 9 +++ .../entity_load_deadlock/ChunkMapMixin.java | 70 +++++++++++++++++++ .../entity_load_deadlock/LevelChunkMixin.java | 40 +++++++++++ .../ServerLevelMixin.java | 25 +++++++ 4 files changed, 144 insertions(+) create mode 100644 forge/src/main/java/org/embeddedt/modernfix/forge/ducks/ILevelChunk.java create mode 100644 forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/entity_load_deadlock/ChunkMapMixin.java create mode 100644 forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/entity_load_deadlock/LevelChunkMixin.java create mode 100644 forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/entity_load_deadlock/ServerLevelMixin.java diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/ducks/ILevelChunk.java b/forge/src/main/java/org/embeddedt/modernfix/forge/ducks/ILevelChunk.java new file mode 100644 index 00000000..78d6574a --- /dev/null +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/ducks/ILevelChunk.java @@ -0,0 +1,9 @@ +package org.embeddedt.modernfix.forge.ducks; + +import org.jetbrains.annotations.Nullable; + +public interface ILevelChunk { + void setEntityLoadHook(@Nullable Runnable loadHook); + void runEntityLoadHook(); + boolean getEntitiesWereLoaded(); +} diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/entity_load_deadlock/ChunkMapMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/entity_load_deadlock/ChunkMapMixin.java new file mode 100644 index 00000000..550f08d5 --- /dev/null +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/entity_load_deadlock/ChunkMapMixin.java @@ -0,0 +1,70 @@ +package org.embeddedt.modernfix.forge.mixin.bugfix.entity_load_deadlock; + +import com.google.common.collect.Lists; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.ClassInstanceMultiMap; +import net.minecraft.util.thread.BlockableEventLoop; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunk; +import org.embeddedt.modernfix.forge.ducks.ILevelChunk; +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; + +import java.util.List; + +@Mixin(ChunkMap.class) +public class ChunkMapMixin { + @Shadow @Final private BlockableEventLoop mainThreadExecutor; + @Shadow @Final private ServerLevel level; + private static final ClassInstanceMultiMap[] NO_ENTITY_SECTIONS = new ClassInstanceMultiMap[0]; + + /** + * Some mods try to do chunkloading inside EntityJoinWorldEvent, which causes issues. To address this we + * defer the loading of entities from chunks till after we are out of the chunk system. + *
+ * A different patch is necessary for 1.17+, if the issue can be reproduced there, as entity loading + * works differently. + */ + @Redirect(method = "*(Lnet/minecraft/server/level/ChunkHolder;Lnet/minecraft/world/level/chunk/ChunkAccess;)Lnet/minecraft/world/level/chunk/ChunkAccess;", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;getEntitySections()[Lnet/minecraft/util/ClassInstanceMultiMap;")) + private ClassInstanceMultiMap[] getEntitySections(LevelChunk chunk, ChunkHolder holder, ChunkAccess access) { + ((ILevelChunk)chunk).setEntityLoadHook(() -> { + List list = null; + ClassInstanceMultiMap[] entitySections = chunk.getEntitySections(); + + for (ClassInstanceMultiMap entitySection : entitySections) { + if(entitySection == null) + continue; + for (Entity entity : entitySection.getAllInstances()) { + if (!(entity instanceof Player) && !this.level.loadFromChunk(entity)) { + if (list == null) { + list = Lists.newArrayList(entity); + } else { + list.add(entity); + } + } + } + } + + if (list != null) { + list.forEach(chunk::removeEntity); + } + }); + holder.getOrScheduleFuture(ChunkStatus.FULL, (ChunkMap)(Object)this).thenRun(() -> { + // Ensure that this code runs on the main thread, in case another worker handled the future + this.mainThreadExecutor.execute(() -> { + // hook will be cleared when chunk.setLoaded(false) is called, so entities will not load + // if the chunk was already unloaded when we get here + ((ILevelChunk)chunk).runEntityLoadHook(); + }); + }); + return NO_ENTITY_SECTIONS; + } +} diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/entity_load_deadlock/LevelChunkMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/entity_load_deadlock/LevelChunkMixin.java new file mode 100644 index 00000000..d2a66dbc --- /dev/null +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/entity_load_deadlock/LevelChunkMixin.java @@ -0,0 +1,40 @@ +package org.embeddedt.modernfix.forge.mixin.bugfix.entity_load_deadlock; + +import net.minecraft.world.level.chunk.LevelChunk; +import org.embeddedt.modernfix.forge.ducks.ILevelChunk; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(LevelChunk.class) +public class LevelChunkMixin implements ILevelChunk { + private Runnable entityLoadHook; + private boolean entitiesWereLoaded = false; + + @Override + public void setEntityLoadHook(@Nullable Runnable loadHook) { + entityLoadHook = loadHook; + } + + @Inject(method = "setLoaded", at = @At("RETURN")) + private void clearLoadHook(boolean bl, CallbackInfo ci) { + if(!bl) + entityLoadHook = null; + } + + @Override + public void runEntityLoadHook() { + if(entityLoadHook != null) { + entityLoadHook.run(); + entitiesWereLoaded = true; + entityLoadHook = null; + } + } + + @Override + public boolean getEntitiesWereLoaded() { + return entitiesWereLoaded; + } +} diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/entity_load_deadlock/ServerLevelMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/entity_load_deadlock/ServerLevelMixin.java new file mode 100644 index 00000000..def157d2 --- /dev/null +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/entity_load_deadlock/ServerLevelMixin.java @@ -0,0 +1,25 @@ +package org.embeddedt.modernfix.forge.mixin.bugfix.entity_load_deadlock; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.ClassInstanceMultiMap; +import net.minecraft.world.level.chunk.LevelChunk; +import org.embeddedt.modernfix.forge.ducks.ILevelChunk; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(ServerLevel.class) +public class ServerLevelMixin { + private static final ClassInstanceMultiMap[] NO_ENTITY_SECTIONS = new ClassInstanceMultiMap[0]; + + /** + * Need to ensure entities aren't removed from the level when they were never added. + */ + @Redirect(method = "unload", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;getEntitySections()[Lnet/minecraft/util/ClassInstanceMultiMap;")) + private ClassInstanceMultiMap[] skipUnloadIfNeverLoaded(LevelChunk chunk) { + if(!((ILevelChunk)chunk).getEntitiesWereLoaded()) { + return NO_ENTITY_SECTIONS; + } + return chunk.getEntitySections(); + } +}