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 d967d605c2e4227ae980c30f1c8b86edbc680d6d..6dbae12bbfd47cd4e75bc3089561e8e226e9e604 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;
@@ -1533,9 +1533,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 46dfaed12c998c219a20c711a06531aed2c68012..ebeeb63c3dca505a3ce8b88feaa5d2ca20ec24a2 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 5e94dd9e26aa4fd6545dbaae2ae0cb51cb6f13e0..03feaf0adb8ee87e33744a4615dc2507a02f92d7 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) {
@@ -1064,9 +1065,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
}
|