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 1/5] 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 2/5] 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 3/5] 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 4/5] 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 5/5] 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);