expose skin texture methods in api

This commit is contained in:
Pyrbu 2024-01-07 18:26:17 +01:00
parent c560fe597e
commit 2a1f44b1bb
11 changed files with 72 additions and 43 deletions

@ -0,0 +1,6 @@
package lol.pyr.znpcsplus.api.skin;
public interface Skin {
String getTexture();
String getSignature();
}

@ -1,4 +1,11 @@
package lol.pyr.znpcsplus.api.skin;
import org.bukkit.entity.Player;
import java.util.concurrent.CompletableFuture;
public interface SkinDescriptor {
CompletableFuture<? extends Skin> fetch(Player player);
Skin fetchInstant(Player player);
boolean supportsInstant(Player player);
}

@ -4,7 +4,7 @@ import lol.pyr.znpcsplus.api.entity.EntityPropertyRegistry;
import lol.pyr.znpcsplus.api.skin.SkinDescriptor;
import lol.pyr.znpcsplus.conversion.citizens.model.SectionCitizensTrait;
import lol.pyr.znpcsplus.npc.NpcImpl;
import lol.pyr.znpcsplus.skin.Skin;
import lol.pyr.znpcsplus.skin.SkinImpl;
import lol.pyr.znpcsplus.skin.descriptor.PrefetchedDescriptor;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
@ -21,7 +21,7 @@ public class SkinTrait extends SectionCitizensTrait {
public @NotNull NpcImpl apply(NpcImpl npc, ConfigurationSection section) {
String texture = section.getString("textureRaw");
String signature = section.getString("signature");
if (texture != null && signature != null) npc.setProperty(registry.getByName("skin", SkinDescriptor.class), new PrefetchedDescriptor(new Skin(texture, signature)));
if (texture != null && signature != null) npc.setProperty(registry.getByName("skin", SkinDescriptor.class), new PrefetchedDescriptor(new SkinImpl(texture, signature)));
return npc;
}
}

@ -25,7 +25,7 @@ import lol.pyr.znpcsplus.npc.NpcImpl;
import lol.pyr.znpcsplus.npc.NpcTypeRegistryImpl;
import lol.pyr.znpcsplus.packets.PacketFactory;
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
import lol.pyr.znpcsplus.skin.Skin;
import lol.pyr.znpcsplus.skin.SkinImpl;
import lol.pyr.znpcsplus.skin.cache.MojangSkinCache;
import lol.pyr.znpcsplus.skin.descriptor.FetchingDescriptor;
import lol.pyr.znpcsplus.skin.descriptor.MirrorDescriptor;
@ -36,7 +36,6 @@ import lol.pyr.znpcsplus.util.LookType;
import lol.pyr.znpcsplus.util.NpcLocation;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.DyeColor;
import org.bukkit.inventory.ItemStack;
@ -130,7 +129,7 @@ public class ZNpcImporter implements DataImporter {
npc.setProperty(propertyRegistry.getByName("skin", SkinDescriptor.class), new FetchingDescriptor(skinCache, model.getSkinName()));
}
else if (model.getSkin() != null && model.getSignature() != null) {
npc.setProperty(propertyRegistry.getByName("skin", SkinDescriptor.class), new PrefetchedDescriptor(new Skin(model.getSkin(), model.getSignature())));
npc.setProperty(propertyRegistry.getByName("skin", SkinDescriptor.class), new PrefetchedDescriptor(new SkinImpl(model.getSkin(), model.getSignature())));
}
Map<String, Object> toggleValues = model.getNpcToggleValues();

@ -13,8 +13,8 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
public interface BaseSkinDescriptor extends SkinDescriptor {
CompletableFuture<Skin> fetch(Player player);
Skin fetchInstant(Player player);
CompletableFuture<SkinImpl> fetch(Player player);
SkinImpl fetchInstant(Player player);
boolean supportsInstant(Player player);
String serialize();
@ -27,7 +27,7 @@ public interface BaseSkinDescriptor extends SkinDescriptor {
for (int i = 0; i < (arr.length - 1) / 3; i++) {
properties.add(new TextureProperty(arr[i + 1], arr[i + 2], arr[i + 3]));
}
return new PrefetchedDescriptor(new Skin(properties));
return new PrefetchedDescriptor(new SkinImpl(properties));
}
throw new IllegalArgumentException("Unknown SkinDescriptor type!");
}

@ -36,7 +36,7 @@ public class SkinDescriptorFactoryImpl implements SkinDescriptorFactory {
@Override
public SkinDescriptor createStaticDescriptor(String texture, String signature) {
return new PrefetchedDescriptor(new Skin(texture, signature));
return new PrefetchedDescriptor(new SkinImpl(texture, signature));
}
@Override

@ -6,6 +6,7 @@ import com.github.retrooper.packetevents.protocol.player.TextureProperty;
import com.github.retrooper.packetevents.protocol.player.UserProfile;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import lol.pyr.znpcsplus.api.skin.Skin;
import lol.pyr.znpcsplus.reflection.Reflections;
import java.lang.reflect.InvocationTargetException;
@ -13,21 +14,21 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class Skin {
public class SkinImpl implements Skin {
private final long timestamp = System.currentTimeMillis();
private final List<TextureProperty> properties;
private static final boolean V1_20_2 = PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_20_2);
public Skin(String texture, String signature) {
public SkinImpl(String texture, String signature) {
properties = new ArrayList<>(1);
properties.add(new TextureProperty("textures", texture, signature));
}
public Skin(Collection<TextureProperty> properties) {
public SkinImpl(Collection<TextureProperty> properties) {
this.properties = new ArrayList<>(properties);
}
public Skin(Object propertyMap) {
public SkinImpl(Object propertyMap) {
this.properties = new ArrayList<>();
try {
Collection<?> properties = (Collection<?>) Reflections.PROPERTY_MAP_VALUES_METHOD.get().invoke(propertyMap);
@ -51,7 +52,7 @@ public class Skin {
}
}
public Skin(JsonObject obj) {
public SkinImpl(JsonObject obj) {
properties = new ArrayList<>();
for (JsonElement e : obj.get("properties").getAsJsonArray()) {
JsonObject o = e.getAsJsonObject();
@ -71,4 +72,20 @@ public class Skin {
public boolean isExpired() {
return System.currentTimeMillis() - timestamp > 60000L;
}
@Override
public String getTexture() {
for (TextureProperty property : properties)
if (property.getName().equalsIgnoreCase("textures"))
return property.getValue();
return null;
}
@Override
public String getSignature() {
for (TextureProperty property : properties)
if (property.getName().equalsIgnoreCase("textures"))
return property.getSignature();
return null;
}
}

@ -4,7 +4,7 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import lol.pyr.znpcsplus.config.ConfigManager;
import lol.pyr.znpcsplus.reflection.Reflections;
import lol.pyr.znpcsplus.skin.Skin;
import lol.pyr.znpcsplus.skin.SkinImpl;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@ -24,7 +24,7 @@ public class MojangSkinCache {
private final ConfigManager configManager;
private final Map<String, Skin> cache = new ConcurrentHashMap<>();
private final Map<String, SkinImpl> cache = new ConcurrentHashMap<>();
private final Map<String, CachedId> idCache = new ConcurrentHashMap<>();
public MojangSkinCache(ConfigManager configManager) {
@ -32,11 +32,11 @@ public class MojangSkinCache {
}
public void cleanCache() {
for (Map.Entry<String, Skin> entry : cache.entrySet()) if (entry.getValue().isExpired()) cache.remove(entry.getKey());
for (Map.Entry<String, SkinImpl> entry : cache.entrySet()) if (entry.getValue().isExpired()) cache.remove(entry.getKey());
for (Map.Entry<String, CachedId> entry : idCache.entrySet()) if (entry.getValue().isExpired()) cache.remove(entry.getKey());
}
public CompletableFuture<Skin> fetchByName(String name) {
public CompletableFuture<SkinImpl> fetchByName(String name) {
Player player = Bukkit.getPlayerExact(name);
if (player != null && player.isOnline()) return CompletableFuture.completedFuture(getFromPlayer(player));
@ -53,7 +53,7 @@ public class MojangSkinCache {
if (obj.has("errorMessage")) return fetchByNameFallback(name).join();
String id = obj.get("id").getAsString();
idCache.put(name.toLowerCase(), new CachedId(id));
Skin skin = fetchByUUID(id).join();
SkinImpl skin = fetchByUUID(id).join();
if (skin == null) return fetchByNameFallback(name).join();
return skin;
}
@ -69,7 +69,7 @@ public class MojangSkinCache {
});
}
public CompletableFuture<Skin> fetchByNameFallback(String name) {
public CompletableFuture<SkinImpl> fetchByNameFallback(String name) {
Player player = Bukkit.getPlayerExact(name);
if (player != null && player.isOnline()) return CompletableFuture.completedFuture(getFromPlayer(player));
@ -89,7 +89,7 @@ public class MojangSkinCache {
JsonObject textures = obj.get("textures").getAsJsonObject();
String value = textures.get("raw").getAsJsonObject().get("value").getAsString();
String signature = textures.get("raw").getAsJsonObject().get("signature").getAsString();
Skin skin = new Skin(value, signature);
SkinImpl skin = new SkinImpl(value, signature);
cache.put(uuid, skin);
return skin;
}
@ -105,7 +105,7 @@ public class MojangSkinCache {
});
}
public CompletableFuture<Skin> fetchByUrl(URL url, String variant) {
public CompletableFuture<SkinImpl> fetchByUrl(URL url, String variant) {
return CompletableFuture.supplyAsync(() -> {
URL apiUrl = parseUrl("https://api.mineskin.org/generate/url");
HttpURLConnection connection = null;
@ -127,7 +127,7 @@ public class MojangSkinCache {
if (obj.has("error")) return null;
if (!obj.has("data")) return null;
JsonObject texture = obj.get("data").getAsJsonObject().get("texture").getAsJsonObject();
return new Skin(texture.get("value").getAsString(), texture.get("signature").getAsString());
return new SkinImpl(texture.get("value").getAsString(), texture.get("signature").getAsString());
}
} catch (IOException exception) {
@ -147,26 +147,26 @@ public class MojangSkinCache {
if (!idCache.containsKey(name)) return false;
CachedId id = idCache.get(name);
if (id.isExpired() || !cache.containsKey(id.getId())) return false;
Skin skin = cache.get(id.getId());
SkinImpl skin = cache.get(id.getId());
return !skin.isExpired();
}
public Skin getFullyCachedByName(String s) {
public SkinImpl getFullyCachedByName(String s) {
String name = s.toLowerCase();
if (!idCache.containsKey(name)) return null;
CachedId id = idCache.get(name);
if (id.isExpired() || !cache.containsKey(id.getId())) return null;
Skin skin = cache.get(id.getId());
SkinImpl skin = cache.get(id.getId());
if (skin.isExpired()) return null;
return skin;
}
public CompletableFuture<Skin> fetchByUUID(String uuid) {
public CompletableFuture<SkinImpl> fetchByUUID(String uuid) {
Player player = Bukkit.getPlayer(uuid);
if (player != null && player.isOnline()) return CompletableFuture.completedFuture(getFromPlayer(player));
if (cache.containsKey(uuid)) {
Skin skin = cache.get(uuid);
SkinImpl skin = cache.get(uuid);
if (!skin.isExpired()) return CompletableFuture.completedFuture(skin);
}
@ -179,7 +179,7 @@ public class MojangSkinCache {
try (Reader reader = new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8)) {
JsonObject obj = JsonParser.parseReader(reader).getAsJsonObject();
if (obj.has("errorMessage")) return null;
Skin skin = new Skin(obj);
SkinImpl skin = new SkinImpl(obj);
cache.put(uuid, skin);
return skin;
}
@ -195,12 +195,12 @@ public class MojangSkinCache {
});
}
public Skin getFromPlayer(Player player) {
public SkinImpl getFromPlayer(Player player) {
try {
Object playerHandle = Reflections.GET_PLAYER_HANDLE_METHOD.get().invoke(player);
Object gameProfile = Reflections.GET_PROFILE_METHOD.get().invoke(playerHandle);
Object propertyMap = Reflections.GET_PROPERTY_MAP_METHOD.get().invoke(gameProfile);
return new Skin(propertyMap);
return new SkinImpl(propertyMap);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}

@ -2,7 +2,7 @@ package lol.pyr.znpcsplus.skin.descriptor;
import lol.pyr.znpcsplus.api.skin.SkinDescriptor;
import lol.pyr.znpcsplus.skin.BaseSkinDescriptor;
import lol.pyr.znpcsplus.skin.Skin;
import lol.pyr.znpcsplus.skin.SkinImpl;
import lol.pyr.znpcsplus.skin.cache.MojangSkinCache;
import lol.pyr.znpcsplus.util.PapiUtil;
import org.bukkit.entity.Player;
@ -19,12 +19,12 @@ public class FetchingDescriptor implements BaseSkinDescriptor, SkinDescriptor {
}
@Override
public CompletableFuture<Skin> fetch(Player player) {
public CompletableFuture<SkinImpl> fetch(Player player) {
return skinCache.fetchByName(PapiUtil.set(player, name));
}
@Override
public Skin fetchInstant(Player player) {
public SkinImpl fetchInstant(Player player) {
return skinCache.getFullyCachedByName(PapiUtil.set(player, name));
}

@ -2,7 +2,7 @@ package lol.pyr.znpcsplus.skin.descriptor;
import lol.pyr.znpcsplus.api.skin.SkinDescriptor;
import lol.pyr.znpcsplus.skin.BaseSkinDescriptor;
import lol.pyr.znpcsplus.skin.Skin;
import lol.pyr.znpcsplus.skin.SkinImpl;
import lol.pyr.znpcsplus.skin.cache.MojangSkinCache;
import org.bukkit.entity.Player;
@ -16,12 +16,12 @@ public class MirrorDescriptor implements BaseSkinDescriptor, SkinDescriptor {
}
@Override
public CompletableFuture<Skin> fetch(Player player) {
public CompletableFuture<SkinImpl> fetch(Player player) {
return CompletableFuture.completedFuture(skinCache.getFromPlayer(player));
}
@Override
public Skin fetchInstant(Player player) {
public SkinImpl fetchInstant(Player player) {
return skinCache.getFromPlayer(player);
}

@ -3,7 +3,7 @@ package lol.pyr.znpcsplus.skin.descriptor;
import com.github.retrooper.packetevents.protocol.player.TextureProperty;
import lol.pyr.znpcsplus.api.skin.SkinDescriptor;
import lol.pyr.znpcsplus.skin.BaseSkinDescriptor;
import lol.pyr.znpcsplus.skin.Skin;
import lol.pyr.znpcsplus.skin.SkinImpl;
import lol.pyr.znpcsplus.skin.cache.MojangSkinCache;
import org.bukkit.entity.Player;
@ -11,9 +11,9 @@ import java.net.URL;
import java.util.concurrent.CompletableFuture;
public class PrefetchedDescriptor implements BaseSkinDescriptor, SkinDescriptor {
private final Skin skin;
private final SkinImpl skin;
public PrefetchedDescriptor(Skin skin) {
public PrefetchedDescriptor(SkinImpl skin) {
this.skin = skin;
}
@ -26,12 +26,12 @@ public class PrefetchedDescriptor implements BaseSkinDescriptor, SkinDescriptor
}
@Override
public CompletableFuture<Skin> fetch(Player player) {
public CompletableFuture<SkinImpl> fetch(Player player) {
return CompletableFuture.completedFuture(skin);
}
@Override
public Skin fetchInstant(Player player) {
public SkinImpl fetchInstant(Player player) {
return skin;
}
@ -40,7 +40,7 @@ public class PrefetchedDescriptor implements BaseSkinDescriptor, SkinDescriptor
return true;
}
public Skin getSkin() {
public SkinImpl getSkin() {
return skin;
}