net.minecraft.world.level.storage

This commit is contained in:
Jake Potrebic
2024-12-14 15:58:32 -08:00
parent 767215bf9b
commit d3ec6a433b
8 changed files with 351 additions and 473 deletions

View File

@@ -0,0 +1,20 @@
--- a/net/minecraft/world/level/storage/DimensionDataStorage.java
+++ b/net/minecraft/world/level/storage/DimensionDataStorage.java
@@ -139,7 +_,7 @@
} else {
int i = Util.maxAllowedExecutorThreads();
int size = map.size();
- if (size > i) {
+ if (false && size > i) { // Paper - Separate dimension data IO pool; just throw them into the fixed pool queue
this.pendingWriteFuture = this.pendingWriteFuture.thenCompose(object -> {
List<CompletableFuture<?>> list = new ArrayList<>(i);
int i1 = Mth.positiveCeilDiv(size, i);
@@ -160,7 +_,7 @@
object -> CompletableFuture.allOf(
map.entrySet()
.stream()
- .map(entry -> CompletableFuture.runAsync(() -> tryWrite(entry.getKey(), entry.getValue()), Util.ioPool()))
+ .map(entry -> CompletableFuture.runAsync(() -> tryWrite(entry.getKey(), entry.getValue()), Util.DIMENSION_DATA_IO_POOL)) // Paper - Separate dimension data IO pool
.toArray(CompletableFuture[]::new)
)
);

View File

@@ -0,0 +1,86 @@
--- a/net/minecraft/world/level/storage/LevelStorageSource.java
+++ b/net/minecraft/world/level/storage/LevelStorageSource.java
@@ -66,7 +_,6 @@
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelSettings;
import net.minecraft.world.level.WorldDataConfiguration;
-import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.levelgen.WorldDimensions;
import net.minecraft.world.level.levelgen.WorldGenSettings;
@@ -145,6 +_,7 @@
PrimaryLevelData primaryLevelData = PrimaryLevelData.parse(
dynamic, levelSettings, complete.specialWorldProperty(), worldGenSettings.options(), lifecycle
);
+ primaryLevelData.pdc = dynamic.castTyped(NbtOps.INSTANCE).getElement("BukkitValues", null); // CraftBukkit - Add PDC to world
return new LevelDataAndDimensions(primaryLevelData, complete);
}
@@ -340,25 +_,39 @@
return this.backupDir;
}
- public LevelStorageSource.LevelStorageAccess validateAndCreateAccess(String saveName) throws IOException, ContentValidationException {
+ public LevelStorageSource.LevelStorageAccess validateAndCreateAccess(String saveName, ResourceKey<LevelStem> dimensionType) throws IOException, ContentValidationException { // CraftBukkit
Path levelPath = this.getLevelPath(saveName);
- List<ForbiddenSymlinkInfo> list = this.worldDirValidator.validateDirectory(levelPath, true);
+ List<ForbiddenSymlinkInfo> list = Boolean.getBoolean("paper.disableWorldSymlinkValidation") ? List.of() : this.worldDirValidator.validateDirectory(levelPath, true); // Paper - add skipping of symlinks scan
if (!list.isEmpty()) {
throw new ContentValidationException(levelPath, list);
} else {
- return new LevelStorageSource.LevelStorageAccess(saveName, levelPath);
+ return new LevelStorageSource.LevelStorageAccess(saveName, levelPath, dimensionType); // CraftBukkit
}
}
- public LevelStorageSource.LevelStorageAccess createAccess(String saveName) throws IOException {
+ public LevelStorageSource.LevelStorageAccess createAccess(String saveName, ResourceKey<LevelStem> dimensionType) throws IOException { // CraftBukkit
Path levelPath = this.getLevelPath(saveName);
- return new LevelStorageSource.LevelStorageAccess(saveName, levelPath);
+ return new LevelStorageSource.LevelStorageAccess(saveName, levelPath, dimensionType); // CraftBukkit
}
public DirectoryValidator getWorldDirValidator() {
return this.worldDirValidator;
}
+ // CraftBukkit start
+ public static Path getStorageFolder(Path path, ResourceKey<LevelStem> dimensionType) {
+ if (dimensionType == LevelStem.OVERWORLD) {
+ return path;
+ } else if (dimensionType == LevelStem.NETHER) {
+ return path.resolve("DIM-1");
+ } else if (dimensionType == LevelStem.END) {
+ return path.resolve("DIM1");
+ } else {
+ return path.resolve("dimensions").resolve(dimensionType.location().getNamespace()).resolve(dimensionType.location().getPath());
+ }
+ }
+ // CraftBukkit end
+
public record LevelCandidates(List<LevelStorageSource.LevelDirectory> levels) implements Iterable<LevelStorageSource.LevelDirectory> {
public boolean isEmpty() {
return this.levels.isEmpty();
@@ -409,8 +_,12 @@
public final LevelStorageSource.LevelDirectory levelDirectory;
private final String levelId;
private final Map<LevelResource, Path> resources = Maps.newHashMap();
+ // CraftBukkit start
+ public final ResourceKey<LevelStem> dimensionType;
- LevelStorageAccess(final String levelId, final Path levelDir) throws IOException {
+ LevelStorageAccess(final String levelId, final Path levelDir, final ResourceKey<LevelStem> dimensionType) throws IOException {
+ this.dimensionType = dimensionType;
+ // CraftBukkit end
this.levelId = levelId;
this.levelDirectory = new LevelStorageSource.LevelDirectory(levelDir);
this.lock = DirectoryLock.create(levelDir);
@@ -453,7 +_,7 @@
}
public Path getDimensionPath(ResourceKey<Level> dimensionPath) {
- return DimensionType.getStorageFolder(dimensionPath, this.levelDirectory.path());
+ return getStorageFolder(this.levelDirectory.path(), this.dimensionType); // CraftBukkit
}
private void checkLock() {

View File

@@ -0,0 +1,122 @@
--- a/net/minecraft/world/level/storage/PlayerDataStorage.java
+++ b/net/minecraft/world/level/storage/PlayerDataStorage.java
@@ -14,8 +_,10 @@
import net.minecraft.nbt.NbtAccounter;
import net.minecraft.nbt.NbtIo;
import net.minecraft.nbt.NbtUtils;
+import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.datafix.DataFixTypes;
import net.minecraft.world.entity.player.Player;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.slf4j.Logger;
public class PlayerDataStorage {
@@ -31,6 +_,7 @@
}
public void save(Player player) {
+ if (org.spigotmc.SpigotConfig.disablePlayerDataSaving) return; // Spigot
try {
CompoundTag compoundTag = player.saveWithoutId(new CompoundTag());
Path path = this.playerDir.toPath();
@@ -40,30 +_,46 @@
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.getName().getString());
+ LOGGER.warn("Failed to save player data for {}", player.getScoreboardName(), var7); // Paper - Print exception
}
}
- private void backup(Player player, String suffix) {
+ private void backup(String name, String stringUuid, String suffix) { // CraftBukkit
Path path = this.playerDir.toPath();
- Path path1 = path.resolve(player.getStringUUID() + suffix);
- Path path2 = path.resolve(player.getStringUUID() + "_corrupted_" + LocalDateTime.now().format(FORMATTER) + suffix);
+ Path path1 = path.resolve(stringUuid + suffix); // CraftBukkit
+ Path path2 = path.resolve(stringUuid + "_corrupted_" + LocalDateTime.now().format(FORMATTER) + suffix); // CraftBukkit
if (Files.isRegularFile(path1)) {
try {
Files.copy(path1, path2, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
} catch (Exception var7) {
- LOGGER.warn("Failed to copy the player.dat file for {}", player.getName().getString(), var7);
+ LOGGER.warn("Failed to copy the player.dat file for {}", name, var7); // CraftBukkit
}
}
}
- private Optional<CompoundTag> load(Player player, String suffix) {
- File file = new File(this.playerDir, player.getStringUUID() + suffix);
+ private Optional<CompoundTag> load(String name, String stringUuid, String suffix) { // CraftBukkit
+ File file = new File(this.playerDir, stringUuid + suffix); // CraftBukkit
+ // Spigot Start
+ boolean usingWrongFile = false;
+ if (org.bukkit.Bukkit.getOnlineMode() && !file.exists()) { // Paper - Check online mode first
+ file = new File(file, java.util.UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(java.nio.charset.StandardCharsets.UTF_8)).toString() + suffix);
+ if (file.exists()) {
+ usingWrongFile = true;
+ org.bukkit.Bukkit.getServer().getLogger().warning("Using offline mode UUID file for player " + name + " as it is the only copy we can find.");
+ }
+ }
+ // Spigot End
if (file.exists() && file.isFile()) {
try {
- return Optional.of(NbtIo.readCompressed(file.toPath(), NbtAccounter.unlimitedHeap()));
+ // Spigot Start
+ Optional<CompoundTag> optional = Optional.of(NbtIo.readCompressed(file.toPath(), NbtAccounter.unlimitedHeap()));
+ if (usingWrongFile) {
+ file.renameTo(new File(file.getPath() + ".offline-read"));
+ }
+ return optional;
+ // Spigot End
} catch (Exception var5) {
- LOGGER.warn("Failed to load player data for {}", player.getName().getString());
+ LOGGER.warn("Failed to load player data for {}", name); // CraftBukkit
}
}
@@ -71,16 +_,40 @@
}
public Optional<CompoundTag> load(Player player) {
- Optional<CompoundTag> optional = this.load(player, ".dat");
+ // CraftBukkit start
+ return this.load(player.getName().getString(), player.getStringUUID()).map((tag) -> {
+ if (player instanceof ServerPlayer) {
+ CraftPlayer player1 = (CraftPlayer) player.getBukkitEntity();
+ // Only update first played if it is older than the one we have
+ long modified = new File(this.playerDir, player.getStringUUID() + ".dat").lastModified();
+ if (modified < player1.getFirstPlayed()) {
+ player1.setFirstPlayed(modified);
+ }
+ }
+
+ player.load(tag); // From below
+ return tag;
+ });
+ }
+
+ public Optional<CompoundTag> load(String name, String uuid) {
+ // CraftBukkit end
+ Optional<CompoundTag> optional = this.load(name, uuid, ".dat"); // CraftBukkit
if (optional.isEmpty()) {
- this.backup(player, ".dat");
+ this.backup(name, uuid, ".dat"); // CraftBukkit
}
- return optional.or(() -> this.load(player, ".dat_old")).map(compoundTag -> {
+ return optional.or(() -> this.load(name, uuid, ".dat_old")).map(compoundTag -> { // CraftBukkit
int dataVersion = NbtUtils.getDataVersion(compoundTag, -1);
compoundTag = DataFixTypes.PLAYER.updateToCurrentVersion(this.fixerUpper, compoundTag, dataVersion);
- player.load(compoundTag);
+ // player.load(compoundTag); // CraftBukkit - handled above
return compoundTag;
});
}
+
+ // CraftBukkit start
+ public File getPlayerDir() {
+ return this.playerDir;
+ }
+ // CraftBukkit end
}

View File

@@ -0,0 +1,123 @@
--- a/net/minecraft/world/level/storage/PrimaryLevelData.java
+++ b/net/minecraft/world/level/storage/PrimaryLevelData.java
@@ -74,6 +_,21 @@
private final Set<String> removedFeatureFlags;
private final TimerQueue<MinecraftServer> scheduledEvents;
+ // CraftBukkit start - Add world and pdc
+ public net.minecraft.core.Registry<net.minecraft.world.level.dimension.LevelStem> customDimensions;
+ private net.minecraft.server.level.ServerLevel world;
+ protected net.minecraft.nbt.Tag pdc;
+
+ public void setWorld(net.minecraft.server.level.ServerLevel world) {
+ if (this.world != null) {
+ return;
+ }
+ this.world = world;
+ world.getWorld().readBukkitValues(this.pdc);
+ this.pdc = null;
+ }
+ // CraftBukkit end
+
private PrimaryLevelData(
@Nullable CompoundTag loadedPlayerTag,
boolean wasModded,
@@ -237,7 +_,7 @@
nbt.put("Version", compoundTag);
NbtUtils.addCurrentDataVersion(nbt);
DynamicOps<Tag> dynamicOps = registry.createSerializationContext(NbtOps.INSTANCE);
- WorldGenSettings.encode(dynamicOps, this.worldOptions, registry)
+ WorldGenSettings.encode(dynamicOps, this.worldOptions, new net.minecraft.world.level.levelgen.WorldDimensions(this.customDimensions != null ? this.customDimensions : registry.lookupOrThrow(net.minecraft.core.registries.Registries.LEVEL_STEM))) // CraftBukkit
.resultOrPartial(Util.prefix("WorldGenSettings: ", LOGGER::error))
.ifPresent(worldOptionsTag -> nbt.put("WorldGenSettings", worldOptionsTag));
nbt.putInt("GameType", this.settings.gameType().getId());
@@ -281,6 +_,8 @@
if (this.wanderingTraderId != null) {
nbt.putUUID("WanderingTraderId", this.wanderingTraderId);
}
+ nbt.putString("Bukkit.Version", org.bukkit.Bukkit.getName() + "/" + org.bukkit.Bukkit.getVersion() + "/" + org.bukkit.Bukkit.getBukkitVersion()); // CraftBukkit
+ this.world.getWorld().storeBukkitValues(nbt); // CraftBukkit - add pdc
}
private static ListTag stringCollectionToTag(Set<String> stringCollection) {
@@ -358,6 +_,25 @@
@Override
public void setThundering(boolean thundering) {
+ // Paper start - Add cause to Weather/ThunderChangeEvents
+ this.setThundering(thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.UNKNOWN);
+ }
+ public void setThundering(boolean thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause cause) {
+ // Paper end - Add cause to Weather/ThunderChangeEvents
+ // CraftBukkit start
+ if (this.thundering == thundering) {
+ return;
+ }
+
+ org.bukkit.World world = org.bukkit.Bukkit.getWorld(this.getLevelName());
+ if (world != null) {
+ org.bukkit.event.weather.ThunderChangeEvent thunder = new org.bukkit.event.weather.ThunderChangeEvent(world, thundering, cause); // Paper - Add cause to Weather/ThunderChangeEvents
+ org.bukkit.Bukkit.getServer().getPluginManager().callEvent(thunder);
+ if (thunder.isCancelled()) {
+ return;
+ }
+ }
+ // CraftBukkit end
this.thundering = thundering;
}
@@ -378,6 +_,26 @@
@Override
public void setRaining(boolean isRaining) {
+ // Paper start - Add cause to Weather/ThunderChangeEvents
+ this.setRaining(isRaining, org.bukkit.event.weather.WeatherChangeEvent.Cause.UNKNOWN);
+ }
+
+ public void setRaining(boolean isRaining, org.bukkit.event.weather.WeatherChangeEvent.Cause cause) {
+ // Paper end - Add cause to Weather/ThunderChangeEvents
+ // CraftBukkit start
+ if (this.raining == isRaining) {
+ return;
+ }
+
+ org.bukkit.World world = org.bukkit.Bukkit.getWorld(this.getLevelName());
+ if (world != null) {
+ org.bukkit.event.weather.WeatherChangeEvent weather = new org.bukkit.event.weather.WeatherChangeEvent(world, isRaining, cause); // Paper - Add cause to Weather/ThunderChangeEvents
+ org.bukkit.Bukkit.getServer().getPluginManager().callEvent(weather);
+ if (weather.isCancelled()) {
+ return;
+ }
+ }
+ // CraftBukkit end
this.raining = isRaining;
}
@@ -444,6 +_,12 @@
@Override
public void setDifficulty(Difficulty difficulty) {
this.settings = this.settings.withDifficulty(difficulty);
+ // CraftBukkit start
+ net.minecraft.network.protocol.game.ClientboundChangeDifficultyPacket packet = new net.minecraft.network.protocol.game.ClientboundChangeDifficultyPacket(this.getDifficulty(), this.isDifficultyLocked());
+ for (net.minecraft.server.level.ServerPlayer player : (java.util.List<net.minecraft.server.level.ServerPlayer>) (java.util.List) this.world.players()) {
+ player.connection.send(packet);
+ }
+ // CraftBukkit end
}
@Override
@@ -579,6 +_,14 @@
public LevelSettings getLevelSettings() {
return this.settings.copy();
}
+
+ // CraftBukkit start - Check if the name stored in NBT is the correct one
+ public void checkName(String name) {
+ if (!this.settings.levelName.equals(name)) {
+ this.settings.levelName = name;
+ }
+ }
+ // CraftBukkit end
@Deprecated
public static enum SpecialWorldProperty {