mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-29 03:49:21 +00:00
Revert "async saving player stats and advancements (#334)" This reverts commit107ae7954f. Revert "optimize random tick (#357)" This reverts commit2e822d3714. Revert "disable optimise-random-tick by default" This reverts commit20cc10e45f. Revert "fix random tick do extra tick" This reverts commit4bf675075a. Revert "fix tickingPos out of bounds" This reverts commit0eeb6e719c. Revert "improve ServerStatsCounter compatibility" This reverts commit47c1783afc. Revert "fix random tick" This reverts commitaad17b0a5b. Revert "revert level dat" This reverts commit8d36c9a5f7.
202 lines
10 KiB
Diff
202 lines
10 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com>
|
|
Date: Fri, 23 Aug 2024 22:04:20 -0400
|
|
Subject: [PATCH] Nitori: Async playerdata saving
|
|
|
|
Original license: GPL v3
|
|
Original project: https://github.com/Gensokyo-Reimagined/Nitori
|
|
|
|
diff --git a/net/minecraft/world/level/storage/LevelStorageSource.java b/net/minecraft/world/level/storage/LevelStorageSource.java
|
|
index de43e54698125ce9f319d4889dd49f7029fe95e0..742bd4b60321adc9e63c3de910ea95f4990b618d 100644
|
|
--- a/net/minecraft/world/level/storage/LevelStorageSource.java
|
|
+++ b/net/minecraft/world/level/storage/LevelStorageSource.java
|
|
@@ -520,15 +520,26 @@ public class LevelStorageSource {
|
|
private void saveLevelData(CompoundTag tag) {
|
|
Path path = this.levelDirectory.path();
|
|
|
|
+ // Leaf start - Async playerdata saving
|
|
+ // Save level.dat asynchronously
|
|
+ var nbtBytes = new it.unimi.dsi.fastutil.io.FastByteArrayOutputStream(65536);
|
|
try {
|
|
- Path path1 = Files.createTempFile(path, "level", ".dat");
|
|
- NbtIo.writeCompressed(tag, path1);
|
|
- Path path2 = this.levelDirectory.oldDataFile();
|
|
- Path path3 = this.levelDirectory.dataFile();
|
|
- Util.safeReplaceFile(path3, path1, path2);
|
|
+ NbtIo.writeCompressed(tag, nbtBytes);
|
|
} catch (Exception var6) {
|
|
- LevelStorageSource.LOGGER.error("Failed to save level {}", path, var6);
|
|
+ LevelStorageSource.LOGGER.error("Failed to encode level {}", path, var6);
|
|
}
|
|
+ org.dreeam.leaf.async.AsyncPlayerDataSaving.submit(() -> {
|
|
+ try {
|
|
+ Path path1 = Files.createTempFile(path, "level", ".dat");
|
|
+ org.apache.commons.io.FileUtils.writeByteArrayToFile(path1.toFile(), nbtBytes.array, 0, nbtBytes.length, false);
|
|
+ Path path2 = this.levelDirectory.oldDataFile();
|
|
+ Path path3 = this.levelDirectory.dataFile();
|
|
+ Util.safeReplaceFile(path3, path1, path2);
|
|
+ } catch (Exception var6) {
|
|
+ LevelStorageSource.LOGGER.error("Failed to save level {}", path, var6);
|
|
+ }
|
|
+ });
|
|
+ // Leaf end - Async playerdata saving
|
|
}
|
|
|
|
public Optional<Path> getIconFile() {
|
|
diff --git a/net/minecraft/world/level/storage/PlayerDataStorage.java b/net/minecraft/world/level/storage/PlayerDataStorage.java
|
|
index c44110b123ba5912af18faf0065e9ded780da9b7..fd8b4832c8b4a52bd8f9b3ea59111af85127b573 100644
|
|
--- a/net/minecraft/world/level/storage/PlayerDataStorage.java
|
|
+++ b/net/minecraft/world/level/storage/PlayerDataStorage.java
|
|
@@ -25,6 +25,7 @@ public class PlayerDataStorage {
|
|
private final File playerDir;
|
|
protected final DataFixer fixerUpper;
|
|
private static final DateTimeFormatter FORMATTER = FileNameDateFormatter.create();
|
|
+ private final java.util.Map<java.util.UUID, java.util.concurrent.Future<?>> savingLocks = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(); // Leaf - Async playerdata saving
|
|
|
|
public PlayerDataStorage(LevelStorageSource.LevelStorageAccess levelStorageAccess, DataFixer fixerUpper) {
|
|
this.fixerUpper = fixerUpper;
|
|
@@ -34,19 +35,82 @@ public class PlayerDataStorage {
|
|
|
|
public void save(Player player) {
|
|
if (org.spigotmc.SpigotConfig.disablePlayerDataSaving) return; // Spigot
|
|
+ // Leaf start - Async playerdata saving
|
|
+ CompoundTag compoundTag;
|
|
try {
|
|
- CompoundTag compoundTag = player.saveWithoutId(new CompoundTag());
|
|
- Path path = this.playerDir.toPath();
|
|
- Path path1 = Files.createTempFile(path, player.getStringUUID() + "-", ".dat");
|
|
- NbtIo.writeCompressed(compoundTag, path1);
|
|
- Path path2 = path.resolve(player.getStringUUID() + ".dat");
|
|
- Path path3 = path.resolve(player.getStringUUID() + ".dat_old");
|
|
- Util.safeReplaceFile(path2, path1, path3);
|
|
- } catch (Exception var7) {
|
|
- LOGGER.warn("Failed to save player data for {}", player.getScoreboardName(), var7); // Paper - Print exception
|
|
+ compoundTag = player.saveWithoutId(new CompoundTag());
|
|
+ } catch (Exception exception) {
|
|
+ LOGGER.warn("Failed to encode player data for {}", player.getScoreboardName(), exception);
|
|
+ return;
|
|
}
|
|
+ save(player.getScoreboardName(), player.getUUID(), player.getStringUUID(), compoundTag);
|
|
+ // Leaf end - Async playerdata saving
|
|
}
|
|
|
|
+ // Leaf start - Async playerdata saving
|
|
+ public void save(String playerName, java.util.UUID uniqueId, String stringId, CompoundTag compoundTag) {
|
|
+ var nbtBytes = new it.unimi.dsi.fastutil.io.FastByteArrayOutputStream(65536);
|
|
+ try {
|
|
+ NbtIo.writeCompressed(compoundTag, nbtBytes);
|
|
+ } catch (Exception exception) {
|
|
+ LOGGER.warn("Failed to encode player data for {}", stringId, exception);
|
|
+ }
|
|
+ lockFor(uniqueId, playerName);
|
|
+ synchronized (PlayerDataStorage.this) {
|
|
+ org.dreeam.leaf.async.AsyncPlayerDataSaving.submit(() -> {
|
|
+ try {
|
|
+ Path path = this.playerDir.toPath();
|
|
+ Path path1 = Files.createTempFile(path, stringId + "-", ".dat");
|
|
+ org.apache.commons.io.FileUtils.writeByteArrayToFile(path1.toFile(), nbtBytes.array, 0, nbtBytes.length, false);
|
|
+ Path path2 = path.resolve(stringId + ".dat");
|
|
+ Path path3 = path.resolve(stringId + ".dat_old");
|
|
+ Util.safeReplaceFile(path2, path1, path3);
|
|
+ } catch (Exception var7) {
|
|
+ LOGGER.warn("Failed to save player data for {}", playerName, var7);
|
|
+ } finally {
|
|
+ synchronized (PlayerDataStorage.this) {
|
|
+ savingLocks.remove(uniqueId);
|
|
+ }
|
|
+ }
|
|
+ }).ifPresent(future -> savingLocks.put(uniqueId, future));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void lockFor(java.util.UUID uniqueId, String playerName) {
|
|
+ java.util.concurrent.Future<?> fut;
|
|
+ synchronized (this) {
|
|
+ fut = savingLocks.get(uniqueId);
|
|
+ }
|
|
+ if (fut == null) {
|
|
+ return;
|
|
+ }
|
|
+ while (true) {
|
|
+ try {
|
|
+ fut.get(10_000L, java.util.concurrent.TimeUnit.MILLISECONDS);
|
|
+ break;
|
|
+ } catch (InterruptedException ignored) {
|
|
+ } catch (java.util.concurrent.ExecutionException
|
|
+ | java.util.concurrent.TimeoutException exception) {
|
|
+ LOGGER.warn("Failed to save player data for {}", playerName, exception);
|
|
+
|
|
+ String threadDump = "";
|
|
+ var threadMXBean = java.lang.management.ManagementFactory.getThreadMXBean();
|
|
+ for (var threadInfo : threadMXBean.dumpAllThreads(true, true)) {
|
|
+ if (threadInfo.getThreadName().equals("Leaf IO Thread")) {
|
|
+ threadDump = threadInfo.toString();
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ LOGGER.warn(threadDump);
|
|
+ fut.cancel(true);
|
|
+ break;
|
|
+ } finally {
|
|
+ savingLocks.remove(uniqueId);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Leaf end - Async playerdata saving
|
|
+
|
|
private void backup(String name, String stringUuid, String suffix) { // CraftBukkit
|
|
Path path = this.playerDir.toPath();
|
|
Path path1 = path.resolve(stringUuid + suffix); // CraftBukkit
|
|
@@ -60,7 +124,13 @@ public class PlayerDataStorage {
|
|
}
|
|
}
|
|
|
|
- private Optional<CompoundTag> load(String name, String stringUuid, String suffix) { // CraftBukkit
|
|
+ // Leaf start - Async playerdata saving
|
|
+ private Optional<CompoundTag> load(String name, String stringUuid, String suffix) {
|
|
+ return load(name, stringUuid, suffix, java.util.UUID.fromString(stringUuid));
|
|
+ }
|
|
+ private Optional<CompoundTag> load(String name, String stringUuid, String suffix, java.util.UUID playerUuid) { // CraftBukkit
|
|
+ lockFor(playerUuid, name);
|
|
+ // Leaf end - Async playerdata saving
|
|
File file = new File(this.playerDir, stringUuid + suffix); // CraftBukkit
|
|
// Spigot start
|
|
boolean usingWrongFile = false;
|
|
@@ -91,7 +161,7 @@ public class PlayerDataStorage {
|
|
|
|
public Optional<CompoundTag> load(Player player) {
|
|
// CraftBukkit start
|
|
- return this.load(player.getName().getString(), player.getStringUUID()).map((tag) -> {
|
|
+ return this.load(player.getName().getString(), player.getStringUUID(), player.getUUID()).map((tag) -> { // Leaf - Async playerdata saving
|
|
if (player instanceof ServerPlayer serverPlayer) {
|
|
CraftPlayer craftPlayer = serverPlayer.getBukkitEntity();
|
|
// Only update first played if it is older than the one we have
|
|
@@ -106,20 +176,25 @@ public class PlayerDataStorage {
|
|
});
|
|
}
|
|
|
|
+ // Leaf start - Async playerdata saving
|
|
public Optional<CompoundTag> load(String name, String uuid) {
|
|
+ return this.load(name, uuid, java.util.UUID.fromString(uuid));
|
|
+ }
|
|
+ public Optional<CompoundTag> load(String name, String uuid, java.util.UUID playerUuid) {
|
|
// CraftBukkit end
|
|
- Optional<CompoundTag> optional = this.load(name, uuid, ".dat"); // CraftBukkit
|
|
+ Optional<CompoundTag> optional = this.load(name, uuid, ".dat", playerUuid); // CraftBukkit
|
|
if (optional.isEmpty()) {
|
|
this.backup(name, uuid, ".dat"); // CraftBukkit
|
|
}
|
|
|
|
- return optional.or(() -> this.load(name, uuid, ".dat_old")).map(compoundTag -> { // CraftBukkit
|
|
+ return optional.or(() -> this.load(name, uuid, ".dat_old", playerUuid)).map(compoundTag -> { // CraftBukkit
|
|
int dataVersion = NbtUtils.getDataVersion(compoundTag, -1);
|
|
compoundTag = ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.PLAYER, compoundTag, dataVersion, net.minecraft.SharedConstants.getCurrentVersion().getDataVersion().getVersion()); // Paper - rewrite data conversion system
|
|
// player.load(compoundTag); // CraftBukkit - handled above
|
|
return compoundTag;
|
|
});
|
|
}
|
|
+ // Leaf end - Async playerdata saving
|
|
|
|
// CraftBukkit start
|
|
public File getPlayerDir() {
|