2021-06-11 14:02:28 +02:00
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach@zachbr.io>
Date: Wed, 2 Jan 2019 00:35:43 -0600
2024-01-21 13:56:22 +01:00
Subject: [PATCH] Replace OfflinePlayer#getLastPlayed
2021-06-11 14:02:28 +02:00
Currently OfflinePlayer#getLastPlayed could more accurately be described
as "OfflinePlayer#getLastTimeTheirDataWasSaved".
The API doc says it should return the last time the server "witnessed"
the player, whilst also saying it should return the last time they
logged in. The current implementation does neither.
Given this interesting contradiction in the API documentation and the
current defacto implementation, I've elected to deprecate (with no
intent to remove) and replace it with two new methods, clearly named and
documented as to their purpose.
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
2024-12-03 19:21:12 +01:00
index 2db5ef211ac36d5aa7f337dd4a5c2600796d8b66..ae922d01caae4b2ed42641ae5039abe33603fa29 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
2024-12-03 19:21:12 +01:00
@@ -294,6 +294,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
2023-09-22 00:26:51 +02:00
private int containerCounter;
2021-06-11 14:02:28 +02:00
public boolean wonGame;
2024-01-24 11:45:17 +01:00
private int containerUpdateDelay; // Paper - Configurable container update tick rate
2024-01-21 13:56:22 +01:00
+ public long loginTime; // Paper - Replace OfflinePlayer#getLastPlayed
2021-06-11 14:02:28 +02:00
// Paper start - cancellable death event
2024-01-24 11:45:17 +01:00
public boolean queueHealthUpdatePacket;
2021-06-11 14:02:28 +02:00
public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket;
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
2024-11-09 21:17:42 +01:00
index 8bb2749f751839f7dfd8fb62f676bd54ec8b1b09..4b2826f3319dca1f795653106d22fc6948c6a27a 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
2024-10-27 18:11:15 +01:00
@@ -182,6 +182,7 @@ public abstract class PlayerList {
2021-06-11 14:02:28 +02:00
2023-09-22 00:26:51 +02:00
public void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie clientData) {
2022-09-26 10:02:51 +02:00
player.isRealPlayer = true; // Paper
2024-01-21 13:56:22 +01:00
+ player.loginTime = System.currentTimeMillis(); // Paper - Replace OfflinePlayer#getLastPlayed
2021-06-11 14:02:28 +02:00
GameProfile gameprofile = player.getGameProfile();
GameProfileCache usercache = this.server.getProfileCache();
2024-04-24 07:43:09 +02:00
// Optional optional; // CraftBukkit - decompile error
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
2024-10-23 14:12:17 +02:00
index f6b2ca92fd3510a76cbf56d0ea55aa6caaf12ba1..e0d342a0ddd140b342f7af138c71596c6d718788 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
2024-01-26 20:17:06 +01:00
@@ -262,6 +262,61 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa
2021-06-13 10:26:58 +02:00
return this.getData() != null;
2021-06-11 14:02:28 +02:00
}
+ // Paper start
+ @Override
+ public long getLastLogin() {
+ Player player = getPlayer();
+ if (player != null) return player.getLastLogin();
+
+ CompoundTag data = getPaperData();
+
+ if (data != null) {
+ if (data.contains("LastLogin")) {
+ return data.getLong("LastLogin");
+ } else {
+ // if the player file cannot provide accurate data, this is probably the closest we can approximate
+ File file = getDataFile();
+ return file.lastModified();
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public long getLastSeen() {
+ Player player = getPlayer();
+ if (player != null) return player.getLastSeen();
+
+ CompoundTag data = getPaperData();
+
+ if (data != null) {
+ if (data.contains("LastSeen")) {
+ return data.getLong("LastSeen");
+ } else {
+ // if the player file cannot provide accurate data, this is probably the closest we can approximate
+ File file = getDataFile();
+ return file.lastModified();
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ private CompoundTag getPaperData() {
+ CompoundTag result = getData();
+
+ if (result != null) {
+ if (!result.contains("Paper")) {
+ result.put("Paper", new CompoundTag());
+ }
+ result = result.getCompound("Paper");
+ }
+
+ return result;
+ }
+ // Paper end
+
@Override
2022-06-10 03:20:47 +02:00
public Location getLastDeathLocation() {
if (this.getData().contains("LastDeathLocation", 10)) {
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
2024-12-03 19:21:12 +01:00
index 63cc339b42c47879401628c8d0e0f62bd7dd76b4..d5f89783d12c61967637ed1e87037710df563308 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
2024-10-24 19:29:35 +02:00
@@ -215,6 +215,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
2023-12-09 00:13:02 +01:00
private BorderChangeListener clientWorldBorderListener = this.createWorldBorderListener();
public org.bukkit.event.player.PlayerResourcePackStatusEvent.Status resourcePackStatus; // Paper - more resource pack API
2021-06-11 14:02:28 +02:00
private static final boolean DISABLE_CHANNEL_LIMIT = System.getProperty("paper.disableChannelLimit") != null; // Paper - add a flag to disable the channel limit
2023-12-09 00:13:02 +01:00
+ private long lastSaveTime; // Paper - getLastPlayed replacement API
2021-06-11 14:02:28 +02:00
public CraftPlayer(CraftServer server, ServerPlayer entity) {
2023-12-09 00:13:02 +01:00
super(server, entity);
2024-11-09 21:17:42 +01:00
@@ -2064,6 +2065,18 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
2021-06-11 14:02:28 +02:00
this.firstPlayed = firstPlayed;
}
2023-12-09 00:13:02 +01:00
+ // Paper start - getLastPlayed replacement API
2021-06-11 14:02:28 +02:00
+ @Override
+ public long getLastLogin() {
2023-12-09 00:13:02 +01:00
+ return this.getHandle().loginTime;
2021-06-11 14:02:28 +02:00
+ }
+
+ @Override
+ public long getLastSeen() {
2023-12-09 00:13:02 +01:00
+ return this.isOnline() ? System.currentTimeMillis() : this.lastSaveTime;
2021-06-11 14:02:28 +02:00
+ }
2023-12-09 00:13:02 +01:00
+ // Paper end - getLastPlayed replacement API
2021-06-11 14:02:28 +02:00
+
public void readExtraData(CompoundTag nbttagcompound) {
2021-06-13 10:26:58 +02:00
this.hasPlayedBefore = true;
2021-06-11 14:02:28 +02:00
if (nbttagcompound.contains("bukkit")) {
2024-11-09 21:17:42 +01:00
@@ -2086,6 +2099,8 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
2021-06-11 14:02:28 +02:00
}
public void setExtraData(CompoundTag nbttagcompound) {
+ this.lastSaveTime = System.currentTimeMillis(); // Paper
+
if (!nbttagcompound.contains("bukkit")) {
nbttagcompound.put("bukkit", new CompoundTag());
}
2024-11-09 21:17:42 +01:00
@@ -2100,6 +2115,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
2021-06-13 10:26:58 +02:00
data.putLong("firstPlayed", this.getFirstPlayed());
2021-06-11 14:02:28 +02:00
data.putLong("lastPlayed", System.currentTimeMillis());
data.putString("lastKnownName", handle.getScoreboardName());
+
+ // Paper start - persist for use in offline save data
+ if (!nbttagcompound.contains("Paper")) {
+ nbttagcompound.put("Paper", new CompoundTag());
+ }
+
+ CompoundTag paper = nbttagcompound.getCompound("Paper");
+ paper.putLong("LastLogin", handle.loginTime);
+ paper.putLong("LastSeen", System.currentTimeMillis());
+ // Paper end
}
@Override