diff --git a/patches/server/0143-Basic-PlayerProfile-API.patch b/patches/server/0143-Basic-PlayerProfile-API.patch deleted file mode 100644 index bbce10793..000000000 --- a/patches/server/0143-Basic-PlayerProfile-API.patch +++ /dev/null @@ -1,770 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 15 Jan 2018 22:11:48 -0500 -Subject: [PATCH] Basic PlayerProfile API - -Establishes base extension of profile systems for future edits too - -== AT == -public org.bukkit.craftbukkit.profile.CraftProfileProperty -public org.bukkit.craftbukkit.profile.CraftPlayerTextures -public org.bukkit.craftbukkit.profile.CraftPlayerTextures copyFrom(Lorg/bukkit/profile/PlayerTextures;)V -public org.bukkit.craftbukkit.profile.CraftPlayerTextures rebuildPropertyIfDirty()V -public org.bukkit.craftbukkit.profile.CraftPlayerProfile toString(Lcom/mojang/authlib/properties/PropertyMap;)Ljava/lang/String; -# needed to maintain visibility with overriden methods -public org.bukkit.craftbukkit.profile.CraftPlayerProfile getProperty(Ljava/lang/String;)Lcom/mojang/authlib/properties/Property; -public org.bukkit.craftbukkit.profile.CraftPlayerProfile setProperty(Ljava/lang/String;Lcom/mojang/authlib/properties/Property;)V - -diff --git a/src/main/java/com/destroystokyo/paper/profile/CraftPlayerProfile.java b/src/main/java/com/destroystokyo/paper/profile/CraftPlayerProfile.java -new file mode 100644 -index 0000000000000000000000000000000000000000..3ff790cec1ad89caec4be64421dd7d51652be598 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/profile/CraftPlayerProfile.java -@@ -0,0 +1,399 @@ -+package com.destroystokyo.paper.profile; -+ -+import io.papermc.paper.configuration.GlobalConfiguration; -+import com.google.common.base.Charsets; -+import com.google.common.collect.Iterables; -+import com.mojang.authlib.GameProfile; -+import com.mojang.authlib.properties.Property; -+import com.mojang.authlib.properties.PropertyMap; -+import net.minecraft.Util; -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.server.players.GameProfileCache; -+import org.apache.commons.lang3.Validate; -+import org.bukkit.configuration.serialization.SerializableAs; -+import org.bukkit.craftbukkit.configuration.ConfigSerializationUtil; -+import org.bukkit.craftbukkit.entity.CraftPlayer; -+import org.bukkit.craftbukkit.profile.CraftPlayerTextures; -+import org.bukkit.craftbukkit.profile.CraftProfileProperty; -+import org.bukkit.profile.PlayerTextures; -+import org.jetbrains.annotations.NotNull; -+ -+import javax.annotation.Nonnull; -+import javax.annotation.Nullable; -+import java.util.*; -+import java.util.concurrent.CompletableFuture; -+ -+@SerializableAs("PlayerProfile") -+public class CraftPlayerProfile implements PlayerProfile, SharedPlayerProfile { -+ -+ private GameProfile profile; -+ private final PropertySet properties = new PropertySet(); -+ -+ public CraftPlayerProfile(CraftPlayer player) { -+ this.profile = player.getHandle().getGameProfile(); -+ } -+ -+ public CraftPlayerProfile(UUID id, String name) { -+ this.profile = new GameProfile(id, name); -+ } -+ -+ public CraftPlayerProfile(GameProfile profile) { -+ Validate.notNull(profile, "GameProfile cannot be null!"); -+ this.profile = profile; -+ } -+ -+ @Override -+ public boolean hasProperty(String property) { -+ return profile.getProperties().containsKey(property); -+ } -+ -+ @Override -+ public void setProperty(ProfileProperty property) { -+ String name = property.getName(); -+ PropertyMap properties = profile.getProperties(); -+ properties.removeAll(name); -+ properties.put(name, new Property(name, property.getValue(), property.getSignature())); -+ } -+ -+ @Override -+ public CraftPlayerTextures getTextures() { -+ return new CraftPlayerTextures(this); -+ } -+ -+ @Override -+ public void setTextures(@Nullable PlayerTextures textures) { -+ if (textures == null) { -+ this.removeProperty("textures"); -+ } else { -+ CraftPlayerTextures craftPlayerTextures = new CraftPlayerTextures(this); -+ craftPlayerTextures.copyFrom(textures); -+ craftPlayerTextures.rebuildPropertyIfDirty(); -+ } -+ } -+ -+ public GameProfile getGameProfile() { -+ return profile; -+ } -+ -+ @Nullable -+ @Override -+ public UUID getId() { -+ return profile.getId(); -+ } -+ -+ @Override -+ @Deprecated(forRemoval = true) -+ public UUID setId(@Nullable UUID uuid) { -+ GameProfile prev = this.profile; -+ this.profile = new GameProfile(uuid, prev.getName()); -+ copyProfileProperties(prev, this.profile); -+ return prev.getId(); -+ } -+ -+ @Override -+ public UUID getUniqueId() { -+ return getId(); -+ } -+ -+ @Nullable -+ @Override -+ public String getName() { -+ return profile.getName(); -+ } -+ -+ @Override -+ @Deprecated(forRemoval = true) -+ public String setName(@Nullable String name) { -+ GameProfile prev = this.profile; -+ this.profile = new GameProfile(prev.getId(), name); -+ copyProfileProperties(prev, this.profile); -+ return prev.getName(); -+ } -+ -+ @Nonnull -+ @Override -+ public Set getProperties() { -+ return properties; -+ } -+ -+ @Override -+ public void setProperties(Collection properties) { -+ properties.forEach(this::setProperty); -+ } -+ -+ @Override -+ public void clearProperties() { -+ profile.getProperties().clear(); -+ } -+ -+ @Override -+ public boolean removeProperty(String property) { -+ return !profile.getProperties().removeAll(property).isEmpty(); -+ } -+ -+ @Nullable -+ @Override -+ public Property getProperty(String property) { -+ return Iterables.getFirst(this.profile.getProperties().get(property), null); -+ } -+ -+ @Nullable -+ @Override -+ public void setProperty(@NotNull String propertyName, @Nullable Property property) { -+ PropertyMap properties = profile.getProperties(); -+ properties.removeAll(propertyName); -+ if (property != null) { -+ properties.put(propertyName, property); -+ } -+ } -+ -+ @Override -+ public @NotNull GameProfile buildGameProfile() { -+ GameProfile profile = new GameProfile(this.profile.getId(), this.profile.getName()); -+ profile.getProperties().putAll(this.profile.getProperties()); -+ return profile; -+ } -+ -+ @Override -+ public CraftPlayerProfile clone() { -+ CraftPlayerProfile clone = new CraftPlayerProfile(this.getId(), this.getName()); -+ clone.setProperties(getProperties()); -+ return clone; -+ } -+ -+ @Override -+ public boolean isComplete() { -+ return profile.isComplete(); -+ } -+ -+ @Override -+ public @NotNull CompletableFuture update() { -+ return CompletableFuture.supplyAsync(() -> { -+ final CraftPlayerProfile clone = clone(); -+ clone.complete(true); -+ return clone; -+ }, Util.PROFILE_EXECUTOR); -+ } -+ -+ @Override -+ public boolean completeFromCache() { -+ return completeFromCache(false, GlobalConfiguration.get().proxies.isProxyOnlineMode()); -+ } -+ -+ public boolean completeFromCache(boolean onlineMode) { -+ return completeFromCache(false, onlineMode); -+ } -+ -+ public boolean completeFromCache(boolean lookupUUID, boolean onlineMode) { -+ MinecraftServer server = MinecraftServer.getServer(); -+ String name = profile.getName(); -+ GameProfileCache userCache = server.getProfileCache(); -+ if (profile.getId() == null) { -+ final GameProfile profile; -+ if (onlineMode) { -+ profile = lookupUUID ? userCache.get(name).orElse(null) : userCache.getProfileIfCached(name); -+ } else { -+ // Make an OfflinePlayer using an offline mode UUID since the name has no profile -+ profile = new GameProfile(UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(Charsets.UTF_8)), name); -+ } -+ if (profile != null) { -+ // if old has it, assume its newer, so overwrite, else use cached if it was set and ours wasn't -+ copyProfileProperties(this.profile, profile); -+ this.profile = profile; -+ } -+ } -+ -+ if ((profile.getName() == null || !hasTextures()) && profile.getId() != null) { -+ Optional optProfile = userCache.get(this.profile.getId()); -+ if (optProfile.isPresent()) { -+ GameProfile profile = optProfile.get(); -+ if (this.profile.getName() == null) { -+ // if old has it, assume its newer, so overwrite, else use cached if it was set and ours wasn't -+ copyProfileProperties(this.profile, profile); -+ this.profile = profile; -+ } else { -+ copyProfileProperties(profile, this.profile); -+ } -+ } -+ } -+ return this.profile.isComplete(); -+ } -+ -+ public boolean complete(boolean textures) { -+ return complete(textures, GlobalConfiguration.get().proxies.isProxyOnlineMode()); -+ } -+ public boolean complete(boolean textures, boolean onlineMode) { -+ MinecraftServer server = MinecraftServer.getServer(); -+ boolean isCompleteFromCache = this.completeFromCache(true, onlineMode); -+ if (onlineMode && (!isCompleteFromCache || textures && !hasTextures())) { -+ GameProfile result = server.getSessionService().fillProfileProperties(profile, true); -+ if (result != null) { -+ copyProfileProperties(result, this.profile, true); -+ } -+ if (this.profile.isComplete()) { -+ server.getProfileCache().add(this.profile); -+ } -+ } -+ return profile.isComplete() && (!onlineMode || !textures || hasTextures()); -+ } -+ -+ private static void copyProfileProperties(GameProfile source, GameProfile target) { -+ copyProfileProperties(source, target, false); -+ } -+ -+ private static void copyProfileProperties(GameProfile source, GameProfile target, boolean clearTarget) { -+ PropertyMap sourceProperties = source.getProperties(); -+ PropertyMap targetProperties = target.getProperties(); -+ if (clearTarget) targetProperties.clear(); -+ if (sourceProperties.isEmpty()) { -+ return; -+ } -+ -+ for (Property property : sourceProperties.values()) { -+ targetProperties.removeAll(property.getName()); -+ targetProperties.put(property.getName(), property); -+ } -+ } -+ -+ private static ProfileProperty toBukkit(Property property) { -+ return new ProfileProperty(property.getName(), property.getValue(), property.getSignature()); -+ } -+ -+ public static PlayerProfile asBukkitCopy(GameProfile gameProfile) { -+ CraftPlayerProfile profile = new CraftPlayerProfile(gameProfile.getId(), gameProfile.getName()); -+ copyProfileProperties(gameProfile, profile.profile); -+ return profile; -+ } -+ -+ public static PlayerProfile asBukkitMirror(GameProfile profile) { -+ return new CraftPlayerProfile(profile); -+ } -+ -+ public static Property asAuthlib(ProfileProperty property) { -+ return new Property(property.getName(), property.getValue(), property.getSignature()); -+ } -+ -+ public static GameProfile asAuthlibCopy(PlayerProfile profile) { -+ CraftPlayerProfile craft = ((CraftPlayerProfile) profile); -+ return asAuthlib(craft.clone()); -+ } -+ -+ public static GameProfile asAuthlib(PlayerProfile profile) { -+ CraftPlayerProfile craft = ((CraftPlayerProfile) profile); -+ return craft.getGameProfile(); -+ } -+ -+ @Override -+ public @NotNull Map serialize() { -+ Map map = new LinkedHashMap<>(); -+ if (this.getId() != null) { -+ map.put("uniqueId", this.getId().toString()); -+ } -+ if (this.getName() != null) { -+ map.put("name", getName()); -+ } -+ if (!this.properties.isEmpty()) { -+ List propertiesData = new ArrayList<>(); -+ for (ProfileProperty property : properties) { -+ propertiesData.add(CraftProfileProperty.serialize(new Property(property.getName(), property.getValue(), property.getSignature()))); -+ } -+ map.put("properties", propertiesData); -+ } -+ return map; -+ } -+ -+ public static CraftPlayerProfile deserialize(Map map) { -+ UUID uniqueId = ConfigSerializationUtil.getUuid(map, "uniqueId", true); -+ String name = ConfigSerializationUtil.getString(map, "name", true); -+ -+ // This also validates the deserialized unique id and name (ensures that not both are null): -+ CraftPlayerProfile profile = new CraftPlayerProfile(uniqueId, name); -+ -+ if (map.containsKey("properties")) { -+ for (Object propertyData : (List) map.get("properties")) { -+ if (!(propertyData instanceof Map)) { -+ throw new IllegalArgumentException("Property data (" + propertyData + ") is not a valid Map"); -+ } -+ Property property = CraftProfileProperty.deserialize((Map) propertyData); -+ profile.profile.getProperties().put(property.getName(), property); -+ } -+ } -+ -+ return profile; -+ } -+ -+ @Override -+ public boolean equals(Object obj) { -+ if (this == obj) return true; -+ if (!(obj instanceof CraftPlayerProfile otherProfile)) return false; -+ return Objects.equals(this.profile, otherProfile.profile); -+ } -+ -+ @Override -+ public String toString() { -+ return "CraftPlayerProfile [uniqueId=" + getId() + -+ ", name=" + getName() + -+ ", properties=" + org.bukkit.craftbukkit.profile.CraftPlayerProfile.toString(this.profile.getProperties()) + -+ "]"; -+ } -+ -+ @Override -+ public int hashCode() { -+ return this.profile.hashCode(); -+ } -+ -+ private class PropertySet extends AbstractSet { -+ -+ @Override -+ @Nonnull -+ public Iterator iterator() { -+ return new ProfilePropertyIterator(profile.getProperties().values().iterator()); -+ } -+ -+ @Override -+ public int size() { -+ return profile.getProperties().size(); -+ } -+ -+ @Override -+ public boolean add(ProfileProperty property) { -+ setProperty(property); -+ return true; -+ } -+ -+ @Override -+ public boolean addAll(Collection c) { -+ //noinspection unchecked -+ setProperties((Collection) c); -+ return true; -+ } -+ -+ @Override -+ public boolean contains(Object o) { -+ return o instanceof ProfileProperty && profile.getProperties().containsKey(((ProfileProperty) o).getName()); -+ } -+ -+ private class ProfilePropertyIterator implements Iterator { -+ private final Iterator iterator; -+ -+ ProfilePropertyIterator(Iterator iterator) { -+ this.iterator = iterator; -+ } -+ -+ @Override -+ public boolean hasNext() { -+ return iterator.hasNext(); -+ } -+ -+ @Override -+ public ProfileProperty next() { -+ return toBukkit(iterator.next()); -+ } -+ -+ @Override -+ public void remove() { -+ iterator.remove(); -+ } -+ } -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/profile/PaperAuthenticationService.java b/src/main/java/com/destroystokyo/paper/profile/PaperAuthenticationService.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1459a1f99fe614d072a087cda18788cf13102645 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/profile/PaperAuthenticationService.java -@@ -0,0 +1,31 @@ -+package com.destroystokyo.paper.profile; -+ -+import com.mojang.authlib.*; -+import com.mojang.authlib.minecraft.MinecraftSessionService; -+import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; -+import com.mojang.authlib.yggdrasil.YggdrasilEnvironment; -+ -+import java.net.Proxy; -+ -+public class PaperAuthenticationService extends YggdrasilAuthenticationService { -+ private final Environment environment; -+ public PaperAuthenticationService(Proxy proxy) { -+ super(proxy); -+ this.environment = EnvironmentParser.getEnvironmentFromProperties().orElse(YggdrasilEnvironment.PROD.getEnvironment()); -+ } -+ -+ @Override -+ public UserAuthentication createUserAuthentication(Agent agent) { -+ return new PaperUserAuthentication(this, agent); -+ } -+ -+ @Override -+ public MinecraftSessionService createMinecraftSessionService() { -+ return new PaperMinecraftSessionService(this, this.environment); -+ } -+ -+ @Override -+ public GameProfileRepository createProfileRepository() { -+ return new PaperGameProfileRepository(this, this.environment); -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/profile/PaperGameProfileRepository.java b/src/main/java/com/destroystokyo/paper/profile/PaperGameProfileRepository.java -new file mode 100644 -index 0000000000000000000000000000000000000000..582c169c85ac66f1f9430f79042e4655f776c157 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/profile/PaperGameProfileRepository.java -@@ -0,0 +1,18 @@ -+package com.destroystokyo.paper.profile; -+ -+import com.mojang.authlib.Agent; -+import com.mojang.authlib.Environment; -+import com.mojang.authlib.ProfileLookupCallback; -+import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; -+import com.mojang.authlib.yggdrasil.YggdrasilGameProfileRepository; -+ -+public class PaperGameProfileRepository extends YggdrasilGameProfileRepository { -+ public PaperGameProfileRepository(YggdrasilAuthenticationService authenticationService, Environment environment) { -+ super(authenticationService, environment); -+ } -+ -+ @Override -+ public void findProfilesByNames(String[] names, Agent agent, ProfileLookupCallback callback) { -+ super.findProfilesByNames(names, agent, callback); -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/profile/PaperMinecraftSessionService.java b/src/main/java/com/destroystokyo/paper/profile/PaperMinecraftSessionService.java -new file mode 100644 -index 0000000000000000000000000000000000000000..93d73c27340645c7502acafdc0b2cfbc1a759dd8 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/profile/PaperMinecraftSessionService.java -@@ -0,0 +1,30 @@ -+package com.destroystokyo.paper.profile; -+ -+import com.mojang.authlib.Environment; -+import com.mojang.authlib.GameProfile; -+import com.mojang.authlib.minecraft.MinecraftProfileTexture; -+import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; -+import com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService; -+ -+import java.util.Map; -+ -+public class PaperMinecraftSessionService extends YggdrasilMinecraftSessionService { -+ protected PaperMinecraftSessionService(YggdrasilAuthenticationService authenticationService, Environment environment) { -+ super(authenticationService, environment); -+ } -+ -+ @Override -+ public Map getTextures(GameProfile profile, boolean requireSecure) { -+ return super.getTextures(profile, requireSecure); -+ } -+ -+ @Override -+ public GameProfile fillProfileProperties(GameProfile profile, boolean requireSecure) { -+ return super.fillProfileProperties(profile, requireSecure); -+ } -+ -+ @Override -+ protected GameProfile fillGameProfile(GameProfile profile, boolean requireSecure) { -+ return super.fillGameProfile(profile, requireSecure); -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/profile/PaperUserAuthentication.java b/src/main/java/com/destroystokyo/paper/profile/PaperUserAuthentication.java -new file mode 100644 -index 0000000000000000000000000000000000000000..3cdd06d3af7ff94f1fe1a11b9a9275e17c695a38 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/profile/PaperUserAuthentication.java -@@ -0,0 +1,12 @@ -+package com.destroystokyo.paper.profile; -+ -+import com.mojang.authlib.Agent; -+import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; -+import com.mojang.authlib.yggdrasil.YggdrasilUserAuthentication; -+import java.util.UUID; -+ -+public class PaperUserAuthentication extends YggdrasilUserAuthentication { -+ public PaperUserAuthentication(YggdrasilAuthenticationService authenticationService, Agent agent) { -+ super(authenticationService, UUID.randomUUID().toString(), agent); -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/profile/SharedPlayerProfile.java b/src/main/java/com/destroystokyo/paper/profile/SharedPlayerProfile.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7ac27392a8647ef7d0dc78efe78703e993885017 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/profile/SharedPlayerProfile.java -@@ -0,0 +1,23 @@ -+package com.destroystokyo.paper.profile; -+ -+import com.mojang.authlib.GameProfile; -+import com.mojang.authlib.properties.Property; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+import java.util.UUID; -+ -+public interface SharedPlayerProfile { -+ -+ @Nullable UUID getUniqueId(); -+ -+ @Nullable String getName(); -+ -+ boolean removeProperty(@NotNull String property); -+ -+ @Nullable Property getProperty(@NotNull String propertyName); -+ -+ @Nullable void setProperty(@NotNull String propertyName, @Nullable Property property); -+ -+ @NotNull GameProfile buildGameProfile(); -+} -diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java -index d58d44faa40be2421f4cb54740a3abdbad72875c..9ee4dc54039cbe6b8c9bd3018044c73f923a736e 100644 ---- a/src/main/java/io/papermc/paper/util/MCUtil.java -+++ b/src/main/java/io/papermc/paper/util/MCUtil.java -@@ -1,5 +1,7 @@ - package io.papermc.paper.util; - -+import com.destroystokyo.paper.profile.CraftPlayerProfile; -+import com.destroystokyo.paper.profile.PlayerProfile; - import com.google.common.util.concurrent.ThreadFactoryBuilder; - import io.papermc.paper.math.Position; - import com.google.gson.JsonArray; -@@ -26,6 +28,7 @@ import net.minecraft.world.level.Level; - import net.minecraft.world.level.chunk.ChunkAccess; - import net.minecraft.world.level.chunk.ChunkStatus; - import org.apache.commons.lang.exception.ExceptionUtils; -+import com.mojang.authlib.GameProfile; - import org.bukkit.Location; - import org.bukkit.block.BlockFace; - import org.bukkit.craftbukkit.CraftWorld; -@@ -373,6 +376,10 @@ public final class MCUtil { - return run.get(); - } - -+ public static PlayerProfile toBukkit(GameProfile profile) { -+ return CraftPlayerProfile.asBukkitMirror(profile); -+ } -+ - /** - * Calculates distance between 2 entities - * @param e1 -diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java -index 26fa789a44a1d934944e78eae21f489213f50ae3..12ff7071a5b78a8ae5567aa42b69191166a7cbca 100644 ---- a/src/main/java/net/minecraft/server/Main.java -+++ b/src/main/java/net/minecraft/server/Main.java -@@ -170,7 +170,7 @@ public class Main { - } - - File file = (File) optionset.valueOf("universe"); // CraftBukkit -- Services services = Services.create(new YggdrasilAuthenticationService(Proxy.NO_PROXY), file, optionset); // Paper -+ Services services = Services.create(new com.destroystokyo.paper.profile.PaperAuthenticationService(Proxy.NO_PROXY), file, optionset); // Paper - // CraftBukkit start - String s = (String) Optional.ofNullable((String) optionset.valueOf("world")).orElse(dedicatedserversettings.getProperties().levelName); - LevelStorageSource convertable = LevelStorageSource.createDefault(file.toPath()); -diff --git a/src/main/java/net/minecraft/server/players/GameProfileCache.java b/src/main/java/net/minecraft/server/players/GameProfileCache.java -index 4038bb76339d43f18770624bd7fecc79b8d7f2a9..2456edc11b29a92b1648937cd3dd6a9a05706803 100644 ---- a/src/main/java/net/minecraft/server/players/GameProfileCache.java -+++ b/src/main/java/net/minecraft/server/players/GameProfileCache.java -@@ -136,6 +136,17 @@ public class GameProfileCache { - return this.operationCount.incrementAndGet(); - } - -+ // Paper start -+ public @Nullable GameProfile getProfileIfCached(String name) { -+ GameProfileCache.GameProfileInfo entry = this.profilesByName.get(name.toLowerCase(Locale.ROOT)); -+ if (entry == null) { -+ return null; -+ } -+ entry.setLastAccess(this.getNextOperation()); -+ return entry.getProfile(); -+ } -+ // Paper end -+ - public Optional get(String name) { - String s1 = name.toLowerCase(Locale.ROOT); - GameProfileCache.GameProfileInfo usercache_usercacheentry = (GameProfileCache.GameProfileInfo) this.profilesByName.get(s1); -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 97bd0993b49e18b47c2316663025564bca4d4b41..d92f7eadf13cdab064a1f2a5c132faeabc2e25cb 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -258,6 +258,9 @@ import org.yaml.snakeyaml.error.MarkedYAMLException; - - import net.md_5.bungee.api.chat.BaseComponent; // Spigot - -+import javax.annotation.Nullable; // Paper -+import javax.annotation.Nonnull; // Paper -+ - public final class CraftServer implements Server { - private final String serverName = "Paper"; // Paper - private final String serverVersion; -@@ -300,6 +303,7 @@ public final class CraftServer implements Server { - static { - ConfigurationSerialization.registerClass(CraftOfflinePlayer.class); - ConfigurationSerialization.registerClass(CraftPlayerProfile.class); -+ ConfigurationSerialization.registerClass(com.destroystokyo.paper.profile.CraftPlayerProfile.class); // Paper - CraftItemFactory.instance(); - } - -@@ -2665,5 +2669,37 @@ public final class CraftServer implements Server { - public boolean suggestPlayerNamesWhenNullTabCompletions() { - return io.papermc.paper.configuration.GlobalConfiguration.get().commands.suggestPlayerNamesWhenNullTabCompletions; - } -+ -+ @Override -+ public com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nonnull UUID uuid) { -+ return createProfile(uuid, null); -+ } -+ -+ @Override -+ public com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nonnull String name) { -+ return createProfile(null, name); -+ } -+ -+ @Override -+ public com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nullable UUID uuid, @Nullable String name) { -+ Player player = uuid != null ? Bukkit.getPlayer(uuid) : (name != null ? Bukkit.getPlayerExact(name) : null); -+ if (player != null) return new com.destroystokyo.paper.profile.CraftPlayerProfile((CraftPlayer) player); -+ -+ return new com.destroystokyo.paper.profile.CraftPlayerProfile(uuid, name); -+ } -+ -+ @Override -+ public com.destroystokyo.paper.profile.PlayerProfile createProfileExact(@Nullable UUID uuid, @Nullable String name) { -+ Player player = uuid != null ? Bukkit.getPlayer(uuid) : (name != null ? Bukkit.getPlayerExact(name) : null); -+ if (player == null) return new com.destroystokyo.paper.profile.CraftPlayerProfile(uuid, name); -+ -+ if (java.util.Objects.equals(uuid, player.getUniqueId()) && java.util.Objects.equals(name, player.getName())) { -+ return new com.destroystokyo.paper.profile.CraftPlayerProfile((CraftPlayer) player); -+ } -+ -+ final com.mojang.authlib.GameProfile profile = new com.mojang.authlib.GameProfile(uuid, name); -+ profile.getProperties().putAll(((CraftPlayer)player).getHandle().getGameProfile().getProperties()); -+ return new com.destroystokyo.paper.profile.CraftPlayerProfile(profile); -+ } - // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java -index 3e40d47f504248cd7caeef6b841a8aa6f1976170..6ca6467a47c6658d3a2e2029821aa727599a6f74 100644 ---- a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java -+++ b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java -@@ -27,7 +27,7 @@ import org.bukkit.profile.PlayerProfile; - import org.bukkit.profile.PlayerTextures; - - @SerializableAs("PlayerProfile") --public final class CraftPlayerProfile implements PlayerProfile { -+public final class CraftPlayerProfile implements PlayerProfile, com.destroystokyo.paper.profile.SharedPlayerProfile { // Paper - - @Nonnull - public static GameProfile validateSkullProfile(@Nonnull GameProfile gameProfile) { -@@ -92,8 +92,10 @@ public final class CraftPlayerProfile implements PlayerProfile { - } - } - -- void removeProperty(String propertyName) { -- this.properties.removeAll(propertyName); -+ // Paper start - change return value for shared interface -+ public boolean removeProperty(String propertyName) { -+ return !this.properties.removeAll(propertyName).isEmpty(); -+ // Paper end - } - - void rebuildDirtyProperties() { -@@ -236,6 +238,7 @@ public final class CraftPlayerProfile implements PlayerProfile { - - @Override - public Map serialize() { -+ // Paper - diff on change - Map map = new LinkedHashMap<>(); - if (this.uniqueId != null) { - map.put("uniqueId", this.uniqueId.toString()); -@@ -251,10 +254,12 @@ public final class CraftPlayerProfile implements PlayerProfile { - }); - map.put("properties", propertiesData); - } -+ // Paper - diff on change - return map; - } - - public static CraftPlayerProfile deserialize(Map map) { -+ // Paper - diff on change - UUID uniqueId = ConfigSerializationUtil.getUuid(map, "uniqueId", true); - String name = ConfigSerializationUtil.getString(map, "name", true); - -@@ -270,7 +275,7 @@ public final class CraftPlayerProfile implements PlayerProfile { - profile.properties.put(property.getName(), property); - } - } -- -+ // Paper - diff on change - return profile; - } - } -diff --git a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerTextures.java b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerTextures.java -index e5b61bc1f3a4bfccca386360c4920ffb8b768308..ab1fd3fb39bd40fb867432861462db5f866bce6f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerTextures.java -+++ b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerTextures.java -@@ -48,7 +48,7 @@ public final class CraftPlayerTextures implements PlayerTextures { - } - } - -- private final CraftPlayerProfile profile; -+ private final com.destroystokyo.paper.profile.SharedPlayerProfile profile; // Paper - - // The textures data is loaded lazily: - private boolean loaded = false; -@@ -67,7 +67,7 @@ public final class CraftPlayerTextures implements PlayerTextures { - // GameProfiles (even if these modifications are later reverted). - private boolean dirty = false; - -- CraftPlayerTextures(@Nonnull CraftPlayerProfile profile) { -+ public CraftPlayerTextures(@Nonnull com.destroystokyo.paper.profile.SharedPlayerProfile profile) { // Paper - this.profile = profile; - } - diff --git a/patches/server/0145-Profile-Lookup-Events.patch b/patches/server/0145-Profile-Lookup-Events.patch deleted file mode 100644 index a9a4210f1..000000000 --- a/patches/server/0145-Profile-Lookup-Events.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sat, 17 Jun 2017 17:00:32 -0400 -Subject: [PATCH] Profile Lookup Events - -Adds a Pre Lookup Event and a Post Lookup Event so that plugins may prefill in profile data, and cache the responses from -profiles that had to be looked up. - -diff --git a/src/main/java/com/destroystokyo/paper/profile/PaperGameProfileRepository.java b/src/main/java/com/destroystokyo/paper/profile/PaperGameProfileRepository.java -index 582c169c85ac66f1f9430f79042e4655f776c157..08fdb681a68e8be6e4062af0630957ce3e524806 100644 ---- a/src/main/java/com/destroystokyo/paper/profile/PaperGameProfileRepository.java -+++ b/src/main/java/com/destroystokyo/paper/profile/PaperGameProfileRepository.java -@@ -1,11 +1,16 @@ - package com.destroystokyo.paper.profile; - -+import com.destroystokyo.paper.event.profile.LookupProfileEvent; -+import com.destroystokyo.paper.event.profile.PreLookupProfileEvent; -+import com.google.common.collect.Sets; - import com.mojang.authlib.Agent; - import com.mojang.authlib.Environment; -+import com.mojang.authlib.GameProfile; - import com.mojang.authlib.ProfileLookupCallback; - import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; - import com.mojang.authlib.yggdrasil.YggdrasilGameProfileRepository; - -+import java.util.Set; - public class PaperGameProfileRepository extends YggdrasilGameProfileRepository { - public PaperGameProfileRepository(YggdrasilAuthenticationService authenticationService, Environment environment) { - super(authenticationService, environment); -@@ -13,6 +18,50 @@ public class PaperGameProfileRepository extends YggdrasilGameProfileRepository { - - @Override - public void findProfilesByNames(String[] names, Agent agent, ProfileLookupCallback callback) { -- super.findProfilesByNames(names, agent, callback); -+ Set unfoundNames = Sets.newHashSet(); -+ for (String name : names) { -+ PreLookupProfileEvent event = new PreLookupProfileEvent(name); -+ event.callEvent(); -+ if (event.getUUID() != null) { -+ // Plugin provided UUI, we can skip network call. -+ GameProfile gameprofile = new GameProfile(event.getUUID(), name); -+ // We might even have properties! -+ Set profileProperties = event.getProfileProperties(); -+ if (!profileProperties.isEmpty()) { -+ for (ProfileProperty property : profileProperties) { -+ gameprofile.getProperties().put(property.getName(), CraftPlayerProfile.asAuthlib(property)); -+ } -+ } -+ callback.onProfileLookupSucceeded(gameprofile); -+ } else { -+ unfoundNames.add(name); -+ } -+ } -+ -+ // Some things were not found.... Proceed to look up. -+ if (!unfoundNames.isEmpty()) { -+ String[] namesArr = unfoundNames.toArray(new String[unfoundNames.size()]); -+ super.findProfilesByNames(namesArr, agent, new PreProfileLookupCallback(callback)); -+ } -+ } -+ -+ private static class PreProfileLookupCallback implements ProfileLookupCallback { -+ private final ProfileLookupCallback callback; -+ -+ PreProfileLookupCallback(ProfileLookupCallback callback) { -+ this.callback = callback; -+ } -+ -+ @Override -+ public void onProfileLookupSucceeded(GameProfile gameProfile) { -+ PlayerProfile from = CraftPlayerProfile.asBukkitMirror(gameProfile); -+ new LookupProfileEvent(from).callEvent(); -+ callback.onProfileLookupSucceeded(gameProfile); -+ } -+ -+ @Override -+ public void onProfileLookupFailed(GameProfile gameProfile, Exception e) { -+ callback.onProfileLookupFailed(gameProfile, e); -+ } - } - } diff --git a/patches/server/0277-Don-t-sleep-after-profile-lookups-if-not-needed.patch b/patches/server/0277-Don-t-sleep-after-profile-lookups-if-not-needed.patch deleted file mode 100644 index c4f99ad87..000000000 --- a/patches/server/0277-Don-t-sleep-after-profile-lookups-if-not-needed.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 23 Oct 2018 20:25:05 -0400 -Subject: [PATCH] Don't sleep after profile lookups if not needed - -Mojang was sleeping even if we had no more requests to go after -the current one finished, resulting in 100ms lost per profile lookup - -diff --git a/src/main/java/com/mojang/authlib/yggdrasil/YggdrasilGameProfileRepository.java b/src/main/java/com/mojang/authlib/yggdrasil/YggdrasilGameProfileRepository.java -index cc38e909d1fa83206fa09666599d853a6e89ef36..c48a40155108b6bae18073638a0ba12649344261 100644 ---- a/src/main/java/com/mojang/authlib/yggdrasil/YggdrasilGameProfileRepository.java -+++ b/src/main/java/com/mojang/authlib/yggdrasil/YggdrasilGameProfileRepository.java -@@ -43,6 +43,7 @@ public class YggdrasilGameProfileRepository implements GameProfileRepository { - } - - final int page = 0; -+ boolean hasRequested = false; // Paper - - for (final List request : Iterables.partition(criteria, ENTRIES_PER_PAGE)) { - int failCount = 0; -@@ -68,6 +69,12 @@ public class YggdrasilGameProfileRepository implements GameProfileRepository { - LOGGER.debug("Couldn't find profile {}", name); - callback.onProfileLookupFailed(new GameProfile(null, name), new ProfileNotFoundException("Server did not find the requested profile")); - } -+ // Paper start -+ if (!hasRequested) { -+ hasRequested = true; -+ continue; -+ } -+ // Paper end - - try { - Thread.sleep(DELAY_BETWEEN_PAGES);