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 01/12] 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 02/12] 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 03/12] 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 04/12] 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 05/12] 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 06/12] 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 07/12] 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 08/12] 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 09/12] 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 10/12] 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 11/12] 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 12/12] 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) {