From 00a7d8235097f9d95115f9ff1c2a6bd082cbaf99 Mon Sep 17 00:00:00 2001 From: contaria Date: Tue, 18 Mar 2025 04:56:32 +0100 Subject: [PATCH 1/3] update: fix sodium 2.4.1 compatibility there isn't really a need to profile this anyway since seedqueue worldrenderers dont do any unloading --- build.gradle | 2 +- .../sodium/profiling/ChunkRenderManagerMixin.java | 13 ------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/build.gradle b/build.gradle index 4b84994d..a7f1affd 100644 --- a/build.gradle +++ b/build.gradle @@ -36,7 +36,7 @@ dependencies { } // check for the latest versions at https://jitpack.io/#Minecraft-Java-Edition-Speedrunning/sodium - modCompileOnly "com.github.Minecraft-Java-Edition-Speedrunning:sodium:d488d3a782" + modCompileOnly "com.github.Minecraft-Java-Edition-Speedrunning:sodium:0dd4b2d65a" // check for the latest versions at https://jitpack.io/#kingcontaria/fastreset modCompileOnly ("com.github.KingContaria:fastreset:82fe8eb3b2") { diff --git a/src/main/java/me/contaria/seedqueue/mixin/compat/sodium/profiling/ChunkRenderManagerMixin.java b/src/main/java/me/contaria/seedqueue/mixin/compat/sodium/profiling/ChunkRenderManagerMixin.java index d294e681..7eceea94 100644 --- a/src/main/java/me/contaria/seedqueue/mixin/compat/sodium/profiling/ChunkRenderManagerMixin.java +++ b/src/main/java/me/contaria/seedqueue/mixin/compat/sodium/profiling/ChunkRenderManagerMixin.java @@ -241,19 +241,6 @@ private void profileReset2(CallbackInfo ci) { SeedQueueProfiler.push("reset"); } - @Inject( - method = "update", - at = @At( - value = "INVOKE", - target = "Lme/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager;unloadPending()V", - remap = false - ), - remap = true - ) - private void profileUnloadPending(CallbackInfo ci) { - SeedQueueProfiler.swap("unload_pending"); - } - @Inject( method = "update", at = @At( From ed8f03bb2d6bfa5150e56f5cdc486c48e14d1bc6 Mon Sep 17 00:00:00 2001 From: contaria Date: Tue, 18 Mar 2025 04:57:10 +0100 Subject: [PATCH 2/3] Version 1.4.1 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 868a95fd..61e8489b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ yarn_mappings=1.16.1-build.24 loader_version=0.16.5 # Mod Properties -mod_version=1.4 +mod_version=1.4.1 maven_group=me.contaria archives_base_name=seedqueue From dcba354d168336fd450dc4205cb58d6a3e269ed0 Mon Sep 17 00:00:00 2001 From: Gregor0410 <34042398+gregor0410@users.noreply.github.com> Date: Tue, 17 Jun 2025 20:12:24 +0100 Subject: [PATCH 3/3] feature: add option to delay file creation until world load - does not delay poi file creation, this requires extra effort --- .../java/me/contaria/seedqueue/SeedQueue.java | 9 ++++ .../contaria/seedqueue/SeedQueueConfig.java | 3 ++ .../me/contaria/seedqueue/SeedQueueEntry.java | 15 +++++- .../interfaces/SQLevelStorageSession.java | 7 +++ .../mixin/client/MinecraftClientMixin.java | 10 ++-- .../mixin/server/MinecraftServerMixin.java | 4 ++ .../FileResourcePackProviderMixin.java | 25 +++++++++ .../LevelStorageSessionMixin.java | 52 +++++++++++++++++++ .../optimization/ServerChunkManagerMixin.java | 37 +++++++++++++ .../ThreadedAnvilChunkStorageMixin.java | 3 ++ .../optimization/WorldSaveHandlerMixin.java | 26 ++++++++++ .../assets/seedqueue/lang/en_us.json | 2 + src/main/resources/seedqueue.mixins.json | 8 ++- 13 files changed, 193 insertions(+), 8 deletions(-) create mode 100644 src/main/java/me/contaria/seedqueue/interfaces/SQLevelStorageSession.java create mode 100644 src/main/java/me/contaria/seedqueue/mixin/server/optimization/FileResourcePackProviderMixin.java create mode 100644 src/main/java/me/contaria/seedqueue/mixin/server/optimization/LevelStorageSessionMixin.java create mode 100644 src/main/java/me/contaria/seedqueue/mixin/server/optimization/ServerChunkManagerMixin.java create mode 100644 src/main/java/me/contaria/seedqueue/mixin/server/optimization/WorldSaveHandlerMixin.java diff --git a/src/main/java/me/contaria/seedqueue/SeedQueue.java b/src/main/java/me/contaria/seedqueue/SeedQueue.java index 4f0bf4eb..912b677e 100644 --- a/src/main/java/me/contaria/seedqueue/SeedQueue.java +++ b/src/main/java/me/contaria/seedqueue/SeedQueue.java @@ -1,6 +1,7 @@ package me.contaria.seedqueue; import com.google.gson.JsonParseException; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import me.contaria.seedqueue.compat.ModCompat; import me.contaria.seedqueue.debug.SeedQueueSystemInfo; import me.contaria.seedqueue.debug.SeedQueueWatchdog; @@ -20,6 +21,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.io.File; import java.io.IOException; import java.util.*; import java.util.concurrent.LinkedBlockingQueue; @@ -43,6 +45,13 @@ public class SeedQueue implements ClientModInitializer { public static SeedQueueEntry currentEntry; public static SeedQueueEntry selectedEntry; + public static boolean cancelDirectoryCreate(File instance, Operation original) { + if (config.delayFileCreation && inQueue()) { + return true; + } + return original.call(instance); + } + @Override public void onInitializeClient() { SeedQueueSounds.init(); diff --git a/src/main/java/me/contaria/seedqueue/SeedQueueConfig.java b/src/main/java/me/contaria/seedqueue/SeedQueueConfig.java index 316b4b4c..5f638e07 100644 --- a/src/main/java/me/contaria/seedqueue/SeedQueueConfig.java +++ b/src/main/java/me/contaria/seedqueue/SeedQueueConfig.java @@ -123,6 +123,9 @@ public class SeedQueueConfig implements SpeedrunConfig { @Config.Category("performance") public boolean reduceLevelList = true; + @Config.Category("performance") + public boolean delayFileCreation = true; + @Config.Category("misc") @Config.Numbers.Whole.Bounds(min = -1, max = 500, enforce = Config.Numbers.EnforceBounds.MIN_ONLY) public long chunkMapFreezing = -1; diff --git a/src/main/java/me/contaria/seedqueue/SeedQueueEntry.java b/src/main/java/me/contaria/seedqueue/SeedQueueEntry.java index bc76d29b..c169c44e 100644 --- a/src/main/java/me/contaria/seedqueue/SeedQueueEntry.java +++ b/src/main/java/me/contaria/seedqueue/SeedQueueEntry.java @@ -8,6 +8,7 @@ import me.contaria.seedqueue.compat.WorldPreviewFrameBuffer; import me.contaria.seedqueue.compat.WorldPreviewProperties; import me.contaria.seedqueue.debug.SeedQueueProfiler; +import me.contaria.seedqueue.interfaces.SQLevelStorageSession; import me.contaria.seedqueue.interfaces.SQMinecraftServer; import me.contaria.seedqueue.interfaces.SQWorldGenerationProgressTracker; import me.contaria.seedqueue.mixin.accessor.MinecraftServerAccessor; @@ -18,6 +19,9 @@ import net.minecraft.world.level.storage.LevelStorage; import org.jetbrains.annotations.Nullable; +import java.io.File; +import java.util.List; + /** * Stores the {@link MinecraftServer} and any other resources related to a seed in the queue. */ @@ -46,6 +50,7 @@ public class SeedQueueEntry { @Nullable private SeedQueueSettingsCache settingsCache; + private int perspective; private volatile boolean locked; @@ -59,7 +64,7 @@ public class SeedQueueEntry { */ public int mainPosition = -1; - public SeedQueueEntry(MinecraftServer server, LevelStorage.Session session, MinecraftClient.IntegratedResourceManager resourceManager, @Nullable YggdrasilAuthenticationService yggdrasilAuthenticationService, @Nullable MinecraftSessionService minecraftSessionService, @Nullable GameProfileRepository gameProfileRepository, @Nullable UserCache userCache) { + public SeedQueueEntry(MinecraftServer server, LevelStorage.Session session, MinecraftClient.IntegratedResourceManager resourceManager, @Nullable YggdrasilAuthenticationService yggdrasilAuthenticationService, @Nullable MinecraftSessionService minecraftSessionService, @Nullable GameProfileRepository gameProfileRepository, @Nullable UserCache userCache, @Nullable WorldGenerationProgressTracker worldGenerationProgressTracker) { this.server = server; this.session = session; this.resourceManager = resourceManager; @@ -350,6 +355,13 @@ public synchronized void load() { if (this.discarded) { throw new IllegalStateException("Tried to load \"" + this.session.getDirectoryName() + "\" but it has already been discarded!"); } + try { + ((SQLevelStorageSession) this.session).seedQueue$createLock(); + } catch (Exception e) { + SeedQueue.LOGGER.error("Failed to create session lock for \"{}\"!", this.session.getDirectoryName(), e); + return; + } + this.loaded = true; @@ -407,4 +419,5 @@ public int getProgressPercentage() { } return ((SQWorldGenerationProgressTracker) this.worldGenerationProgressTracker).seedQueue$getProgressPercentage(); } + } diff --git a/src/main/java/me/contaria/seedqueue/interfaces/SQLevelStorageSession.java b/src/main/java/me/contaria/seedqueue/interfaces/SQLevelStorageSession.java new file mode 100644 index 00000000..da792ae7 --- /dev/null +++ b/src/main/java/me/contaria/seedqueue/interfaces/SQLevelStorageSession.java @@ -0,0 +1,7 @@ +package me.contaria.seedqueue.interfaces; + +import java.io.IOException; + +public interface SQLevelStorageSession { + void seedQueue$createLock() throws IOException; +} diff --git a/src/main/java/me/contaria/seedqueue/mixin/client/MinecraftClientMixin.java b/src/main/java/me/contaria/seedqueue/mixin/client/MinecraftClientMixin.java index 7727ea39..add80652 100644 --- a/src/main/java/me/contaria/seedqueue/mixin/client/MinecraftClientMixin.java +++ b/src/main/java/me/contaria/seedqueue/mixin/client/MinecraftClientMixin.java @@ -46,15 +46,13 @@ import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyArg; -import org.spongepowered.asm.mixin.injection.Slice; +import org.spongepowered.asm.mixin.injection.*; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.io.File; import java.net.Proxy; +import java.util.ArrayList; import java.util.Optional; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicReference; @@ -232,7 +230,7 @@ private MinecraftServer loadServer(Function serverFacto private void queueServer(MinecraftClient client, IntegratedServer server, Operation original, @Local LevelStorage.Session session, @Local MinecraftClient.IntegratedResourceManager resourceManager, @Local YggdrasilAuthenticationService yggdrasilAuthenticationService, @Local MinecraftSessionService minecraftSessionService, @Local GameProfileRepository gameProfileRepository, @Local UserCache userCache) { if (SeedQueue.inQueue()) { ((SQMinecraftServer) server).seedQueue$setExecutor(SeedQueueExecutorWrapper.SEEDQUEUE_EXECUTOR); - SeedQueue.add(new SeedQueueEntry(server, session, resourceManager, yggdrasilAuthenticationService, minecraftSessionService, gameProfileRepository, userCache)); + SeedQueue.add(new SeedQueueEntry(server, session, resourceManager, yggdrasilAuthenticationService, minecraftSessionService, gameProfileRepository, userCache,null)); return; } original.call(client, server); @@ -371,7 +369,7 @@ private boolean cancelWorldGenTrackerSetNull(AtomicReference instance, Object ) ) private boolean cancelSessionLevelDatInit(LevelStorage.Session instance, RegistryTracker registryTracker, SaveProperties saveProperties) { - return SeedQueue.inQueue() || SeedQueue.currentEntry == null; + return !SeedQueue.config.delayFileCreation; } @WrapWithCondition( diff --git a/src/main/java/me/contaria/seedqueue/mixin/server/MinecraftServerMixin.java b/src/main/java/me/contaria/seedqueue/mixin/server/MinecraftServerMixin.java index e10b84dd..d3aec8f4 100644 --- a/src/main/java/me/contaria/seedqueue/mixin/server/MinecraftServerMixin.java +++ b/src/main/java/me/contaria/seedqueue/mixin/server/MinecraftServerMixin.java @@ -1,6 +1,7 @@ package me.contaria.seedqueue.mixin.server; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import me.contaria.seedqueue.SeedQueue; @@ -23,8 +24,10 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.io.File; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; @@ -268,4 +271,5 @@ private void pauseServer(MinecraftServer server, boolean value, Operation public int seedQueue$incrementAndGetEntityID() { return this.maxEntityId.incrementAndGet(); } + } diff --git a/src/main/java/me/contaria/seedqueue/mixin/server/optimization/FileResourcePackProviderMixin.java b/src/main/java/me/contaria/seedqueue/mixin/server/optimization/FileResourcePackProviderMixin.java new file mode 100644 index 00000000..a0f8a54a --- /dev/null +++ b/src/main/java/me/contaria/seedqueue/mixin/server/optimization/FileResourcePackProviderMixin.java @@ -0,0 +1,25 @@ +package me.contaria.seedqueue.mixin.server.optimization; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import me.contaria.seedqueue.SeedQueue; +import net.minecraft.resource.FileResourcePackProvider; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import java.io.File; + +@Mixin(FileResourcePackProvider.class) +public class FileResourcePackProviderMixin { + + @WrapOperation( + method = "register", + at = @At( + value = "INVOKE", + target = "Ljava/io/File;mkdirs()Z" + ) + ) + private boolean delayDirectoryCreate(File instance, Operation original) { + return SeedQueue.cancelDirectoryCreate(instance, original); + } +} diff --git a/src/main/java/me/contaria/seedqueue/mixin/server/optimization/LevelStorageSessionMixin.java b/src/main/java/me/contaria/seedqueue/mixin/server/optimization/LevelStorageSessionMixin.java new file mode 100644 index 00000000..680d9905 --- /dev/null +++ b/src/main/java/me/contaria/seedqueue/mixin/server/optimization/LevelStorageSessionMixin.java @@ -0,0 +1,52 @@ +package me.contaria.seedqueue.mixin.server.optimization; + +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import me.contaria.seedqueue.SeedQueue; +import me.contaria.seedqueue.interfaces.SQLevelStorageSession; +import me.contaria.seedqueue.interfaces.SQMinecraftServer; +import net.minecraft.world.level.storage.LevelStorage; +import net.minecraft.world.level.storage.SessionLock; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.io.IOException; +import java.nio.file.Path; + +@Mixin(LevelStorage.Session.class) +public class LevelStorageSessionMixin implements SQLevelStorageSession { + @Shadow @Mutable + private SessionLock lock; + + @Shadow @Final private Path directory; + + @WrapOperation( + method = "", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/level/storage/SessionLock;create(Ljava/nio/file/Path;)Lnet/minecraft/world/level/storage/SessionLock;" + ) + ) + private SessionLock skipSessionLockCreation(Path path, Operation original) throws IOException { + return SeedQueue.inQueue()? null : original.call(path); + } + + public void seedQueue$createLock() throws IOException { + this.lock = SessionLock.create(this.directory); + } + + @Inject(method = "checkValid", at = @At("HEAD"),cancellable = true) + private void dontRequireLockWhileInQueue(CallbackInfo ci) { + if (SeedQueue.inQueue() || SeedQueue.getThreadLocalEntry().isPresent()) { + ci.cancel(); + } + } + +} diff --git a/src/main/java/me/contaria/seedqueue/mixin/server/optimization/ServerChunkManagerMixin.java b/src/main/java/me/contaria/seedqueue/mixin/server/optimization/ServerChunkManagerMixin.java new file mode 100644 index 00000000..12c3fa84 --- /dev/null +++ b/src/main/java/me/contaria/seedqueue/mixin/server/optimization/ServerChunkManagerMixin.java @@ -0,0 +1,37 @@ +package me.contaria.seedqueue.mixin.server.optimization; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import me.contaria.seedqueue.SeedQueue; +import me.contaria.seedqueue.interfaces.SQMinecraftServer; +import net.minecraft.server.world.ServerChunkManager; +import net.minecraft.server.world.ServerWorld; +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 java.io.File; + +@Mixin(ServerChunkManager.class) +public class ServerChunkManagerMixin { + + @Shadow @Final private ServerWorld world; + + @WrapOperation( + method = "", + at = @At( + value = "INVOKE", + target = "Ljava/io/File;mkdirs()Z" + ) + ) + private boolean delayDirectoryCreate(File instance, Operation original) { + SQMinecraftServer server = (SQMinecraftServer) this.world.getServer(); + if(server.seedQueue$inQueue()){ + return true; + } else { + return original.call(instance); + } + } + +} diff --git a/src/main/java/me/contaria/seedqueue/mixin/server/optimization/ThreadedAnvilChunkStorageMixin.java b/src/main/java/me/contaria/seedqueue/mixin/server/optimization/ThreadedAnvilChunkStorageMixin.java index ed7b1160..fb95a9c4 100644 --- a/src/main/java/me/contaria/seedqueue/mixin/server/optimization/ThreadedAnvilChunkStorageMixin.java +++ b/src/main/java/me/contaria/seedqueue/mixin/server/optimization/ThreadedAnvilChunkStorageMixin.java @@ -7,11 +7,14 @@ import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ThreadedAnvilChunkStorage; import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.poi.PointOfInterestStorage; 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 java.util.function.BooleanSupplier; + @Mixin(ThreadedAnvilChunkStorage.class) public abstract class ThreadedAnvilChunkStorageMixin { diff --git a/src/main/java/me/contaria/seedqueue/mixin/server/optimization/WorldSaveHandlerMixin.java b/src/main/java/me/contaria/seedqueue/mixin/server/optimization/WorldSaveHandlerMixin.java new file mode 100644 index 00000000..c3ce80a0 --- /dev/null +++ b/src/main/java/me/contaria/seedqueue/mixin/server/optimization/WorldSaveHandlerMixin.java @@ -0,0 +1,26 @@ +package me.contaria.seedqueue.mixin.server.optimization; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import me.contaria.seedqueue.SeedQueue; +import net.minecraft.world.WorldSaveHandler; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import java.io.File; + +@Mixin(WorldSaveHandler.class) +public class WorldSaveHandlerMixin { + + @WrapOperation( + method = "", + at = @At( + value = "INVOKE", + target = "Ljava/io/File;mkdirs()Z" + ) + ) + private boolean delayDirectoryCreate(File instance, Operation original) { + return SeedQueue.cancelDirectoryCreate(instance, original); + } + +} diff --git a/src/main/resources/assets/seedqueue/lang/en_us.json b/src/main/resources/assets/seedqueue/lang/en_us.json index f3d2cd34..923e029f 100644 --- a/src/main/resources/assets/seedqueue/lang/en_us.json +++ b/src/main/resources/assets/seedqueue/lang/en_us.json @@ -129,6 +129,8 @@ "speedrunapi.config.seedqueue.option.reduceSchedulingBudget.description": "Reduces the amount of Sodium chunk rebuilds scheduled per frame. This improves framerate stability at the cost of slower chunk loads.", "speedrunapi.config.seedqueue.option.reduceLevelList": "Reduce World List", "speedrunapi.config.seedqueue.option.reduceLevelList.description": "Hides worlds that have been reset on the Wall Screen or during preview from the world list to avoid lag.", + "speedrunapi.config.seedqueue.option.delayFileCreation": "Delay File Creation", + "speedrunapi.config.seedqueue.option.delayFileCreation.description": "Delays the creation of world files until world enter.\n Provides significant performance increase for slow storage devices.", "speedrunapi.config.seedqueue.option.useWatchdog": "Watchdog", "speedrunapi.config.seedqueue.option.useWatchdog.description": "Launches an extra thread that prints out the main threads stacktrace every 10 seconds to diagnose freezing issues.", "speedrunapi.config.seedqueue.option.showDebugMenu": "Show Debug Menu", diff --git a/src/main/resources/seedqueue.mixins.json b/src/main/resources/seedqueue.mixins.json index 8d9f6b7c..7e77d71f 100644 --- a/src/main/resources/seedqueue.mixins.json +++ b/src/main/resources/seedqueue.mixins.json @@ -57,5 +57,11 @@ "server.synchronization.ScheduledTickMixin", "server.synchronization.WeightedBlockStateProviderMixin" ], - "plugin": "me.contaria.seedqueue.SeedQueueMixinConfigPlugin" + "plugin": "me.contaria.seedqueue.SeedQueueMixinConfigPlugin", + "mixins": [ + "server.optimization.FileResourcePackProviderMixin", + "server.optimization.LevelStorageSessionMixin", + "server.optimization.ServerChunkManagerMixin", + "server.optimization.WorldSaveHandlerMixin" + ] } \ No newline at end of file