From a38e46a970e972ac1272fa7c4a8dffafe528bfcd Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 26 Feb 2023 13:33:53 -0500 Subject: [PATCH 01/20] Check JEI version dynamically --- .../modernfix/core/config/ModernFixEarlyConfig.java | 4 +++- .../mixin/perf/blast_search_trees/MinecraftMixin.java | 7 ++++++- src/main/resources/META-INF/mods.toml | 9 +-------- 3 files changed, 10 insertions(+), 10 deletions(-) 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 93a70702..43ea82f2 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -1,6 +1,7 @@ package org.embeddedt.modernfix.core.config; import net.minecraftforge.fml.loading.FMLLoader; +import net.minecraftforge.fml.loading.moddiscovery.ModInfo; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -43,7 +44,8 @@ public class ModernFixEarlyConfig { /* off by default in 1.18 because it doesn't work as well */ this.addMixinRule("perf.faster_singleplayer_load", false); /* Keep this off if JEI isn't installed to prevent breaking vanilla gameplay */ - this.addMixinRule("perf.blast_search_trees", FMLLoader.getLoadingModList().getModFileById("jei") != null); + Optional jeiMod = FMLLoader.getLoadingModList().getMods().stream().filter(mod -> mod.getModId().equals("jei")).findFirst(); + this.addMixinRule("perf.blast_search_trees", jeiMod.isPresent() && jeiMod.get().getVersion().getMajorVersion() >= 10); this.addMixinRule("safety", true); this.addMixinRule("launch.transformer_cache", false); this.addMixinRule("launch.class_search_cache", true); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/blast_search_trees/MinecraftMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/blast_search_trees/MinecraftMixin.java index 3e2335f6..cc051e63 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/blast_search_trees/MinecraftMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/blast_search_trees/MinecraftMixin.java @@ -2,7 +2,9 @@ package org.embeddedt.modernfix.mixin.perf.blast_search_trees; import net.minecraft.client.Minecraft; import net.minecraft.client.searchtree.SearchRegistry; +import net.minecraftforge.fml.ModContainer; import net.minecraftforge.fml.ModList; +import net.minecraftforge.forgespi.language.IModFileInfo; import org.embeddedt.modernfix.searchtree.DummySearchTree; import org.embeddedt.modernfix.searchtree.JEIBackedSearchTree; import org.spongepowered.asm.mixin.Final; @@ -12,6 +14,8 @@ 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.Optional; + @Mixin(Minecraft.class) public class MinecraftMixin { @Shadow @Final private SearchRegistry searchRegistry; @@ -19,7 +23,8 @@ public class MinecraftMixin { @Inject(method = "createSearchTrees", at = @At("HEAD"), cancellable = true) private void replaceSearchTrees(CallbackInfo ci) { ci.cancel(); - if(ModList.get().getModFileById("jei") != null) { + Optional jeiContainer = ModList.get().getModContainerById("jei"); + if(jeiContainer.isPresent() && jeiContainer.get().getModInfo().getVersion().getMajorVersion() >= 10) { this.searchRegistry.register(SearchRegistry.CREATIVE_NAMES, new JEIBackedSearchTree(false)); this.searchRegistry.register(SearchRegistry.CREATIVE_TAGS, new JEIBackedSearchTree(true)); } else { diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 9e1e31c5..34107536 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -55,11 +55,4 @@ mandatory = true # This version range declares a minimum of the current minecraft version up to but not including the next major version versionRange = "[1.18.2,1.19)" ordering = "NONE" -side = "BOTH" -[[dependencies.modernfix]] -modId = "jei" -mandatory = false -# This version range declares a minimum of the current minecraft version up to but not including the next major version -versionRange = "[9.9999,)" -ordering = "BEFORE" -side = "CLIENT" \ No newline at end of file +side = "BOTH" \ No newline at end of file From d9b2a880bbc3c7f26d03791737a7eb19f5be8236 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 27 Feb 2023 09:31:16 -0500 Subject: [PATCH 02/20] Handle mods that request paths with double slashes --- .../perf/resourcepacks/ModFileResourcePackMixin.java | 6 ++---- .../mixin/perf/resourcepacks/VanillaPackMixin.java | 3 ++- .../java/org/embeddedt/modernfix/util/FileUtil.java | 12 ++++++++++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/resourcepacks/ModFileResourcePackMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/resourcepacks/ModFileResourcePackMixin.java index 9e11a02a..f4e7d0e9 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/resourcepacks/ModFileResourcePackMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/resourcepacks/ModFileResourcePackMixin.java @@ -5,20 +5,18 @@ import net.minecraft.server.packs.PackType; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.fml.loading.moddiscovery.ModFile; import net.minecraftforge.fml.packs.ModFileResourcePack; -import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.util.FileUtil; 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.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.io.IOException; import java.nio.file.FileSystem; -import java.nio.file.FileVisitOption; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; @@ -96,7 +94,7 @@ public abstract class ModFileResourcePackMixin { @Inject(method = "hasResource(Ljava/lang/String;)Z", at = @At(value = "HEAD"), cancellable = true) private void useCacheForExistence(String path, CallbackInfoReturnable cir) { - cir.setReturnValue(this.containedPaths.contains(path)); + cir.setReturnValue(this.containedPaths.contains(FileUtil.normalize(path))); } /** diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/resourcepacks/VanillaPackMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/resourcepacks/VanillaPackMixin.java index d3e133a6..018f0cd5 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/resourcepacks/VanillaPackMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/resourcepacks/VanillaPackMixin.java @@ -10,6 +10,7 @@ import net.minecraft.resources.ResourceLocation; import org.apache.commons.lang3.tuple.Pair; import org.embeddedt.modernfix.FileWalker; import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.util.FileUtil; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -71,6 +72,6 @@ public class VanillaPackMixin { @Inject(method = "hasResource", at = @At(value = "INVOKE", target = "Ljava/lang/Class;getResource(Ljava/lang/String;)Ljava/net/URL;"), cancellable = true) private void useCacheForExistence(PackType type, ResourceLocation location, CallbackInfoReturnable cir) { - cir.setReturnValue(containedPaths.contains(type.getDirectory() + "/" + location.getNamespace() + "/" + location.getPath())); + cir.setReturnValue(containedPaths.contains(type.getDirectory() + "/" + location.getNamespace() + "/" + FileUtil.normalize(location.getPath()))); } } diff --git a/src/main/java/org/embeddedt/modernfix/util/FileUtil.java b/src/main/java/org/embeddedt/modernfix/util/FileUtil.java index 7e8dda59..51045bda 100644 --- a/src/main/java/org/embeddedt/modernfix/util/FileUtil.java +++ b/src/main/java/org/embeddedt/modernfix/util/FileUtil.java @@ -1,10 +1,22 @@ package org.embeddedt.modernfix.util; import java.io.File; +import java.util.regex.Pattern; public class FileUtil { public static File childFile(File file) { file.getParentFile().mkdirs(); return file; } + + private static final Pattern SLASH_PATTERN = Pattern.compile("(?:\\\\+|\\/+)"); + + /** + * Normalize a path by removing double slashes, etc. + * @param path input path + * @return a normalized version of the path + */ + public static String normalize(String path) { + return SLASH_PATTERN.matcher(path).replaceAll("/"); + } } From c27f189154c1c667f2c53b731c06fddd143b5e9a Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 27 Feb 2023 09:32:33 -0500 Subject: [PATCH 03/20] Turn off faster singleplayer load by default for now --- .../embeddedt/modernfix/core/config/ModernFixEarlyConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b1f6c09a..f8a6265e 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -50,7 +50,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); + this.addMixinRule("perf.faster_singleplayer_load", false); /* 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); From fca7c9f7ef2d41576ebffe516feb1e9a788a72cd Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 27 Feb 2023 12:17:54 -0500 Subject: [PATCH 04/20] Skip reloading server resources if switching worlds and the datapack order didn't change --- .../core/config/ModernFixEarlyConfig.java | 1 + .../ICachingResourceClient.java | 10 +++ .../perf/reuse_datapacks/MinecraftMixin.java | 65 +++++++++++++++++++ .../reuse_datapacks/MinecraftServerMixin.java | 27 ++++++++ src/main/resources/modernfix.mixins.json | 2 + 5 files changed, 105 insertions(+) create mode 100644 src/main/java/org/embeddedt/modernfix/duck/reuse_datapacks/ICachingResourceClient.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/reuse_datapacks/MinecraftMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/reuse_datapacks/MinecraftServerMixin.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 f8a6265e..38b9a191 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -26,6 +26,7 @@ public class ModernFixEarlyConfig { this.addMixinRule("perf.reduce_blockstate_cache_rebuilds", true); this.addMixinRule("perf.boost_worker_count", true); this.addMixinRule("perf.skip_first_datapack_reload", true); + this.addMixinRule("perf.reuse_datapacks", true); this.addMixinRule("perf.parallelize_model_loading", true); this.addMixinRule("perf.parallelize_model_loading.multipart", false); this.addMixinRule("perf.cache_strongholds", true); diff --git a/src/main/java/org/embeddedt/modernfix/duck/reuse_datapacks/ICachingResourceClient.java b/src/main/java/org/embeddedt/modernfix/duck/reuse_datapacks/ICachingResourceClient.java new file mode 100644 index 00000000..c05d5bce --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/duck/reuse_datapacks/ICachingResourceClient.java @@ -0,0 +1,10 @@ +package org.embeddedt.modernfix.duck.reuse_datapacks; + +import net.minecraft.server.ServerResources; + +import java.util.Collection; + +public interface ICachingResourceClient { + void setCachedResources(ServerResources r); + void setCachedDataPackConfig(Collection c); +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/reuse_datapacks/MinecraftMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/reuse_datapacks/MinecraftMixin.java new file mode 100644 index 00000000..461633f5 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/reuse_datapacks/MinecraftMixin.java @@ -0,0 +1,65 @@ +package org.embeddedt.modernfix.mixin.perf.reuse_datapacks; + +import com.google.common.collect.ImmutableList; +import net.minecraft.client.Minecraft; +import net.minecraft.commands.Commands; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.ServerResources; +import net.minecraft.server.packs.PackResources; +import net.minecraft.server.packs.repository.Pack; +import net.minecraft.server.packs.repository.PackRepository; +import net.minecraft.world.level.DataPackConfig; +import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.duck.reuse_datapacks.ICachingResourceClient; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +@Mixin(Minecraft.class) +public class MinecraftMixin implements ICachingResourceClient { + private ServerResources cachedResources; + private List cachedDataPackConfig; + + private List loadingDataPackConfig; + + @Redirect(method = "makeServerStem", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;configurePackRepository(Lnet/minecraft/server/packs/repository/PackRepository;Lnet/minecraft/world/level/DataPackConfig;Z)Lnet/minecraft/world/level/DataPackConfig;")) + private DataPackConfig saveLoadingConfig(PackRepository repo, DataPackConfig inCodec, boolean vanillaOnly) { + DataPackConfig config = MinecraftServer.configurePackRepository(repo, inCodec, vanillaOnly); + loadingDataPackConfig = repo.getSelectedPacks().stream().map(Pack::getId).collect(ImmutableList.toImmutableList()); + return config; + } + + @Redirect(method = "makeServerStem", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/ServerResources;loadResources(Ljava/util/List;Lnet/minecraft/commands/Commands$CommandSelection;ILjava/util/concurrent/Executor;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;")) + private CompletableFuture useCachedResources(List list, Commands.CommandSelection arg, int i, Executor executor, Executor executor2) { + if(cachedResources != null) { + if(cachedDataPackConfig.equals(loadingDataPackConfig)) { + ModernFix.LOGGER.warn("Reusing loaded server resources from previous world"); + return CompletableFuture.completedFuture(cachedResources); + } else { + ModernFix.LOGGER.warn("Discarding cached server resources, datapack configs have changed"); + ModernFix.LOGGER.warn("Old: {}", "[" + String.join(", ", cachedDataPackConfig) + "]"); + ModernFix.LOGGER.warn("New: {}", "[" + String.join(", ", loadingDataPackConfig) + "]"); + cachedResources.close(); + cachedResources = null; + cachedDataPackConfig = null; + } + } + return ServerResources.loadResources(list, arg, i, executor, executor2); + } + + + @Override + public void setCachedResources(ServerResources r) { + cachedResources = r; + } + + @Override + public void setCachedDataPackConfig(Collection c) { + cachedDataPackConfig = ImmutableList.copyOf(c); + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/reuse_datapacks/MinecraftServerMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/reuse_datapacks/MinecraftServerMixin.java new file mode 100644 index 00000000..f1f4d959 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/reuse_datapacks/MinecraftServerMixin.java @@ -0,0 +1,27 @@ +package org.embeddedt.modernfix.mixin.perf.reuse_datapacks; + +import com.google.common.collect.ImmutableList; +import net.minecraft.client.Minecraft; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.ServerResources; +import net.minecraft.server.packs.repository.Pack; +import net.minecraft.server.packs.repository.PackRepository; +import org.embeddedt.modernfix.duck.reuse_datapacks.ICachingResourceClient; +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(MinecraftServer.class) +public class MinecraftServerMixin { + + @Shadow @Final private PackRepository packRepository; + + @Redirect(method = "stopServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/ServerResources;close()V")) + private void saveResources(ServerResources resources) { + ICachingResourceClient client = ((ICachingResourceClient) Minecraft.getInstance()); + client.setCachedDataPackConfig(this.packRepository.getSelectedPacks().stream().map(Pack::getId).collect(ImmutableList.toImmutableList())); + client.setCachedResources(resources); + } +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 5d7dec48..7f861eee 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -90,6 +90,8 @@ "perf.faster_texture_stitching.StitcherMixin", "bugfix.packet_leak.ClientPlayNetHandlerMixin", "bugfix.packet_leak.SCustomPayloadPlayPacketMixin", + "perf.reuse_datapacks.MinecraftMixin", + "perf.reuse_datapacks.MinecraftServerMixin", "perf.faster_singleplayer_load.MinecraftServerMixin" ], "injectors": { From 9902b97b1d860b524808f85702b4313cb68c8c71 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 27 Feb 2023 20:58:46 -0500 Subject: [PATCH 05/20] Warn if LazyDFU is not installed --- .../org/embeddedt/modernfix/ModernFix.java | 26 ++++++++++++++++--- .../assets/modernfix/lang/en_us.json | 1 + 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/ModernFix.java b/src/main/java/org/embeddedt/modernfix/ModernFix.java index 5c455d43..27ed116c 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFix.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFix.java @@ -3,14 +3,13 @@ package org.embeddedt.modernfix; import net.minecraftforge.api.distmarker.Dist; 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.*; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.server.FMLServerStartedEvent; import net.minecraftforge.fml.event.server.FMLServerStartingEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.fml.loading.FMLLoader; import net.minecraftforge.fml.network.FMLNetworkConstants; import org.apache.commons.lang3.tuple.Pair; @@ -65,6 +64,7 @@ public class ModernFix { INSTANCE = this; // Register ourselves for server and other game events we are interested in MinecraftForge.EVENT_BUS.register(this); + FMLJavaModLoadingContext.get().getModEventBus().addListener(this::commonSetup); 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); @@ -72,6 +72,24 @@ public class ModernFix { MinecraftForge.EVENT_BUS.register(KubeUtil.class); } + private static boolean dfuModPresent() { + for(String modId : new String[] { "lazydfu", "datafixerslayer" }) { + if(ModList.get().isLoaded(modId)) + return true; + } + return false; + } + + @SubscribeEvent + public void commonSetup(FMLCommonSetupEvent event) { + if(!dfuModPresent()) { + event.enqueueWork(() -> { + ModLoader.get().addWarning(new ModLoadingWarning(ModLoadingContext.get().getActiveContainer().getModInfo(), ModLoadingStage.COMMON_SETUP, "modernfix.no_lazydfu")); + }); + } + + } + @SubscribeEvent public void onServerStarted(FMLServerStartedEvent event) { if(FMLLoader.getDist() == Dist.DEDICATED_SERVER) { diff --git a/src/main/resources/assets/modernfix/lang/en_us.json b/src/main/resources/assets/modernfix/lang/en_us.json index 8b1b7ad4..b757242b 100644 --- a/src/main/resources/assets/modernfix/lang/en_us.json +++ b/src/main/resources/assets/modernfix/lang/en_us.json @@ -1,5 +1,6 @@ { "modernfix.jei_load": "Loading JEI, this may take a while", + "modernfix.no_lazydfu": "ModernFix detected that DFU rules were compiled on startup. This slows down game launching. Installing LazyDFU to resolve this is highly recommended.", "asynclocator.map.locating": "Map (Locating...)", "asynclocator.map.none": "Map (No nearby feature found)" } From 6e58570ea757f35c1aad8b4563b5971df68b2bd3 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 27 Feb 2023 21:02:18 -0500 Subject: [PATCH 06/20] Remove CTM from dev environment, not needed anymore --- build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle b/build.gradle index e3ecc829..8c1d559c 100644 --- a/build.gradle +++ b/build.gradle @@ -91,7 +91,6 @@ 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) { From 7342bb4fb4cde5049abc020f97612f4b147a39d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8B=82=E6=83=B3ThePotato?= <110756250+Kasualix@users.noreply.github.com> Date: Tue, 28 Feb 2023 22:49:18 +0800 Subject: [PATCH 07/20] Update zh_cn.json (#26) --- src/main/resources/assets/modernfix/lang/zh_cn.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/resources/assets/modernfix/lang/zh_cn.json b/src/main/resources/assets/modernfix/lang/zh_cn.json index 0c9c92a5..f8e78167 100644 --- a/src/main/resources/assets/modernfix/lang/zh_cn.json +++ b/src/main/resources/assets/modernfix/lang/zh_cn.json @@ -1,5 +1,6 @@ { - "modernfix.jei_load": "正在加载JEI,这需要一点时间", - "asynclocator.map.locating": "地图(正在定位...)", + "modernfix.jei_load": "正在加载JEI,这需要一点时间。", + "modernfix.no_lazydfu": "现代化修复检测到DFU规则在游戏启动时已被编译。这会降低游戏启动速度。非常推荐安装DFU载入优化来解决这个问题。", + "asynclocator.map.locating": "地图(定位中……)", "asynclocator.map.none": "地图(未能找到相关地物)" } From b9050368bcae25ef8e90659526e4209d4af3798a Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 1 Mar 2023 14:36:10 -0500 Subject: [PATCH 08/20] Reduce verbosity of some log messages --- .../embeddedt/modernfix/blockstate/BlockStateCacheHandler.java | 2 +- .../mixin/perf/skip_first_datapack_reload/MinecraftMixin.java | 2 +- .../mixin/perf/thread_priorities/IntegratedServerMixin.java | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java b/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java index e9bd7c9f..4c439b5d 100644 --- a/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java +++ b/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java @@ -53,7 +53,7 @@ public class BlockStateCacheHandler { currentRebuildThread = null; } } else { - ModernFix.LOGGER.warn("Deferred blockstate cache rebuild"); + ModernFix.LOGGER.debug("Deferred blockstate cache rebuild"); } } diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/skip_first_datapack_reload/MinecraftMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/skip_first_datapack_reload/MinecraftMixin.java index b6a8079e..1dd623d1 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/skip_first_datapack_reload/MinecraftMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/skip_first_datapack_reload/MinecraftMixin.java @@ -36,7 +36,7 @@ public abstract class MinecraftMixin { @Redirect(method = "loadWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;makeServerStem(Lnet/minecraft/core/RegistryAccess$RegistryHolder;Ljava/util/function/Function;Lcom/mojang/datafixers/util/Function4;ZLnet/minecraft/world/level/storage/LevelStorageSource$LevelStorageAccess;)Lnet/minecraft/client/Minecraft$ServerStem;", ordinal = 0)) private Minecraft.ServerStem skipFirstReload(Minecraft client, RegistryAccess.RegistryHolder dynamicRegistries, Function worldStorageToDatapackFunction, Function4 quadFunction, boolean vanillaOnly, LevelStorageSource.LevelStorageAccess levelSave, String worldName, RegistryAccess.RegistryHolder originalRegistries, Function levelSaveToDatapackFunction, Function4 quadFunction2, boolean vanillaOnly2, Minecraft.ExperimentalDialogType selectionType, boolean creating) throws InterruptedException, ExecutionException { if(!creating) { - ModernFix.LOGGER.warn("Skipping first reload, this is still experimental"); + ModernFix.LOGGER.debug("Skipping first datapack reload"); ModernFix.runningFirstInjection = true; ((ILevelSave)levelSave).runWorldPersistenceHooks(levelSource); ModernFix.runningFirstInjection = false; diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/thread_priorities/IntegratedServerMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/thread_priorities/IntegratedServerMixin.java index 10f57276..810ec467 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/thread_priorities/IntegratedServerMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/thread_priorities/IntegratedServerMixin.java @@ -23,7 +23,6 @@ public class IntegratedServerMixin { @Inject(method = "", at = @At("RETURN")) private void adjustServerPriority(Thread pServerThread, Minecraft pMinecraft, RegistryAccess.RegistryHolder pRegistryHolder, LevelStorageSource.LevelStorageAccess pStorageSource, PackRepository pPackRepository, ServerResources pResources, WorldData pWorldData, MinecraftSessionService pSessionService, GameProfileRepository pProfileRepository, GameProfileCache pProfileCache, ChunkProgressListenerFactory pProgressListenerfactory, CallbackInfo ci) { int pri = ModernFixConfig.INTEGRATED_SERVER_PRIORITY.get(); - ModernFix.LOGGER.info("Changing server thread priority to " + pri); pServerThread.setPriority(pri); } } From cc79bf7274c9393593bbdf9b8a7500466853af17 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 1 Mar 2023 14:50:44 -0500 Subject: [PATCH 09/20] Allow JEPB and JEResources to use integrated server resources --- build.gradle | 3 +++ .../core/config/ModernFixEarlyConfig.java | 1 + .../LootTableHelperMixin.java | 20 +++++++++++++++++++ .../PiglinBarteringRecipeBuilderMixin.java | 20 +++++++++++++++++++ src/main/resources/modernfix.mixins.json | 2 ++ 5 files changed, 46 insertions(+) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/LootTableHelperMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/PiglinBarteringRecipeBuilderMixin.java diff --git a/build.gradle b/build.gradle index 8c1d559c..db8e0333 100644 --- a/build.gradle +++ b/build.gradle @@ -91,6 +91,9 @@ dependencies { modCompileOnly("curse.maven:refinedstorage-243076:${refined_storage_version}") modImplementation("dev.latvian.mods:kubejs-forge:${kubejs_version}") + modImplementation("curse.maven:jeresources-240630:3545538") + modImplementation("curse.maven:jepb-437558:3172880") + modImplementation("curse.maven:babel-436964:3196072") } tasks.withType(JavaCompile) { 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 38b9a191..1beb4b03 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -21,6 +21,7 @@ public class ModernFixEarlyConfig { this.addMixinRule("feature.measure_time", true); this.addMixinRule("feature.reduce_loading_screen_freezes", false); this.addMixinRule("perf.fast_registry_validation", true); + this.addMixinRule("perf.use_integrated_resources", true); this.addMixinRule("perf.remove_biome_temperature_cache", true); this.addMixinRule("perf.resourcepacks", true); this.addMixinRule("perf.reduce_blockstate_cache_rebuilds", true); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/LootTableHelperMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/LootTableHelperMixin.java new file mode 100644 index 00000000..ddfaf64b --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/LootTableHelperMixin.java @@ -0,0 +1,20 @@ +package org.embeddedt.modernfix.mixin.perf.use_integrated_resources; + +import jeresources.util.LootTableHelper; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.Level; +import net.minecraftforge.fml.server.ServerLifecycleHooks; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(LootTableHelper.class) +public class LootTableHelperMixin { + @Redirect(method = "getManager(Lnet/minecraft/world/level/Level;)Lnet/minecraft/world/level/storage/loot/LootTables;", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;getServer()Lnet/minecraft/server/MinecraftServer;")) + private static MinecraftServer useIntegrated(Level level) { + MinecraftServer server = level.getServer(); + if(server != null) + return server; + return ServerLifecycleHooks.getCurrentServer(); + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/PiglinBarteringRecipeBuilderMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/PiglinBarteringRecipeBuilderMixin.java new file mode 100644 index 00000000..a333fa7e --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/PiglinBarteringRecipeBuilderMixin.java @@ -0,0 +1,20 @@ +package org.embeddedt.modernfix.mixin.perf.use_integrated_resources; + +import com.thenatekirby.jepb.plugin.PiglinBarteringRecipeBuilder; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.Level; +import net.minecraftforge.fml.server.ServerLifecycleHooks; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(PiglinBarteringRecipeBuilder.class) +public class PiglinBarteringRecipeBuilderMixin { + @Redirect(method = "getManager(Lnet/minecraft/world/level/Level;)Lnet/minecraft/world/level/storage/loot/LootTables;", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;getServer()Lnet/minecraft/server/MinecraftServer;")) + private static MinecraftServer useIntegrated(Level level) { + MinecraftServer server = level.getServer(); + if(server != null) + return server; + return ServerLifecycleHooks.getCurrentServer(); + } +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 7f861eee..c0591966 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -92,6 +92,8 @@ "bugfix.packet_leak.SCustomPayloadPlayPacketMixin", "perf.reuse_datapacks.MinecraftMixin", "perf.reuse_datapacks.MinecraftServerMixin", + "perf.use_integrated_resources.LootTableHelperMixin", + "perf.use_integrated_resources.PiglinBarteringRecipeBuilderMixin", "perf.faster_singleplayer_load.MinecraftServerMixin" ], "injectors": { From db95e37d224c2c130b67de70fd7b0e1cc6a5d27c Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 1 Mar 2023 20:03:47 -0500 Subject: [PATCH 10/20] Fix MC-218112 --- .../core/config/ModernFixEarlyConfig.java | 1 + .../mc218112/SynchedEntityDataMixin.java | 34 ++++++++++++++ .../SynchedEntityDataMixin_Client.java | 46 +++++++++++++++++++ src/main/resources/modernfix.mixins.json | 2 + 4 files changed, 83 insertions(+) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/bugfix/mc218112/SynchedEntityDataMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/bugfix/mc218112/SynchedEntityDataMixin_Client.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 1beb4b03..22c90055 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -36,6 +36,7 @@ public class ModernFixEarlyConfig { this.addMixinRule("bugfix.edge_chunk_not_saved", true); this.addMixinRule("bugfix.packet_leak", false); this.addMixinRule("bugfix.structure_manager_crash", true); + this.addMixinRule("bugfix.mc218112", true); this.addMixinRule("perf.async_jei", true); this.addMixinRule("perf.thread_priorities", true); this.addMixinRule("perf.preload_block_classes", false); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/bugfix/mc218112/SynchedEntityDataMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/mc218112/SynchedEntityDataMixin.java new file mode 100644 index 00000000..64b4f16b --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/mc218112/SynchedEntityDataMixin.java @@ -0,0 +1,34 @@ +package org.embeddedt.modernfix.mixin.bugfix.mc218112; + +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.SynchedEntityData; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.util.Map; +import java.util.concurrent.locks.ReadWriteLock; + +@Mixin(SynchedEntityData.class) +public class SynchedEntityDataMixin { + @Shadow @Final private Map> itemsById; + + @Shadow @Final private ReadWriteLock lock; + + @Shadow private boolean isEmpty; + + @Inject(method = "createDataItem", at = @At(value = "INVOKE", target = "Ljava/util/Map;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) + private void putWithLock(EntityDataAccessor key, T value, CallbackInfo ci, SynchedEntityData.DataItem item) { + ci.cancel(); + try { + this.itemsById.put(key.getId(), item); + this.isEmpty = false; + } finally { + this.lock.writeLock().unlock(); + } + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/bugfix/mc218112/SynchedEntityDataMixin_Client.java b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/mc218112/SynchedEntityDataMixin_Client.java new file mode 100644 index 00000000..156442e0 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/mc218112/SynchedEntityDataMixin_Client.java @@ -0,0 +1,46 @@ +package org.embeddedt.modernfix.mixin.bugfix.mc218112; + +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.world.entity.Entity; +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.Map; +import java.util.concurrent.locks.ReadWriteLock; + +@Mixin(SynchedEntityData.class) +public abstract class SynchedEntityDataMixin_Client { + @Shadow @Final private ReadWriteLock lock; + + @Shadow private boolean isDirty; + + @Shadow protected abstract void assignValue(SynchedEntityData.DataItem target, SynchedEntityData.DataItem source); + + @Shadow @Final private Entity entity; + + @Shadow @Final private Map> itemsById; + + /** + * @author embeddedt + * @reason always unlock + */ + @Overwrite + public void assignValues(List> entries) { + this.lock.writeLock().lock(); + try { + for(SynchedEntityData.DataItem dataentry : entries) { + SynchedEntityData.DataItem dataentry1 = this.itemsById.get(dataentry.getAccessor().getId()); + if (dataentry1 != null) { + this.assignValue(dataentry1, dataentry); + this.entity.onSyncedDataUpdated(dataentry.getAccessor()); + } + } + } finally { + this.lock.writeLock().unlock(); + } + this.isDirty = true; + } +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index c0591966..4650ceeb 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -52,6 +52,7 @@ "perf.fast_registry_validation.ForgeRegistryMixin", "perf.cache_strongholds.ChunkGeneratorMixin", "perf.cache_upgraded_structures.StructureManagerMixin", + "bugfix.mc218112.SynchedEntityDataMixin", "perf.cache_strongholds.ServerLevelMixin" ], "client": [ @@ -94,6 +95,7 @@ "perf.reuse_datapacks.MinecraftServerMixin", "perf.use_integrated_resources.LootTableHelperMixin", "perf.use_integrated_resources.PiglinBarteringRecipeBuilderMixin", + "bugfix.mc218112.SynchedEntityDataMixin_Client", "perf.faster_singleplayer_load.MinecraftServerMixin" ], "injectors": { From ce1462efd12852b4e520014f387fd07ccb0d5577 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 2 Mar 2023 15:53:00 -0500 Subject: [PATCH 11/20] Add system to detect and correct SynchedEntityData ID mismatches Should fix weird stacktraces being thrown when mods like Citadel and Caves and Cliffs Backport are installed together --- .../org/embeddedt/modernfix/ModernFix.java | 4 + .../embeddedt/modernfix/ModernFixClient.java | 85 ++++++++++++++++++- .../entity/EntityDataIDSyncHandler.java | 66 ++++++++++++++ .../mixin/core/SynchedEntityDataMixin.java | 24 ++++++ .../modernfix/packet/EntityIDSyncPacket.java | 78 +++++++++++++++++ .../modernfix/packet/PacketHandler.java | 22 +++++ .../resources/META-INF/accesstransformer.cfg | 4 +- src/main/resources/modernfix.mixins.json | 1 + 8 files changed, 282 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/embeddedt/modernfix/entity/EntityDataIDSyncHandler.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/core/SynchedEntityDataMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/packet/EntityIDSyncPacket.java create mode 100644 src/main/java/org/embeddedt/modernfix/packet/PacketHandler.java diff --git a/src/main/java/org/embeddedt/modernfix/ModernFix.java b/src/main/java/org/embeddedt/modernfix/ModernFix.java index 27ed116c..bf73fc45 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFix.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFix.java @@ -16,6 +16,8 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.embeddedt.modernfix.core.config.ModernFixConfig; +import org.embeddedt.modernfix.entity.EntityDataIDSyncHandler; +import org.embeddedt.modernfix.packet.PacketHandler; import org.embeddedt.modernfix.structure.AsyncLocator; import org.embeddedt.modernfix.util.KubeUtil; @@ -70,6 +72,8 @@ public class ModernFix { ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModernFixConfig.COMMON_CONFIG); if(ModList.get().isLoaded("kubejs")) MinecraftForge.EVENT_BUS.register(KubeUtil.class); + MinecraftForge.EVENT_BUS.register(EntityDataIDSyncHandler.class); + PacketHandler.register(); } private static boolean dfuModPresent() { diff --git a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java index 90779e01..7b97709a 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java @@ -1,8 +1,12 @@ package org.embeddedt.modernfix; +import com.mojang.datafixers.util.Pair; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.ConnectScreen; import net.minecraft.client.gui.screens.TitleScreen; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.world.entity.Entity; import net.minecraftforge.client.event.GuiOpenEvent; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.common.MinecraftForge; @@ -11,12 +15,17 @@ import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.ModContainer; import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.network.NetworkEvent; import org.embeddedt.modernfix.core.ModernFixMixinPlugin; import org.embeddedt.modernfix.load.LoadEvents; +import org.embeddedt.modernfix.packet.EntityIDSyncPacket; import org.embeddedt.modernfix.screen.DeferredLevelLoadingScreen; import java.lang.management.ManagementFactory; -import java.util.Optional; +import java.lang.reflect.Field; +import java.sql.Ref; +import java.util.*; +import java.util.function.Supplier; public class ModernFixClient { public static long worldLoadStartTime; @@ -71,4 +80,78 @@ public class ModernFixClient { event.getLeft().add(brandingString); } } + + /** + * Check if the IDs match and remap them if not. + * @return true if ID remap was needed + */ + private static boolean compareAndSwitchIds(Class eClass, String fieldName, EntityDataAccessor accessor, int newId) { + if(accessor.id != newId) { + ModernFix.LOGGER.warn("Corrected ID mismatch on {} field {}. Client had {} but server wants {}.", + eClass, + fieldName, + accessor.id, + newId); + accessor.id = newId; + return true; + } else { + ModernFix.LOGGER.debug("{} {} ID fine: {}", eClass, fieldName, newId); + return false; + } + } + + /** + * Horrendous hack to allow tracking every synced entity data manager. + * + * This is to ensure we can perform ID fixup on already constructed managers. + */ + public static Set allEntityDatas = Collections.newSetFromMap(new WeakHashMap<>()); + + /** + * Extremely hacky method to detect and correct mismatched entity data parameter IDs on the client and server. + * + * The technique is far from ideal, but it should detect reliably and also not break already constructed entities. + */ + public static void handleEntityIDSync(EntityIDSyncPacket packet, Supplier context) { + Map, List>> info = packet.getFieldInfo(); + context.get().enqueueWork(() -> { + boolean fixNeeded = false; + for(Map.Entry, List>> entry : info.entrySet()) { + Class eClass = entry.getKey(); + for(Pair field : entry.getValue()) { + String fieldName = field.getFirst(); + int newId = field.getSecond(); + try { + Field f = eClass.getDeclaredField(fieldName); + f.setAccessible(true); + EntityDataAccessor accessor = (EntityDataAccessor)f.get(null); + if(compareAndSwitchIds(eClass, fieldName, accessor, newId)) + fixNeeded = true; + } catch(NoSuchFieldException e) { + ModernFix.LOGGER.warn("Couldn't find field on {}: {}", eClass, fieldName); + } catch(ReflectiveOperationException e) { + throw new RuntimeException("Unexpected exception", e); + } + } + } + /* Now the ID mappings on synced entity data instances are probably all wrong. Fix that. */ + List dataEntries; + synchronized (allEntityDatas) { + if(fixNeeded) { + dataEntries = new ArrayList<>(allEntityDatas); + for(SynchedEntityData manager : dataEntries) { + Map> fixedMap = new HashMap<>(); + List> items = new ArrayList<>(manager.itemsById.values()); + for(SynchedEntityData.DataItem item : items) { + fixedMap.put(item.getAccessor().id, item); + } + manager.itemsById = fixedMap; + } + } + allEntityDatas.clear(); + } + }); + + context.get().setPacketHandled(true); + } } diff --git a/src/main/java/org/embeddedt/modernfix/entity/EntityDataIDSyncHandler.java b/src/main/java/org/embeddedt/modernfix/entity/EntityDataIDSyncHandler.java new file mode 100644 index 00000000..e1124721 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/entity/EntityDataIDSyncHandler.java @@ -0,0 +1,66 @@ +package org.embeddedt.modernfix.entity; + +import com.mojang.datafixers.util.Pair; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.world.entity.Entity; +import net.minecraftforge.event.OnDatapackSyncEvent; +import net.minecraftforge.eventbus.api.EventPriority; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraftforge.fml.network.PacketDistributor; +import net.minecraftforge.fml.server.ServerLifecycleHooks; +import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.packet.EntityIDSyncPacket; +import org.embeddedt.modernfix.packet.PacketHandler; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EntityDataIDSyncHandler { + private static Map, List>> fieldsToSyncMap; + @SubscribeEvent(priority = EventPriority.HIGHEST) + @SuppressWarnings("unchecked") + public static void onDatapackSyncEvent(OnDatapackSyncEvent event) { + if(event.getPlayer() != null) { + /* Compute the current set of serializer IDs in use and send them */ + try { + if(fieldsToSyncMap == null) { + fieldsToSyncMap = new HashMap<>(); + Field entityPoolField = ObfuscationReflectionHelper.findField(SynchedEntityData.class, "field_187232_a"); + Map, Integer> entityPoolMap = (Map, Integer>)entityPoolField.get(null); + List fieldsToSync = new ArrayList<>(); + for(Class eClass : entityPoolMap.keySet()) { + fieldsToSync.clear(); + Field[] classFields = eClass.getDeclaredFields(); + for(Field field : classFields) { + if(!Modifier.isStatic(field.getModifiers())) + continue; + field.setAccessible(true); + Object o = field.get(null); + if(o != null && EntityDataAccessor.class.isAssignableFrom(o.getClass())) { + fieldsToSync.add(field); + } + } + for(Field field : fieldsToSync) { + int id = ((EntityDataAccessor)field.get(null)).id; + fieldsToSyncMap.computeIfAbsent(eClass, k -> new ArrayList<>()).add(Pair.of(field.getName(), id)); + } + } + } + EntityIDSyncPacket packet = new EntityIDSyncPacket(fieldsToSyncMap); + ModernFix.LOGGER.debug("Sending ID correction packet to client with " + fieldsToSyncMap.size() + " classes"); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(event::getPlayer), packet); + } catch(ObfuscationReflectionHelper.UnableToFindFieldException | ReflectiveOperationException e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/core/SynchedEntityDataMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/core/SynchedEntityDataMixin.java new file mode 100644 index 00000000..67133e3f --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/core/SynchedEntityDataMixin.java @@ -0,0 +1,24 @@ +package org.embeddedt.modernfix.mixin.core; + +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.world.entity.Entity; +import org.embeddedt.modernfix.ModernFixClient; +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(SynchedEntityData.class) +public class SynchedEntityDataMixin { + /** + * Store this in our set of all entity data objects. + * + * Not an ideal solution, but it should guarantee compatibility with mods. + */ + @Inject(method = "", at = @At("RETURN")) + private void storeInSet(Entity arg, CallbackInfo ci) { + synchronized (ModernFixClient.allEntityDatas) { + ModernFixClient.allEntityDatas.add((SynchedEntityData)(Object)this); + } + } +} diff --git a/src/main/java/org/embeddedt/modernfix/packet/EntityIDSyncPacket.java b/src/main/java/org/embeddedt/modernfix/packet/EntityIDSyncPacket.java new file mode 100644 index 00000000..6fe2c6b1 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/packet/EntityIDSyncPacket.java @@ -0,0 +1,78 @@ +package org.embeddedt.modernfix.packet; + +import com.mojang.datafixers.util.Pair; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.world.entity.Entity; +import org.embeddedt.modernfix.ModernFix; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.*; + +public class EntityIDSyncPacket { + private Map, List>> map; + + public EntityIDSyncPacket(Map, List>> map) { + this.map = map; + } + + public Map, List>> getFieldInfo() { + return this.map; + } + + public EntityIDSyncPacket() { + this.map = new HashMap<>(); + } + + public void serialize(FriendlyByteBuf buf) { + buf.writeVarInt(map.keySet().size()); + for(Map.Entry, List>> entry : map.entrySet()) { + buf.writeUtf(entry.getKey().getName()); + buf.writeVarInt(entry.getValue().size()); + for(Pair field : entry.getValue()) { + buf.writeUtf(field.getFirst()); + buf.writeVarInt(field.getSecond()); + } + } + } + + @SuppressWarnings("unchecked") + public static EntityIDSyncPacket deserialize(FriendlyByteBuf buf) { + EntityIDSyncPacket self = new EntityIDSyncPacket(); + int numEntityClasses = buf.readVarInt(); + for(int i = 0; i < numEntityClasses; i++) { + String clzName = buf.readUtf(); + try { + Class clz; + try { + clz = Class.forName(clzName); + } catch(ClassNotFoundException e) { + ModernFix.LOGGER.warn("Entity class not found: {}", clzName); + break; + } + if(!Entity.class.isAssignableFrom(clz)) { + ModernFix.LOGGER.error("Not an entity: " + clzName); + break; + } + int numFields = buf.readVarInt(); + for(int j = 0; j < numFields; j++) { + String fieldName = buf.readUtf(); + int id = buf.readVarInt(); + Field f = clz.getDeclaredField(fieldName); + if(!Modifier.isStatic(f.getModifiers())) + continue; + f.setAccessible(true); + if(!EntityDataAccessor.class.isAssignableFrom(f.get(null).getClass())) { + ModernFix.LOGGER.error("Not a data accessor field: " + clz + "." + fieldName); + continue; + } + self.map.computeIfAbsent((Class)clz, k -> new ArrayList<>()).add(Pair.of(fieldName, id)); + } + } catch(ReflectiveOperationException e) { + ModernFix.LOGGER.error("Error deserializing packet", e); + } + } + return self; + } +} diff --git a/src/main/java/org/embeddedt/modernfix/packet/PacketHandler.java b/src/main/java/org/embeddedt/modernfix/packet/PacketHandler.java new file mode 100644 index 00000000..7471e8fa --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/packet/PacketHandler.java @@ -0,0 +1,22 @@ +package org.embeddedt.modernfix.packet; + +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.fml.network.NetworkRegistry; +import net.minecraftforge.fml.network.simple.SimpleChannel; +import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.ModernFixClient; + +public class PacketHandler { + private static final String PROTOCOL_VERSION = "1"; + public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel( + new ResourceLocation(ModernFix.MODID, "main"), + () -> PROTOCOL_VERSION, + NetworkRegistry.acceptMissingOr(PROTOCOL_VERSION), + NetworkRegistry.acceptMissingOr(PROTOCOL_VERSION) + ); + + public static void register() { + int id = 1; + INSTANCE.registerMessage(id++, EntityIDSyncPacket.class, EntityIDSyncPacket::serialize, EntityIDSyncPacket::deserialize, ModernFixClient::handleEntityIDSync); + } +} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 47aa894e..a8145c22 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -8,4 +8,6 @@ public net.minecraft.client.renderer.model.ModelBakery field_217849_F # unbakedC 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 +public net.minecraft.client.Minecraft field_213277_ad # progressListener +public-f net.minecraft.network.datasync.DataParameter field_187157_a # id +public-f net.minecraft.network.datasync.EntityDataManager field_187234_c # itemsById \ No newline at end of file diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 4650ceeb..8dc0bbf7 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -57,6 +57,7 @@ ], "client": [ "core.MinecraftMixin", + "core.SynchedEntityDataMixin", "feature.measure_time.MinecraftMixin", "feature.reduce_loading_screen_freezes.ModelBakeryMixin", "perf.skip_first_datapack_reload.MinecraftMixin", From e8311d0b95e5ce45740e626443bd6bf68496c0a6 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 2 Mar 2023 16:04:03 -0500 Subject: [PATCH 12/20] Fix Twilight Forest CME during game startup --- build.gradle | 1 + .../core/config/ModernFixEarlyConfig.java | 1 + .../TwilightForestModMixin.java | 22 +++++++++++++++++++ src/main/resources/modernfix.mixins.json | 1 + 4 files changed, 25 insertions(+) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/bugfix/tf_cme_on_load/TwilightForestModMixin.java diff --git a/build.gradle b/build.gradle index db8e0333..a3395261 100644 --- a/build.gradle +++ b/build.gradle @@ -94,6 +94,7 @@ dependencies { modImplementation("curse.maven:jeresources-240630:3545538") modImplementation("curse.maven:jepb-437558:3172880") modImplementation("curse.maven:babel-436964:3196072") + modCompileOnly("curse.maven:twforest-227639:3575220") } tasks.withType(JavaCompile) { 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 22c90055..c458a5c0 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -37,6 +37,7 @@ public class ModernFixEarlyConfig { this.addMixinRule("bugfix.packet_leak", false); this.addMixinRule("bugfix.structure_manager_crash", true); this.addMixinRule("bugfix.mc218112", true); + this.addMixinRule("bugfix.tf_cme_on_load", true); this.addMixinRule("perf.async_jei", true); this.addMixinRule("perf.thread_priorities", true); this.addMixinRule("perf.preload_block_classes", false); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/bugfix/tf_cme_on_load/TwilightForestModMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/tf_cme_on_load/TwilightForestModMixin.java new file mode 100644 index 00000000..67f0bd2c --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/tf_cme_on_load/TwilightForestModMixin.java @@ -0,0 +1,22 @@ +package org.embeddedt.modernfix.mixin.bugfix.tf_cme_on_load; + +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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import twilightforest.TwilightForestMod; +import twilightforest.worldgen.biomes.BiomeKeys; + +@Mixin(TwilightForestMod.class) +public class TwilightForestModMixin { + @Redirect(method = "init", at = @At(value = "INVOKE", target = "Ltwilightforest/worldgen/biomes/BiomeKeys;addBiomeTypes()V"), remap = false) + private static void avoidBiomeTypes() { + + } + + @Inject(method = "lambda$init$1", at = @At(value = "INVOKE", target = "Ltwilightforest/block/TFBlocks;tfCompostables()V", ordinal = 0)) + private static void doBiomeTypes(CallbackInfo ci) { + BiomeKeys.addBiomeTypes(); + } +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 8dc0bbf7..b79452ef 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -8,6 +8,7 @@ "mixins": [ "bugfix.edge_chunk_not_saved.ChunkManagerMixin", "bugfix.structure_manager_crash.StructureManagerMixin", + "bugfix.tf_cme_on_load.TwilightForestModMixin", "perf.remove_biome_temperature_cache.BiomeMixin", "perf.resourcepacks.ModFileResourcePackMixin", "perf.resourcepacks.VanillaPackMixin", From 0cf089febedeab72b43457f25e864c85cd1072a0 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 2 Mar 2023 16:11:15 -0500 Subject: [PATCH 13/20] Skip entity ID sync in singleplayer --- .../embeddedt/modernfix/entity/EntityDataIDSyncHandler.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/embeddedt/modernfix/entity/EntityDataIDSyncHandler.java b/src/main/java/org/embeddedt/modernfix/entity/EntityDataIDSyncHandler.java index e1124721..63b47dd3 100644 --- a/src/main/java/org/embeddedt/modernfix/entity/EntityDataIDSyncHandler.java +++ b/src/main/java/org/embeddedt/modernfix/entity/EntityDataIDSyncHandler.java @@ -30,6 +30,10 @@ public class EntityDataIDSyncHandler { @SuppressWarnings("unchecked") public static void onDatapackSyncEvent(OnDatapackSyncEvent event) { if(event.getPlayer() != null) { + if(!ServerLifecycleHooks.getCurrentServer().isDedicatedServer() && event.getPlayerList().getPlayerCount() == 0) { + ModernFix.LOGGER.debug("Not syncing IDs on integrated server"); + return; + } /* Compute the current set of serializer IDs in use and send them */ try { if(fieldsToSyncMap == null) { From 5560ef47c0dc04b1f0f213ff7d0c70dbc432f57a Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 3 Mar 2023 21:18:22 -0500 Subject: [PATCH 14/20] Make JEResources compileOnly on 1.18 since it behaves weirdly in dev --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index dbd4a66d..2268061a 100644 --- a/build.gradle +++ b/build.gradle @@ -91,7 +91,7 @@ dependencies { modCompileOnly("mezz.jei:jei-${minecraft_version}-forge:${jei_version}") modRuntimeOnly("curse.maven:jei-238222:4352925") - modImplementation("curse.maven:jeresources-240630:3831559") + modCompileOnly("curse.maven:jeresources-240630:3831559") } tasks.withType(JavaCompile) { From 010de8c30fec8750b81cf96e4e14ddea2f838a47 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 3 Mar 2023 21:20:02 -0500 Subject: [PATCH 15/20] Mark branding mixin as not required --- .../modernfix/mixin/feature/branding/BrandingControlMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/feature/branding/BrandingControlMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/feature/branding/BrandingControlMixin.java index 83f59aa4..fc0c618d 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/feature/branding/BrandingControlMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/feature/branding/BrandingControlMixin.java @@ -15,7 +15,7 @@ import java.util.Optional; @Mixin(value = BrandingControl.class, remap = false) public class BrandingControlMixin { - @Inject(method = "computeBranding", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/ModList;get()Lnet/minecraftforge/fml/ModList;"), locals = LocalCapture.CAPTURE_FAILHARD) + @Inject(method = "computeBranding", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/ModList;get()Lnet/minecraftforge/fml/ModList;"), locals = LocalCapture.CAPTURE_FAILHARD, require = 0) private static void addModernFixBranding(CallbackInfo ci, ImmutableList.Builder builder) { Optional mfContainer = ModList.get().getModContainerById("modernfix"); if(mfContainer.isPresent()) From 84ba47f174fadc28680120dfc483b98ce40a7226 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 3 Mar 2023 21:43:32 -0500 Subject: [PATCH 16/20] Fix compatibility with Performant --- .../embeddedt/modernfix/core/config/ModernFixEarlyConfig.java | 1 + 1 file changed, 1 insertion(+) 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 c458a5c0..43baf26b 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -65,6 +65,7 @@ public class ModernFixEarlyConfig { disableIfModPresent("mixin.perf.thread_priorities", "smoothboot"); disableIfModPresent("mixin.perf.async_jei", "modernui"); disableIfModPresent("mixin.perf.compress_biome_container", "chocolate"); + disableIfModPresent("mixin.bugfix.mc218112", "performant"); } private void disableIfModPresent(String configName, String... ids) { From a54e7b831a57d49831ad783f920490867a430450 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 4 Mar 2023 09:10:12 -0500 Subject: [PATCH 17/20] Improve compatibility of ID desync fix, and add Roadrunner support --- .../embeddedt/modernfix/ModernFixClient.java | 35 +++++++++++++++++-- .../mc218112/SynchedEntityDataMixin.java | 34 ------------------ .../resources/META-INF/accesstransformer.cfg | 3 +- src/main/resources/modernfix.mixins.json | 1 - 4 files changed, 34 insertions(+), 39 deletions(-) delete mode 100644 src/main/java/org/embeddedt/modernfix/mixin/bugfix/mc218112/SynchedEntityDataMixin.java diff --git a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java index 7b97709a..f0bd2dfc 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java @@ -1,6 +1,7 @@ package org.embeddedt.modernfix; import com.mojang.datafixers.util.Pair; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.ConnectScreen; import net.minecraft.client.gui.screens.TitleScreen; @@ -105,7 +106,19 @@ public class ModernFixClient { * * This is to ensure we can perform ID fixup on already constructed managers. */ - public static Set allEntityDatas = Collections.newSetFromMap(new WeakHashMap<>()); + public static final Set allEntityDatas = Collections.newSetFromMap(new WeakHashMap<>()); + + private static final Field entriesArrayField; + static { + Field field; + try { + field = SynchedEntityData.class.getDeclaredField("entriesArray"); + field.setAccessible(true); + } catch(ReflectiveOperationException e) { + field = null; + } + entriesArrayField = field; + } /** * Extremely hacky method to detect and correct mismatched entity data parameter IDs on the client and server. @@ -140,12 +153,28 @@ public class ModernFixClient { if(fixNeeded) { dataEntries = new ArrayList<>(allEntityDatas); for(SynchedEntityData manager : dataEntries) { - Map> fixedMap = new HashMap<>(); + Int2ObjectOpenHashMap> fixedMap = new Int2ObjectOpenHashMap<>(); List> items = new ArrayList<>(manager.itemsById.values()); for(SynchedEntityData.DataItem item : items) { fixedMap.put(item.getAccessor().id, item); } - manager.itemsById = fixedMap; + manager.lock.writeLock().lock(); + try { + manager.itemsById.replaceAll((id, parameter) -> fixedMap.get((int)id)); + if(entriesArrayField != null) { + try { + SynchedEntityData.DataItem[] dataArray = new SynchedEntityData.DataItem[items.size()]; + for(int i = 0; i < dataArray.length; i++) { + dataArray[i] = fixedMap.get(i); + } + entriesArrayField.set(manager, dataArray); + } catch(ReflectiveOperationException e) { + ModernFix.LOGGER.error(e); + } + } + } finally { + manager.lock.writeLock().unlock(); + } } } allEntityDatas.clear(); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/bugfix/mc218112/SynchedEntityDataMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/mc218112/SynchedEntityDataMixin.java deleted file mode 100644 index 64b4f16b..00000000 --- a/src/main/java/org/embeddedt/modernfix/mixin/bugfix/mc218112/SynchedEntityDataMixin.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.embeddedt.modernfix.mixin.bugfix.mc218112; - -import net.minecraft.network.syncher.EntityDataAccessor; -import net.minecraft.network.syncher.SynchedEntityData; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; - -import java.util.Map; -import java.util.concurrent.locks.ReadWriteLock; - -@Mixin(SynchedEntityData.class) -public class SynchedEntityDataMixin { - @Shadow @Final private Map> itemsById; - - @Shadow @Final private ReadWriteLock lock; - - @Shadow private boolean isEmpty; - - @Inject(method = "createDataItem", at = @At(value = "INVOKE", target = "Ljava/util/Map;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) - private void putWithLock(EntityDataAccessor key, T value, CallbackInfo ci, SynchedEntityData.DataItem item) { - ci.cancel(); - try { - this.itemsById.put(key.getId(), item); - this.isEmpty = false; - } finally { - this.lock.writeLock().unlock(); - } - } -} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index a8145c22..7e921c8a 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -10,4 +10,5 @@ public net.minecraft.util.concurrent.ThreadTaskExecutor func_213160_bf()V # runA public net.minecraft.server.MinecraftServer field_211151_aa # nextTickTime public net.minecraft.client.Minecraft field_213277_ad # progressListener public-f net.minecraft.network.datasync.DataParameter field_187157_a # id -public-f net.minecraft.network.datasync.EntityDataManager field_187234_c # itemsById \ No newline at end of file +public-f net.minecraft.network.datasync.EntityDataManager field_187234_c # itemsById +public-f net.minecraft.network.datasync.EntityDataManager field_187235_d # lock \ No newline at end of file diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index b79452ef..d42fa2d3 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -53,7 +53,6 @@ "perf.fast_registry_validation.ForgeRegistryMixin", "perf.cache_strongholds.ChunkGeneratorMixin", "perf.cache_upgraded_structures.StructureManagerMixin", - "bugfix.mc218112.SynchedEntityDataMixin", "perf.cache_strongholds.ServerLevelMixin" ], "client": [ From 1c9935e2986906940956e057cdcc0bb56f0a1c36 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 4 Mar 2023 10:36:11 -0500 Subject: [PATCH 18/20] Use MethodHandles to select LWJGL 3.3 methods if needed --- .../modernfix/textures/StbStitcher.java | 113 +++++++++++++++++- 1 file changed, 111 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java b/src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java index cc386233..d2fbb230 100644 --- a/src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java +++ b/src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java @@ -11,12 +11,119 @@ import org.lwjgl.stb.STBRPNode; import org.lwjgl.stb.STBRPRect; import org.lwjgl.stb.STBRectPack; +import static java.lang.invoke.MethodHandles.*; +import static java.lang.invoke.MethodType.*; + +import java.lang.invoke.MethodHandle; +import java.sql.Ref; 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 { + /* Most of this logic is to allow use of LWJGL versions where coordinates are short and versions where they are int */ + private static final MethodHandle MH_rect_shortSet, MH_rect_intSet, MH_rect_intX, MH_rect_intY, MH_rect_shortX, + MH_rect_shortY; + + static { + MethodHandle shortM = null, intM = null; + List exceptions = new ArrayList<>(); + try { + intM = publicLookup().findVirtual(STBRPRect.class, "set", methodType(STBRPRect.class, + int.class, /* id */ + int.class, + int.class, + int.class, + int.class, + boolean.class)); + } catch(ReflectiveOperationException e) { + exceptions.add(e); + } + try { + shortM = publicLookup().findVirtual(STBRPRect.class, "set", methodType(STBRPRect.class, + int.class, /* id */ + short.class, + short.class, + short.class, + short.class, + boolean.class)); + } catch(ReflectiveOperationException e) { + exceptions.add(e); + } + if(shortM == null && intM == null) { + IllegalStateException e = new IllegalStateException("An STBRPRect set method could not be located"); + exceptions.forEach(e::addSuppressed); + throw e; + } + MH_rect_shortSet = shortM; + MH_rect_intSet = intM; + /* Now look for X methods */ + exceptions.clear(); + try { + intM = publicLookup().findVirtual(STBRPRect.class, "x", methodType(int.class)); + } catch(ReflectiveOperationException e) { + exceptions.add(e); + } + try { + shortM = publicLookup().findVirtual(STBRPRect.class, "x", methodType(short.class)); + } catch(ReflectiveOperationException e) { + exceptions.add(e); + } + if(shortM == null && intM == null) { + IllegalStateException e = new IllegalStateException("An STBRPRect x() method could not be located"); + exceptions.forEach(e::addSuppressed); + throw e; + } + MH_rect_shortX = shortM; + MH_rect_intX = intM; + /* Assume that Y is the same */ + try { + if(MH_rect_shortX != null) { + MH_rect_shortY = publicLookup().findVirtual(STBRPRect.class, "y", methodType(short.class)); + MH_rect_intY = null; + } else { /* it must be int */ + MH_rect_intY = publicLookup().findVirtual(STBRPRect.class, "y", methodType(int.class)); + MH_rect_shortY = null; + } + } catch(ReflectiveOperationException e) { + throw new IllegalStateException("An STBRPRect y() method could not be located", e); + } + } + + private static STBRPRect setWrapper(STBRPRect rect, int id, int width, int height, int x, int y, boolean was_packed) { + try { + if(MH_rect_shortSet != null) + return (STBRPRect)MH_rect_shortSet.invokeExact(rect, id, (short)width, (short)height, (short)0, (short)0, false); + else + return (STBRPRect)MH_rect_intSet.invokeExact(rect, id, width, height, 0, 0, false); + } catch(Throwable e) { + throw new AssertionError(e); + } + } + + private static int getX(STBRPRect rect) { + try { + if(MH_rect_shortX != null) + return (short)MH_rect_shortX.invokeExact(rect); + else + return (int)MH_rect_intX.invokeExact(rect); + } catch(Throwable e) { + throw new AssertionError(e); + } + } + + private static int getY(STBRPRect rect) { + try { + if(MH_rect_shortX != null) + return (short)MH_rect_shortY.invokeExact(rect); + else + return (int)MH_rect_intY.invokeExact(rect); + } catch(Throwable e) { + throw new AssertionError(e); + } + } + public static Pair, List> packRects(Stitcher.Holder[] holders) { int holderSize = holders.length; @@ -36,7 +143,9 @@ public class StbStitcher { 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); + STBRPRect rect = rectBuf.get(j); + + setWrapper(rect, j, width, height, 0, 0, false); sqSize += (width * height); } @@ -63,7 +172,7 @@ public class StbStitcher { } // 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())); + infoList.add(new LoadableSpriteInfo(holder.spriteInfo, width, height, getX(rect), getY(rect))); //holder.spriteInfo.initSprite(size, size, rect.x(), rect.y(), false); } From 6d7a450ec8ba6e18856a9ce77c147512c0bdf833 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 4 Mar 2023 15:05:24 -0500 Subject: [PATCH 19/20] Modify branding control mixin priority --- .../modernfix/mixin/feature/branding/BrandingControlMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/feature/branding/BrandingControlMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/feature/branding/BrandingControlMixin.java index fc0c618d..2afc8190 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/feature/branding/BrandingControlMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/feature/branding/BrandingControlMixin.java @@ -13,7 +13,7 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import java.util.List; import java.util.Optional; -@Mixin(value = BrandingControl.class, remap = false) +@Mixin(value = BrandingControl.class, remap = false, priority = 1100) public class BrandingControlMixin { @Inject(method = "computeBranding", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/ModList;get()Lnet/minecraftforge/fml/ModList;"), locals = LocalCapture.CAPTURE_FAILHARD, require = 0) private static void addModernFixBranding(CallbackInfo ci, ImmutableList.Builder builder) { From 95d4430064b8da11aa79bbf5aba8c4a4216d749c Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 4 Mar 2023 15:34:14 -0500 Subject: [PATCH 20/20] Mark 1.18 versions as beta --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2268061a..e51ee094 100644 --- a/build.gradle +++ b/build.gradle @@ -157,7 +157,7 @@ curseforge { id = "790626" changelog = '[Changelog is not currently available]' changelogType = "markdown" - releaseType = "release" + releaseType = "beta" addGameVersion "Forge" addGameVersion minecraft_version mainArtifact remapJar