2020-04-18 06:24:29 +02:00
|
|
|
package net.citizensnpcs.trait;
|
|
|
|
|
2021-01-10 16:52:24 +01:00
|
|
|
import com.google.common.base.Charsets;
|
2020-04-18 20:07:03 +02:00
|
|
|
import com.google.common.base.Preconditions;
|
2021-01-10 16:52:24 +01:00
|
|
|
import com.google.common.io.BaseEncoding;
|
2020-04-18 20:07:03 +02:00
|
|
|
|
|
|
|
import net.citizensnpcs.Settings.Setting;
|
|
|
|
import net.citizensnpcs.api.npc.NPC;
|
2020-04-18 06:24:29 +02:00
|
|
|
import net.citizensnpcs.api.persistence.Persist;
|
|
|
|
import net.citizensnpcs.api.trait.Trait;
|
|
|
|
import net.citizensnpcs.api.trait.TraitName;
|
2020-12-28 03:39:56 +01:00
|
|
|
import net.citizensnpcs.api.util.DataKey;
|
|
|
|
import net.citizensnpcs.api.util.Placeholders;
|
2020-04-18 20:07:03 +02:00
|
|
|
import net.citizensnpcs.npc.skin.SkinnableEntity;
|
2020-12-28 03:39:56 +01:00
|
|
|
import net.md_5.bungee.api.ChatColor;
|
2020-04-18 06:24:29 +02:00
|
|
|
|
|
|
|
@TraitName("skintrait")
|
|
|
|
public class SkinTrait extends Trait {
|
|
|
|
@Persist
|
|
|
|
private boolean fetchDefaultSkin = true;
|
2020-12-28 03:39:56 +01:00
|
|
|
private String filledPlaceholder;
|
2020-04-18 20:07:03 +02:00
|
|
|
@Persist
|
|
|
|
private String signature;
|
|
|
|
@Persist
|
|
|
|
private String skinName;
|
|
|
|
@Persist
|
|
|
|
private String textureRaw;
|
2020-12-28 03:39:56 +01:00
|
|
|
private int timer;
|
2020-04-18 20:07:03 +02:00
|
|
|
@Persist
|
|
|
|
private boolean updateSkins = Setting.NPC_SKIN_USE_LATEST.asBoolean();
|
2020-04-18 06:24:29 +02:00
|
|
|
|
|
|
|
public SkinTrait() {
|
|
|
|
super("skintrait");
|
|
|
|
}
|
|
|
|
|
2020-12-28 03:39:56 +01:00
|
|
|
private void checkPlaceholder(boolean update) {
|
2020-12-29 07:25:12 +01:00
|
|
|
if (skinName == null)
|
|
|
|
return;
|
2020-12-28 03:39:56 +01:00
|
|
|
String filled = ChatColor.stripColor(Placeholders.replace(skinName, null, npc).toLowerCase());
|
|
|
|
if (!filled.equalsIgnoreCase(skinName)) {
|
|
|
|
filledPlaceholder = filled;
|
|
|
|
if (update) {
|
|
|
|
onSkinChange(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-18 20:43:08 +02:00
|
|
|
/**
|
|
|
|
* Clears skin texture and name.
|
|
|
|
*/
|
2020-04-18 20:07:03 +02:00
|
|
|
public void clearTexture() {
|
|
|
|
textureRaw = null;
|
|
|
|
signature = null;
|
|
|
|
skinName = null;
|
|
|
|
}
|
|
|
|
|
2020-04-18 20:43:08 +02:00
|
|
|
/**
|
|
|
|
* Whether to fetch the Mojang skin using the NPC's name on spawn.
|
|
|
|
*/
|
2020-04-18 06:24:29 +02:00
|
|
|
public boolean fetchDefaultSkin() {
|
|
|
|
return fetchDefaultSkin;
|
|
|
|
}
|
|
|
|
|
2020-04-18 20:43:08 +02:00
|
|
|
/**
|
|
|
|
* @return The texture signature, or null
|
|
|
|
*/
|
2020-04-18 20:07:03 +02:00
|
|
|
public String getSignature() {
|
|
|
|
return signature;
|
|
|
|
}
|
|
|
|
|
2020-04-18 20:43:08 +02:00
|
|
|
/**
|
|
|
|
* @return The skin name if set, or null (i.e. using the NPC's name)
|
|
|
|
*/
|
2020-04-18 20:07:03 +02:00
|
|
|
public String getSkinName() {
|
2020-12-28 03:39:56 +01:00
|
|
|
return filledPlaceholder != null && skinName != null ? filledPlaceholder : skinName;
|
2020-04-18 20:07:03 +02:00
|
|
|
}
|
|
|
|
|
2020-04-18 20:43:08 +02:00
|
|
|
/**
|
|
|
|
* @return The encoded texture data, or null
|
|
|
|
*/
|
2020-04-18 20:07:03 +02:00
|
|
|
public String getTexture() {
|
|
|
|
return textureRaw;
|
|
|
|
}
|
|
|
|
|
2020-12-28 03:39:56 +01:00
|
|
|
@Override
|
|
|
|
public void load(DataKey key) {
|
|
|
|
checkPlaceholder(false);
|
|
|
|
}
|
|
|
|
|
2020-04-18 20:07:03 +02:00
|
|
|
@SuppressWarnings("deprecation")
|
|
|
|
private void migrate() {
|
|
|
|
boolean update = false;
|
|
|
|
if (npc.data().has(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_METADATA)) {
|
|
|
|
textureRaw = npc.data().get(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_METADATA);
|
|
|
|
npc.data().remove(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_METADATA);
|
|
|
|
update = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
if (npc.data().has(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_SIGN_METADATA)) {
|
|
|
|
signature = npc.data().get(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_SIGN_METADATA);
|
|
|
|
npc.data().remove(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_SIGN_METADATA);
|
|
|
|
update = true;
|
|
|
|
}
|
|
|
|
if (npc.data().has(NPC.PLAYER_SKIN_UUID_METADATA)) {
|
|
|
|
this.skinName = npc.data().get(NPC.PLAYER_SKIN_UUID_METADATA);
|
|
|
|
npc.data().remove(NPC.PLAYER_SKIN_UUID_METADATA);
|
|
|
|
update = true;
|
|
|
|
}
|
|
|
|
if (npc.data().has(NPC.PLAYER_SKIN_USE_LATEST)) {
|
|
|
|
this.updateSkins = npc.data().get(NPC.PLAYER_SKIN_USE_LATEST);
|
|
|
|
npc.data().remove(NPC.PLAYER_SKIN_USE_LATEST);
|
|
|
|
}
|
|
|
|
if (update) {
|
|
|
|
onSkinChange(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void onSkinChange(boolean forceUpdate) {
|
|
|
|
if (npc.isSpawned() && npc.getEntity() instanceof SkinnableEntity) {
|
|
|
|
((SkinnableEntity) npc.getEntity()).getSkinTracker().notifySkinChange(forceUpdate);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
migrate();
|
2020-12-28 03:39:56 +01:00
|
|
|
if (timer-- > 0)
|
|
|
|
return;
|
|
|
|
timer = Setting.PLACEHOLDER_SKIN_UPDATE_FREQUENCY.asInt();
|
|
|
|
if (filledPlaceholder == null)
|
|
|
|
return;
|
|
|
|
checkPlaceholder(true);
|
2020-04-18 20:07:03 +02:00
|
|
|
}
|
|
|
|
|
2020-04-18 20:43:08 +02:00
|
|
|
/**
|
|
|
|
* @see #fetchDefaultSkin
|
|
|
|
*/
|
2020-04-18 06:24:29 +02:00
|
|
|
public void setFetchDefaultSkin(boolean fetch) {
|
|
|
|
this.fetchDefaultSkin = fetch;
|
|
|
|
}
|
2020-04-18 20:07:03 +02:00
|
|
|
|
2020-04-18 20:43:08 +02:00
|
|
|
/**
|
|
|
|
* @see #shouldUpdateSkins()
|
|
|
|
*/
|
2020-04-18 20:07:03 +02:00
|
|
|
public void setShouldUpdateSkins(boolean update) {
|
|
|
|
this.updateSkins = update;
|
|
|
|
}
|
|
|
|
|
2020-04-18 20:43:08 +02:00
|
|
|
/**
|
|
|
|
* Sets the skin name - will respawn NPC if spawned.
|
|
|
|
*
|
|
|
|
* @param name
|
|
|
|
* The skin name
|
|
|
|
*/
|
2020-04-18 20:07:03 +02:00
|
|
|
public void setSkinName(String name) {
|
|
|
|
setSkinName(name, false);
|
|
|
|
}
|
|
|
|
|
2020-04-18 20:43:08 +02:00
|
|
|
/**
|
|
|
|
* Sets the skin name - will respawn NPC if spawned.
|
|
|
|
*
|
|
|
|
* @param name
|
|
|
|
* The skin name
|
|
|
|
* @param forceUpdate
|
|
|
|
* Whether to force update if no data has been fetched yet
|
|
|
|
* @see net.citizensnpcs.npc.skin.Skin#get(SkinnableEntity, boolean)
|
|
|
|
*/
|
2020-04-18 20:07:03 +02:00
|
|
|
public void setSkinName(String name, boolean forceUpdate) {
|
|
|
|
Preconditions.checkNotNull(name);
|
2020-12-28 03:39:56 +01:00
|
|
|
setSkinNameInternal(name);
|
2020-04-18 20:07:03 +02:00
|
|
|
onSkinChange(forceUpdate);
|
|
|
|
}
|
|
|
|
|
2020-12-28 03:39:56 +01:00
|
|
|
private void setSkinNameInternal(String name) {
|
|
|
|
skinName = ChatColor.stripColor(name.toLowerCase());
|
|
|
|
checkPlaceholder(false);
|
|
|
|
String filled = ChatColor.stripColor(Placeholders.replace(skinName, null, npc).toLowerCase());
|
|
|
|
if (!filled.equalsIgnoreCase(skinName)) {
|
|
|
|
filledPlaceholder = filled;
|
|
|
|
} else {
|
|
|
|
filledPlaceholder = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-18 20:43:08 +02:00
|
|
|
/**
|
|
|
|
* Sets the skin data directly, respawning the NPC if spawned
|
|
|
|
*
|
|
|
|
* @param skinName
|
2020-04-29 13:18:16 +02:00
|
|
|
* Skin name, for caching purposes
|
2020-04-18 20:43:08 +02:00
|
|
|
* @param signature
|
|
|
|
* {@link #getSignature()}
|
|
|
|
* @param data
|
|
|
|
* {@link #getTexture()}
|
|
|
|
*/
|
2020-04-18 20:07:03 +02:00
|
|
|
public void setSkinPersistent(String skinName, String signature, String data) {
|
|
|
|
Preconditions.checkNotNull(skinName);
|
|
|
|
Preconditions.checkNotNull(signature);
|
|
|
|
Preconditions.checkNotNull(data);
|
|
|
|
|
2020-12-28 03:39:56 +01:00
|
|
|
setSkinNameInternal(skinName);
|
2021-01-10 16:52:24 +01:00
|
|
|
String json = new String(BaseEncoding.base64().decode(textureRaw), Charsets.UTF_8);
|
|
|
|
if (!json.contains("textures")) {
|
|
|
|
throw new IllegalArgumentException("Invalid texture data");
|
|
|
|
}
|
2020-04-18 20:07:03 +02:00
|
|
|
this.signature = signature;
|
|
|
|
this.textureRaw = data;
|
|
|
|
this.updateSkins = false;
|
|
|
|
npc.data().setPersistent("cached-skin-uuid-name", skinName.toLowerCase());
|
|
|
|
onSkinChange(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setTexture(String value, String signature) {
|
|
|
|
this.textureRaw = value;
|
|
|
|
this.signature = signature;
|
|
|
|
}
|
|
|
|
|
2020-04-18 20:43:08 +02:00
|
|
|
/**
|
|
|
|
* @return Whether the skin should be updated from Mojang periodically
|
|
|
|
*/
|
2020-04-18 20:07:03 +02:00
|
|
|
public boolean shouldUpdateSkins() {
|
|
|
|
return updateSkins;
|
|
|
|
}
|
2020-04-18 06:24:29 +02:00
|
|
|
}
|