From 33b007c39f4d7c384abc2588e39eaacb455bfac3 Mon Sep 17 00:00:00 2001 From: Cryptite Date: Sat, 16 Nov 2024 09:36:10 -0600 Subject: [PATCH] More more patch work --- gradle.properties | 2 +- patches/api/0010-Add-Vanish.patch | 30 ++++ .../api/0012-Add-PlayerLoadStatsEvent.patch | 65 ++++++++ .../0014-Equipment-Packet-Caching.patch | 157 ++++++++++++++++++ ... => 0015-Add-ChunkStatusChangeEvent.patch} | 10 +- .../server/0016-Biome-freeze-override.patch | 27 +++ patches/server/0017-Add-Vanish.patch | 84 ++++++++++ patches/server/0018-Add-jackson.patch | 24 +++ .../0021-Add-PlayerLoadStatsEvent.patch | 42 +++++ 9 files changed, 435 insertions(+), 6 deletions(-) create mode 100644 patches/api/0010-Add-Vanish.patch create mode 100644 patches/api/0012-Add-PlayerLoadStatsEvent.patch create mode 100644 patches/server/0014-Equipment-Packet-Caching.patch rename patches/server/{0014-ChunkStatusChangeEvent.patch => 0015-Add-ChunkStatusChangeEvent.patch} (82%) create mode 100644 patches/server/0016-Biome-freeze-override.patch create mode 100644 patches/server/0017-Add-Vanish.patch create mode 100644 patches/server/0018-Add-jackson.patch create mode 100644 patches/server/0021-Add-PlayerLoadStatsEvent.patch diff --git a/gradle.properties b/gradle.properties index 890044234..0765f7661 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ group=com.lokamc.slice version=1.21.3-R0.1-SNAPSHOT mcVersion=1.21.3 -paperRef=661839e0334b68600bfcf58507c932f5743b7d90 +paperRef=be886cf4e7ba906a3e79d9d38835d35abf60a0ce updatingMinecraft=false org.gradle.caching=true diff --git a/patches/api/0010-Add-Vanish.patch b/patches/api/0010-Add-Vanish.patch new file mode 100644 index 000000000..5bfc39fd8 --- /dev/null +++ b/patches/api/0010-Add-Vanish.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Cryptite +Date: Sat, 16 Nov 2024 09:10:35 -0600 +Subject: [PATCH] Add Vanish + + +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index d0ae8a94db20281d3664d74718c65234eb2e5f83..6324e8f11a382288fc0a6c30f47760ea50e231d5 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -1172,4 +1172,19 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + */ + void broadcastHurtAnimation(@NotNull java.util.Collection players); + // Paper end - broadcast hurt animation ++ ++ // Slice start ++ /** ++ * Returns true if the entity is vanished and cannot emit sounds, effects, etc. ++ */ ++ boolean isVanished(); ++ ++ /** ++ * Sets whether the entity is vanished and cannot emit sounds, effects, etc. ++ * ++ * @param vanished the saveable status ++ * @see #isVanished() ++ */ ++ void setVanished(boolean vanished); ++ // Slice end + } diff --git a/patches/api/0012-Add-PlayerLoadStatsEvent.patch b/patches/api/0012-Add-PlayerLoadStatsEvent.patch new file mode 100644 index 000000000..27ac6d9fe --- /dev/null +++ b/patches/api/0012-Add-PlayerLoadStatsEvent.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Cryptite +Date: Sat, 16 Nov 2024 09:34:15 -0600 +Subject: [PATCH] Add PlayerLoadStatsEvent + + +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerLoadStatsEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerLoadStatsEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8c74868a7445b478a80aff160a7a588a885aa889 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerLoadStatsEvent.java +@@ -0,0 +1,53 @@ ++package com.destroystokyo.paper.event.player; ++ ++import org.bukkit.Bukkit; ++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 player stats can be provided. If null, will load from disk, otherwise will use provided data ++ */ ++public class PlayerLoadStatsEvent extends Event { ++ private static final HandlerList handlers = new HandlerList(); ++ private final UUID playerId; ++ private String json; ++ ++ public PlayerLoadStatsEvent(@NotNull UUID playerId) { ++ super(!Bukkit.isPrimaryThread()); ++ this.playerId = playerId; ++ } ++ ++ /** ++ * Gets the player's unique ID. ++ * ++ * @return The unique ID ++ */ ++ @NotNull ++ public UUID getUniqueId() { ++ return playerId; ++ } ++ ++ @Nullable ++ public String getStatistics() { ++ return json; ++ } ++ ++ public void setStatistics(@NotNull String json) { ++ this.json = json; ++ } ++ ++ @NotNull ++ @Override ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++} diff --git a/patches/server/0014-Equipment-Packet-Caching.patch b/patches/server/0014-Equipment-Packet-Caching.patch new file mode 100644 index 000000000..176ab11ac --- /dev/null +++ b/patches/server/0014-Equipment-Packet-Caching.patch @@ -0,0 +1,157 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Cryptite +Date: Wed, 13 Nov 2024 08:07:59 -0600 +Subject: [PATCH] Equipment Packet Caching + + +diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetEquipmentPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetEquipmentPacket.java +index 830bd76916e26a3a54954d3cf7b7520af52a2258..dc9c7a844c2aee1dae80006eafe085c6fa126ae1 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetEquipmentPacket.java ++++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetEquipmentPacket.java +@@ -30,6 +30,16 @@ public class ClientboundSetEquipmentPacket implements Packet> equipmentList, net.minecraft.world.entity.LivingEntity entity, boolean sanitize, String tag) { ++ this.entity = id; ++ this.sanitize = sanitize; ++ slots = new java.util.ArrayList<>(equipmentList.size()); ++ for (Pair pair : equipmentList) { ++ EquipmentSlot slot = pair.getFirst(); ++ slots.add(Pair.of(slot, entity.getOrCreateCachedEquipmentItem(tag, slot, pair.getSecond()))); ++ } ++ } ++ + private ClientboundSetEquipmentPacket(RegistryFriendlyByteBuf buf) { + this.entity = buf.readVarInt(); + this.slots = Lists.newArrayList(); +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index 6a3a8f0466998409a01223bc0c16d92b96e50118..096fc42fddbbbe1f7bb5cd260cd2f0d580c6b77a 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -298,6 +298,11 @@ public abstract class LivingEntity extends Entity implements Attackable { + public boolean silentDeath = false; // Paper - mark entity as dying silently for cancellable death event + public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API + ++ // Slice start ++ private static final java.util.Map> equipmentPacketCache = new java.util.HashMap<>(); ++ protected final java.util.Map cachedEquipmentPacket = new java.util.HashMap<>(); ++ // Slice end ++ + @Override + public float getBukkitYaw() { + return this.getYHeadRot(); +@@ -3361,6 +3366,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + if (map != null) { + this.handleHandSwap(map); + if (!map.isEmpty()) { ++ cachedEquipmentPacket.clear(); // Slice - Must invalidate cached equipment map if we have changes + this.handleEquipmentChanges(map); + } + } +@@ -4781,4 +4787,84 @@ public abstract class LivingEntity extends Entity implements Attackable { + public static record Fallsounds(SoundEvent small, SoundEvent big) { + + } ++ ++ // Slice start ++ public static void invalidateCachedEquipment(String tag) { ++ com.google.common.cache.Cache removedCache = equipmentPacketCache.remove(tag); ++ if (removedCache != null) { ++ removedCache.asMap().clear(); ++ } ++ } ++ ++ public ItemStack getOrCreateCachedEquipmentItem(String tag, EquipmentSlot slot, ItemStack itemStack) { ++ return equipmentPacketCache.computeIfAbsent(tag, s -> com.google.common.cache.CacheBuilder.newBuilder() ++ .expireAfterAccess(10, java.util.concurrent.TimeUnit.MINUTES) ++ .build()) ++ .asMap() ++ .computeIfAbsent(itemStack.hashCode(), i -> { ++ String name = slot.name(); ++ ++ //How neat is this. ++ if (name.equals("MAINHAND")) { ++ name = "HAND"; ++ } else if (name.equals("OFFHAND")) { ++ name = "OFF_HAND"; ++ } ++ ++ org.bukkit.event.entity.EntityEquipmentItemLookup event = new org.bukkit.event.entity.EntityEquipmentItemLookup(getBukkitEntity(), tag, org.bukkit.inventory.EquipmentSlot.valueOf(name), CraftItemStack.asBukkitCopy(itemStack)); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ org.bukkit.inventory.ItemStack eventItem = event.getItemStack(); ++ return CraftItemStack.asNMSCopy(eventItem); ++ }); ++ } ++ // Slice end ++ ++ // Slice start ++ public void sendEquipment(java.util.function.Consumer> consumer, ServerPlayer p) { ++ org.bukkit.event.player.PlayerReceiveEquipmentEvent event = new org.bukkit.event.player.PlayerReceiveEquipmentEvent(p.getBukkitEntity(), getBukkitEntity()); ++ level().getCraftServer().getPluginManager().callEvent(event); ++ ++ boolean sendEquipment = !event.isCancelled(); ++ String tag = event.getTag(); ++ if (sendEquipment && this instanceof ServerPlayer player && tag != null) { ++ ClientboundSetEquipmentPacket equipmentPacket = player.cachedEquipmentPacket.get(tag); ++ if (equipmentPacket != null) { ++ //Event says use a tag, and our tag exists; so we simply used our entire cached packet ++ consumer.accept(equipmentPacket); ++ return; ++ } ++ } ++ ++ if (sendEquipment) { ++ List> list = Lists.newArrayList(); ++ Iterator iterator = EquipmentSlot.VALUES.iterator(); ++ ++ while (iterator.hasNext()) { ++ EquipmentSlot enumitemslot = (EquipmentSlot) iterator.next(); ++ ItemStack itemstack = getItemBySlot(enumitemslot); ++ ++ if (!itemstack.isEmpty()) { ++ ItemStack finalItemStack; ++ if (tag != null) { ++ finalItemStack = getOrCreateCachedEquipmentItem(tag, enumitemslot, itemstack); ++ } else { ++ finalItemStack = itemstack.copy(); ++ } ++ ++ list.add(Pair.of(enumitemslot, finalItemStack)); ++ } ++ } ++ ++ if (!list.isEmpty()) { ++ ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(getId(), list, true); ++ if (tag != null) { ++ cachedEquipmentPacket.put(tag, equipmentPacket); ++ } ++ consumer.accept(equipmentPacket); ++ } ++ ++ detectEquipmentUpdatesPublic(); // CraftBukkit - SPIGOT-3789: sync again immediately after sending ++ } ++ } ++ // Slice end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index d0c409f4efad289e3e325f44b500fc72589d89d4..baecf1c7bb459786bdbe6f7381ef148e0dad0ef5 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -1205,6 +1205,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + } + // Paper end - body yaw API + ++ // Slice start ++ @Override ++ public void sendEquipment(Player p) { ++ if (entity instanceof net.minecraft.world.entity.LivingEntity livingEntity) { ++ net.minecraft.server.level.ServerPlayer serverPlayer = ((CraftPlayer) p).getHandle(); ++ livingEntity.sendEquipment(packet -> serverPlayer.connection.send(packet), serverPlayer); ++ } ++ } ++ // Slice end ++ + // Paper start - Expose canUseSlot + @Override + public boolean canUseEquipmentSlot(org.bukkit.inventory.EquipmentSlot slot) { diff --git a/patches/server/0014-ChunkStatusChangeEvent.patch b/patches/server/0015-Add-ChunkStatusChangeEvent.patch similarity index 82% rename from patches/server/0014-ChunkStatusChangeEvent.patch rename to patches/server/0015-Add-ChunkStatusChangeEvent.patch index 0023650e9..42da4363c 100644 --- a/patches/server/0014-ChunkStatusChangeEvent.patch +++ b/patches/server/0015-Add-ChunkStatusChangeEvent.patch @@ -1,11 +1,11 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Cryptite -Date: Wed, 13 Nov 2024 08:07:59 -0600 -Subject: [PATCH] ChunkStatusChangeEvent +Date: Sat, 16 Nov 2024 08:48:20 -0600 +Subject: [PATCH] Add ChunkStatusChangeEvent diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java -index eafa4e6d55cd0f9314ac0f2b96a7f48fbb5e1a4c..1c39f73a10a05b792adf4d98b7db24edb2938030 100644 +index eafa4e6d55cd0f9314ac0f2b96a7f48fbb5e1a4c..ee5f51bc5f31f269bdac239cb48265ae355db1ff 100644 --- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java +++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java @@ -1261,6 +1261,13 @@ public final class NewChunkHolder { @@ -14,8 +14,8 @@ index eafa4e6d55cd0f9314ac0f2b96a7f48fbb5e1a4c..1c39f73a10a05b792adf4d98b7db24ed + // Slice start + new com.destroystokyo.paper.event.chunk.ChunkStatusChangeEvent(new org.bukkit.craftbukkit.CraftChunk(chunk), -+ com.destroystokyo.paper.event.chunk.ChunkStatusChangeEvent.ChunkStatus.valueOf(currState.name()), -+ com.destroystokyo.paper.event.chunk.ChunkStatusChangeEvent.ChunkStatus.valueOf(nextState.name())) ++ com.destroystokyo.paper.event.chunk.ChunkStatusChangeEvent.ChunkStatus.valueOf(current.name()), ++ com.destroystokyo.paper.event.chunk.ChunkStatusChangeEvent.ChunkStatus.valueOf(current.name())) + .callEvent(); + // Slice end + diff --git a/patches/server/0016-Biome-freeze-override.patch b/patches/server/0016-Biome-freeze-override.patch new file mode 100644 index 000000000..1d3dd24c2 --- /dev/null +++ b/patches/server/0016-Biome-freeze-override.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Cryptite +Date: Sat, 16 Nov 2024 08:58:56 -0600 +Subject: [PATCH] Biome freeze override + + +diff --git a/src/main/java/net/minecraft/world/level/biome/Biome.java b/src/main/java/net/minecraft/world/level/biome/Biome.java +index b725eea9d3ca81d2ef7802f5d0346d924aa1f808..1d903fa83432ed971f784b8cb244b0c5b163830e 100644 +--- a/src/main/java/net/minecraft/world/level/biome/Biome.java ++++ b/src/main/java/net/minecraft/world/level/biome/Biome.java +@@ -71,6 +71,7 @@ public final class Biome { + long2FloatLinkedOpenHashMap.defaultReturnValue(Float.NaN); + return long2FloatLinkedOpenHashMap; + })); ++ public Boolean canFreeze = null; // Slice + + Biome(Biome.ClimateSettings weather, BiomeSpecialEffects effects, BiomeGenerationSettings generationSettings, MobSpawnSettings spawnSettings) { + this.climateSettings = weather; +@@ -120,6 +121,8 @@ public final class Biome { + } + + public boolean shouldFreeze(LevelReader world, BlockPos pos, boolean doWaterCheck) { ++ if (canFreeze != null) return canFreeze; // Slice ++ + if (this.warmEnoughToRain(pos, world.getSeaLevel())) { + return false; + } else { diff --git a/patches/server/0017-Add-Vanish.patch b/patches/server/0017-Add-Vanish.patch new file mode 100644 index 000000000..6b86126ad --- /dev/null +++ b/patches/server/0017-Add-Vanish.patch @@ -0,0 +1,84 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Cryptite +Date: Sat, 16 Nov 2024 09:10:35 -0600 +Subject: [PATCH] Add Vanish + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 64a5c8f8918284d61619adcad3040f5ef70e8ef0..d10e360e664ae5ccb85c0c77848e527bc39ad775 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -432,6 +432,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + private UUID originWorld; + public boolean freezeLocked = false; // Paper - Freeze Tick Lock API + public boolean fixedPose = false; // Paper - Expand Pose API ++ public boolean vanished; // Slice + + public void setOrigin(@javax.annotation.Nonnull Location location) { + this.origin = location.toVector(); +@@ -1425,7 +1426,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + + private boolean vibrationAndSoundEffectsFromBlock(BlockPos pos, BlockState state, boolean playSound, boolean emitEvent, Vec3 movement) { +- if (state.isAir()) { ++ if (vanished || state.isAir()) { // Slice + return false; + } else { + boolean flag2 = this.isStateClimbable(state); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index ddabaed899c755925ad8618b78c33dacaf2126ac..aefa94ffd630e2dd6aefd547664ae25d2a81420c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -1306,4 +1306,16 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + } + } + // Paper end - broadcast hurt animation ++ ++ // Slice start ++ @Override ++ public boolean isVanished() { ++ return this.entity.vanished; ++ } ++ ++ @Override ++ public void setVanished(boolean vanished) { ++ this.entity.vanished = vanished; ++ } ++ // Slice end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java +index da1c1fe0faf6819b15a81d6ad53370948e5f984f..84eff85e98484c9701e203bb1fa61435ee88bab4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java +@@ -69,6 +69,14 @@ public class CraftInventoryCustom extends CraftInventory { + } + // Paper end + ++ // Slice start ++ public void setLocation(Location location) { ++ if (this.inventory instanceof MinecraftInventory minecraftInventory) { ++ minecraftInventory.location = location; ++ } ++ } ++ // Slice end ++ + static class MinecraftInventory implements Container { + private final NonNullList items; + private int maxStack = MAX_STACK; +@@ -77,6 +85,7 @@ public class CraftInventoryCustom extends CraftInventory { + private final net.kyori.adventure.text.Component adventure$title; // Paper + private InventoryType type; + private final InventoryHolder owner; ++ private Location location; // Slice + + // Paper start + public MinecraftInventory(InventoryHolder owner, InventoryType type, net.kyori.adventure.text.Component title) { +@@ -239,7 +248,7 @@ public class CraftInventoryCustom extends CraftInventory { + + @Override + public Location getLocation() { +- return null; ++ return location; + } + + // Paper start diff --git a/patches/server/0018-Add-jackson.patch b/patches/server/0018-Add-jackson.patch new file mode 100644 index 000000000..4143bf211 --- /dev/null +++ b/patches/server/0018-Add-jackson.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Cryptite +Date: Sat, 16 Nov 2024 09:14:26 -0600 +Subject: [PATCH] Add jackson + + +diff --git a/build.gradle.kts b/build.gradle.kts +index 32751460e29684401a461fddf82c371b3ff627dd..d6dae3101aa719b194a9426a13bf76379f281379 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -26,6 +26,13 @@ abstract class MockitoAgentProvider : CommandLineArgumentProvider { + + dependencies { + implementation(project(":slice-api")) ++ ++ // Slice start - JSON logging for DataDog ingestion ++ implementation("com.fasterxml.jackson.core:jackson-core:2.13.0") ++ implementation("com.fasterxml.jackson.core:jackson-databind:2.13.0") ++ implementation("com.fasterxml.jackson.core:jackson-annotations:2.13.0") ++ // Slice end ++ + // Paper start + implementation("org.jline:jline-terminal-jansi:3.21.0") + implementation("net.minecrell:terminalconsoleappender:1.3.0") diff --git a/patches/server/0021-Add-PlayerLoadStatsEvent.patch b/patches/server/0021-Add-PlayerLoadStatsEvent.patch new file mode 100644 index 000000000..18393bbf0 --- /dev/null +++ b/patches/server/0021-Add-PlayerLoadStatsEvent.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Cryptite +Date: Sat, 16 Nov 2024 09:34:15 -0600 +Subject: [PATCH] Add PlayerLoadStatsEvent + + +diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java +index b775de1732238954e9bbbd072277254d2dc91b18..e590ce0e76985dd5c701ae933509221a2853266a 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -1414,7 +1414,7 @@ public abstract class PlayerList { + } + } + +- serverstatisticmanager = new ServerStatsCounter(this.server, file1); ++ serverstatisticmanager = new ServerStatsCounter(this.server, file1, uuid); // Slice + // this.stats.put(uuid, serverstatisticmanager); // CraftBukkit + } + +diff --git a/src/main/java/net/minecraft/stats/ServerStatsCounter.java b/src/main/java/net/minecraft/stats/ServerStatsCounter.java +index da7e1a69ecb4e6b3be2d8544ac406aa519bd196e..3bac27ffaea7fe873aa73605256f83837322fe0a 100644 +--- a/src/main/java/net/minecraft/stats/ServerStatsCounter.java ++++ b/src/main/java/net/minecraft/stats/ServerStatsCounter.java +@@ -45,10 +45,16 @@ public class ServerStatsCounter extends StatsCounter { + private final File file; + private final Set> dirty = Sets.newHashSet(); + +- public ServerStatsCounter(MinecraftServer server, File file) { ++ public ServerStatsCounter(MinecraftServer server, File file, java.util.UUID uuid) { // Slice + this.server = server; + this.file = file; +- if (file.isFile()) { ++ // Slice start - If event supplies stats, use it. Otherwise just load from disk as usual ++ com.destroystokyo.paper.event.player.PlayerLoadStatsEvent event = new com.destroystokyo.paper.event.player.PlayerLoadStatsEvent(uuid); ++ org.bukkit.Bukkit.getPluginManager().callEvent(event); ++ String providedJson = event.getStatistics(); ++ if (providedJson != null) { ++ this.parseLocal(server.getFixerUpper(), providedJson); ++ } else if (file.isFile()) { // Slice end + try { + this.parseLocal(server.getFixerUpper(), FileUtils.readFileToString(file)); + } catch (IOException ioexception) {