Fix mineskin API calls and hologram name height

This commit is contained in:
fullwall 2023-03-29 18:32:47 +08:00
parent 9b7a6e0a65
commit e8a5a1ceb4
5 changed files with 62 additions and 28 deletions

View File

@ -94,6 +94,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
private Settings config;
private boolean enabled;
private LocationLookup locationLookup;
private final NMSHelper nmsHelper = new NMSHelper() {
private boolean SUPPORT_OWNER_PROFILE = true;
@ -555,7 +556,6 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
private void startMetrics() {
try {
Metrics metrics = new Metrics(this, 2463);
metrics.addCustomChart(new Metrics.SingleLineChart("total_npcs", new Callable<Integer>() {
@Override
public Integer call() {

View File

@ -2604,12 +2604,12 @@ public class NPCCommands {
@Command(
aliases = { "npc" },
usage = "skin (-c(lear) -l(atest)) [name] (or --url [url] --file [file] or -t [uuid/name] [data] [signature])",
usage = "skin (-c(lear) -l(atest)) [name] (or --url [url] --file [file] (-s(lim)) 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",
modifiers = { "skin" },
min = 1,
max = 4,
flags = "ctl",
flags = "ctls",
permission = "citizens.npc.skin")
@Requirements(types = EntityType.PLAYER, selected = true, ownership = true)
public void skin(final CommandContext args, final CommandSender sender, final NPC npc, @Flag("url") String url,
@ -2619,21 +2619,23 @@ public class NPCCommands {
if (args.hasFlag('c')) {
trait.clearTexture();
} else if (url != null || file != null) {
Messaging.sendErrorTr(sender, Messages.FETCHING_SKIN, file);
Messaging.sendTr(sender, Messages.FETCHING_SKIN, file);
Bukkit.getScheduler().runTaskAsynchronously(CitizensAPI.getPlugin(), () -> {
try {
JSONObject data = null;
if (file != null) {
File skin = new File(new File(CitizensAPI.getDataFolder(), "skins"), file);
if (!skin.exists()
|| !skin.getParentFile().equals(new File(CitizensAPI.getDataFolder(), "skins"))) {
File skinsFolder = new File(CitizensAPI.getDataFolder(), "skins");
File skin = new File(skinsFolder, file);
if (!skin.exists() || !skin.isFile() || skin.isHidden()
|| !skin.getParentFile().equals(skinsFolder)) {
Bukkit.getScheduler().runTask(CitizensAPI.getPlugin(),
() -> Messaging.sendErrorTr(sender, Messages.INVALID_SKIN_FILE, file));
return;
}
data = MojangSkinGenerator.generateFromPNG(Files.readAllBytes(skin.toPath()));
data = MojangSkinGenerator.generateFromPNG(Files.readAllBytes(skin.toPath()),
args.hasFlag('s'));
} else {
MojangSkinGenerator.generateFromURL(url);
data = MojangSkinGenerator.generateFromURL(url, args.hasFlag('s'));
}
String uuid = (String) data.get("uuid");
JSONObject texture = (JSONObject) data.get("texture");
@ -2642,17 +2644,17 @@ public class NPCCommands {
Bukkit.getScheduler().runTask(CitizensAPI.getPlugin(), () -> {
try {
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 == null ? file : url);
} catch (IllegalArgumentException e) {
Messaging.sendErrorTr(sender, Messages.ERROR_SETTING_SKIN_URL, url);
Messaging.sendErrorTr(sender, Messages.ERROR_SETTING_SKIN_URL, url == null ? file : url);
}
});
} catch (Throwable t) {
if (Messaging.isDebugging()) {
t.printStackTrace();
}
Bukkit.getScheduler().runTask(CitizensAPI.getPlugin(),
() -> Messaging.sendErrorTr(sender, Messages.ERROR_SETTING_SKIN_URL, url));
Bukkit.getScheduler().runTask(CitizensAPI.getPlugin(), () -> Messaging.sendErrorTr(sender,
Messages.ERROR_SETTING_SKIN_URL, url == null ? file : url));
}
});
return;

View File

@ -110,6 +110,7 @@ public class HologramTrait extends Trait {
if (useTextDisplay) {
((TextDisplay) hologramNPC.getEntity()).setBillboard(Billboard.CENTER);
((TextDisplay) hologramNPC.getEntity()).setInterpolationDelay(0);
}
Matcher itemMatcher = ITEM_MATCHER.matcher(line);
@ -143,14 +144,11 @@ public class HologramTrait extends Trait {
}
private double getEntityHeight() {
return NMS.getHeight(npc.getEntity());
return NMS.getHeight(npc.getEntity()) + (useTextDisplay ? 0.27 : 0);
}
private double getHeight(int lineNumber) {
double base = (lastNameplateVisible ? 0 : -getLineHeight());
if (useTextDisplay) {
base += 0.27;
}
for (int i = 0; i <= lineNumber; i++) {
HologramLine line = lines.get(i);
base += line.mb + getLineHeight();

View File

@ -54,11 +54,7 @@ public class MoneyAction extends NPCShopAction {
Player player = (Player) entity;
return Transaction.create(() -> {
return economy.has(player, money);
}, () -> {
economy.withdrawPlayer(player, money);
}, () -> {
economy.depositPlayer(player, money);
});
}, () -> economy.withdrawPlayer(player, money), () -> economy.depositPlayer(player, money));
}
public static class MoneyActionGUI implements GUI {

View File

@ -6,7 +6,6 @@ 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;
@ -14,28 +13,49 @@ import java.util.concurrent.Executors;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import com.google.common.io.CharStreams;
import net.citizensnpcs.api.util.Messaging;
public class MojangSkinGenerator {
public static JSONObject generateFromPNG(final byte[] png) throws InterruptedException, ExecutionException {
public static JSONObject generateFromPNG(final byte[] png, boolean slim)
throws InterruptedException, ExecutionException {
return EXECUTOR.submit(() -> {
DataOutputStream out = null;
BufferedReader reader = null;
try {
URL target = new URL("https://api.mineskin.org/generate/upload");
URL target = new URL("https://api.mineskin.org/generate/upload" + (slim ? "?model=slim" : ""));
HttpURLConnection con = (HttpURLConnection) target.openConnection();
con.setRequestMethod("POST");
con.setDoOutput(true);
con.setRequestProperty("User-Agent", "Citizens/2.0");
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.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\"skin.png\"\r\n");
out.writeBytes("Content-Type: image/png\r\n\r\n");
out.write(png);
out.writeBytes("\r\n");
out.writeBytes("--*****\r\n");
out.writeBytes("Content-Disposition: form-data; name=\"name\";\r\n\r\n\r\n");
if (slim) {
out.writeBytes("--*****\r\n");
out.writeBytes("Content-Disposition: form-data; name=\"variant\";\r\n\r\n");
out.writeBytes("slim\r\n");
}
out.writeBytes("--*****--\r\n");
out.flush();
out.close();
if (con.getResponseCode() != 200) {
if (Messaging.isDebugging()) {
reader = new BufferedReader(new InputStreamReader(con.getErrorStream()));
Messaging.log(new String(CharStreams.toString(reader)));
}
return null;
}
reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
JSONObject output = (JSONObject) new JSONParser().parse(reader);
JSONObject data = (JSONObject) output.get("data");
@ -58,7 +78,8 @@ public class MojangSkinGenerator {
}).get();
}
public static JSONObject generateFromURL(final String url) throws InterruptedException, ExecutionException {
public static JSONObject generateFromURL(final String url, boolean slim)
throws InterruptedException, ExecutionException {
return EXECUTOR.submit(() -> {
DataOutputStream out = null;
BufferedReader reader = null;
@ -67,11 +88,28 @@ public class MojangSkinGenerator {
HttpURLConnection con = (HttpURLConnection) target.openConnection();
con.setRequestMethod("POST");
con.setDoOutput(true);
con.setRequestProperty("User-Agent", "Citizens/2.0");
con.setRequestProperty("Cache-Control", "no-cache");
con.setRequestProperty("Accept", "application/json");
con.setRequestProperty("Content-Type", "application/json");
con.setConnectTimeout(1000);
con.setReadTimeout(30000);
out = new DataOutputStream(con.getOutputStream());
out.writeBytes("url=" + URLEncoder.encode(url, "UTF-8"));
JSONObject req = new JSONObject();
req.put("url", url);
req.put("name", "");
if (slim) {
req.put("variant", "slim");
}
out.writeBytes(req.toJSONString().replace("\\", ""));
out.close();
if (con.getResponseCode() != 200) {
if (Messaging.isDebugging()) {
reader = new BufferedReader(new InputStreamReader(con.getErrorStream()));
Messaging.log(new String(CharStreams.toString(reader)));
}
return null;
}
reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
JSONObject output = (JSONObject) new JSONParser().parse(reader);
JSONObject data = (JSONObject) output.get("data");