net.minecraft.world.level.storage

This commit is contained in:
Jake Potrebic 2024-12-14 15:58:32 -08:00
parent 767215bf9b
commit d3ec6a433b
No known key found for this signature in database
GPG key ID: ECE0B3C133C016C5
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 {

View file

@ -1,20 +0,0 @@
--- a/net/minecraft/world/level/storage/DimensionDataStorage.java
+++ b/net/minecraft/world/level/storage/DimensionDataStorage.java
@@ -139,7 +139,7 @@
} else {
int i = Util.maxAllowedExecutorThreads();
int j = map.size();
- if (j > i) {
+ if (false && j > 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 k = Mth.positiveCeilDiv(j, i);
@@ -160,7 +160,7 @@
v -> 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

@ -1,107 +0,0 @@
--- a/net/minecraft/world/level/storage/LevelStorageSource.java
+++ b/net/minecraft/world/level/storage/LevelStorageSource.java
@@ -68,7 +68,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;
@@ -149,7 +148,7 @@
}
public static WorldDataConfiguration readDataConfig(Dynamic<?> dynamic) {
- DataResult dataresult = WorldDataConfiguration.CODEC.parse(dynamic);
+ DataResult<WorldDataConfiguration> dataresult = WorldDataConfiguration.CODEC.parse(dynamic); // CraftBukkit - decompile error
Logger logger = LevelStorageSource.LOGGER;
Objects.requireNonNull(logger);
@@ -168,6 +167,7 @@
WorldDimensions.Complete worlddimensions_b = generatorsettings.dimensions().bake(dimensionsRegistry);
Lifecycle lifecycle = worlddimensions_b.lifecycle().add(registries.allRegistriesLifecycle());
PrimaryLevelData worlddataserver = PrimaryLevelData.parse(dynamic1, worldsettings, worlddimensions_b.specialWorldProperty(), generatorsettings.options(), lifecycle);
+ worlddataserver.pdc = ((Dynamic<Tag>) dynamic1).getElement("BukkitValues", null); // CraftBukkit - Add PDC to world
return new LevelDataAndDimensions(worlddataserver, worlddimensions_b);
}
@@ -409,26 +409,40 @@
return this.backupDir;
}
- public LevelStorageSource.LevelStorageAccess validateAndCreateAccess(String directoryName) throws IOException, ContentValidationException {
- Path path = this.getLevelPath(directoryName);
- List<ForbiddenSymlinkInfo> list = this.worldDirValidator.validateDirectory(path, true);
+ public LevelStorageSource.LevelStorageAccess validateAndCreateAccess(String s, ResourceKey<LevelStem> dimensionType) throws IOException, ContentValidationException { // CraftBukkit
+ Path path = this.getLevelPath(s);
+ List<ForbiddenSymlinkInfo> list = Boolean.getBoolean("paper.disableWorldSymlinkValidation") ? List.of() : this.worldDirValidator.validateDirectory(path, true); // Paper - add skipping of symlinks scan
if (!list.isEmpty()) {
throw new ContentValidationException(path, list);
} else {
- return new LevelStorageSource.LevelStorageAccess(directoryName, path);
+ return new LevelStorageSource.LevelStorageAccess(s, path, dimensionType); // CraftBukkit
}
}
- public LevelStorageSource.LevelStorageAccess createAccess(String directoryName) throws IOException {
- Path path = this.getLevelPath(directoryName);
+ public LevelStorageSource.LevelStorageAccess createAccess(String s, ResourceKey<LevelStem> dimensionType) throws IOException { // CraftBukkit
+ Path path = this.getLevelPath(s);
- return new LevelStorageSource.LevelStorageAccess(directoryName, path);
+ return new LevelStorageSource.LevelStorageAccess(s, path, 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 static record LevelCandidates(List<LevelStorageSource.LevelDirectory> levels) implements Iterable<LevelStorageSource.LevelDirectory> {
@@ -488,8 +502,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 s, final Path path) throws IOException {
+ LevelStorageAccess(final String s, final Path path, final ResourceKey<LevelStem> dimensionType) throws IOException {
+ this.dimensionType = dimensionType;
+ // CraftBukkit end
this.levelId = s;
this.levelDirectory = new LevelStorageSource.LevelDirectory(path);
this.lock = DirectoryLock.create(path);
@@ -529,7 +547,7 @@
}
public Path getLevelPath(LevelResource savePath) {
- Map map = this.resources;
+ Map<LevelResource, Path> map = this.resources; // CraftBukkit - decompile error
LevelStorageSource.LevelDirectory convertable_b = this.levelDirectory;
Objects.requireNonNull(this.levelDirectory);
@@ -537,7 +555,7 @@
}
public Path getDimensionPath(ResourceKey<Level> key) {
- return DimensionType.getStorageFolder(key, this.levelDirectory.path());
+ return LevelStorageSource.getStorageFolder(this.levelDirectory.path(), this.dimensionType); // CraftBukkit
}
private void checkLock() {

View file

@ -1,143 +0,0 @@
--- a/net/minecraft/world/level/storage/PlayerDataStorage.java
+++ b/net/minecraft/world/level/storage/PlayerDataStorage.java
@@ -15,8 +15,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 {
@@ -33,6 +35,7 @@
}
public void save(Player player) {
+ if (org.spigotmc.SpigotConfig.disablePlayerDataSaving) return; // Spigot
try {
CompoundTag nbttagcompound = player.saveWithoutId(new CompoundTag());
Path path = this.playerDir.toPath();
@@ -44,39 +47,60 @@
Util.safeReplaceFile(path2, path1, path3);
} catch (Exception exception) {
- PlayerDataStorage.LOGGER.warn("Failed to save player data for {}", player.getName().getString());
+ PlayerDataStorage.LOGGER.warn("Failed to save player data for {}", player.getScoreboardName(), exception); // Paper - Print exception
}
}
- private void backup(Player player, String extension) {
+ private void backup(String name, String s1, String s) { // name, uuid, extension
Path path = this.playerDir.toPath();
- String s1 = player.getStringUUID();
- Path path1 = path.resolve(s1 + extension);
+ // String s1 = entityhuman.getStringUUID(); // CraftBukkit - used above
+ Path path1 = path.resolve(s1 + s);
- s1 = player.getStringUUID();
- Path path2 = path.resolve(s1 + "_corrupted_" + LocalDateTime.now().format(PlayerDataStorage.FORMATTER) + extension);
+ // s1 = entityhuman.getStringUUID(); // CraftBukkit - used above
+ Path path2 = path.resolve(s1 + "_corrupted_" + LocalDateTime.now().format(PlayerDataStorage.FORMATTER) + s);
if (Files.isRegularFile(path1, new LinkOption[0])) {
try {
Files.copy(path1, path2, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
} catch (Exception exception) {
- PlayerDataStorage.LOGGER.warn("Failed to copy the player.dat file for {}", player.getName().getString(), exception);
+ PlayerDataStorage.LOGGER.warn("Failed to copy the player.dat file for {}", name, exception); // CraftBukkit
}
}
}
- private Optional<CompoundTag> load(Player player, String extension) {
+ // CraftBukkit start
+ private Optional<CompoundTag> load(String name, String s1, String s) { // name, uuid, extension
+ // CraftBukkit end
File file = this.playerDir;
- String s1 = player.getStringUUID();
- File file1 = new File(file, s1 + extension);
+ // String s1 = entityhuman.getStringUUID(); // CraftBukkit - used above
+ File file1 = new File(file, s1 + s);
+ // Spigot Start
+ boolean usingWrongFile = false;
+ if ( org.bukkit.Bukkit.getOnlineMode() && !file1.exists() ) // Paper - Check online mode first
+ {
+ file1 = new File( file, java.util.UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + name ).getBytes( java.nio.charset.StandardCharsets.UTF_8 ) ).toString() + s );
+ if ( file1.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 (file1.exists() && file1.isFile()) {
try {
- return Optional.of(NbtIo.readCompressed(file1.toPath(), NbtAccounter.unlimitedHeap()));
+ // Spigot Start
+ Optional<CompoundTag> optional = Optional.of(NbtIo.readCompressed(file1.toPath(), NbtAccounter.unlimitedHeap()));
+ if ( usingWrongFile )
+ {
+ file1.renameTo( new File( file1.getPath() + ".offline-read" ) );
+ }
+ return optional;
+ // Spigot End
} catch (Exception exception) {
- PlayerDataStorage.LOGGER.warn("Failed to load player data for {}", player.getName().getString());
+ PlayerDataStorage.LOGGER.warn("Failed to load player data for {}", name); // CraftBukkit
}
}
@@ -84,20 +108,44 @@
}
public Optional<CompoundTag> load(Player player) {
- Optional<CompoundTag> optional = this.load(player, ".dat");
+ // CraftBukkit start
+ return this.load(player.getName().getString(), player.getStringUUID()).map((nbttagcompound) -> {
+ 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(nbttagcompound); // From below
+ return nbttagcompound;
+ });
+ }
+
+ 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(() -> {
- return this.load(player, ".dat_old");
+ return this.load(name, uuid, ".dat_old"); // CraftBukkit
}).map((nbttagcompound) -> {
int i = NbtUtils.getDataVersion(nbttagcompound, -1);
nbttagcompound = DataFixTypes.PLAYER.updateToCurrentVersion(this.fixerUpper, nbttagcompound, i);
- player.load(nbttagcompound);
+ // entityhuman.load(nbttagcompound); // CraftBukkit - handled above
return nbttagcompound;
});
}
+
+ // CraftBukkit start
+ public File getPlayerDir() {
+ return this.playerDir;
+ }
+ // CraftBukkit end
}

View file

@ -1,203 +0,0 @@
--- a/net/minecraft/world/level/storage/PrimaryLevelData.java
+++ b/net/minecraft/world/level/storage/PrimaryLevelData.java
@@ -20,15 +20,12 @@
import net.minecraft.SharedConstants;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
+import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.UUIDUtil;
-import net.minecraft.nbt.CompoundTag;
-import net.minecraft.nbt.ListTag;
-import net.minecraft.nbt.NbtOps;
-import net.minecraft.nbt.NbtUtils;
-import net.minecraft.nbt.StringTag;
-import net.minecraft.nbt.Tag;
import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Difficulty;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.GameType;
@@ -36,12 +33,26 @@
import net.minecraft.world.level.LevelSettings;
import net.minecraft.world.level.WorldDataConfiguration;
import net.minecraft.world.level.border.WorldBorder;
+import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.dimension.end.EndDragonFight;
-import net.minecraft.world.level.levelgen.WorldGenSettings;
import net.minecraft.world.level.levelgen.WorldOptions;
import net.minecraft.world.level.timers.TimerCallbacks;
import net.minecraft.world.level.timers.TimerQueue;
import org.slf4j.Logger;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.ListTag;
+import net.minecraft.nbt.NbtOps;
+import net.minecraft.nbt.NbtUtils;
+import net.minecraft.nbt.StringTag;
+import net.minecraft.nbt.Tag;
+import net.minecraft.network.protocol.game.ClientboundChangeDifficultyPacket;
+import net.minecraft.world.level.levelgen.WorldDimensions;
+import net.minecraft.world.level.levelgen.WorldGenSettings;
+import org.bukkit.Bukkit;
+import org.bukkit.event.weather.ThunderChangeEvent;
+import org.bukkit.event.weather.WeatherChangeEvent;
+// CraftBukkit end
public class PrimaryLevelData implements ServerLevelData, WorldData {
@@ -79,7 +90,21 @@
private boolean wasModded;
private final Set<String> removedFeatureFlags;
private final TimerQueue<MinecraftServer> scheduledEvents;
+ // CraftBukkit start - Add world and pdc
+ public Registry<LevelStem> customDimensions;
+ private ServerLevel world;
+ protected Tag pdc;
+ public void setWorld(ServerLevel world) {
+ if (this.world != null) {
+ return;
+ }
+ this.world = world;
+ world.getWorld().readBukkitValues(this.pdc);
+ this.pdc = null;
+ }
+ // CraftBukkit end
+
private PrimaryLevelData(@Nullable CompoundTag playerData, boolean modded, BlockPos spawnPos, float spawnAngle, long time, long timeOfDay, int version, int clearWeatherTime, int rainTime, boolean raining, int thunderTime, boolean thundering, boolean initialized, boolean difficultyLocked, WorldBorder.Settings worldBorder, int wanderingTraderSpawnDelay, int wanderingTraderSpawnChance, @Nullable UUID wanderingTraderId, Set<String> serverBrands, Set<String> removedFeatures, TimerQueue<MinecraftServer> scheduledEvents, @Nullable CompoundTag customBossEvents, EndDragonFight.Data dragonFight, LevelSettings levelInfo, WorldOptions generatorOptions, PrimaryLevelData.SpecialWorldProperty specialProperty, Lifecycle lifecycle) {
this.wasModded = modded;
this.spawnPos = spawnPos;
@@ -116,7 +141,7 @@
public static <T> PrimaryLevelData parse(Dynamic<T> dynamic, LevelSettings info, PrimaryLevelData.SpecialWorldProperty specialProperty, WorldOptions generatorOptions, Lifecycle lifecycle) {
long i = dynamic.get("Time").asLong(0L);
- OptionalDynamic optionaldynamic = dynamic.get("Player");
+ OptionalDynamic<T> optionaldynamic = dynamic.get("Player"); // CraftBukkit - decompile error
Codec codec = CompoundTag.CODEC;
Objects.requireNonNull(codec);
@@ -136,7 +161,7 @@
WorldBorder.Settings worldborder_c = WorldBorder.Settings.read(dynamic, WorldBorder.DEFAULT_SETTINGS);
int k1 = dynamic.get("WanderingTraderSpawnDelay").asInt(0);
int l1 = dynamic.get("WanderingTraderSpawnChance").asInt(0);
- UUID uuid = (UUID) dynamic.get("WanderingTraderId").read(UUIDUtil.CODEC).result().orElse((Object) null);
+ UUID uuid = (UUID) dynamic.get("WanderingTraderId").read(UUIDUtil.CODEC).result().orElse(null); // CraftBukkit - decompile error
Set set = (Set) dynamic.get("ServerBrands").asStream().flatMap((dynamic1) -> {
return dynamic1.asString().result().stream();
}).collect(Collectors.toCollection(Sets::newLinkedHashSet));
@@ -145,7 +170,7 @@
}).collect(Collectors.toSet());
TimerQueue customfunctioncallbacktimerqueue = new TimerQueue<>(TimerCallbacks.SERVER_CALLBACKS, dynamic.get("ScheduledEvents").asStream());
CompoundTag nbttagcompound1 = (CompoundTag) dynamic.get("CustomBossEvents").orElseEmptyMap().getValue();
- DataResult dataresult = dynamic.get("DragonFight").read(EndDragonFight.Data.CODEC);
+ DataResult<EndDragonFight.Data> dataresult = dynamic.get("DragonFight").read(EndDragonFight.Data.CODEC); // CraftBukkit - decompile error
Logger logger = PrimaryLevelData.LOGGER;
Objects.requireNonNull(logger);
@@ -180,7 +205,7 @@
levelNbt.put("Version", nbttagcompound2);
NbtUtils.addCurrentDataVersion(levelNbt);
DynamicOps<Tag> dynamicops = registryManager.createSerializationContext(NbtOps.INSTANCE);
- DataResult dataresult = WorldGenSettings.encode(dynamicops, this.worldOptions, registryManager);
+ DataResult<Tag> dataresult = WorldGenSettings.encode(dynamicops, this.worldOptions, new WorldDimensions(this.customDimensions != null ? this.customDimensions : registryManager.lookupOrThrow(Registries.LEVEL_STEM))); // CraftBukkit
Logger logger = PrimaryLevelData.LOGGER;
Objects.requireNonNull(logger);
@@ -230,11 +255,13 @@
levelNbt.putUUID("WanderingTraderId", this.wanderingTraderId);
}
+ levelNbt.putString("Bukkit.Version", Bukkit.getName() + "/" + Bukkit.getVersion() + "/" + Bukkit.getBukkitVersion()); // CraftBukkit
+ this.world.getWorld().storeBukkitValues(levelNbt); // CraftBukkit - add pdc
}
private static ListTag stringCollectionToTag(Set<String> strings) {
ListTag nbttaglist = new ListTag();
- Stream stream = strings.stream().map(StringTag::valueOf);
+ Stream<StringTag> stream = strings.stream().map(StringTag::valueOf); // CraftBukkit - decompile error
Objects.requireNonNull(nbttaglist);
stream.forEach(nbttaglist::add);
@@ -310,6 +337,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 = Bukkit.getWorld(this.getLevelName());
+ if (world != null) {
+ ThunderChangeEvent thunder = new ThunderChangeEvent(world, thundering, cause); // Paper - Add cause to Weather/ThunderChangeEvents
+ Bukkit.getServer().getPluginManager().callEvent(thunder);
+ if (thunder.isCancelled()) {
+ return;
+ }
+ }
+ // CraftBukkit end
this.thundering = thundering;
}
@@ -330,6 +376,26 @@
@Override
public void setRaining(boolean raining) {
+ // Paper start - Add cause to Weather/ThunderChangeEvents
+ this.setRaining(raining, org.bukkit.event.weather.WeatherChangeEvent.Cause.UNKNOWN);
+ }
+
+ public void setRaining(boolean raining, org.bukkit.event.weather.WeatherChangeEvent.Cause cause) {
+ // Paper end - Add cause to Weather/ThunderChangeEvents
+ // CraftBukkit start
+ if (this.raining == raining) {
+ return;
+ }
+
+ org.bukkit.World world = Bukkit.getWorld(this.getLevelName());
+ if (world != null) {
+ WeatherChangeEvent weather = new WeatherChangeEvent(world, raining, cause); // Paper - Add cause to Weather/ThunderChangeEvents
+ Bukkit.getServer().getPluginManager().callEvent(weather);
+ if (weather.isCancelled()) {
+ return;
+ }
+ }
+ // CraftBukkit end
this.raining = raining;
}
@@ -396,6 +462,12 @@
@Override
public void setDifficulty(Difficulty difficulty) {
this.settings = this.settings.withDifficulty(difficulty);
+ // CraftBukkit start
+ ClientboundChangeDifficultyPacket packet = new ClientboundChangeDifficultyPacket(this.getDifficulty(), this.isDifficultyLocked());
+ for (ServerPlayer player : (java.util.List<ServerPlayer>) (java.util.List) this.world.players()) {
+ player.connection.send(packet);
+ }
+ // CraftBukkit end
}
@Override
@@ -532,6 +604,14 @@
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 */
@Deprecated
public static enum SpecialWorldProperty {