From b653ce3c1c1e3e2da137fc1ec6c3a4983c18f88f Mon Sep 17 00:00:00 2001
From: Nathan Adams <dinnerbone@dinnerbone.com>
Date: Mon, 12 Dec 2011 17:39:52 +0000
Subject: [PATCH] Implemented (offline)player date methods

---
 .../net/minecraft/server/EntityPlayer.java    |  8 ++-
 .../net/minecraft/server/WorldNBTStorage.java |  7 ++
 .../craftbukkit/CraftOfflinePlayer.java       | 66 +++++++++++++++++++
 .../craftbukkit/entity/CraftPlayer.java       | 47 +++++++++++++
 4 files changed, 127 insertions(+), 1 deletion(-)

diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java
index 8f1ac3bc68..10a60488c7 100644
--- a/src/main/java/net/minecraft/server/EntityPlayer.java
+++ b/src/main/java/net/minecraft/server/EntityPlayer.java
@@ -9,9 +9,9 @@ import java.util.Set;
 import org.bukkit.Bukkit;
 import org.bukkit.craftbukkit.ChunkCompressionThread;
 import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
 import org.bukkit.craftbukkit.event.CraftEventFactory;
 import org.bukkit.craftbukkit.inventory.CraftItemStack;
-import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason;
 import org.bukkit.event.entity.PlayerDeathEvent;
 // CraftBukkit end
 
@@ -72,11 +72,13 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
         if (nbttagcompound.hasKey("playerGameType")) {
             this.itemInWorldManager.a(nbttagcompound.getInt("playerGameType"));
         }
+        getPlayer().readExtraData(nbttagcompound); // CraftBukkit
     }
 
     public void b(NBTTagCompound nbttagcompound) {
         super.b(nbttagcompound);
         nbttagcompound.setInt("playerGameType", this.itemInWorldManager.a());
+        getPlayer().setExtraData(nbttagcompound); // CraftBukkit
     }
 
     public void spawnIn(World world) {
@@ -647,5 +649,9 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
         this.cf = -1; // lastSentExp. Find line: "if (this.expTotal != this.XXXX) {"
         this.giveExp(this.newExp);
     }
+
+    public CraftPlayer getPlayer() {
+        return (CraftPlayer)getBukkitEntity();
+    }
     // CraftBukkit end
 }
diff --git a/src/main/java/net/minecraft/server/WorldNBTStorage.java b/src/main/java/net/minecraft/server/WorldNBTStorage.java
index 7f05f2732d..017575f22e 100644
--- a/src/main/java/net/minecraft/server/WorldNBTStorage.java
+++ b/src/main/java/net/minecraft/server/WorldNBTStorage.java
@@ -12,6 +12,7 @@ import java.util.List;
 import java.util.logging.Logger;
 
 import java.util.UUID; // CraftBukkit
+import org.bukkit.craftbukkit.entity.CraftPlayer; // CraftBukkit
 
 public class WorldNBTStorage implements PlayerFileData, IDataManager {
 
@@ -202,6 +203,12 @@ public class WorldNBTStorage implements PlayerFileData, IDataManager {
         NBTTagCompound nbttagcompound = this.getPlayerData(entityhuman.name);
 
         if (nbttagcompound != null) {
+            // CraftBukkit start
+            if (entityhuman instanceof EntityPlayer) {
+                CraftPlayer player = (CraftPlayer)entityhuman.bukkitEntity;
+                player.setFirstPlayed(new File(playerDir, entityhuman.name + ".dat").lastModified());
+            }
+            // CraftBukkit end
             entityhuman.e(nbttagcompound);
         }
     }
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
index 68789a9f8e..4f8fd21d95 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
@@ -1,8 +1,11 @@
 package org.bukkit.craftbukkit;
 
+import java.io.File;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import net.minecraft.server.EntityPlayer;
+import net.minecraft.server.NBTTagCompound;
+import net.minecraft.server.WorldNBTStorage;
 import org.bukkit.Bukkit;
 import org.bukkit.OfflinePlayer;
 import org.bukkit.Server;
@@ -14,10 +17,12 @@ import org.bukkit.entity.Player;
 public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializable {
     private final String name;
     private final CraftServer server;
+    private final WorldNBTStorage storage;
 
     protected CraftOfflinePlayer(CraftServer server, String name) {
         this.server = server;
         this.name = name;
+        this.storage = (WorldNBTStorage)(server.console.worlds.get(0).getDataManager());
     }
 
     public boolean isOnline() {
@@ -119,4 +124,65 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa
         hash = 97 * hash + (this.getName() != null ? this.getName().hashCode() : 0);
         return hash;
     }
+
+    private NBTTagCompound getData() {
+        return storage.getPlayerData(getName());
+    }
+
+    private NBTTagCompound getBukkitData() {
+        NBTTagCompound result = getData();
+
+        if (result != null) {
+            if (!result.hasKey("bukkit")) {
+                result.setCompound("bukkit", new NBTTagCompound());
+            }
+            result = result.getCompound("bukkit");
+        }
+
+        return result;
+    }
+
+    private File getDataFile() {
+        return new File(storage.getPlayerDir(), name + ".dat");
+    }
+
+    public long getFirstPlayed() {
+        Player player = getPlayer();
+        if (player != null) return player.getFirstPlayed();
+
+        NBTTagCompound data = getBukkitData();
+
+        if (data != null) {
+            if (data.hasKey("firstPlayed")) {
+                return data.getLong("firstPlayed");
+            } else {
+                File file = getDataFile();
+                return file.lastModified();
+            }
+        } else {
+            return 0;
+        }
+    }
+
+    public long getLastPlayed() {
+        Player player = getPlayer();
+        if (player != null) return player.getFirstPlayed();
+
+        NBTTagCompound data = getBukkitData();
+
+        if (data != null) {
+            if (data.hasKey("lastPlayed")) {
+                return data.getLong("lastPlayed");
+            } else {
+                File file = getDataFile();
+                return file.lastModified();
+            }
+        } else {
+            return 0;
+        }
+    }
+
+    public boolean hasPlayedBefore() {
+        return getData() != null;
+    }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index ba2757bf9e..bb94842e8c 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -2,9 +2,12 @@ package org.bukkit.craftbukkit.entity;
 
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
+import java.util.Calendar;
+import java.util.Date;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import net.minecraft.server.EntityPlayer;
+import net.minecraft.server.NBTTagCompound;
 import net.minecraft.server.Packet131ItemData;
 import net.minecraft.server.Packet200Statistic;
 import net.minecraft.server.Packet201PlayerInfo;
@@ -39,8 +42,14 @@ import org.bukkit.map.MapView;
 
 @DelegateDeserialization(CraftOfflinePlayer.class)
 public class CraftPlayer extends CraftHumanEntity implements Player {
+    private long firstPlayed = 0;
+    private long lastPlayed = 0;
+    private boolean hasPlayedBefore = false;
+
     public CraftPlayer(CraftServer server, EntityPlayer entity) {
         super(server, entity);
+
+        firstPlayed = System.currentTimeMillis();
     }
 
     @Override
@@ -567,4 +576,42 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
         hash = 97 * hash + (this.getName() != null ? this.getName().hashCode() : 0);
         return hash;
     }
+
+    public long getFirstPlayed() {
+        return firstPlayed;
+    }
+
+    public long getLastPlayed() {
+        return lastPlayed;
+    }
+
+    public boolean hasPlayedBefore() {
+        return hasPlayedBefore;
+    }
+
+    public void setFirstPlayed(long firstPlayed) {
+        this.firstPlayed = firstPlayed;
+    }
+
+    public void readExtraData(NBTTagCompound nbttagcompound) {
+        hasPlayedBefore = true;
+        if (nbttagcompound.hasKey("bukkit")) {
+            NBTTagCompound data = nbttagcompound.getCompound("bukkit");
+
+            if (data.hasKey("firstPlayed")) {
+                firstPlayed = data.getLong("firstPlayed");
+                lastPlayed = data.getLong("lastPlayed");
+            }
+        }
+    }
+
+    public void setExtraData(NBTTagCompound nbttagcompound) {
+        if (!nbttagcompound.hasKey("bukkit")) {
+            nbttagcompound.setCompound("bukkit", new NBTTagCompound());
+        }
+
+        NBTTagCompound data = nbttagcompound.getCompound("bukkit");
+        data.setLong("firstPlayed", getFirstPlayed());
+        data.setLong("lastPlayed", System.currentTimeMillis());
+    }
 }