aboutsummaryrefslogtreecommitdiffhomepage
path: root/paper-server/patches/features/0032-Incremental-chunk-and-player-saving.patch
blob: 964ec03fd8874f6453ac69ad96cba42ce81bf306 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Sun, 9 Jun 2019 03:53:22 +0100
Subject: [PATCH] Incremental chunk and player saving


diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 3f880bdfd95f7556d1d76e4602a6d24dda78438c..79d050947960b26ef375c6f1986b617ad2ff081b 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -960,7 +960,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
         boolean var4;
         try {
             this.isSaving = true;
-            this.getPlayerList().saveAll();
+            this.getPlayerList().saveAll(); // Paper - Incremental chunk and player saving; diff on change
             var4 = this.saveAllChunks(suppressLog, flush, forced);
         } finally {
             this.isSaving = false;
@@ -1550,9 +1550,29 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
         }
 
         this.ticksUntilAutosave--;
-        if (this.autosavePeriod > 0 && this.ticksUntilAutosave <= 0) { // CraftBukkit
-            this.autoSave();
+        // Paper start - Incremental chunk and player saving
+        final ProfilerFiller profiler = Profiler.get();
+        int playerSaveInterval = io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.rate;
+        if (playerSaveInterval < 0) {
+            playerSaveInterval = autosavePeriod;
+        }
+        profiler.push("save");
+        final boolean fullSave = autosavePeriod > 0 && this.tickCount % autosavePeriod == 0;
+        try {
+            this.isSaving = true;
+            if (playerSaveInterval > 0) {
+                this.playerList.saveAll(playerSaveInterval);
+            }
+            for (final ServerLevel level : this.getAllLevels()) {
+                if (level.paperConfig().chunks.autoSaveInterval.value() > 0) {
+                    level.saveIncrementally(fullSave);
+                }
+            }
+        } finally {
+            this.isSaving = false;
         }
+        profiler.pop();
+        // Paper end - Incremental chunk and player saving
 
         ProfilerFiller profilerFiller = Profiler.get();
         this.runAllTasks(); // Paper - move runAllTasks() into full server tick (previously for timings)
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 9caa06f09409d36abf9e0a770ba004f4049e8e09..fc3b0db0f0a85fb42cb5fa8a1d78d4c4691ab519 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -1316,6 +1316,28 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
         return !this.server.isUnderSpawnProtection(this, pos, player) && this.getWorldBorder().isWithinBounds(pos);
     }
 
+    // Paper start - Incremental chunk and player saving
+    public void saveIncrementally(boolean doFull) {
+        if (doFull) {
+            org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(this.getWorld()));
+        }
+
+        if (doFull) {
+            this.saveLevelData(true);
+        }
+        // chunk autosave is already called by the ChunkSystem during unload processing (ChunkMap#processUnloads)
+        // Copied from save()
+        // CraftBukkit start - moved from MinecraftServer.saveChunks
+        if (doFull) { // Paper
+            ServerLevel serverLevel1 = this;
+            this.serverLevelData.setWorldBorder(serverLevel1.getWorldBorder().createSettings());
+            this.serverLevelData.setCustomBossEvents(this.server.getCustomBossEvents().save(this.registryAccess()));
+            this.levelStorageAccess.saveDataTag(this.server.registryAccess(), this.serverLevelData, this.server.getPlayerList().getSingleplayerData());
+        }
+        // CraftBukkit end
+    }
+    // Paper end - Incremental chunk and player saving
+
     public void save(@Nullable ProgressListener progress, boolean flush, boolean skipSave) {
         // Paper start - add close param
         this.save(progress, flush, skipSave, false);
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index e61fe83479f095e8addbd3e8f1d5179c998ae1eb..0a7e5106a1d39150326e7c323030df5d32ecef1e 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -180,6 +180,7 @@ import org.slf4j.Logger;
 
 public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer { // Paper - rewrite chunk system
     private static final Logger LOGGER = LogUtils.getLogger();
+    public long lastSave = MinecraftServer.currentTick; // Paper - Incremental chunk and player saving
     private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32;
     private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10;
     private static final int FLY_STAT_RECORDING_SPEED = 25;
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 42c1f5d0f384e0e4f348e161b4461858a6d84227..2f7f5f933cf3adb6022664a0ad9b97c8f8bc8fd4 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -482,6 +482,7 @@ public abstract class PlayerList {
 
     protected void save(ServerPlayer player) {
         if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit
+        player.lastSave = MinecraftServer.currentTick; // Paper - Incremental chunk and player saving
         this.playerIo.save(player);
         ServerStatsCounter serverStatsCounter = player.getStats(); // CraftBukkit
         if (serverStatsCounter != null) {
@@ -1069,9 +1070,23 @@ public abstract class PlayerList {
     }
 
     public void saveAll() {
+        // Paper start - Incremental chunk and player saving
+        this.saveAll(-1);
+    }
+
+    public void saveAll(final int interval) {
         io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main
+        int numSaved = 0;
+        final long now = MinecraftServer.currentTick;
         for (int i = 0; i < this.players.size(); i++) {
-            this.save(this.players.get(i));
+            final ServerPlayer player = this.players.get(i);
+            if (interval == -1 || now - player.lastSave >= interval) {
+                this.save(player);
+                if (interval != -1 && ++numSaved >= io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.maxPerTick()) {
+                    break;
+                }
+            }
+            // Paper end - Incremental chunk and player saving
         }
         return null; }); // Paper - ensure main
     }