mirror of
https://github.com/CitizensDev/Citizens2.git
synced 2024-11-26 12:46:04 +01:00
Add /npc skin --file
This commit is contained in:
parent
c171e3f29b
commit
f29780874d
@ -415,6 +415,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
|
|||||||
return new ShopTrait(shops);
|
return new ShopTrait(shops);
|
||||||
}));
|
}));
|
||||||
selector = new NPCSelector(this);
|
selector = new NPCSelector(this);
|
||||||
|
|
||||||
Bukkit.getPluginManager().registerEvents(new EventListen(storedRegistries), this);
|
Bukkit.getPluginManager().registerEvents(new EventListen(storedRegistries), this);
|
||||||
Bukkit.getPluginManager().registerEvents(new Placeholders(), this);
|
Bukkit.getPluginManager().registerEvents(new Placeholders(), this);
|
||||||
Placeholders.registerNPCPlaceholder(Pattern.compile("command_[a-zA-Z_0-9]+"), (npc, sender, input) -> {
|
Placeholders.registerNPCPlaceholder(Pattern.compile("command_[a-zA-Z_0-9]+"), (npc, sender, input) -> {
|
||||||
|
@ -1,12 +1,7 @@
|
|||||||
package net.citizensnpcs.commands;
|
package net.citizensnpcs.commands;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.File;
|
||||||
import java.io.DataOutputStream;
|
import java.nio.file.Files;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -43,7 +38,6 @@ import org.bukkit.entity.Zombie;
|
|||||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.json.simple.JSONObject;
|
import org.json.simple.JSONObject;
|
||||||
import org.json.simple.parser.JSONParser;
|
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
@ -148,6 +142,7 @@ import net.citizensnpcs.trait.WolfModifiers;
|
|||||||
import net.citizensnpcs.trait.waypoint.Waypoints;
|
import net.citizensnpcs.trait.waypoint.Waypoints;
|
||||||
import net.citizensnpcs.util.Anchor;
|
import net.citizensnpcs.util.Anchor;
|
||||||
import net.citizensnpcs.util.Messages;
|
import net.citizensnpcs.util.Messages;
|
||||||
|
import net.citizensnpcs.util.MojangSkinGenerator;
|
||||||
import net.citizensnpcs.util.NMS;
|
import net.citizensnpcs.util.NMS;
|
||||||
import net.citizensnpcs.util.PlayerAnimation;
|
import net.citizensnpcs.util.PlayerAnimation;
|
||||||
import net.citizensnpcs.util.StringHelper;
|
import net.citizensnpcs.util.StringHelper;
|
||||||
@ -2609,7 +2604,7 @@ public class NPCCommands {
|
|||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
aliases = { "npc" },
|
aliases = { "npc" },
|
||||||
usage = "skin (-c(lear) -l(atest)) [name] (or --url [url] or -t [uuid/name] [data] [signature])",
|
usage = "skin (-c(lear) -l(atest)) [name] (or --url [url] --file [file] or -t [uuid/name] [data] [signature])",
|
||||||
desc = "Sets an NPC's skin name. Use -l to set the skin to always update to the latest",
|
desc = "Sets an NPC's skin name. Use -l to set the skin to always update to the latest",
|
||||||
modifiers = { "skin" },
|
modifiers = { "skin" },
|
||||||
min = 1,
|
min = 1,
|
||||||
@ -2617,74 +2612,49 @@ public class NPCCommands {
|
|||||||
flags = "ctl",
|
flags = "ctl",
|
||||||
permission = "citizens.npc.skin")
|
permission = "citizens.npc.skin")
|
||||||
@Requirements(types = EntityType.PLAYER, selected = true, ownership = true)
|
@Requirements(types = EntityType.PLAYER, selected = true, ownership = true)
|
||||||
public void skin(final CommandContext args, final CommandSender sender, final NPC npc, @Flag("url") String url)
|
public void skin(final CommandContext args, final CommandSender sender, final NPC npc, @Flag("url") String url,
|
||||||
throws CommandException {
|
@Flag("file") String file) throws CommandException {
|
||||||
String skinName = npc.getName();
|
String skinName = npc.getName();
|
||||||
final SkinTrait trait = npc.getOrAddTrait(SkinTrait.class);
|
final SkinTrait trait = npc.getOrAddTrait(SkinTrait.class);
|
||||||
if (args.hasFlag('c')) {
|
if (args.hasFlag('c')) {
|
||||||
trait.clearTexture();
|
trait.clearTexture();
|
||||||
} else if (url != null) {
|
} else if (url != null || file != null) {
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(CitizensAPI.getPlugin(), new Runnable() {
|
Messaging.sendErrorTr(sender, Messages.FETCHING_SKIN, file);
|
||||||
@Override
|
Bukkit.getScheduler().runTaskAsynchronously(CitizensAPI.getPlugin(), () -> {
|
||||||
public void run() {
|
|
||||||
DataOutputStream out = null;
|
|
||||||
BufferedReader reader = null;
|
|
||||||
try {
|
try {
|
||||||
URL target = new URL("https://api.mineskin.org/generate/url");
|
JSONObject data = null;
|
||||||
HttpURLConnection con = (HttpURLConnection) target.openConnection();
|
if (file != null) {
|
||||||
con.setRequestMethod("POST");
|
File skin = new File(new File(CitizensAPI.getDataFolder(), "skins"), file);
|
||||||
con.setDoOutput(true);
|
if (!skin.exists()
|
||||||
con.setConnectTimeout(1000);
|
|| !skin.getParentFile().equals(new File(CitizensAPI.getDataFolder(), "skins"))) {
|
||||||
con.setReadTimeout(30000);
|
Bukkit.getScheduler().runTask(CitizensAPI.getPlugin(),
|
||||||
out = new DataOutputStream(con.getOutputStream());
|
() -> Messaging.sendErrorTr(sender, Messages.INVALID_SKIN_FILE, file));
|
||||||
out.writeBytes("url=" + URLEncoder.encode(url, "UTF-8"));
|
return;
|
||||||
out.close();
|
}
|
||||||
reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
|
data = MojangSkinGenerator.generateFromPNG(Files.readAllBytes(skin.toPath()));
|
||||||
JSONObject output = (JSONObject) new JSONParser().parse(reader);
|
} else {
|
||||||
JSONObject data = (JSONObject) output.get("data");
|
MojangSkinGenerator.generateFromURL(url);
|
||||||
|
}
|
||||||
String uuid = (String) data.get("uuid");
|
String uuid = (String) data.get("uuid");
|
||||||
JSONObject texture = (JSONObject) data.get("texture");
|
JSONObject texture = (JSONObject) data.get("texture");
|
||||||
String textureEncoded = (String) texture.get("value");
|
String textureEncoded = (String) texture.get("value");
|
||||||
String signature = (String) texture.get("signature");
|
String signature = (String) texture.get("signature");
|
||||||
con.disconnect();
|
Bukkit.getScheduler().runTask(CitizensAPI.getPlugin(), () -> {
|
||||||
Bukkit.getScheduler().runTask(CitizensAPI.getPlugin(), new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
try {
|
||||||
trait.setSkinPersistent(uuid, signature, textureEncoded);
|
trait.setSkinPersistent(uuid, signature, textureEncoded);
|
||||||
Messaging.sendTr(sender, Messages.SKIN_URL_SET, npc.getName(), url);
|
Messaging.sendTr(sender, Messages.SKIN_URL_SET, npc.getName(), url);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
Messaging.sendErrorTr(sender, Messages.ERROR_SETTING_SKIN_URL, url);
|
Messaging.sendErrorTr(sender, Messages.ERROR_SETTING_SKIN_URL, url);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
if (Messaging.isDebugging()) {
|
if (Messaging.isDebugging()) {
|
||||||
t.printStackTrace();
|
t.printStackTrace();
|
||||||
}
|
}
|
||||||
Bukkit.getScheduler().runTask(CitizensAPI.getPlugin(), new Runnable() {
|
Bukkit.getScheduler().runTask(CitizensAPI.getPlugin(),
|
||||||
@Override
|
() -> Messaging.sendErrorTr(sender, Messages.ERROR_SETTING_SKIN_URL, url));
|
||||||
public void run() {
|
|
||||||
Messaging.sendErrorTr(sender, Messages.ERROR_SETTING_SKIN_URL, url);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} finally {
|
|
||||||
if (out != null) {
|
|
||||||
try {
|
|
||||||
out.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (reader != null) {
|
|
||||||
try {
|
|
||||||
reader.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
} else if (args.hasFlag('t')) {
|
} else if (args.hasFlag('t')) {
|
||||||
if (args.argsLength() != 4)
|
if (args.argsLength() != 4)
|
||||||
|
@ -114,6 +114,7 @@ public class Messages {
|
|||||||
public static final String FAILED_LOAD_SAVES = "citizens.saves.load-failed";
|
public static final String FAILED_LOAD_SAVES = "citizens.saves.load-failed";
|
||||||
public static final String FAILED_TO_MOUNT_NPC = "citizens.commands.npc.mount.failed";
|
public static final String FAILED_TO_MOUNT_NPC = "citizens.commands.npc.mount.failed";
|
||||||
public static final String FAILED_TO_REMOVE = "citizens.commands.trait.failed-to-remove";
|
public static final String FAILED_TO_REMOVE = "citizens.commands.trait.failed-to-remove";
|
||||||
|
public static final String FETCHING_SKIN = "citizens.commands.npc.skin.fetching";
|
||||||
public static final String FLYABLE_SET = "citizens.commands.npc.flyable.set";
|
public static final String FLYABLE_SET = "citizens.commands.npc.flyable.set";
|
||||||
public static final String FLYABLE_UNSET = "citizens.commands.npc.flyable.unset";
|
public static final String FLYABLE_UNSET = "citizens.commands.npc.flyable.unset";
|
||||||
public static final String FOLLOW_PLAYER_NOT_INGAME = "citizens.commands.npc.follow.player-not-ingame";
|
public static final String FOLLOW_PLAYER_NOT_INGAME = "citizens.commands.npc.follow.player-not-ingame";
|
||||||
@ -189,6 +190,7 @@ public class Messages {
|
|||||||
public static final String INVALID_SHEEP_COLOR = "citizens.commands.npc.sheep.invalid-color";
|
public static final String INVALID_SHEEP_COLOR = "citizens.commands.npc.sheep.invalid-color";
|
||||||
public static final String INVALID_SHULKER_COLOR = "citizens.commands.npc.shulker.invalid-color";
|
public static final String INVALID_SHULKER_COLOR = "citizens.commands.npc.shulker.invalid-color";
|
||||||
public static final String INVALID_SKELETON_TYPE = "citizens.commands.npc.skeletontype.invalid-type";
|
public static final String INVALID_SKELETON_TYPE = "citizens.commands.npc.skeletontype.invalid-type";
|
||||||
|
public static final String INVALID_SKIN_FILE = "citizens.commands.npc.skin.invalid-file";
|
||||||
public static final String INVALID_SOUND = "citizens.commands.npc.sound.invalid-sound";
|
public static final String INVALID_SOUND = "citizens.commands.npc.sound.invalid-sound";
|
||||||
public static final String INVALID_SPAWN_LOCATION = "citizens.commands.npc.create.invalid-location";
|
public static final String INVALID_SPAWN_LOCATION = "citizens.commands.npc.create.invalid-location";
|
||||||
public static final String INVALID_TRIGGER_TELEPORT_FORMAT = "citizens.editors.waypoints.triggers.teleport.invalid-format";
|
public static final String INVALID_TRIGGER_TELEPORT_FORMAT = "citizens.editors.waypoints.triggers.teleport.invalid-format";
|
||||||
|
@ -0,0 +1,98 @@
|
|||||||
|
package net.citizensnpcs.util;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
import org.json.simple.parser.JSONParser;
|
||||||
|
|
||||||
|
public class MojangSkinGenerator {
|
||||||
|
public static JSONObject generateFromPNG(final byte[] png) throws InterruptedException, ExecutionException {
|
||||||
|
return EXECUTOR.submit(() -> {
|
||||||
|
DataOutputStream out = null;
|
||||||
|
BufferedReader reader = null;
|
||||||
|
try {
|
||||||
|
URL target = new URL("https://api.mineskin.org/generate/upload");
|
||||||
|
HttpURLConnection con = (HttpURLConnection) target.openConnection();
|
||||||
|
con.setRequestMethod("POST");
|
||||||
|
con.setDoOutput(true);
|
||||||
|
con.setRequestProperty("Cache-Control", "no-cache");
|
||||||
|
con.setRequestProperty("Content-Type", "multipart/form-data;boundary=*****");
|
||||||
|
con.setConnectTimeout(1000);
|
||||||
|
con.setReadTimeout(30000);
|
||||||
|
out = new DataOutputStream(con.getOutputStream());
|
||||||
|
out.writeBytes("--*****\r\n");
|
||||||
|
out.writeBytes("Content-Disposition: form-data; name=\"skin.png\";filename=\"skin.png\"\r\n\r\n");
|
||||||
|
out.write(png);
|
||||||
|
out.writeBytes("\r\n");
|
||||||
|
out.writeBytes("--*****--\r\n");
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
|
||||||
|
JSONObject output = (JSONObject) new JSONParser().parse(reader);
|
||||||
|
JSONObject data = (JSONObject) output.get("data");
|
||||||
|
con.disconnect();
|
||||||
|
return data;
|
||||||
|
} finally {
|
||||||
|
if (out != null) {
|
||||||
|
try {
|
||||||
|
out.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (reader != null) {
|
||||||
|
try {
|
||||||
|
reader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JSONObject generateFromURL(final String url) throws InterruptedException, ExecutionException {
|
||||||
|
return EXECUTOR.submit(() -> {
|
||||||
|
DataOutputStream out = null;
|
||||||
|
BufferedReader reader = null;
|
||||||
|
try {
|
||||||
|
URL target = new URL("https://api.mineskin.org/generate/url");
|
||||||
|
HttpURLConnection con = (HttpURLConnection) target.openConnection();
|
||||||
|
con.setRequestMethod("POST");
|
||||||
|
con.setDoOutput(true);
|
||||||
|
con.setConnectTimeout(1000);
|
||||||
|
con.setReadTimeout(30000);
|
||||||
|
out = new DataOutputStream(con.getOutputStream());
|
||||||
|
out.writeBytes("url=" + URLEncoder.encode(url, "UTF-8"));
|
||||||
|
out.close();
|
||||||
|
reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
|
||||||
|
JSONObject output = (JSONObject) new JSONParser().parse(reader);
|
||||||
|
JSONObject data = (JSONObject) output.get("data");
|
||||||
|
con.disconnect();
|
||||||
|
return data;
|
||||||
|
} finally {
|
||||||
|
if (out != null) {
|
||||||
|
try {
|
||||||
|
out.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (reader != null) {
|
||||||
|
try {
|
||||||
|
reader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor();
|
||||||
|
}
|
@ -276,6 +276,8 @@ citizens.commands.npc.skin.error-setting-url=Error downloading skin texture from
|
|||||||
citizens.commands.npc.skin.skin-url-set=Downloaded [[{0}]]''s skin from [[{1}]].
|
citizens.commands.npc.skin.skin-url-set=Downloaded [[{0}]]''s skin from [[{1}]].
|
||||||
citizens.commands.npc.skin.set=[[{0}]]''s skin name set to [[{1}]].
|
citizens.commands.npc.skin.set=[[{0}]]''s skin name set to [[{1}]].
|
||||||
citizens.commands.npc.skin.missing-skin=A skin name is required.
|
citizens.commands.npc.skin.missing-skin=A skin name is required.
|
||||||
|
citizens.commands.npc.skin.fetching=Attempting to generate skin using https://mineskin.org
|
||||||
|
citizens.commands.npc.skin.invalid-file=Skin file [[{0}]] not found. Must be a file under plugins/Citizens2/skins/<file.png>
|
||||||
citizens.commands.npc.skin.cleared=[[{0}]]''s skin name was cleared.
|
citizens.commands.npc.skin.cleared=[[{0}]]''s skin name was cleared.
|
||||||
citizens.commands.npc.skin.layers-set=[[{0}]]''s skin layers: cape - [[{1}]], hat - [[{2}]], jacket - [[{3}]], sleeves - [[{4}]], pants - [[{5}]].
|
citizens.commands.npc.skin.layers-set=[[{0}]]''s skin layers: cape - [[{1}]], hat - [[{2}]], jacket - [[{3}]], sleeves - [[{4}]], pants - [[{5}]].
|
||||||
citizens.commands.npc.size.description=[[{0}]]''s size is [[{1}]].
|
citizens.commands.npc.size.description=[[{0}]]''s size is [[{1}]].
|
||||||
|
Loading…
Reference in New Issue
Block a user