From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Wed, 2 Jan 2019 00:35:43 -0600 Subject: [PATCH] Replace OfflinePlayer#getLastPlayed 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 index 8d958ac09bd9484d879eee6acb6aaea20f4f8339..3e0ddfe11d74ce47a023837b2ee472f0bc4c48c3 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -296,6 +296,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { private int containerCounter; public boolean wonGame; private int containerUpdateDelay; // Paper - Configurable container update tick rate + public long loginTime; // Paper - Replace OfflinePlayer#getLastPlayed // Paper start - cancellable death event public boolean queueHealthUpdatePacket; 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 index 9294ab23940cb2a822ba760052e3ad369abdfed6..d013e72511d1763a55e5e0837b682d02f87aff63 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java @@ -183,6 +183,7 @@ public abstract class PlayerList { public void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie clientData) { player.isRealPlayer = true; // Paper + player.loginTime = System.currentTimeMillis(); // Paper - Replace OfflinePlayer#getLastPlayed GameProfile gameprofile = player.getGameProfile(); GameProfileCache usercache = this.server.getProfileCache(); // Optional optional; // CraftBukkit - decompile error diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java index f6b2ca92fd3510a76cbf56d0ea55aa6caaf12ba1..e0d342a0ddd140b342f7af138c71596c6d718788 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java @@ -262,6 +262,61 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa return this.getData() != null; } + // 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 public Location getLastDeathLocation() { if (this.getData().contains("LastDeathLocation", 10)) { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index 159bba49095aec77cce5f53d4388a5dff0afcc60..f351250b8e8b66bcf72230bbc76835fcb45817e1 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -215,6 +215,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { private BorderChangeListener clientWorldBorderListener = this.createWorldBorderListener(); public org.bukkit.event.player.PlayerResourcePackStatusEvent.Status resourcePackStatus; // Paper - more resource pack API private static final boolean DISABLE_CHANNEL_LIMIT = System.getProperty("paper.disableChannelLimit") != null; // Paper - add a flag to disable the channel limit + private long lastSaveTime; // Paper - getLastPlayed replacement API public CraftPlayer(CraftServer server, ServerPlayer entity) { super(server, entity); @@ -2076,6 +2077,18 @@ public class CraftPlayer extends CraftHumanEntity implements Player { this.firstPlayed = firstPlayed; } + // Paper start - getLastPlayed replacement API + @Override + public long getLastLogin() { + return this.getHandle().loginTime; + } + + @Override + public long getLastSeen() { + return this.isOnline() ? System.currentTimeMillis() : this.lastSaveTime; + } + // Paper end - getLastPlayed replacement API + public void readExtraData(CompoundTag nbttagcompound) { this.hasPlayedBefore = true; if (nbttagcompound.contains("bukkit")) { @@ -2098,6 +2111,8 @@ public class CraftPlayer extends CraftHumanEntity implements Player { } public void setExtraData(CompoundTag nbttagcompound) { + this.lastSaveTime = System.currentTimeMillis(); // Paper + if (!nbttagcompound.contains("bukkit")) { nbttagcompound.put("bukkit", new CompoundTag()); } @@ -2112,6 +2127,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player { data.putLong("firstPlayed", this.getFirstPlayed()); 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