diff --git a/logs/2023-06-28-1.log.gz b/logs/2023-06-28-1.log.gz
new file mode 100644
index 0000000..1423f84
Binary files /dev/null and b/logs/2023-06-28-1.log.gz differ
diff --git a/logs/2023-06-28-2.log.gz b/logs/2023-06-28-2.log.gz
new file mode 100644
index 0000000..fe90cdd
Binary files /dev/null and b/logs/2023-06-28-2.log.gz differ
diff --git a/pom.xml b/pom.xml
index f7515f3..13c384a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -44,8 +44,8 @@
-->
org.spigotmc
- spigot-api
- 1.19.4-R0.1-SNAPSHOT
+ spigot
+ 1.20.1-R0.1-SNAPSHOT
provided
diff --git a/src/main/java/xyz/atnrch/nicko/NickoBukkit.java b/src/main/java/xyz/atnrch/nicko/NickoBukkit.java
index ca4a53f..4b13b40 100644
--- a/src/main/java/xyz/atnrch/nicko/NickoBukkit.java
+++ b/src/main/java/xyz/atnrch/nicko/NickoBukkit.java
@@ -98,8 +98,10 @@ public class NickoBukkit extends JavaPlugin {
command.setExecutor(new NickoCommand());
}
- Structure.addGlobalIngredient('#', new SimpleItem(new ItemBuilder(Material.BLACK_STAINED_GLASS_PANE).setDisplayName(" ")));
- Structure.addGlobalIngredient('%', new SimpleItem(new ItemBuilder(Material.ORANGE_STAINED_GLASS_PANE).setDisplayName(" ")));
+ //new SimpleItem(new ItemBuilder(Material.BLACK_STAINED_GLASS_PANE).setDisplayName(" "))
+ //new SimpleItem(new ItemBuilder(Material.ORANGE_STAINED_GLASS_PANE).setDisplayName(" "))
+ Structure.addGlobalIngredient('#', new SimpleItem(new ItemBuilder(Material.AIR)));
+ Structure.addGlobalIngredient('%', new SimpleItem(new ItemBuilder(Material.AIR)));
Structure.addGlobalIngredient('U', new OptionUnavailable());
Structure.addGlobalIngredient('E', new ExitGUI());
diff --git a/src/main/java/xyz/atnrch/nicko/anvil/AnvilManager.java b/src/main/java/xyz/atnrch/nicko/anvil/AnvilManager.java
index 312b255..66f9611 100644
--- a/src/main/java/xyz/atnrch/nicko/anvil/AnvilManager.java
+++ b/src/main/java/xyz/atnrch/nicko/anvil/AnvilManager.java
@@ -39,7 +39,6 @@ public class AnvilManager {
public AnvilGUI.Builder getNameThenSkinAnvil() {
return new AnvilGUI.Builder()
.plugin(NickoBukkit.getInstance())
- .preventClose()
.itemLeft(getLeftItem(false))
.interactableSlots(AnvilGUI.Slot.OUTPUT)
.onClick((slot, snapshot) -> {
@@ -60,7 +59,6 @@ public class AnvilManager {
public AnvilGUI.Builder getNameAnvil() {
return new AnvilGUI.Builder()
.plugin(NickoBukkit.getInstance())
- .preventClose()
.itemLeft(getLeftItem(false))
.interactableSlots(AnvilGUI.Slot.OUTPUT)
.onClick((slot, snapshot) -> {
@@ -99,10 +97,12 @@ public class AnvilManager {
}
private List sendResultAndClose(ActionResult actionResult) {
+ final I18N i18n = new I18N(player);
if (!actionResult.isError()) {
- player.sendMessage(I18N.translate(player, I18NDict.Event.Disguise.SUCCESS));
+ player.sendMessage(i18n.translate(I18NDict.Event.Disguise.SUCCESS));
} else {
- player.sendMessage(I18N.translate(player, I18NDict.Event.Disguise.FAIL, I18N.translateWithoutPrefix(player, actionResult.getErrorMessage())));
+ // TODO (Ineanto, 6/28/23): Check weirdness with error message not being translated sometimes
+ player.sendMessage(i18n.translate(I18NDict.Event.Disguise.FAIL, i18n.translateWithoutPrefix(actionResult.getErrorKey())));
}
return Collections.singletonList(AnvilGUI.ResponseAction.close());
}
diff --git a/src/main/java/xyz/atnrch/nicko/command/sub/NickoCheckSubCmd.java b/src/main/java/xyz/atnrch/nicko/command/sub/NickoCheckSubCmd.java
index 438b5e8..451677f 100644
--- a/src/main/java/xyz/atnrch/nicko/command/sub/NickoCheckSubCmd.java
+++ b/src/main/java/xyz/atnrch/nicko/command/sub/NickoCheckSubCmd.java
@@ -14,10 +14,11 @@ public class NickoCheckSubCmd {
public void execute(Player player, String[] args) {
final String targetName = args[1];
final Player target = Bukkit.getPlayerExact(targetName);
+ final I18N i18n = new I18N(player);
AppearanceManager appearanceManager;
if (MojangUtils.isUsernameInvalid(targetName)) {
- player.sendMessage(I18N.translate(player, I18NDict.Error.INVALID_USERNAME));
+ player.sendMessage(i18n.translate(I18NDict.Error.INVALID_USERNAME));
return;
}
@@ -28,15 +29,16 @@ public class NickoCheckSubCmd {
}
final StringJoiner builder = new StringJoiner("\n");
- builder.add("§c" + NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§6Check for: §f§o" + targetName);
- if (!appearanceManager.hasData()) {
- builder.add("§cThis player has not data.");
+ builder.add("§c" + NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§cCheck for: §f§o" + targetName);
+ if (appearanceManager.hasData()) {
+ builder.add("§cNicked: §a✔");
+ builder.add("§cName: §6" + appearanceManager.getName());
+ builder.add("§cSkin: §6" + appearanceManager.getSkin());
} else {
- builder.add("§7- §fNicked: §a✔");
- builder.add("§7- §fName: §6" + appearanceManager.getName());
- builder.add("§7- §fSkin: §6" + appearanceManager.getSkin());
+ builder.add("§cNicked: §c❌");
+ builder.add("§cName: §7N/A");
+ builder.add("§cSkin: §7N/A");
}
-
player.sendMessage(builder.toString());
}
}
diff --git a/src/main/java/xyz/atnrch/nicko/disguise/ActionResult.java b/src/main/java/xyz/atnrch/nicko/disguise/ActionResult.java
index 0e84447..7906963 100644
--- a/src/main/java/xyz/atnrch/nicko/disguise/ActionResult.java
+++ b/src/main/java/xyz/atnrch/nicko/disguise/ActionResult.java
@@ -1,24 +1,22 @@
package xyz.atnrch.nicko.disguise;
-import xyz.atnrch.nicko.i18n.I18NDict;
-
public class ActionResult {
- private final I18NDict errorMessage;
+ private final String errorKey;
private boolean error = false;
private R result;
public ActionResult() {
- this.errorMessage = null;
+ this.errorKey = null;
}
- public ActionResult(I18NDict errorMessage) {
- this.errorMessage = errorMessage;
+ public ActionResult(String errorMessage) {
+ this.errorKey = errorMessage;
this.error = true;
this.result = null;
}
public ActionResult(R result) {
- this.errorMessage = null;
+ this.errorKey = null;
this.result = result;
}
@@ -30,7 +28,7 @@ public class ActionResult {
return error;
}
- public I18NDict getErrorMessage() {
- return errorMessage;
+ public String getErrorKey() {
+ return errorKey;
}
}
diff --git a/src/main/java/xyz/atnrch/nicko/disguise/AppearanceManager.java b/src/main/java/xyz/atnrch/nicko/disguise/AppearanceManager.java
index 282b3f5..6ad5e63 100644
--- a/src/main/java/xyz/atnrch/nicko/disguise/AppearanceManager.java
+++ b/src/main/java/xyz/atnrch/nicko/disguise/AppearanceManager.java
@@ -4,6 +4,7 @@ import com.comphenix.protocol.utility.MinecraftVersion;
import com.comphenix.protocol.wrappers.*;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap;
+import it.unimi.dsi.fastutil.ints.IntList;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Player;
@@ -14,9 +15,7 @@ import xyz.atnrch.nicko.mojang.MojangAPI;
import xyz.atnrch.nicko.mojang.MojangSkin;
import xyz.atnrch.nicko.storage.PlayerDataStore;
import xyz.atnrch.nicko.storage.name.PlayerNameStore;
-import xyz.atnrch.nicko.wrapper.WrapperPlayServerRespawn;
-import xyz.atnrch.nicko.wrapper.WrapperPlayerServerPlayerInfo;
-import xyz.atnrch.nicko.wrapper.WrapperPlayerServerPlayerInfoRemove;
+import xyz.atnrch.nicko.wrapper.*;
import java.io.IOException;
import java.util.EnumSet;
@@ -104,11 +103,25 @@ public class AppearanceManager {
updateMetadata();
updateTabList(gameProfile, displayName);
respawnPlayer();
+ updateOthers();
}
player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
return new ActionResult<>();
}
+ public void updateOthers() {
+ WrapperPlayServerEntityDestroy destroy = new WrapperPlayServerEntityDestroy();
+ WrapperPlayServerNamedEntitySpawn spawn = new WrapperPlayServerNamedEntitySpawn();
+ destroy.setEntityIds(IntList.of(player.getEntityId()));
+ spawn.setEntityId(player.getEntityId());
+ spawn.setLocation(player.getLocation());
+ spawn.setPlayerId(player.getUniqueId());
+ Bukkit.getOnlinePlayers().stream().filter(receiver -> receiver.getUniqueId() != player.getUniqueId()).forEach(receiver -> {
+ destroy.sendPacket(receiver);
+ spawn.sendPacket(receiver);
+ });
+ }
+
private ActionResult updateGameProfileSkin(WrappedGameProfile gameProfile, boolean skinChange) {
final boolean changeOnlyName = profile.getSkin() != null && !profile.getSkin().equalsIgnoreCase(player.getName());
@@ -154,7 +167,6 @@ public class AppearanceManager {
respawn.setCopyMetadata(true);
respawn.sendPacket(player);
player.setFlying(wasFlying);
- player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
player.updateInventory();
}
@@ -171,13 +183,13 @@ public class AppearanceManager {
EnumWrappers.PlayerInfoAction.UPDATE_GAME_MODE,
EnumWrappers.PlayerInfoAction.UPDATE_LATENCY);
remove.setUUIDs(ImmutableList.of(player.getUniqueId()));
- remove.sendPacket(player);
+ remove.broadcastPacket();
add.setActions(actions);
} else {
final WrapperPlayerServerPlayerInfo remove = new WrapperPlayerServerPlayerInfo();
remove.setActions(EnumSet.of(EnumWrappers.PlayerInfoAction.REMOVE_PLAYER));
add.setActions(EnumSet.of(EnumWrappers.PlayerInfoAction.ADD_PLAYER));
- remove.sendPacket(player);
+ remove.broadcastPacket();
}
// Yes, I skip providing chat session data.
@@ -194,6 +206,6 @@ public class AppearanceManager {
gameProfile,
WrappedChatComponent.fromText(displayName)
)));
- add.sendPacket(player);
+ add.broadcastPacket();
}
}
\ No newline at end of file
diff --git a/src/main/java/xyz/atnrch/nicko/event/PlayerJoinListener.java b/src/main/java/xyz/atnrch/nicko/event/PlayerJoinListener.java
index e56372e..1d09488 100644
--- a/src/main/java/xyz/atnrch/nicko/event/PlayerJoinListener.java
+++ b/src/main/java/xyz/atnrch/nicko/event/PlayerJoinListener.java
@@ -10,7 +10,6 @@ import xyz.atnrch.nicko.disguise.ActionResult;
import xyz.atnrch.nicko.disguise.AppearanceManager;
import xyz.atnrch.nicko.i18n.I18N;
import xyz.atnrch.nicko.i18n.I18NDict;
-import xyz.atnrch.nicko.storage.PlayerDataStore;
import xyz.atnrch.nicko.storage.name.PlayerNameStore;
public class PlayerJoinListener implements Listener {
@@ -18,20 +17,19 @@ public class PlayerJoinListener implements Listener {
public void onPlayerJoin(PlayerJoinEvent event) {
final Player player = event.getPlayer();
final NickoBukkit instance = NickoBukkit.getInstance();
-
- final PlayerDataStore dataStore = instance.getDataStore();
+ final I18N i18n = new I18N(player);
final PlayerNameStore nameStore = instance.getNameStore();
- nameStore.storeName(player);
- // TODO: 2/20/23 BungeeCord transfer
+ // TODO: 2/20/23 Fetch data from BungeeCord
+ nameStore.storeName(player);
Bukkit.getScheduler().runTaskLater(instance, () -> {
final AppearanceManager appearanceManager = AppearanceManager.get(player);
if (appearanceManager.hasData()) {
final ActionResult actionResult = appearanceManager.updatePlayer(appearanceManager.needsASkinChange());
if (!actionResult.isError()) {
- player.sendMessage(I18N.translate(player, I18NDict.Event.PreviousSkin.SUCCESS));
+ player.sendMessage(i18n.translate(I18NDict.Event.PreviousSkin.SUCCESS));
} else {
- player.sendMessage(I18N.translate(player, I18NDict.Event.PreviousSkin.FAIL, I18N.translateWithoutPrefix(player, actionResult.getErrorMessage())));
+ player.sendMessage(i18n.translate(I18NDict.Event.PreviousSkin.FAIL, i18n.translateWithoutPrefix(actionResult.getErrorKey())));
}
}
}, 20L);
diff --git a/src/main/java/xyz/atnrch/nicko/gui/items/admin/cache/InvalidateCompleteCache.java b/src/main/java/xyz/atnrch/nicko/gui/items/admin/cache/InvalidateCompleteCache.java
index 5ec26d3..9fef719 100644
--- a/src/main/java/xyz/atnrch/nicko/gui/items/admin/cache/InvalidateCompleteCache.java
+++ b/src/main/java/xyz/atnrch/nicko/gui/items/admin/cache/InvalidateCompleteCache.java
@@ -25,8 +25,9 @@ public class InvalidateCompleteCache extends SuppliedItem {
final ClickType clickType = click.getClickType();
if (clickType.isLeftClick() || clickType.isRightClick()) {
final Player player = click.getPlayer();
+ final I18N i18n = new I18N(player);
click.getEvent().getView().close();
- player.sendMessage(I18N.translate(player, I18NDict.Event.Admin.CACHE_CLEAN));
+ player.sendMessage(i18n.translate(I18NDict.Event.Admin.CACHE_CLEAN));
NickoBukkit.getInstance().getMojangAPI().getCache().invalidateAll();
return true;
}
diff --git a/src/main/java/xyz/atnrch/nicko/gui/items/main/ResetAppearance.java b/src/main/java/xyz/atnrch/nicko/gui/items/main/ResetAppearance.java
index fb380ec..eeb4246 100644
--- a/src/main/java/xyz/atnrch/nicko/gui/items/main/ResetAppearance.java
+++ b/src/main/java/xyz/atnrch/nicko/gui/items/main/ResetAppearance.java
@@ -18,21 +18,23 @@ public class ResetAppearance extends SuppliedItem {
return builder;
}, (event) -> {
final Player player = event.getPlayer();
+ final I18N i18n = new I18N(player);
+
final ClickType clickType = event.getClickType();
if (clickType.isLeftClick() || clickType.isRightClick()) {
final AppearanceManager appearanceManager = AppearanceManager.get(player);
if (!appearanceManager.hasData()) {
- player.sendMessage(I18N.translate(player, I18NDict.Event.Undisguise.NONE));
+ player.sendMessage(i18n.translate(I18NDict.Event.Undisguise.NONE));
event.getEvent().getView().close();
return true;
}
if (!appearanceManager.reset().isError()) {
- player.sendMessage(I18N.translate(player, I18NDict.Event.Undisguise.SUCCESS));
+ player.sendMessage(i18n.translate(I18NDict.Event.Undisguise.SUCCESS));
return true;
} else {
- player.sendMessage(I18N.translate(player, I18NDict.Event.Undisguise.FAIL));
+ player.sendMessage(i18n.translate(I18NDict.Event.Undisguise.FAIL));
return false;
}
}
diff --git a/src/main/java/xyz/atnrch/nicko/i18n/I18N.java b/src/main/java/xyz/atnrch/nicko/i18n/I18N.java
index 117f8c9..be3d1c7 100644
--- a/src/main/java/xyz/atnrch/nicko/i18n/I18N.java
+++ b/src/main/java/xyz/atnrch/nicko/i18n/I18N.java
@@ -11,8 +11,51 @@ import java.util.Optional;
public class I18N {
private final static MessageFormat formatter = new MessageFormat("");
+ private final Player player;
+ private final Locale playerLocale;
- private static Locale getLocale(Player player) {
+ public I18N(Player player) {
+ this.player = player;
+ this.playerLocale = getPlayerLocale();
+ }
+
+ public String translate(String key, Object... arguments) {
+ final NickoBukkit instance = NickoBukkit.getInstance();
+ final String string = readString(key);
+
+ try {
+ formatter.applyPattern(string);
+ return instance.getNickoConfig().getPrefix() + formatter.format(arguments);
+ } catch (Exception e) {
+ return instance.getNickoConfig().getPrefix() + key;
+ }
+ }
+
+ public String translateWithoutPrefix(String key, Object... arguments) {
+ final String translation = readString(key);
+ try {
+ formatter.applyPattern(translation);
+ return formatter.format(arguments);
+ } catch (Exception e) {
+ return key;
+ }
+ }
+
+ private String readString(String key) {
+ final NickoBukkit instance = NickoBukkit.getInstance();
+ String string;
+ if (playerLocale == Locale.CUSTOM) {
+ string = instance.getLocaleFileManager().get(key);
+ } else {
+ final InputStream resource = instance.getResource(playerLocale.getCode() + ".yml");
+ final YamlConfig yamlConfig = YamlConfig.load(resource);
+ string = yamlConfig.getString(key);
+ }
+
+ return string;
+ }
+
+ private Locale getPlayerLocale() {
final NickoBukkit instance = NickoBukkit.getInstance();
try {
final Optional profile = instance.getDataStore().getData(player.getUniqueId());
@@ -22,41 +65,4 @@ public class I18N {
return Locale.FALLBACK_LOCALE;
}
}
-
- public static String translate(Player player, I18NDict key, Object... arguments) {
- final NickoBukkit instance = NickoBukkit.getInstance();
- final String translation = findTranslation(player, key);
-
- try {
- formatter.applyPattern(translation);
- return instance.getNickoConfig().getPrefix() + formatter.format(arguments);
- } catch (Exception e) {
- return instance.getNickoConfig().getPrefix() + key.key();
- }
- }
-
- public static String translateWithoutPrefix(Player player, I18NDict key, Object... arguments) {
- final String translation = findTranslation(player, key);
- try {
- formatter.applyPattern(translation);
- return formatter.format(arguments);
- } catch (Exception e) {
- return key.key();
- }
- }
-
- private static String findTranslation(Player player, I18NDict key) {
- final NickoBukkit instance = NickoBukkit.getInstance();
- final Locale locale = getLocale(player);
- String translation;
- if (locale == Locale.CUSTOM) {
- translation = instance.getLocaleFileManager().get(key.key());
- } else {
- final InputStream resource = instance.getResource(locale.getCode() + ".yml");
- final YamlConfig yamlConfig = YamlConfig.load(resource);
- translation = yamlConfig.getString(key.key());
- }
-
- return translation;
- }
}
diff --git a/src/main/java/xyz/atnrch/nicko/i18n/I18NDict.java b/src/main/java/xyz/atnrch/nicko/i18n/I18NDict.java
index 6c3bd2c..894f129 100644
--- a/src/main/java/xyz/atnrch/nicko/i18n/I18NDict.java
+++ b/src/main/java/xyz/atnrch/nicko/i18n/I18NDict.java
@@ -1,44 +1,36 @@
package xyz.atnrch.nicko.i18n;
public class I18NDict {
- private final String key;
-
- public I18NDict(String key) { this.key = key; }
-
public static class Event {
public static class Admin {
- public static final I18NDict CACHE_CLEAN = new I18NDict("event.admin.cache_clear");
+ public static final String CACHE_CLEAN = "event.admin.cache_clear";
}
public static class Disguise {
- public static final I18NDict SUCCESS = new I18NDict("event.disguise.success");
- public static final I18NDict FAIL = new I18NDict("event.disguise.fail");
+ public static final String SUCCESS = "event.disguise.success";
+ public static final String FAIL = "event.disguise.fail";
}
public static class Undisguise {
- public static final I18NDict SUCCESS = new I18NDict("event.undisguise.success");
- public static final I18NDict FAIL = new I18NDict("event.undisguise.fail");
- public static final I18NDict NONE = new I18NDict("event.undisguise.none");
+ public static final String SUCCESS = "event.undisguise.success";
+ public static final String FAIL = "event.undisguise.fail";
+ public static final String NONE = "event.undisguise.none";
}
public static class PreviousSkin {
- public static final I18NDict SUCCESS = new I18NDict("event.previous_skin_applied.success");
- public static final I18NDict FAIL = new I18NDict("event.previous_skin_applied.fail");
+ public static final String SUCCESS = "event.previous_skin_applied.success";
+ public static final String FAIL = "event.previous_skin_applied.fail";
}
}
public static class Error {
- public static final I18NDict PLAYER_OFFLINE = new I18NDict("error.player_offline");
- public static final I18NDict SKIN_FAIL_MOJANG = new I18NDict("error.couldnt_get_skin_from_mojang");
- public static final I18NDict SKIN_FAIL_CACHE = new I18NDict("error.couldnt_get_skin_from_cache");
- public static final I18NDict NAME_FAIL_MOJANG = new I18NDict("error.couldnt_get_name_from_mojang");
- public static final I18NDict INVALID_USERNAME = new I18NDict("error.invalid_username");
- public static final I18NDict UNEXPECTED_ERROR = new I18NDict("error.generic");
- public static final I18NDict SQL_ERROR = new I18NDict("error.sql");
- public static final I18NDict JSON_ERROR = new I18NDict("error.json");
- }
-
- public String key() {
- return key;
+ public static final String UNEXPECTED_ERROR = "error.invalid_name";
+ public static final String PLAYER_OFFLINE = "error.player_offline";
+ public static final String SKIN_FAIL_MOJANG = "error.couldnt_get_skin_from_mojang";
+ public static final String SKIN_FAIL_CACHE = "error.couldnt_get_skin_from_cache";
+ public static final String NAME_FAIL_MOJANG = "error.couldnt_get_name_from_mojang";
+ public static final String INVALID_USERNAME = "error.invalid_username";
+ public static final String SQL_ERROR = "error.sql";
+ public static final String JSON_ERROR = "error.json";
}
}
diff --git a/src/main/java/xyz/atnrch/nicko/mojang/MojangAPI.java b/src/main/java/xyz/atnrch/nicko/mojang/MojangAPI.java
index 46eb2f1..f5689fe 100644
--- a/src/main/java/xyz/atnrch/nicko/mojang/MojangAPI.java
+++ b/src/main/java/xyz/atnrch/nicko/mojang/MojangAPI.java
@@ -73,6 +73,7 @@ public class MojangAPI {
con.setRequestMethod("GET");
switch (con.getResponseCode()) {
+ case 404:
case 400:
logger.warning("Failed to parse request: Invalid Name");
return getErrorObject();
diff --git a/src/main/java/xyz/atnrch/nicko/wrapper/WrapperPlayServerEntityDestroy.java b/src/main/java/xyz/atnrch/nicko/wrapper/WrapperPlayServerEntityDestroy.java
new file mode 100644
index 0000000..38f9067
--- /dev/null
+++ b/src/main/java/xyz/atnrch/nicko/wrapper/WrapperPlayServerEntityDestroy.java
@@ -0,0 +1,41 @@
+package xyz.atnrch.nicko.wrapper;
+
+import com.comphenix.protocol.PacketType;
+import com.comphenix.protocol.events.PacketContainer;
+import com.comphenix.protocol.wrappers.Converters;
+import it.unimi.dsi.fastutil.ints.IntList;
+
+/**
+ * Sent by the server to the client to remove one or more entities.
+ */
+public class WrapperPlayServerEntityDestroy extends AbstractPacket {
+
+ /**
+ * The packet type that is wrapped by this wrapper.
+ */
+ public static final PacketType TYPE = PacketType.Play.Server.ENTITY_DESTROY;
+
+ public WrapperPlayServerEntityDestroy() {
+ super(new PacketContainer(TYPE), TYPE);
+ handle.getModifier().writeDefaults();
+ }
+
+ /**
+ * Gets a list of entity ids to remove
+ *
+ * @return 'entityIds' to remove
+ */
+ public IntList getEntityIds() {
+ return this.handle.getModifier().withType(IntList.class, Converters.passthrough(IntList.class)).read(0);
+ }
+
+ /**
+ * Sets the list of entity ids to remove
+ *
+ * @param value New value for field 'entityIds'
+ */
+ public void setEntityIds(IntList value) {
+ this.handle.getModifier().withType(IntList.class, Converters.passthrough(IntList.class)).write(0, value);
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/atnrch/nicko/wrapper/WrapperPlayServerNamedEntitySpawn.java b/src/main/java/xyz/atnrch/nicko/wrapper/WrapperPlayServerNamedEntitySpawn.java
new file mode 100644
index 0000000..baa5bb9
--- /dev/null
+++ b/src/main/java/xyz/atnrch/nicko/wrapper/WrapperPlayServerNamedEntitySpawn.java
@@ -0,0 +1,173 @@
+package xyz.atnrch.nicko.wrapper;
+
+import com.comphenix.protocol.PacketType;
+import com.comphenix.protocol.events.PacketContainer;
+import org.bukkit.Location;
+import org.bukkit.World;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.UUID;
+
+/**
+ * This packet is sent by the server when a player comes into visible range, not when a player joins.
+ */
+public class WrapperPlayServerNamedEntitySpawn extends AbstractPacket {
+ /**
+ * The packet type that is wrapped by this wrapper.
+ */
+ public static final PacketType TYPE = PacketType.Play.Server.NAMED_ENTITY_SPAWN;
+
+ /**
+ * Constructors a new wrapper for the specified packet
+ */
+ public WrapperPlayServerNamedEntitySpawn() {
+ super(new PacketContainer(TYPE), TYPE);
+ handle.getModifier().writeDefaults();
+ }
+
+ /**
+ * Retrieves entity id of the player
+ *
+ * @return 'entityId'
+ */
+ public int getEntityId() {
+ return this.handle.getIntegers().read(0);
+ }
+
+ /**
+ * Sets the entity id of the player
+ *
+ * @param value New value for field 'entityId'
+ */
+ public void setEntityId(int value) {
+ this.handle.getIntegers().write(0, value);
+ }
+
+ /**
+ * Retrieves the unique id of the player
+ *
+ * @return 'playerId'
+ */
+ public UUID getPlayerId() {
+ return this.handle.getUUIDs().read(0);
+ }
+
+ /**
+ * Sets the unique id of the player
+ *
+ * @param value New value for field 'playerId'
+ */
+ public void setPlayerId(UUID value) {
+ this.handle.getUUIDs().write(0, value);
+ }
+
+ /**
+ * Retrieves the value of field 'x'
+ *
+ * @return 'x'
+ */
+ public double getX() {
+ return this.handle.getDoubles().read(0);
+ }
+
+ /**
+ * Sets the value of field 'x'
+ *
+ * @param value New value for field 'x'
+ */
+ public void setX(double value) {
+ this.handle.getDoubles().write(0, value);
+ }
+
+ /**
+ * Retrieves the value of field 'y'
+ *
+ * @return 'y'
+ */
+ public double getY() {
+ return this.handle.getDoubles().read(1);
+ }
+
+ /**
+ * Sets the value of field 'y'
+ *
+ * @param value New value for field 'y'
+ */
+ public void setY(double value) {
+ this.handle.getDoubles().write(1, value);
+ }
+
+ /**
+ * Retrieves the value of field 'z'
+ *
+ * @return 'z'
+ */
+ public double getZ() {
+ return this.handle.getDoubles().read(2);
+ }
+
+ /**
+ * Sets the value of field 'z'
+ *
+ * @param value New value for field 'z'
+ */
+ public void setZ(double value) {
+ this.handle.getDoubles().write(2, value);
+ }
+
+ /**
+ * Retrieves the discrete rotation around the y-axis (yaw)
+ *
+ * @return 'yRot'
+ */
+ public byte getYRotRaw() {
+ return this.handle.getBytes().read(0);
+ }
+
+ /**
+ * Sets the discrete rotation around the y-axis (yaw)
+ *
+ * @param value New value for field 'yRot'
+ */
+ public void setYRotRaw(byte value) {
+ this.handle.getBytes().write(0, value);
+ }
+
+ /**
+ * Retrieves the value of field 'xRot'
+ *
+ * @return 'xRot'
+ */
+ public byte getXRotRaw() {
+ return this.handle.getBytes().read(1);
+ }
+
+ /**
+ * Sets the discrete rotation around the x-axis (pitch)
+ *
+ * @param value New value for field 'xRot'
+ */
+ public void setXRotRaw(byte value) {
+ this.handle.getBytes().write(1, value);
+ }
+
+ public Location getLocation(@Nullable World world) {
+ return new Location(world, getX(), getY(), getZ(), angleToDegrees(getYRotRaw()), angleToDegrees(getXRotRaw()));
+ }
+ public void setLocation(@Nonnull Location location) {
+ setX(location.getX());
+ setY(location.getY());
+ setZ(location.getZ());
+ setYRotRaw(degreesToAngle(location.getYaw()));
+ setXRotRaw(degreesToAngle(location.getPitch()));
+ }
+
+ private float angleToDegrees(byte rawAngle) {
+ return rawAngle / 256.0F * 360.0F;
+ }
+
+ private byte degreesToAngle(float degree) {
+ return (byte)((int)(degree * 256.0F / 360.0F));
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/en.yml b/src/main/resources/en.yml
index 3d65290..a0d4833 100644
--- a/src/main/resources/en.yml
+++ b/src/main/resources/en.yml
@@ -1,5 +1,5 @@
error:
- couldnt_get_name_from_mojang: "Unable to get username from Mojang."
+ invalid_name: "Unable to get username from Mojang."
couldnt_get_skin_from_cache: "Unable to get skin from the cache."
couldnt_get_skin_from_mojang: "Unable to get skin from Mojang."
generic: "Unknown error"