package com.cryptomorin.xseries.profiles.objects;
import com.cryptomorin.xseries.profiles.PlayerProfiles;
import com.cryptomorin.xseries.profiles.PlayerUUIDs;
import com.cryptomorin.xseries.profiles.exceptions.InvalidProfileException;
import com.cryptomorin.xseries.profiles.exceptions.UnknownPlayerException;
import com.cryptomorin.xseries.profiles.mojang.MojangAPI;
import com.cryptomorin.xseries.profiles.mojang.PlayerProfileFetcherThread;
import com.cryptomorin.xseries.profiles.mojang.ProfileRequestConfiguration;
import com.cryptomorin.xseries.profiles.objects.cache.TimedCacheableProfileable;
import com.cryptomorin.xseries.profiles.objects.transformer.ProfileTransformer;
import com.cryptomorin.xseries.profiles.objects.transformer.TransformableProfile;
import com.cryptomorin.xseries.reflection.XReflection;
import com.google.common.base.Function;
import com.google.common.base.Strings;
import com.mojang.authlib.GameProfile;
import org.bukkit.OfflinePlayer;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Skull;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import javax.annotation.Nonnull;
import java.util.*;
import java.util.concurrent.CompletableFuture;
/**
* Represents any object that has a {@link GameProfile} or one can be created with it.
* These objects are cached.
*
* A {@link GameProfile} is an object that represents information about a Minecraft player's
* account in general (not specific to this or any other server)
* The most important information contained within this profile however, is the
* skin texture URL which the client needs to properly see the texture on items/blocks.
*/
public interface Profileable {
/**
* This method should not be used directly unless you know what you're doing.
*
* The texture which might be cached. If any errors occur, the check may be re-evaluated.
* The cached values might also be re-evaluated due to expiration.
* @throws com.cryptomorin.xseries.profiles.exceptions.ProfileException may also throw other internal exceptions (most likely bugs)
* @return the original profile (not cloned if possible) for an instance that's always guaranteed to be a copy
* you can use {@link #getDisposableProfile()} instead. Null if no profile is set (only happens for {@link ProfileContainer}).
*/
@Nullable
@Unmodifiable
@ApiStatus.Internal
GameProfile getProfile();
/**
* Same as {@link #getProfile()}, except some implementations of {@link Profileable}
* cannot inherently return any original instance as they're not cacheable, so this
* method ensures that no duplicate cloning of {@link GameProfile} occurs for performance.
*
* For most implementations however, this defaults to a simple cloning of the cached instances.
* @return always a copied version of {@link #getProfile()} that you can change. Null if {@link #getProfile()} is null
*/
@Nullable
@ApiStatus.Internal
default GameProfile getDisposableProfile() {
GameProfile profile = getProfile();
return profile == null ? null : PlayerProfiles.clone(profile);
}
/**
* Adds transformer (read {@link ProfileTransformer}) information to a copied version
* of this profile (so it doesn't affect this instance).
*
* Profiles are copied before being transformed, so the main cache remains intact
* but the result of transformed profiles are never cached.
* @param transformers a list of transformers to apply in order once {@link #getProfile()} is called.
*/
default Profileable transform(ProfileTransformer... transformers) {
return new TransformableProfile(this, Arrays.asList(transformers));
}
/**
* A string representation of the {@link #getProfile()} which is useful for data storage.
* @return null if {@link #getProfile()} is null or the set profile doesn't have a texture property.
*/
@Nullable
default String getProfileValue() {
GameProfile profile = getProfile();
return PlayerProfiles.getTextureProperty(profile).map(PlayerProfiles::getPropertyValue).orElse(null);
}
@Nonnull
@ApiStatus.Experimental
static > CompletableFuture prepare(@Nonnull C profileables) {
return prepare(profileables, null, null);
}
@Nonnull
@ApiStatus.Experimental
static > CompletableFuture prepare(
@Nonnull C profileables, @Nullable ProfileRequestConfiguration config,
@Nullable Function errorHandler) {
CompletableFuture