From e34afb295fa89ab296a403e9c67f1f22bfbfd03e Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 15 Jan 2018 21:46:46 -0500
Subject: [PATCH] Basic PlayerProfile API

Provides basic elements of a PlayerProfile to be used by future API/events

diff --git a/src/main/java/com/destroystokyo/paper/profile/PlayerProfile.java b/src/main/java/com/destroystokyo/paper/profile/PlayerProfile.java
new file mode 100644
index 00000000..f3868f94
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/profile/PlayerProfile.java
@@ -0,0 +1,90 @@
+package com.destroystokyo.paper.profile;
+
+import com.mojang.authlib.GameProfile;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Collection;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * Represents a players profile for the game, such as UUID, Name, and textures.
+ */
+public interface PlayerProfile {
+
+    /**
+     * @return The players name, if set
+     */
+    @Nullable String getName();
+
+    /**
+     * @return The players unique identifier, if set
+     */
+    @Nullable UUID getId();
+
+    /**
+     * @return A copy of this players properties, such as textures.
+     * Values specified here are subject to implementation details.
+     */
+    @Nonnull Set<ProfileProperty> getProperties();
+
+    /**
+     * Sets a property. If the property already exists, the previous one will be replaced
+     * @param property Property to set.
+     */
+    void setProperty(ProfileProperty property);
+
+    /**
+     * Sets multiple properties. If any of the set properties already exist, it will be replaced
+     * @param properties The properties to set
+     */
+    void setProperties(Collection<ProfileProperty> properties);
+
+    /**
+     * Removes a specific property from this profile
+     * @param property The property to remove
+     * @return If a property was removed
+     */
+    boolean removeProperty(String property);
+
+    /**
+     * Removes a specific property from this profile
+     * @param property The property to remove
+     * @return If a property was removed
+     */
+    default boolean removeProperty(@Nonnull ProfileProperty property) {
+        return removeProperty(property.getName());
+    }
+
+    /**
+     * Removes all properties in the collection
+     * @param properties The properties to remove
+     * @return If any property was removed
+     */
+    default boolean removeProperties(Collection<ProfileProperty> properties) {
+        boolean removed = false;
+        for (ProfileProperty property : properties) {
+            if (removeProperty(property)) {
+                removed = true;
+            }
+        }
+        return removed;
+    }
+
+    /**
+     * Clears all properties on this profile
+     */
+    void clearProperties();
+
+    /**
+     * @return Does this profile have Name, UUID and Textures filled in
+     */
+    boolean isComplete();
+
+    /**
+     * @deprecated Will be removed in 1.13
+     */
+    @Deprecated
+    GameProfile getGameProfile();
+}
diff --git a/src/main/java/com/destroystokyo/paper/profile/ProfileProperty.java b/src/main/java/com/destroystokyo/paper/profile/ProfileProperty.java
new file mode 100644
index 00000000..d17061e6
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/profile/ProfileProperty.java
@@ -0,0 +1,72 @@
+package com.destroystokyo.paper.profile;
+
+import com.google.common.base.Preconditions;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Objects;
+
+/**
+ * Represents a property on a {@link PlayerProfile}
+ */
+public class ProfileProperty {
+    private final String name;
+    private final String value;
+    private final String signature;
+
+    public ProfileProperty(@Nonnull String name, @Nonnull String value) {
+        this(name, value, null);
+    }
+
+    public ProfileProperty(@Nonnull String name, @Nonnull String value, @Nullable String signature) {
+        this.name = Preconditions.checkNotNull(name, "ProfileProperty name can not be null");
+        this.value = Preconditions.checkNotNull(value, "ProfileProperty value can not be null");
+        this.signature = signature;
+    }
+
+    /**
+     * @return The property name, ie "textures"
+     */
+    @Nonnull
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @return The property value, likely to be base64 encoded
+     */
+    @Nonnull
+    public String getValue() {
+        return value;
+    }
+
+    /**
+     * @return A signature from Mojang for signed properties
+     */
+    @Nullable
+    public String getSignature() {
+        return signature;
+    }
+
+    /**
+     * @return If this property has a signature or not
+     */
+    public boolean isSigned() {
+        return this.signature != null;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        ProfileProperty that = (ProfileProperty) o;
+        return Objects.equals(name, that.name) &&
+                Objects.equals(value, that.value) &&
+                Objects.equals(signature, that.signature);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name);
+    }
+}
diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java
index ed403c33..690d9c07 100644
--- a/src/main/java/org/bukkit/Bukkit.java
+++ b/src/main/java/org/bukkit/Bukkit.java
@@ -44,6 +44,9 @@ import org.bukkit.generator.ChunkGenerator;
 import org.bukkit.inventory.ItemFactory;
 import org.bukkit.inventory.meta.ItemMeta;
 
+import javax.annotation.Nullable; // Paper
+import javax.annotation.Nonnull; // Paper
+
 /**
  * Represents the Bukkit core, for version and Server singleton handling
  */
@@ -1216,6 +1219,37 @@ public final class Bukkit {
     public static boolean suggestPlayerNamesWhenNullTabCompletions() {
         return server.suggestPlayerNamesWhenNullTabCompletions();
     }
+
+    /**
+     * Creates a PlayerProfile for the specified uuid, with name as null
+     * @param uuid UUID to create profile for
+     * @return A PlayerProfile object
+     */
+    public static com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nonnull UUID uuid) {
+        return server.createProfile(uuid);
+    }
+
+    /**
+     * Creates a PlayerProfile for the specified name, with UUID as null
+     * @param name Name to create profile for
+     * @return A PlayerProfile object
+     */
+    public static com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nonnull String name) {
+        return server.createProfile(name);
+    }
+
+    /**
+     * Creates a PlayerProfile for the specified name/uuid
+     *
+     * Both UUID and Name can not be null at same time. One must be supplied.
+     *
+     * @param uuid UUID to create profile for
+     * @param name Name to create profile for
+     * @return A PlayerProfile object
+     */
+    public static com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nullable UUID uuid, @Nullable String name) {
+        return server.createProfile(uuid, name);
+    }
     // Paper end
 
     public static Server.Spigot spigot()
diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java
index 87ab9d2b..f2ee6516 100644
--- a/src/main/java/org/bukkit/Server.java
+++ b/src/main/java/org/bukkit/Server.java
@@ -45,6 +45,9 @@ import org.bukkit.generator.ChunkGenerator;
 import org.bukkit.inventory.ItemFactory;
 import org.bukkit.inventory.meta.ItemMeta;
 
+import javax.annotation.Nullable; // Paper
+import javax.annotation.Nonnull; // Paper
+
 /**
  * Represents a server implementation.
  */
@@ -1041,5 +1044,30 @@ public interface Server extends PluginMessageRecipient {
      * @return true if player names should be suggested
      */
     boolean suggestPlayerNamesWhenNullTabCompletions();
+
+    /**
+     * Creates a PlayerProfile for the specified uuid, with name as null
+     * @param uuid UUID to create profile for
+     * @return A PlayerProfile object
+     */
+    com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nonnull UUID uuid);
+
+    /**
+     * Creates a PlayerProfile for the specified name, with UUID as null
+     * @param name Name to create profile for
+     * @return A PlayerProfile object
+     */
+    com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nonnull String name);
+
+    /**
+     * Creates a PlayerProfile for the specified name/uuid
+     *
+     * Both UUID and Name can not be null at same time. One must be supplied.
+     *
+     * @param uuid UUID to create profile for
+     * @param name Name to create profile for
+     * @return A PlayerProfile object
+     */
+    com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nullable UUID uuid, @Nullable String name);
     // Paper end
 }
-- 
2.15.1