diff --git a/patches/api/0008-Add-player-data-saving-events.patch b/patches/api/0008-Add-player-data-saving-events.patch new file mode 100644 index 000000000..58341af0e --- /dev/null +++ b/patches/api/0008-Add-player-data-saving-events.patch @@ -0,0 +1,133 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tom +Date: Mon, 28 Feb 2022 09:36:31 -0600 +Subject: [PATCH] Add player data saving events + + +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerLoadDataEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerLoadDataEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ae0132d9c7ae17b478d1d504961e1fd6b479f6d0 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerLoadDataEvent.java +@@ -0,0 +1,63 @@ ++package com.destroystokyo.paper.event.player; ++ ++import com.google.gson.JsonObject; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++import java.util.UUID; ++ ++/** ++ * Calls an event in which playerdata can be provided. If null, will load from disk, otherwise will use provided data ++ */ ++public class PlayerLoadDataEvent extends Event { ++ private static final HandlerList handlers = new HandlerList(); ++ private final UUID playerId; ++ private Object playerData; ++ private JsonObject statistics; ++ ++ public PlayerLoadDataEvent(@NotNull UUID playerId) { ++ super(); ++ this.playerId = playerId; ++ } ++ ++ /** ++ * Gets the player's unique ID. ++ * ++ * @return The unique ID ++ */ ++ @NotNull ++ public UUID getUniqueId() { ++ return playerId; ++ } ++ ++ @Nullable ++ public Object getPlayerData() { ++ return playerData; ++ } ++ ++ public void setPlayerData(@NotNull Object playerData) { ++ this.playerData = playerData; ++ } ++ ++ @Nullable ++ public JsonObject getStatistics() { ++ return statistics; ++ } ++ ++ public void setStatistics(@NotNull JsonObject statistics) { ++ this.statistics = statistics; ++ } ++ ++ @NotNull ++ @Override ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerSaveDataEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerSaveDataEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c706201394d89f4a6f795ebbbac3d1041f395104 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerSaveDataEvent.java +@@ -0,0 +1,52 @@ ++package com.destroystokyo.paper.event.player; ++ ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Calls whenever playerdata is attempted to be saved. This is fired even if SpigotConfig.disablePlayerDataSaving is true ++ */ ++public class PlayerSaveDataEvent extends Event implements Cancellable { ++ private static final HandlerList handlers = new HandlerList(); ++ private final Player player; ++ private boolean cancel; ++ ++ public PlayerSaveDataEvent(@NotNull Player player) { ++ super(); ++ this.player = player; ++ } ++ ++ /** ++ * Gets the player ++ * ++ * @return The player ++ */ ++ @NotNull ++ public Player getPlayer() { ++ return player; ++ } ++ ++ @NotNull ++ @Override ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return cancel; ++ } ++ ++ @Override ++ public void setCancelled(boolean cancel) { ++ this.cancel = cancel; ++ } ++} diff --git a/patches/server/0016-Add-player-data-saving-events.patch b/patches/server/0016-Add-player-data-saving-events.patch new file mode 100644 index 000000000..ec55e3aa3 --- /dev/null +++ b/patches/server/0016-Add-player-data-saving-events.patch @@ -0,0 +1,121 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tom +Date: Mon, 28 Feb 2022 09:36:31 -0600 +Subject: [PATCH] Add player data saving events + + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +index 170f58e56c6a6cae26f7c9e55c74c3c3074500da..754ac18682a9d693c2b282e7f015926a94c4ca15 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +@@ -606,6 +606,8 @@ public class ServerPlayerGameMode { + enuminteractionresult1 = stack.useOn(itemactioncontext, hand); + } + ++ world.pendingPlayerBlockEvents.remove(blockposition); // Paper ++ + if (enuminteractionresult1.consumesAction()) { + CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger(player, blockposition, itemstack1); + } +diff --git a/src/main/java/net/minecraft/stats/ServerStatsCounter.java b/src/main/java/net/minecraft/stats/ServerStatsCounter.java +index ee5bb1a8edb812d48d5af45ea8485f574dcb2ad5..94317f2dcf997fbe4707fc3e2d231176d55992ec 100644 +--- a/src/main/java/net/minecraft/stats/ServerStatsCounter.java ++++ b/src/main/java/net/minecraft/stats/ServerStatsCounter.java +@@ -201,7 +201,12 @@ public class ServerStatsCounter extends StatsCounter { + return nbttagcompound; + } + +- protected String toJson() { ++ // Slice start - OBFHELPER ++ public String toJson() { ++ return serialize().toString(); ++ } ++ ++ public JsonObject serialize() { // Slice end + Map, JsonObject> map = Maps.newHashMap(); + ObjectIterator objectiterator = this.stats.object2IntEntrySet().iterator(); + +@@ -227,7 +232,7 @@ public class ServerStatsCounter extends StatsCounter { + + jsonobject1.add("stats", jsonobject); + jsonobject1.addProperty("DataVersion", SharedConstants.getCurrentVersion().getWorldVersion()); +- return jsonobject1.toString(); ++ return jsonobject1; // Slice + } + + private static ResourceLocation getKey(Stat stat) { +diff --git a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java +index 35c39aed9583275ef25d32c783715798b52bdb63..258813e65b521dccb19f4f3248588a7106a1e24b 100644 +--- a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java ++++ b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java +@@ -33,6 +33,7 @@ public class PlayerDataStorage { + + public void save(Player player) { + if (org.spigotmc.SpigotConfig.disablePlayerDataSaving) return; // Spigot ++ if (!new com.destroystokyo.paper.event.player.PlayerSaveDataEvent((org.bukkit.entity.Player) player.getBukkitEntity()).callEvent()) return; // Slice + try { + CompoundTag nbttagcompound = player.saveWithoutId(new CompoundTag()); + File file = File.createTempFile(player.getStringUUID() + "-", ".dat", this.playerDir); +@@ -52,32 +53,40 @@ public class PlayerDataStorage { + public CompoundTag load(Player player) { + CompoundTag nbttagcompound = null; + +- try { +- File file = new File(this.playerDir, player.getStringUUID() + ".dat"); +- // Spigot Start +- boolean usingWrongFile = false; +- if ( org.bukkit.Bukkit.getOnlineMode() && !file.exists() ) // Paper - Check online mode first +- { +- file = new File( this.playerDir, java.util.UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + player.getScoreboardName() ).getBytes( "UTF-8" ) ).toString() + ".dat"); +- if ( file.exists() ) ++ // Slice start - If event supplies playerdata, use it. Otherwise just load from disk as usual ++ com.destroystokyo.paper.event.player.PlayerLoadDataEvent event = new com.destroystokyo.paper.event.player.PlayerLoadDataEvent(player.getUUID()); ++ org.bukkit.Bukkit.getPluginManager().callEvent(event); ++ ++ Object playerData = event.getPlayerData(); ++ if (playerData != null) { ++ nbttagcompound = (CompoundTag) playerData; ++ } else { ++ try { ++ File file = new File(this.playerDir, player.getStringUUID() + ".dat"); ++ // Spigot Start ++ boolean usingWrongFile = false; ++ if (org.bukkit.Bukkit.getOnlineMode() && !file.exists()) // Paper - Check online mode first + { +- usingWrongFile = true; +- org.bukkit.Bukkit.getServer().getLogger().warning( "Using offline mode UUID file for player " + player.getScoreboardName() + " as it is the only copy we can find." ); ++ file = new File(this.playerDir, java.util.UUID.nameUUIDFromBytes(("OfflinePlayer:" + player.getScoreboardName()).getBytes("UTF-8")).toString() + ".dat"); ++ if (file.exists()) { ++ usingWrongFile = true; ++ org.bukkit.Bukkit.getServer().getLogger().warning("Using offline mode UUID file for player " + player.getScoreboardName() + " as it is the only copy we can find."); ++ } + } +- } +- // Spigot End ++ // Spigot End + +- if (file.exists() && file.isFile()) { +- nbttagcompound = NbtIo.readCompressed(file); +- } +- // Spigot Start +- if ( usingWrongFile ) +- { +- file.renameTo( new File( file.getPath() + ".offline-read" ) ); ++ if (file.exists() && file.isFile()) { ++ nbttagcompound = NbtIo.readCompressed(file); ++ } ++ // Spigot Start ++ if (usingWrongFile) { ++ file.renameTo(new File(file.getPath() + ".offline-read")); ++ } ++ // Spigot End ++ } catch (Exception exception) { ++ PlayerDataStorage.LOGGER.warn("Failed to load player data for {}", player.getName().getString()); + } +- // Spigot End +- } catch (Exception exception) { +- PlayerDataStorage.LOGGER.warn("Failed to load player data for {}", player.getName().getString()); ++ // Slice end + } + + if (nbttagcompound != null) {