From 21177ea0e4f926a2e459e31dbadab1f134cbba99 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 29 Apr 2023 16:36:10 -0400 Subject: [PATCH 01/10] Fix mixin crash --- .../ItemModelShaperMixin.java | 67 +-------------- .../modernfix/util/ItemMesherMap.java | 85 +++++++++++++++++++ 2 files changed, 87 insertions(+), 65 deletions(-) create mode 100644 src/main/java/org/embeddedt/modernfix/util/ItemMesherMap.java diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ItemModelShaperMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ItemModelShaperMixin.java index 018cdf66..62d3c0a6 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ItemModelShaperMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ItemModelShaperMixin.java @@ -9,6 +9,7 @@ import net.minecraftforge.client.ItemModelMesherForge; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.IRegistryDelegate; import org.embeddedt.modernfix.dynamicresources.ModelLocationCache; +import org.embeddedt.modernfix.util.ItemMesherMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.*; @@ -37,71 +38,7 @@ public abstract class ItemModelShaperMixin extends ItemModelShaper { private void replaceLocationMap(CallbackInfo ci) { overrideLocations = new HashMap<>(); // need to replace this map because mods query locations through it - locations = new Map, ModelResourceLocation>() { - @Override - public int size() { - return ForgeRegistries.ITEMS.getValues().size(); - } - - @Override - public boolean isEmpty() { - return false; - } - - @Override - public boolean containsKey(Object key) { - return true; - } - - @Override - public boolean containsValue(Object value) { - return false; - } - - @Override - public ModelResourceLocation get(Object key) { - return getLocation(((IRegistryDelegate)key).get()); - } - - @Nullable - @Override - public ModelResourceLocation put(IRegistryDelegate key, ModelResourceLocation value) { - throw new UnsupportedOperationException(); - } - - @Override - public ModelResourceLocation remove(Object key) { - throw new UnsupportedOperationException(); - } - - @Override - public void putAll(@NotNull Map, ? extends ModelResourceLocation> m) { - throw new UnsupportedOperationException(); - } - - @Override - public void clear() { - throw new UnsupportedOperationException(); - } - - @NotNull - @Override - public Set> keySet() { - throw new UnsupportedOperationException(); - } - - @NotNull - @Override - public Collection values() { - throw new UnsupportedOperationException(); - } - - @NotNull - @Override - public Set, ModelResourceLocation>> entrySet() { - throw new UnsupportedOperationException(); - } - }; + locations = new ItemMesherMap(this::getLocation); } private ModelResourceLocation getLocation(Item item) { diff --git a/src/main/java/org/embeddedt/modernfix/util/ItemMesherMap.java b/src/main/java/org/embeddedt/modernfix/util/ItemMesherMap.java new file mode 100644 index 00000000..d3f19f80 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/util/ItemMesherMap.java @@ -0,0 +1,85 @@ +package org.embeddedt.modernfix.util; + +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.IRegistryDelegate; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; + +public class ItemMesherMap implements Map, ModelResourceLocation> { + private final Function getLocation; + + public ItemMesherMap(Function getLocation) { + this.getLocation = getLocation; + } + + @Override + public int size() { + return ForgeRegistries.ITEMS.getValues().size(); + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean containsKey(Object key) { + return true; + } + + @Override + public boolean containsValue(Object value) { + return false; + } + + @Override + public ModelResourceLocation get(Object key) { + return getLocation.apply(((IRegistryDelegate)key).get()); + } + + @Nullable + @Override + public ModelResourceLocation put(IRegistryDelegate key, ModelResourceLocation value) { + throw new UnsupportedOperationException(); + } + + @Override + public ModelResourceLocation remove(Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public void putAll(@NotNull Map, ? extends ModelResourceLocation> m) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public Set> keySet() { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public Collection values() { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public Set, ModelResourceLocation>> entrySet() { + throw new UnsupportedOperationException(); + } +} From 609da0f5455cc720f9c1b1f7e547f99f1cf14053 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 29 Apr 2023 16:50:02 -0400 Subject: [PATCH 02/10] Add option to remove spawn chunks --- .../core/config/ModernFixEarlyConfig.java | 1 + .../mixin/devenv/MinecraftServerMixin.java | 21 -------------- .../MinecraftServerMixin.java | 26 +++++++++++++++++ .../ServerChunkCacheAccessor.java | 12 ++++++++ .../remove_spawn_chunks/ServerLevelMixin.java | 28 +++++++++++++++++++ src/main/resources/modernfix.mixins.json | 4 ++- 6 files changed, 70 insertions(+), 22 deletions(-) delete mode 100644 src/main/java/org/embeddedt/modernfix/mixin/devenv/MinecraftServerMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/MinecraftServerMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/ServerChunkCacheAccessor.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/ServerLevelMixin.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 a2770142..1921a81d 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -104,6 +104,7 @@ public class ModernFixEarlyConfig { this.addMixinRule("launch.class_search_cache", true); boolean isDevEnv = !FMLLoader.isProduction() && FMLLoader.getLoadingModList().getModFileById("modernfix").getFile().getLocator() instanceof ExplodedDirectoryLocator; this.addMixinRule("devenv", isDevEnv); + this.addMixinRule("perf.remove_spawn_chunks", isDevEnv); /* Mod compat */ disableIfModPresent("mixin.perf.thread_priorities", "smoothboot"); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/devenv/MinecraftServerMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/devenv/MinecraftServerMixin.java deleted file mode 100644 index 176ac2c6..00000000 --- a/src/main/java/org/embeddedt/modernfix/mixin/devenv/MinecraftServerMixin.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.embeddedt.modernfix.mixin.devenv; - -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerChunkCache; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -/* Disable waiting for spawn chunk load */ -@Mixin(MinecraftServer.class) -public class MinecraftServerMixin { - @Redirect(method = "prepareLevels", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;getTickingGenerated()I")) - private int noSpawnChunkWait(ServerChunkCache cache) { - return 441; - } - - @Redirect(method = "prepareLevels", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;waitUntilNextTick()V")) - private void noWaitTick(MinecraftServer server) { - - } -} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/MinecraftServerMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/MinecraftServerMixin.java new file mode 100644 index 00000000..c48deeda --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/MinecraftServerMixin.java @@ -0,0 +1,26 @@ +package org.embeddedt.modernfix.mixin.perf.remove_spawn_chunks; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.DistanceManager; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.TicketType; +import net.minecraft.util.Unit; +import net.minecraft.world.level.ChunkPos; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(value = MinecraftServer.class, priority = 1100) +public class MinecraftServerMixin { + @Redirect(method = "prepareLevels", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;addRegionTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V")) + private void addSpawnChunkTicket(ServerChunkCache cache, TicketType type, ChunkPos pos, int distance, Object o) { + DistanceManager manager = ((ServerChunkCacheAccessor)cache).getDistanceManager(); + /* make one chunk load */ + manager.addTicket(TicketType.START, pos, 44, Unit.INSTANCE); + } + + @Redirect(method = "prepareLevels", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;getTickingGenerated()I"), require = 0) + private int getGenerated(ServerChunkCache cache) { + return 441; + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/ServerChunkCacheAccessor.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/ServerChunkCacheAccessor.java new file mode 100644 index 00000000..76ed3c26 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/ServerChunkCacheAccessor.java @@ -0,0 +1,12 @@ +package org.embeddedt.modernfix.mixin.perf.remove_spawn_chunks; + +import net.minecraft.server.level.DistanceManager; +import net.minecraft.server.level.ServerChunkCache; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ServerChunkCache.class) +public interface ServerChunkCacheAccessor { + @Accessor("distanceManager") + DistanceManager getDistanceManager(); +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/ServerLevelMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/ServerLevelMixin.java new file mode 100644 index 00000000..3545dbbe --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/ServerLevelMixin.java @@ -0,0 +1,28 @@ +package org.embeddedt.modernfix.mixin.perf.remove_spawn_chunks; + +import net.minecraft.server.level.DistanceManager; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.TicketType; +import net.minecraft.util.Unit; +import net.minecraft.world.level.ChunkPos; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(ServerLevel.class) +public class ServerLevelMixin { + @Redirect(method = "setDefaultSpawnPos", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;removeRegionTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V")) + private void removeTicket(ServerChunkCache cache, TicketType type, ChunkPos pos, int distance, Object o) { + DistanceManager manager = ((ServerChunkCacheAccessor)cache).getDistanceManager(); + /* make one chunk load */ + manager.removeTicket(TicketType.START, pos, 44, Unit.INSTANCE); + } + + @Redirect(method = "setDefaultSpawnPos", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;addRegionTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V")) + private void addTicket(ServerChunkCache cache, TicketType type, ChunkPos pos, int distance, Object o) { + DistanceManager manager = ((ServerChunkCacheAccessor)cache).getDistanceManager(); + /* make one chunk load */ + manager.addTicket(TicketType.START, pos, 44, Unit.INSTANCE); + } +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index bc1b1668..bdfba0a8 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -76,7 +76,9 @@ "perf.compress_blockstate.BlockBehaviourMixin", "perf.dedup_blockstate_flattening_map.BlockStateDataMixin", "perf.dedup_blockstate_flattening_map.ChunkPalettedStorageFixMixin", - "devenv.MinecraftServerMixin", + "perf.remove_spawn_chunks.ServerChunkCacheAccessor", + "perf.remove_spawn_chunks.MinecraftServerMixin", + "perf.remove_spawn_chunks.ServerLevelMixin", "devenv.GameDataMixin" ], "client": [ From fe0b82e6da1eaf892e3d74ee8a57bd762e672edb Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 29 Apr 2023 17:33:10 -0400 Subject: [PATCH 03/10] Fix RemoveBlockGoal permaloading chunks, remove START ticket entirely --- .../core/config/ModernFixEarlyConfig.java | 1 + .../RemoveBlockGoalMixin.java | 33 +++++++++++++++++++ .../MinecraftServerMixin.java | 6 ++-- .../remove_spawn_chunks/ServerLevelMixin.java | 8 ----- src/main/resources/modernfix.mixins.json | 1 + 5 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/bugfix/remove_block_chunkloading/RemoveBlockGoalMixin.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 1921a81d..60483967 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -75,6 +75,7 @@ public class ModernFixEarlyConfig { this.addMixinRule("perf.dynamic_structure_manager", true); this.addMixinRule("bugfix.mc218112", true); this.addMixinRule("bugfix.chunk_deadlock", true); + this.addMixinRule("bugfix.remove_block_chunkloading", true); this.addMixinRule("bugfix.paper_chunk_patches", true); this.addMixinRule("bugfix.chunk_deadlock.valhesia", modPresent("valhelsia_structures")); this.addMixinRule("bugfix.tf_cme_on_load", modPresent("twilightforest")); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/bugfix/remove_block_chunkloading/RemoveBlockGoalMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/remove_block_chunkloading/RemoveBlockGoalMixin.java new file mode 100644 index 00000000..4f5d4521 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/remove_block_chunkloading/RemoveBlockGoalMixin.java @@ -0,0 +1,33 @@ +package org.embeddedt.modernfix.mixin.bugfix.remove_block_chunkloading; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.ai.goal.RemoveBlockGoal; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.event.ForgeEventFactory; +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(RemoveBlockGoal.class) +public class RemoveBlockGoalMixin { + @Shadow @Final private Mob removerMob; + + @Redirect(method = "canUse", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/common/ForgeHooks;canEntityDestroy(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/LivingEntity;)Z")) + private boolean fireGriefingEvent(Level level, BlockPos pos, LivingEntity entity) { + return ForgeEventFactory.getMobGriefingEvent(level, entity); + } + + @Redirect(method = "isValidTarget", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;is(Lnet/minecraft/world/level/block/Block;)Z")) + private boolean checkBlockValidDestroyTarget(BlockState state, Block desiredBlock, LevelReader level, BlockPos pos) { + if(!(state.canEntityDestroy(level, pos, this.removerMob) && ForgeEventFactory.onEntityDestroyBlock(this.removerMob, pos, state))) + return false; + return state.is(desiredBlock); + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/MinecraftServerMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/MinecraftServerMixin.java index c48deeda..ab053461 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/MinecraftServerMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/MinecraftServerMixin.java @@ -6,6 +6,7 @@ import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.TicketType; import net.minecraft.util.Unit; import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.ChunkStatus; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; @@ -14,9 +15,8 @@ import org.spongepowered.asm.mixin.injection.Redirect; public class MinecraftServerMixin { @Redirect(method = "prepareLevels", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;addRegionTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V")) private void addSpawnChunkTicket(ServerChunkCache cache, TicketType type, ChunkPos pos, int distance, Object o) { - DistanceManager manager = ((ServerChunkCacheAccessor)cache).getDistanceManager(); - /* make one chunk load */ - manager.addTicket(TicketType.START, pos, 44, Unit.INSTANCE); + // load first chunk + cache.getChunk(pos.x, pos.z, ChunkStatus.FULL, true); } @Redirect(method = "prepareLevels", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;getTickingGenerated()I"), require = 0) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/ServerLevelMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/ServerLevelMixin.java index 3545dbbe..7e61e732 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/ServerLevelMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/remove_spawn_chunks/ServerLevelMixin.java @@ -1,10 +1,8 @@ package org.embeddedt.modernfix.mixin.perf.remove_spawn_chunks; -import net.minecraft.server.level.DistanceManager; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.TicketType; -import net.minecraft.util.Unit; import net.minecraft.world.level.ChunkPos; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -14,15 +12,9 @@ import org.spongepowered.asm.mixin.injection.Redirect; public class ServerLevelMixin { @Redirect(method = "setDefaultSpawnPos", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;removeRegionTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V")) private void removeTicket(ServerChunkCache cache, TicketType type, ChunkPos pos, int distance, Object o) { - DistanceManager manager = ((ServerChunkCacheAccessor)cache).getDistanceManager(); - /* make one chunk load */ - manager.removeTicket(TicketType.START, pos, 44, Unit.INSTANCE); } @Redirect(method = "setDefaultSpawnPos", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;addRegionTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V")) private void addTicket(ServerChunkCache cache, TicketType type, ChunkPos pos, int distance, Object o) { - DistanceManager manager = ((ServerChunkCacheAccessor)cache).getDistanceManager(); - /* make one chunk load */ - manager.addTicket(TicketType.START, pos, 44, Unit.INSTANCE); } } diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index bdfba0a8..6b05bb8c 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -20,6 +20,7 @@ "bugfix.refinedstorage.te_bug.FluidExternalStorageMixin", "bugfix.refinedstorage.te_bug.ItemExternalStorageCacheMixin", "bugfix.refinedstorage.te_bug.ItemExternalStorageMixin", + "bugfix.remove_block_chunkloading.RemoveBlockGoalMixin", "bugfix.chunk_deadlock.ServerChunkCacheMixin", "bugfix.chunk_deadlock.valhesia.BlockStateBaseMixin", "perf.dedicated_reload_executor.MinecraftServerMixin", From e7a1ce74cc83d5d4327fa11af274e949f34dd1c8 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 29 Apr 2023 20:35:18 -0400 Subject: [PATCH 04/10] Move pack caching logic into separate version-independent class --- .../ModFileResourcePackMixin.java | 99 +++-------------- .../perf/resourcepacks/VanillaPackMixin.java | 4 +- .../CachedResourcePath.java | 41 +++---- .../resources/PackResourcesCacheEngine.java | 100 ++++++++++++++++++ 4 files changed, 134 insertions(+), 110 deletions(-) rename src/main/java/org/embeddedt/modernfix/{util => resources}/CachedResourcePath.java (70%) create mode 100644 src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java 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 cd8a862e..ee0e070a 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 @@ -1,20 +1,14 @@ package org.embeddedt.modernfix.mixin.perf.resourcepacks; -import com.google.common.base.Joiner; -import com.google.common.collect.Interner; -import com.google.common.collect.Interners; import net.minecraft.server.packs.PackType; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.ResourcePackFileNotFoundException; import net.minecraftforge.fml.loading.moddiscovery.ModFile; import net.minecraftforge.fml.packs.ModFileResourcePack; -import org.apache.commons.lang3.tuple.Triple; -import org.embeddedt.modernfix.util.CachedResourcePath; -import org.embeddedt.modernfix.util.FileUtil; +import org.embeddedt.modernfix.resources.PackResourcesCacheEngine; import org.embeddedt.modernfix.util.PackTypeHelper; 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; @@ -27,89 +21,34 @@ import java.io.InputStream; import java.nio.file.*; import java.util.*; import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.Stream; @Mixin(ModFileResourcePack.class) public abstract class ModFileResourcePackMixin { @Shadow public abstract Set getNamespaces(PackType type); @Shadow(remap = false) @Final private ModFile modFile; - private EnumMap> namespacesByType; - private EnumMap>> rootListingByNamespaceAndType; - private Set containedPaths; - private boolean useNamespaceCaches; - private FileSystem resourcePackFS; - private static Joiner slashJoiner = Joiner.on('/'); + + private PackResourcesCacheEngine cacheEngine; @Inject(method = "", at = @At("TAIL")) private void cacheResources(ModFile modFile, CallbackInfo ci) { - this.resourcePackFS = modFile.getLocator().findPath(modFile, "").getFileSystem(); - this.useNamespaceCaches = false; - this.namespacesByType = new EnumMap<>(PackType.class); - for(PackType type : PackType.values()) { - if(!PackTypeHelper.isVanillaPackType(type)) - continue; - this.namespacesByType.put(type, this.getNamespaces(type)); - } - this.useNamespaceCaches = true; - this.rootListingByNamespaceAndType = new EnumMap<>(PackType.class); - this.containedPaths = new HashSet<>(); - for(PackType type : PackType.values()) { - Set namespaces = PackTypeHelper.isVanillaPackType(type) ? this.namespacesByType.get(type) : this.getNamespaces(type); - HashMap> rootListingForNamespaces = new HashMap<>(); - for(String namespace : namespaces) { - try { - Path root = modFile.getLocator().findPath(modFile, type.getDirectory(), namespace).toAbsolutePath(); - try (Stream stream = Files.walk(root)) { - ArrayList rootListingPaths = new ArrayList<>(); - stream - .map(path -> root.relativize(path.toAbsolutePath())) - .filter(this::isValidCachedResourcePath) - .forEach(path -> { - CachedResourcePath listing = new CachedResourcePath(path); - if(!listing.getFileName().endsWith(".mcmeta")) { - rootListingPaths.add(listing); - } - this.containedPaths.add(new CachedResourcePath(new String[] { type.getDirectory(), namespace }, listing)); - }); - rootListingPaths.trimToSize(); - rootListingForNamespaces.put(namespace, rootListingPaths); - } - } catch(IOException e) { - rootListingForNamespaces.put(namespace, Collections.emptyList()); - } - } - if(PackTypeHelper.isVanillaPackType(type)) - this.rootListingByNamespaceAndType.put(type, rootListingForNamespaces); - } + this.cacheEngine = new PackResourcesCacheEngine(this::getNamespaces, (type, namespace) -> { + return modFile.getLocator().findPath(modFile, type.getDirectory(), namespace); + }); } - - private boolean isValidCachedResourcePath(Path path) { - if(path.getFileName() == null || path.getNameCount() == 0) { - return false; - } - String str = path.toString(); - if(str.length() == 0) - return false; - for(int i = 0; i < str.length(); i++) { - if(!ResourceLocation.validPathChar(str.charAt(i))) { - return false; - } - } - return true; - } - @Inject(method = "getNamespaces", at = @At("HEAD"), cancellable = true) private void useCacheForNamespaces(PackType type, CallbackInfoReturnable> cir) { - if(useNamespaceCaches && PackTypeHelper.isVanillaPackType(type)) { - cir.setReturnValue(this.namespacesByType.get(type)); + if(cacheEngine != null) { + Set namespaces = cacheEngine.getNamespaces(type); + if(namespaces != null) + cir.setReturnValue(namespaces); } } @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(new CachedResourcePath(path))); + if(cacheEngine != null) + cir.setReturnValue(this.cacheEngine.hasResource(path)); } @Inject(method = "getResource(Ljava/lang/String;)Ljava/io/InputStream;", at = @At(value = "INVOKE", target = "Ljava/nio/file/Files;exists(Ljava/nio/file/Path;[Ljava/nio/file/LinkOption;)Z"), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) @@ -128,18 +67,8 @@ public abstract class ModFileResourcePackMixin { @Inject(method = "getResources", at = @At("HEAD"), cancellable = true) private void fastGetResources(PackType type, String resourceNamespace, String pathIn, int maxDepth, Predicate filter, CallbackInfoReturnable> cir) { - if(!PackTypeHelper.isVanillaPackType(type)) + if(!PackTypeHelper.isVanillaPackType(type) || this.cacheEngine == null) return; - if(!pathIn.endsWith("/")) - pathIn = pathIn + "/"; - final String testPath = pathIn; - cir.setReturnValue(this.rootListingByNamespaceAndType.get(type).getOrDefault(resourceNamespace, Collections.emptyList()).stream(). - filter(path -> path.getNameCount() <= maxDepth). // Make sure the depth is within bounds - filter(path -> path.getFullPath().startsWith(testPath)). // Make sure the target path is inside this one - filter(path -> filter.test(path.getFileName())). // Test the file name against the predicate - // Finally we need to form the RL, so use the first name as the domain, and the rest as the path - // It is VERY IMPORTANT that we do not rely on Path.toString as this is inconsistent between operating systems - map(path -> new ResourceLocation(resourceNamespace, path.getFullPath())). - collect(Collectors.toList())); + cir.setReturnValue(this.cacheEngine.getResources(type, resourceNamespace, pathIn, maxDepth, filter)); } } 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 4e991034..54a52349 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 @@ -4,6 +4,7 @@ import com.google.common.base.Joiner; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.minecraft.server.packs.PackType; import net.minecraft.server.packs.VanillaPackResources; import net.minecraft.resources.ResourceLocation; @@ -40,7 +41,7 @@ public class VanillaPackMixin { private void cacheContainedPaths(String[] p_i47912_1_, CallbackInfo ci) { if(containedPaths != null) return; - containedPaths = new HashSet<>(); + containedPaths = new ObjectOpenHashSet<>(); Joiner slashJoiner = Joiner.on('/'); for(PackType type : PackType.values()) { if(!PackTypeHelper.isVanillaPackType(type)) @@ -59,6 +60,7 @@ public class VanillaPackMixin { e.printStackTrace(); } } + ((ObjectOpenHashSet)containedPaths).trim(); } @Redirect(method = "getResources(Ljava/util/Collection;ILjava/lang/String;Ljava/nio/file/Path;Ljava/lang/String;Ljava/util/function/Predicate;)V", at = @At(value = "INVOKE", target = "Ljava/nio/file/Files;walk(Ljava/nio/file/Path;I[Ljava/nio/file/FileVisitOption;)Ljava/util/stream/Stream;")) diff --git a/src/main/java/org/embeddedt/modernfix/util/CachedResourcePath.java b/src/main/java/org/embeddedt/modernfix/resources/CachedResourcePath.java similarity index 70% rename from src/main/java/org/embeddedt/modernfix/util/CachedResourcePath.java rename to src/main/java/org/embeddedt/modernfix/resources/CachedResourcePath.java index 889311ae..8f3d458f 100644 --- a/src/main/java/org/embeddedt/modernfix/util/CachedResourcePath.java +++ b/src/main/java/org/embeddedt/modernfix/resources/CachedResourcePath.java @@ -1,31 +1,23 @@ -package org.embeddedt.modernfix.util; +package org.embeddedt.modernfix.resources; -import com.google.common.base.Joiner; import com.google.common.base.Splitter; -import com.google.common.collect.ImmutableList; import com.google.common.collect.Interner; import com.google.common.collect.Interners; -import com.google.common.collect.Streams; +import org.embeddedt.modernfix.util.FileUtil; -import java.lang.ref.WeakReference; import java.nio.file.Path; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; -import java.util.List; public class CachedResourcePath { private final String[] pathComponents; - private int hashCode = 0; - private static final Interner PATH_COMPONENT_INTERNER = Interners.newStrongInterner(); + public static final Interner PATH_COMPONENT_INTERNER = Interners.newStrongInterner(); private static final Splitter SLASH_SPLITTER = Splitter.on('/'); - private static final Joiner SLASH_JOINER = Joiner.on('/'); - private WeakReference fullPathCache = new WeakReference<>(null); private static final String[] NO_PREFIX = new String[0]; - public CachedResourcePath(Path path) { - this(NO_PREFIX, path, path.getNameCount(), true); + public CachedResourcePath(String[] prefix, Path path) { + this(prefix, path, path.getNameCount(), true); } public CachedResourcePath(String s) { @@ -67,11 +59,7 @@ public class CachedResourcePath { @Override public int hashCode() { - int result = hashCode; - if(result != 0) - return result; - hashCode = Arrays.hashCode(pathComponents); - return hashCode; + return Arrays.hashCode(pathComponents); } @Override @@ -90,12 +78,17 @@ public class CachedResourcePath { return pathComponents.length; } - public String getFullPath() { - String fPath = fullPathCache.get(); - if(fPath == null) { - fPath = SLASH_JOINER.join(pathComponents); - fullPathCache = new WeakReference<>(fPath); + public String getNameAt(int i) { + return pathComponents[i]; + } + + public String getFullPath(int startIndex) { + StringBuilder sb = new StringBuilder(); + for(int i = startIndex; i < pathComponents.length; i++) { + sb.append(pathComponents[i]); + if(i != (pathComponents.length - 1)) + sb.append('/'); } - return fPath; + return sb.toString(); } } diff --git a/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java b/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java new file mode 100644 index 00000000..47577b5f --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java @@ -0,0 +1,100 @@ +package org.embeddedt.modernfix.resources; + +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.PackType; +import org.embeddedt.modernfix.util.PackTypeHelper; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Stream; + +public class PackResourcesCacheEngine { + private final Map> namespacesByType; + private final Set containedPaths; + + public PackResourcesCacheEngine(Function> namespacesRetriever, BiFunction basePathRetriever) { + this.namespacesByType = new EnumMap<>(PackType.class); + for(PackType type : PackType.values()) { + if(!PackTypeHelper.isVanillaPackType(type)) + continue; + this.namespacesByType.put(type, namespacesRetriever.apply(type)); + } + this.containedPaths = new ObjectOpenHashSet<>(); + for(PackType type : PackType.values()) { + Collection namespaces = PackTypeHelper.isVanillaPackType(type) ? this.namespacesByType.get(type) : namespacesRetriever.apply(type); + for(String namespace : namespaces) { + try { + Path root = basePathRetriever.apply(type, namespace).toAbsolutePath(); + try (Stream stream = Files.walk(root)) { + stream + .map(path -> root.relativize(path.toAbsolutePath())) + .filter(PackResourcesCacheEngine::isValidCachedResourcePath) + .forEach(path -> { + this.containedPaths.add(new CachedResourcePath(new String[] { type.getDirectory(), namespace }, path)); + }); + } + } catch(IOException ignored) { + } + } + } + ((ObjectOpenHashSet)this.containedPaths).trim(); + } + + private static boolean isValidCachedResourcePath(Path path) { + if(path.getFileName() == null || path.getNameCount() == 0) { + return false; + } + String str = path.toString(); + if(str.length() == 0) + return false; + for(int i = 0; i < str.length(); i++) { + if(!ResourceLocation.validPathChar(str.charAt(i))) { + return false; + } + } + return true; + } + + public Set getNamespaces(PackType type) { + if(PackTypeHelper.isVanillaPackType(type)) + return this.namespacesByType.get(type); + else + return null; + } + + public boolean hasResource(String path) { + return this.containedPaths.contains(new CachedResourcePath(path)); + } + + public Collection getResources(PackType type, String resourceNamespace, String pathIn, int maxDepth, Predicate filter) { + String testPath = pathIn.endsWith("/") ? pathIn : (pathIn + "/"); + ArrayList resources = new ArrayList<>(); + String typeDirectory = CachedResourcePath.PATH_COMPONENT_INTERNER.intern(type.getDirectory()); + resourceNamespace = CachedResourcePath.PATH_COMPONENT_INTERNER.intern(resourceNamespace); + for(CachedResourcePath cachePath : this.containedPaths) { + if(cachePath.getNameCount() < 2) + continue; + if((cachePath.getNameCount() - 2) > maxDepth) + continue; + // we interned, so reference equality is safe + if(cachePath.getNameAt(0) != typeDirectory || cachePath.getNameAt(1) != resourceNamespace) + continue; + if(cachePath.getFileName().endsWith(".mcmeta")) + continue; + String fullPath = cachePath.getFullPath(2); + if(!fullPath.startsWith(testPath)) + continue; + if(!filter.test(cachePath.getFileName())) + continue; + ResourceLocation foundResource = new ResourceLocation(resourceNamespace, fullPath); + resources.add(foundResource); + } + return resources; + } +} From cf1727219612da135e7254930f2e9527ebb8fbb6 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 29 Apr 2023 21:03:44 -0400 Subject: [PATCH 05/10] Fix devenv mixins not actually applying in 1.18 --- .../modernfix/core/config/ModernFixEarlyConfig.java | 5 ++++- 1 file changed, 4 insertions(+), 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 86820c05..bbbf26b6 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -2,7 +2,9 @@ package org.embeddedt.modernfix.core.config; import net.minecraftforge.fml.loading.FMLLoader; import net.minecraftforge.fml.loading.moddiscovery.ExplodedDirectoryLocator; +import net.minecraftforge.fml.loading.moddiscovery.MinecraftLocator; import net.minecraftforge.fml.loading.moddiscovery.ModInfo; +import net.minecraftforge.forgespi.locating.IModLocator; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -90,7 +92,8 @@ public class ModernFixEarlyConfig { this.addMixinRule("perf.blast_search_trees", (jeiMod.isPresent() && jeiMod.get().getVersion().getMajorVersion() >= 10) || FMLLoader.getLoadingModList().getModFileById("roughlyenoughitems") != null); this.addMixinRule("safety", true); this.addMixinRule("launch.class_search_cache", true); - boolean isDevEnv = !FMLLoader.isProduction() && FMLLoader.getLoadingModList().getModFileById("modernfix").getFile().getLocator() instanceof ExplodedDirectoryLocator; + IModLocator mfLocator = FMLLoader.getLoadingModList().getModFileById("modernfix").getFile().getLocator(); + boolean isDevEnv = !FMLLoader.isProduction() && (mfLocator instanceof ExplodedDirectoryLocator || mfLocator instanceof MinecraftLocator); this.addMixinRule("devenv", isDevEnv); this.addMixinRule("perf.remove_spawn_chunks", isDevEnv); From 7039bcada7cd8196b836f613e1785c4bed056c8c Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 29 Apr 2023 21:24:06 -0400 Subject: [PATCH 06/10] Reintroduce separate root listing list --- .../resources/PackResourcesCacheEngine.java | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java b/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java index 47577b5f..30590ac7 100644 --- a/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java +++ b/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java @@ -1,5 +1,9 @@ package org.embeddedt.modernfix.resources; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.mojang.datafixers.util.Pair; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.PackType; @@ -14,9 +18,16 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; +/** + * The core of the resource pack cache system. + * + * Using a dedicated set and also separate lists is important; testing without this showed a huge performance + * drop. + */ public class PackResourcesCacheEngine { private final Map> namespacesByType; private final Set containedPaths; + private final EnumMap>> resourceListings; public PackResourcesCacheEngine(Function> namespacesRetriever, BiFunction basePathRetriever) { this.namespacesByType = new EnumMap<>(PackType.class); @@ -26,22 +37,31 @@ public class PackResourcesCacheEngine { this.namespacesByType.put(type, namespacesRetriever.apply(type)); } this.containedPaths = new ObjectOpenHashSet<>(); + this.resourceListings = new EnumMap<>(PackType.class); for(PackType type : PackType.values()) { Collection namespaces = PackTypeHelper.isVanillaPackType(type) ? this.namespacesByType.get(type) : namespacesRetriever.apply(type); + ImmutableMap.Builder> packTypedMap = ImmutableMap.builder(); for(String namespace : namespaces) { try { + ImmutableList.Builder namespacedList = ImmutableList.builder(); Path root = basePathRetriever.apply(type, namespace).toAbsolutePath(); + String[] prefix = new String[] { type.getDirectory(), namespace }; try (Stream stream = Files.walk(root)) { stream .map(path -> root.relativize(path.toAbsolutePath())) .filter(PackResourcesCacheEngine::isValidCachedResourcePath) .forEach(path -> { - this.containedPaths.add(new CachedResourcePath(new String[] { type.getDirectory(), namespace }, path)); + CachedResourcePath cachedPath = new CachedResourcePath(prefix, path); + this.containedPaths.add(cachedPath); + if(!cachedPath.getFileName().endsWith(".mcmeta")) + namespacedList.add(cachedPath); }); } + packTypedMap.put(namespace, namespacedList.build()); } catch(IOException ignored) { } } + this.resourceListings.put(type, packTypedMap.build()); } ((ObjectOpenHashSet)this.containedPaths).trim(); } @@ -73,20 +93,16 @@ public class PackResourcesCacheEngine { } public Collection getResources(PackType type, String resourceNamespace, String pathIn, int maxDepth, Predicate filter) { + if(!PackTypeHelper.isVanillaPackType(type)) + throw new IllegalArgumentException("Only vanilla PackTypes are supported"); + List paths = resourceListings.get(type).getOrDefault(resourceNamespace, Collections.emptyList()); + if(paths.isEmpty()) + return Collections.emptyList(); String testPath = pathIn.endsWith("/") ? pathIn : (pathIn + "/"); ArrayList resources = new ArrayList<>(); - String typeDirectory = CachedResourcePath.PATH_COMPONENT_INTERNER.intern(type.getDirectory()); - resourceNamespace = CachedResourcePath.PATH_COMPONENT_INTERNER.intern(resourceNamespace); - for(CachedResourcePath cachePath : this.containedPaths) { - if(cachePath.getNameCount() < 2) - continue; + for(CachedResourcePath cachePath : paths) { if((cachePath.getNameCount() - 2) > maxDepth) continue; - // we interned, so reference equality is safe - if(cachePath.getNameAt(0) != typeDirectory || cachePath.getNameAt(1) != resourceNamespace) - continue; - if(cachePath.getFileName().endsWith(".mcmeta")) - continue; String fullPath = cachePath.getFullPath(2); if(!fullPath.startsWith(testPath)) continue; From c561d818f398f9b9f6b826db34b705a97c187f74 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 30 Apr 2023 19:07:06 -0400 Subject: [PATCH 07/10] Implement improved version of LazyDFU (having it installed is still beneficial) Now DFU classes are not loaded until the first time DFU is actually needed to update something. This saves quite a bit of RAM. This is a better version of dedup_blockstate_flattening_map so the latter is removed. --- .../core/config/ModernFixEarlyConfig.java | 2 +- .../modernfix/dfu/LazyDataFixer.java | 96 +++++++++++++++++++ .../BlockStateDataMixin.java | 21 ---- .../ChunkPalettedStorageFixMixin.java | 31 ------ .../perf/dynamic_dfu/DataFixersMixin.java | 30 ++++++ src/main/resources/modernfix.mixins.json | 3 +- 6 files changed, 128 insertions(+), 55 deletions(-) create mode 100644 src/main/java/org/embeddedt/modernfix/dfu/LazyDataFixer.java delete mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/dedup_blockstate_flattening_map/BlockStateDataMixin.java delete mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/dedup_blockstate_flattening_map/ChunkPalettedStorageFixMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_dfu/DataFixersMixin.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 60483967..f3019646 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -62,7 +62,6 @@ public class ModernFixEarlyConfig { /* Use a simpler ArrayMap if FerriteCore is using the map intelligently anyway */ this.addMixinRule("perf.state_definition_construct", modPresent("ferritecore")); this.addMixinRule("perf.cache_strongholds", true); - this.addMixinRule("perf.dedup_blockstate_flattening_map", false); this.addMixinRule("perf.clear_mixin_classinfo", false); this.addMixinRule("perf.cache_upgraded_structures", true); this.addMixinRule("perf.biome_zoomer", true); @@ -93,6 +92,7 @@ public class ModernFixEarlyConfig { this.addMixinRule("perf.nbt_memory_usage", true); this.addMixinRule("perf.patchouli_deduplicate_books", modPresent("patchouli")); this.addMixinRule("perf.datapack_reload_exceptions", true); + this.addMixinRule("perf.dynamic_dfu", true); this.addMixinRule("perf.async_locator", true); this.addMixinRule("perf.faster_texture_stitching", true); this.addMixinRule("perf.faster_texture_loading", true); diff --git a/src/main/java/org/embeddedt/modernfix/dfu/LazyDataFixer.java b/src/main/java/org/embeddedt/modernfix/dfu/LazyDataFixer.java new file mode 100644 index 00000000..dd9dfbdb --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/dfu/LazyDataFixer.java @@ -0,0 +1,96 @@ +package org.embeddedt.modernfix.dfu; + +import com.mojang.datafixers.DSL; +import com.mojang.datafixers.DataFix; +import com.mojang.datafixers.DataFixUtils; +import com.mojang.datafixers.DataFixer; +import com.mojang.datafixers.schemas.Schema; +import com.mojang.datafixers.types.Type; +import com.mojang.datafixers.types.constant.EmptyPart; +import com.mojang.datafixers.types.templates.TypeTemplate; +import com.mojang.serialization.Dynamic; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.SharedConstants; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.Collections; +import java.util.Map; +import java.util.function.Supplier; + +public class LazyDataFixer implements DataFixer { + private static final Logger LOGGER = LogManager.getLogger("ModernFix"); + private DataFixer backingDataFixer; + private final Supplier dfuSupplier; + private static final Schema FAKE_SCHEMA = new EmptySchema(); + + public LazyDataFixer(Supplier dfuSupplier) { + LOGGER.info("Bypassed Mojang DFU"); + this.backingDataFixer = null; + this.dfuSupplier = dfuSupplier; + } + @Override + public Dynamic update(DSL.TypeReference type, Dynamic input, int version, int newVersion) { + if(version >= newVersion) + return input; + synchronized (this) { + if(backingDataFixer == null) { + LOGGER.info("Instantiating Mojang DFU"); + backingDataFixer = dfuSupplier.get(); + } + } + return backingDataFixer.update(type, input, version, newVersion); + } + + /** + * "getSchema is only there for checks that are not important" - fry, 2021 + */ + @Override + public Schema getSchema(int key) { + return FAKE_SCHEMA; + } + + /** + * Empty schema that also returns empty Type instances to prevent crashes. + */ + static class EmptySchema extends Schema { + public EmptySchema() { + super(DataFixUtils.makeKey(SharedConstants.getCurrentVersion().getWorldVersion()), null); + } + + private static final Type EMPTY_TYPE = new EmptyPart(); + private static final TypeTemplate FAKE_TEMPLATE = EMPTY_TYPE.template(); + + + @Override + protected Map> buildTypes() { + Object2ObjectOpenHashMap> map = new Object2ObjectOpenHashMap<>(); + map.defaultReturnValue(new EmptyPart()); + return map; + } + + @Override + public TypeTemplate resolveTemplate(String name) { + return FAKE_TEMPLATE; + } + + @Override + public Type getChoiceType(DSL.TypeReference type, String choiceName) { + return EMPTY_TYPE; + } + + @Override + public void registerTypes(Schema schema, Map> entityTypes, Map> blockEntityTypes) { + } + + @Override + public Map> registerEntities(Schema schema) { + return Collections.emptyMap(); + } + + @Override + public Map> registerBlockEntities(Schema schema) { + return Collections.emptyMap(); + } + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dedup_blockstate_flattening_map/BlockStateDataMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dedup_blockstate_flattening_map/BlockStateDataMixin.java deleted file mode 100644 index 63da3acc..00000000 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/dedup_blockstate_flattening_map/BlockStateDataMixin.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.embeddedt.modernfix.mixin.perf.dedup_blockstate_flattening_map; - -import net.minecraft.util.datafix.fixes.BlockStateData; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(BlockStateData.class) -public class BlockStateDataMixin { - @Inject(method = {"register", "finalizeMaps"}, at = @At("HEAD"), cancellable = true) - private static void noFlattening(CallbackInfo ci) { - ci.cancel(); - } - - @Inject(method = {"upgradeBlockStateTag", "upgradeBlock(I)Ljava/lang/String;", "upgradeBlock(Ljava/lang/String;)Ljava/lang/String;", "getTag"}, at = @At("HEAD"), require = 4) - private static void preventCorruption(CallbackInfoReturnable cir) { - throw new UnsupportedOperationException("Performing the Flattening is currently disabled in the ModernFix config."); - } -} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dedup_blockstate_flattening_map/ChunkPalettedStorageFixMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dedup_blockstate_flattening_map/ChunkPalettedStorageFixMixin.java deleted file mode 100644 index 962a7fee..00000000 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/dedup_blockstate_flattening_map/ChunkPalettedStorageFixMixin.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.embeddedt.modernfix.mixin.perf.dedup_blockstate_flattening_map; - -import com.mojang.serialization.Dynamic; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtOps; -import net.minecraft.util.datafix.fixes.ChunkPalettedStorageFix; -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.CallbackInfoReturnable; - -import java.util.function.Consumer; - -@Mixin(ChunkPalettedStorageFix.class) -public class ChunkPalettedStorageFixMixin { - @Redirect(method = "", at = @At(value = "INVOKE", target = "Lcom/mojang/datafixers/DataFixUtils;make(Ljava/lang/Object;Ljava/util/function/Consumer;)Ljava/lang/Object;")) - private static Object skipMakingMap(Object o, Consumer consumer) { - return o; - } - - @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/datafix/fixes/BlockStateData;getTag(I)Lcom/mojang/serialization/Dynamic;")) - private static Dynamic getFakeAirTag(int id) { - return new Dynamic<>(NbtOps.INSTANCE, new CompoundTag()); - } - - @Inject(method = "fix", at = @At("HEAD")) - private void skipFix(CallbackInfoReturnable> cir) { - throw new UnsupportedOperationException("No Flattening for you."); - } -} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_dfu/DataFixersMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_dfu/DataFixersMixin.java new file mode 100644 index 00000000..f8e48cfa --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_dfu/DataFixersMixin.java @@ -0,0 +1,30 @@ +package org.embeddedt.modernfix.mixin.perf.dynamic_dfu; + +import com.mojang.datafixers.DataFixer; +import net.minecraft.util.datafix.DataFixers; +import org.embeddedt.modernfix.dfu.LazyDataFixer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(DataFixers.class) +public abstract class DataFixersMixin { + @Shadow protected static DataFixer createFixerUpper() { + throw new AssertionError(); + } + + private static LazyDataFixer lazyDataFixer; + + /** + * Avoid classloading the DFU logic until we actually need it. + */ + @Inject(method = "createFixerUpper", at = @At("HEAD"), cancellable = true) + private static void createLazyFixerUpper(CallbackInfoReturnable cir) { + if(lazyDataFixer == null) { + lazyDataFixer = new LazyDataFixer(DataFixersMixin::createFixerUpper); + cir.setReturnValue(lazyDataFixer); + } + } +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 6b05bb8c..1e8dca49 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -24,6 +24,7 @@ "bugfix.chunk_deadlock.ServerChunkCacheMixin", "bugfix.chunk_deadlock.valhesia.BlockStateBaseMixin", "perf.dedicated_reload_executor.MinecraftServerMixin", + "perf.dynamic_dfu.DataFixersMixin", "perf.remove_biome_temperature_cache.BiomeMixin", "perf.resourcepacks.ModFileResourcePackMixin", "perf.resourcepacks.VanillaPackMixin", @@ -75,8 +76,6 @@ "perf.biome_zoomer.FuzzyOffsetBiomeZoomerMixin", "perf.compress_blockstate.BlockStateBaseMixin", "perf.compress_blockstate.BlockBehaviourMixin", - "perf.dedup_blockstate_flattening_map.BlockStateDataMixin", - "perf.dedup_blockstate_flattening_map.ChunkPalettedStorageFixMixin", "perf.remove_spawn_chunks.ServerChunkCacheAccessor", "perf.remove_spawn_chunks.MinecraftServerMixin", "perf.remove_spawn_chunks.ServerLevelMixin", From fead01b1428c6a84f6eb2c092b52dc4fc392f668 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 30 Apr 2023 19:17:04 -0400 Subject: [PATCH 08/10] Update LazyDFU warning --- src/main/resources/assets/modernfix/lang/en_us.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/modernfix/lang/en_us.json b/src/main/resources/assets/modernfix/lang/en_us.json index ddd8c10b..108f5124 100644 --- a/src/main/resources/assets/modernfix/lang/en_us.json +++ b/src/main/resources/assets/modernfix/lang/en_us.json @@ -2,7 +2,7 @@ "key.modernfix": "ModernFix", "key.modernfix.config": "Open config screen", "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.", + "modernfix.no_lazydfu": "LazyDFU is not installed. If Minecraft needs to update game data from an older version, there may be noticeable lag.", "modernfix.config": "ModernFix mixin config", "modernfix.config.done_restart": "Done (restart required)", "modernfix.option.on": "on", From cc78749e87ad6f919859dba6ad51e5b9aac615c8 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 30 Apr 2023 19:17:20 -0400 Subject: [PATCH 09/10] Remove LazyDFU from dev, as rule optimization would now only be performed if older game data is loaded --- build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle b/build.gradle index 4ab0f76e..ec910a7b 100644 --- a/build.gradle +++ b/build.gradle @@ -86,7 +86,6 @@ dependencies { // your forge dependency, this is **required** when using Forge Loom in forge mode! forge "net.minecraftforge:forge:${project.forge_version}" - modRuntimeOnly "curse.maven:lazydfu-460819:${lazydfu_version}" modCompileOnly("mezz.jei:jei-${minecraft_version}:${jei_version}") //modRuntimeOnly("mezz.jei:jei-${minecraft_version}:${jei_version}") From 7e87aae3f66b2f92e2136fd7ae55ead8d51fa7be Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 30 Apr 2023 19:20:04 -0400 Subject: [PATCH 10/10] Hide LazyDFU missing warning in dev --- src/main/java/org/embeddedt/modernfix/ModernFix.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/embeddedt/modernfix/ModernFix.java b/src/main/java/org/embeddedt/modernfix/ModernFix.java index 5ee1161f..06924e2c 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFix.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFix.java @@ -129,7 +129,7 @@ public class ModernFix { if(ModList.get().isLoaded(modId)) return true; } - return false; + return !FMLLoader.isProduction(); } @SubscribeEvent