From 34706c7cd77fe2107794347cbf77ca59250019dd Mon Sep 17 00:00:00 2001 From: LexManos Date: Tue, 3 Apr 2018 15:26:28 -0700 Subject: [PATCH] Slow down Forge chunk gen worker when save queue is to high. Prevents task from completing while tons of chunks are pending save. And add minimum notification every 60 seconds. --- jsons/1.12.2.json | 10 ++-- .../chunk/storage/AnvilChunkLoader.java.patch | 10 ++++ .../server/command/ChunkGenWorker.java | 57 ++++++++++++++----- 3 files changed, 58 insertions(+), 19 deletions(-) diff --git a/jsons/1.12.2.json b/jsons/1.12.2.json index 5f6635fc4..e09adb0c9 100644 --- a/jsons/1.12.2.json +++ b/jsons/1.12.2.json @@ -1,10 +1,10 @@ { "assetIndex": { "id": "1.12", - "sha1": "98c430c16a705f18a58a281b27caabf3ef09d40d", - "size": 169253, - "url": "https://launchermeta.mojang.com/mc/assets/1.12/98c430c16a705f18a58a281b27caabf3ef09d40d/1.12.json", - "totalSize": 127453671 + "sha1": "e75e9535754c6f2158b0b18b35660f45c4495d78", + "size": 169257, + "url": "https://launchermeta.mojang.com/mc/assets/1.12/e75e9535754c6f2158b0b18b35660f45c4495d78/1.12.json", + "totalSize": 127722338 }, "assets": "1.12", "downloads": { @@ -719,6 +719,6 @@ "minecraftArguments": "--username ${auth_player_name} --version ${version_name} --gameDir ${game_directory} --assetsDir ${assets_root} --assetIndex ${assets_index_name} --uuid ${auth_uuid} --accessToken ${auth_access_token} --userType ${user_type} --versionType ${version_type}", "minimumLauncherVersion": 18, "releaseTime": "2017-09-18T08:39:46+00:00", - "time": "2018-02-15T16:26:45+00:00", + "time": "2018-04-02T07:39:26+00:00", "type": "release" } diff --git a/patches/minecraft/net/minecraft/world/chunk/storage/AnvilChunkLoader.java.patch b/patches/minecraft/net/minecraft/world/chunk/storage/AnvilChunkLoader.java.patch index bafb37b69..2d4bf100d 100644 --- a/patches/minecraft/net/minecraft/world/chunk/storage/AnvilChunkLoader.java.patch +++ b/patches/minecraft/net/minecraft/world/chunk/storage/AnvilChunkLoader.java.patch @@ -179,3 +179,13 @@ } @Nullable +@@ -563,4 +650,9 @@ + return entity; + } + } ++ ++ public int getPendingSaveCount() ++ { ++ return this.field_75828_a.size(); ++ } + } diff --git a/src/main/java/net/minecraftforge/server/command/ChunkGenWorker.java b/src/main/java/net/minecraftforge/server/command/ChunkGenWorker.java index 148bb1eaa..89a14ba40 100644 --- a/src/main/java/net/minecraftforge/server/command/ChunkGenWorker.java +++ b/src/main/java/net/minecraftforge/server/command/ChunkGenWorker.java @@ -18,6 +18,7 @@ */ package net.minecraftforge.server.command; +import java.io.IOException; import java.util.ArrayDeque; import java.util.Queue; @@ -26,8 +27,10 @@ import net.minecraft.server.management.PlayerChunkMapEntry; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentBase; import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.MinecraftException; import net.minecraft.world.WorldServer; import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.storage.AnvilChunkLoader; import net.minecraftforge.common.DimensionManager; import net.minecraftforge.common.WorldWorkerManager.IWorker; @@ -40,6 +43,7 @@ public class ChunkGenWorker implements IWorker private final Queue queue; private final int notificationFrequency; private int lastNotification = 0; + private long lastNotifcationTime = 0; private int genned = 0; private Boolean keepingLoaded; @@ -51,6 +55,7 @@ public class ChunkGenWorker implements IWorker this.dim = dim; this.queue = buildQueue(); this.notificationFrequency = interval != -1 ? interval : Math.max(total / 20, 100); //Every 5% or every 100, whichever is more. + this.lastNotifcationTime = System.currentTimeMillis(); //We also notify at least once every 60 seconds, to show we haven't froze. } protected Queue buildQueue() @@ -97,34 +102,48 @@ public class ChunkGenWorker implements IWorker } @Override - public void work() + public boolean doWork() { + WorldServer world = DimensionManager.getWorld(dim); + if (world == null) + { + DimensionManager.initDimension(dim); + world = DimensionManager.getWorld(dim); + if (world == null) + { + listener.sendMessage(TextComponentHelper.createComponentTranslation(listener, "commands.forge.gen.dim_fail", dim)); + queue.clear(); + return false; + } + } + + AnvilChunkLoader loader = world.getChunkProvider().chunkLoader instanceof AnvilChunkLoader ? (AnvilChunkLoader)world.getChunkProvider().chunkLoader : null; + if (loader != null && loader.getPendingSaveCount() > 100) + { + + if (lastNotifcationTime < System.currentTimeMillis() - 10*1000) + { + listener.sendMessage(TextComponentHelper.createComponentTranslation(listener, "commands.forge.gen.progress", total - queue.size(), total)); + lastNotifcationTime = System.currentTimeMillis(); + } + return false; + } + BlockPos next = queue.poll(); if (next != null) { - WorldServer world = DimensionManager.getWorld(dim); - if (world == null) - { - DimensionManager.initDimension(dim); - world = DimensionManager.getWorld(dim); - if (world == null) - { - listener.sendMessage(TextComponentHelper.createComponentTranslation(listener, "commands.forge.gen.dim_fail", dim)); - queue.clear(); - return; - } - } // While we work we don't want to cause world load spam so pause unloading the world. if (keepingLoaded == null) { keepingLoaded = DimensionManager.keepDimensionLoaded(dim, true); } - if (++lastNotification >= notificationFrequency) + if (++lastNotification >= notificationFrequency || lastNotifcationTime < System.currentTimeMillis() - 60*1000) { listener.sendMessage(TextComponentHelper.createComponentTranslation(listener, "commands.forge.gen.progress", total - queue.size(), total)); lastNotification = 0; + lastNotifcationTime = System.currentTimeMillis(); } int x = next.getX(); @@ -144,6 +163,14 @@ public class ChunkGenWorker implements IWorker world.getChunkFromChunkCoords(x + 1, z + 1), world.getChunkFromChunkCoords(x, z + 1), }; + try + { + world.getChunkProvider().chunkLoader.saveChunk(world, target); + } + catch (IOException | MinecraftException e) + { + listener.sendMessage(TextComponentHelper.createComponentTranslation(listener, "commands.forge.gen.saveerror", e.getMessage())); + } genned++; } @@ -162,6 +189,8 @@ public class ChunkGenWorker implements IWorker { DimensionManager.keepDimensionLoaded(dim, false); } + return false; } + return true; } }