- * Copyright (C) Kristian S. Strangeland
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package xyz.ineanto.nicko.packet.wrapper;
-
-import com.comphenix.protocol.PacketType;
-import com.comphenix.protocol.ProtocolLibrary;
-import com.comphenix.protocol.events.PacketContainer;
-import com.google.common.base.Objects;
-import org.bukkit.entity.Player;
-
-public abstract class AbstractPacket {
- protected PacketContainer handle;
-
- /**
- * Constructs a new strongly typed wrapper for the given packet.
- *
- * @param handle - handle to the raw packet data.
- * @param type - the packet type.
- */
- protected AbstractPacket(PacketContainer handle, PacketType type) {
- // Make sure we're given a valid packet
- if (handle == null)
- throw new IllegalArgumentException("Packet handle cannot be NULL.");
- if (!Objects.equal(handle.getType(), type))
- throw new IllegalArgumentException(handle.getHandle()
- + " is not a packet of type " + type);
-
- this.handle = handle;
- }
-
- /**
- * Retrieve a handle to the raw packet data.
- *
- * @return Raw packet data.
- */
- public PacketContainer getHandle() {
- return handle;
- }
-
- /**
- * Send the current packet to the given receiver.
- *
- * @param receiver - the receiver.
- * @throws RuntimeException If the packet cannot be sent.
- */
- public void sendPacket(Player receiver) {
- ProtocolLibrary.getProtocolManager().sendServerPacket(receiver,
- getHandle());
- }
-
- /**
- * Send the current packet to all online players.
- */
- public void broadcastPacket() {
- ProtocolLibrary.getProtocolManager().broadcastServerPacket(getHandle());
- }
-}
\ No newline at end of file
diff --git a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayServerEntityDestroy.java b/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayServerEntityDestroy.java
deleted file mode 100644
index a23f1a6..0000000
--- a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayServerEntityDestroy.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package xyz.ineanto.nicko.packet.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();
- }
-
- /**
- * 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)).writeSafely(0, value);
- }
-
-}
\ No newline at end of file
diff --git a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayServerRespawn.java b/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayServerRespawn.java
deleted file mode 100644
index f746450..0000000
--- a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayServerRespawn.java
+++ /dev/null
@@ -1,147 +0,0 @@
-package xyz.ineanto.nicko.packet.wrapper;
-
-import com.comphenix.protocol.PacketType;
-import com.comphenix.protocol.events.InternalStructure;
-import com.comphenix.protocol.events.PacketContainer;
-import com.comphenix.protocol.reflect.FuzzyReflection;
-import com.comphenix.protocol.reflect.StructureModifier;
-import com.comphenix.protocol.reflect.accessors.Accessors;
-import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
-import com.comphenix.protocol.utility.MinecraftReflection;
-import com.comphenix.protocol.utility.MinecraftVersion;
-import com.comphenix.protocol.wrappers.BukkitConverters;
-import com.comphenix.protocol.wrappers.EnumWrappers;
-import com.comphenix.protocol.wrappers.MinecraftKey;
-import com.google.common.hash.Hashing;
-import org.bukkit.Bukkit;
-import org.bukkit.GameMode;
-import org.bukkit.World;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.RecordComponent;
-import java.util.Arrays;
-
-/**
- * PacketPlayServerRespawn Wrapper class (1.20.X to 1.21.X)
- *
- * In 1.20.2, all the fields were merged inside a
- * single "CommonPlayerSpawnInfo" record.
- *
- * @author inenato (w/ additional help from lukalt), based on work from dmulloy2 and Kristian S. Strangeland
- */
-public class WrapperPlayServerRespawn extends AbstractPacket {
- public static final PacketType TYPE = PacketType.Play.Server.RESPAWN;
-
- private InternalStructure spawnInfoStructure = null;
-
- public WrapperPlayServerRespawn() {
- super(new PacketContainer(TYPE), TYPE);
- handle.getModifier().writeDefaults();
- if (MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
- spawnInfoStructure = handle.getStructures().read(0);
- }
- }
-
- public void setDimension(World value) {
- final MinecraftVersion v1_20_5 = new MinecraftVersion(1, 20, 5);
-
- if (!MinecraftVersion.getCurrentVersion().isAtLeast(v1_20_5)) {
- // 1.20 - 1.20.4
- final StructureModifier structureModifier = spawnInfoStructure == null ?
- handle.getStructures() : spawnInfoStructure.getStructures();
-
- final StructureModifier worldStructureModifier = spawnInfoStructure == null ?
- handle.getWorldKeys() : spawnInfoStructure.getWorldKeys();
-
- final InternalStructure dimensionType = structureModifier.read(0);
- dimensionType.getMinecraftKeys().writeSafely(0, new MinecraftKey("minecraft", "dimension_type"));
- dimensionType.getMinecraftKeys().writeSafely(1, new MinecraftKey("minecraft", "overworld"));
- structureModifier.writeSafely(0, dimensionType);
- worldStructureModifier.writeSafely(0, value);
- } else {
- // 1.20.5 to 1.21.1
-
- try {
- final Class> spawnInfoClass = MinecraftReflection.getMinecraftClass("network.protocol.game.CommonPlayerSpawnInfo");
-
- Class>[] componentTypes = Arrays.stream(spawnInfoClass.getRecordComponents())
- .map(RecordComponent::getType)
- .toArray(Class>[]::new);
- final Constructor> spawnInfoConstructor = spawnInfoClass.getDeclaredConstructor(componentTypes);
-
- /**
- * Holder dimensionType,
- * ResourceKey dimension,
- * long seed,
- * GameType gameType,
- * GameType previousGameType,
- * boolean isDebug,
- * boolean isFlat,
- * Optional lastDeathLocation,
- * int portalCooldown
- */
-
- final World world = Bukkit.getWorld("world");
-
- FuzzyReflection.fromClass(spawnInfoClass).getConstructor(
- FuzzyMethodContract
- .newBuilder()
- .build()
- );
-
- final Object spawnInfo = spawnInfoConstructor.newInstance(
- BukkitConverters.getDimensionConverter().getGeneric(world),
- BukkitConverters.getWorldKeyConverter().getGeneric(world),
- world.getSeed(),
- EnumWrappers.getGameModeConverter().getGeneric(EnumWrappers.NativeGameMode.fromBukkit(GameMode.SURVIVAL)),
- EnumWrappers.getGameModeConverter().getGeneric(EnumWrappers.NativeGameMode.fromBukkit(GameMode.SURVIVAL)),
- false,
- false,
- BukkitConverters.getSectionPositionConverter()
- );
-
- final Field commonSpawnDataField = Accessors.getFieldAccessor(TYPE.getPacketClass(), spawnInfoClass, true).getField();
- commonSpawnDataField.set(spawnInfoStructure.getHandle(), spawnInfo);
- } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException |
- InstantiationException e) {
- throw new RuntimeException();
- }
- }
- }
-
- public void setGameMode(GameMode value) {
- if (!MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
- // 1.20 to 1.20.1
- handle.getGameModes().writeSafely(0, EnumWrappers.NativeGameMode.fromBukkit(value));
- return;
- }
-
- spawnInfoStructure.getGameModes().writeSafely(0, EnumWrappers.NativeGameMode.fromBukkit(value));
- }
-
- public void setPreviousGameMode(GameMode value) {
- if (!MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
- // 1.20 to 1.20.1
- handle.getGameModes().writeSafely(1, EnumWrappers.NativeGameMode.fromBukkit(value));
- return;
- }
-
- spawnInfoStructure.getGameModes().writeSafely(1, EnumWrappers.NativeGameMode.fromBukkit(value));
- }
-
- public void setCopyMetadata(boolean value) {
- if (!MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) return;
-
- // 1.20 to 1.20.1
- handle.getBooleans().writeSafely(0, value);
- }
-
- public void setSeed(long value) {
- if (!MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
- // 1.20 to 1.20.1
- handle.getLongs().writeSafely(0, Hashing.sha256().hashLong(value).asLong());
- }
- }
-}
diff --git a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayServerSpawnEntity.java b/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayServerSpawnEntity.java
deleted file mode 100644
index 0512717..0000000
--- a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayServerSpawnEntity.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package xyz.ineanto.nicko.packet.wrapper;
-
-import com.comphenix.protocol.PacketType;
-import com.comphenix.protocol.events.PacketContainer;
-import org.bukkit.Location;
-import org.bukkit.entity.EntityType;
-
-import javax.annotation.Nonnull;
-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 WrapperPlayServerSpawnEntity extends AbstractPacket {
- /**
- * The packet type that is wrapped by this wrapper.
- */
- public static final PacketType TYPE = PacketType.Play.Server.SPAWN_ENTITY;
-
- /**
- * Constructors a new wrapper for the specified packet
- */
- public WrapperPlayServerSpawnEntity() {
- super(new PacketContainer(TYPE), TYPE);
- handle.getModifier().writeDefaults();
- }
-
- /**
- * Sets the entity id of the player
- *
- * @param value New value for field 'entityId'
- */
- public void setEntityId(int value) {
- this.handle.getIntegers().writeSafely(0, value);
- this.handle.getEntityTypeModifier().writeSafely(0, EntityType.PLAYER);
- }
-
- /**
- * Sets the unique id of the player
- *
- * @param value New value for field 'playerId'
- */
- public void setPlayerId(UUID value) {
- this.handle.getUUIDs().writeSafely(0, value);
- }
-
- /**
- * Sets the value of field 'x'
- *
- * @param value New value for field 'x'
- */
- public void setX(double value) {
- this.handle.getDoubles().writeSafely(0, value);
- }
-
- /**
- * Sets the value of field 'y'
- *
- * @param value New value for field 'y'
- */
- public void setY(double value) {
- this.handle.getDoubles().writeSafely(1, value);
- }
-
- /**
- * Sets the value of field 'z'
- *
- * @param value New value for field 'z'
- */
- public void setZ(double value) {
- this.handle.getDoubles().write(2, value);
- }
-
- /**
- * Sets the discrete rotation around the y-axis (yaw)
- *
- * @param value New value for field 'yRot'
- */
- public void setYRotRaw(byte value) {
- this.handle.getBytes().writeSafely(0, value);
- }
-
- /**
- * Sets the discrete rotation around the x-axis (pitch)
- *
- * @param value New value for field 'xRot'
- */
- public void setXRotRaw(byte value) {
- this.handle.getBytes().writeSafely(1, value);
- }
-
- public void setLocation(@Nonnull Location location) {
- setX(location.getX());
- setY(location.getY());
- setZ(location.getZ());
- setYRotRaw(degreesToAngle(location.getYaw()));
- setXRotRaw(degreesToAngle(location.getPitch()));
- }
-
- private byte degreesToAngle(float degree) {
- return (byte)((int)(degree * 256.0F / 360.0F));
- }
-}
\ No newline at end of file
diff --git a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayerServerPlayerInfo.java b/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayerServerPlayerInfo.java
deleted file mode 100644
index ca37dc0..0000000
--- a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayerServerPlayerInfo.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package xyz.ineanto.nicko.packet.wrapper;
-
-import com.comphenix.protocol.PacketType;
-import com.comphenix.protocol.events.PacketContainer;
-import com.comphenix.protocol.utility.MinecraftVersion;
-import com.comphenix.protocol.wrappers.EnumWrappers;
-import com.comphenix.protocol.wrappers.PlayerInfoData;
-
-import java.util.List;
-import java.util.Set;
-
-/**
- * Up-to-date version of the Wrapper class
- * for the PlayerServerPlayerInfo.
- *
- * @author ineanto, based on work from dmulloy2 and Kristian S. Strangeland
- */
-public class WrapperPlayerServerPlayerInfo extends AbstractPacket {
- public static final PacketType TYPE = PacketType.Play.Server.PLAYER_INFO;
-
- public WrapperPlayerServerPlayerInfo() {
- super(new PacketContainer(TYPE), TYPE);
- handle.getModifier().writeDefaults();
- }
-
- public void setActions(Set value) {
- if (MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove()) {
- handle.getPlayerInfoActions().writeSafely(0, value);
- } else {
- handle.getPlayerInfoAction().writeSafely(0, value.stream().iterator().next()); // Get the first Value.
- }
- }
-
- public void setData(List value) {
- handle.getPlayerInfoDataLists().writeSafely(1, value);
- }
-}
diff --git a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayerServerPlayerInfoRemove.java b/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayerServerPlayerInfoRemove.java
deleted file mode 100644
index 2273c48..0000000
--- a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayerServerPlayerInfoRemove.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package xyz.ineanto.nicko.packet.wrapper;
-
-import com.comphenix.protocol.PacketType;
-import com.comphenix.protocol.events.PacketContainer;
-
-import java.util.List;
-import java.util.UUID;
-
-/**
- * Up-to-date version of the Wrapper class
- * for the PlayerServerPlayerInfoRemove.
- *
- * @author ineanto, based on work from dmulloy2 and Kristian S. Strangeland
- */
-
-public class WrapperPlayerServerPlayerInfoRemove extends AbstractPacket {
- public static final PacketType TYPE = PacketType.Play.Server.PLAYER_INFO_REMOVE;
-
- public WrapperPlayerServerPlayerInfoRemove() {
- super(new PacketContainer(TYPE), TYPE);
- handle.getModifier().writeDefaults();
- }
-
- public void setUUIDs(List value) {
- handle.getUUIDLists().writeSafely(0, value);
- }
-}
diff --git a/src/main/java/xyz/ineanto/nicko/profile/NickoProfile.java b/src/main/java/xyz/ineanto/nicko/profile/NickoProfile.java
deleted file mode 100644
index b1a78bb..0000000
--- a/src/main/java/xyz/ineanto/nicko/profile/NickoProfile.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package xyz.ineanto.nicko.profile;
-
-import org.bukkit.entity.Player;
-import xyz.ineanto.nicko.Nicko;
-import xyz.ineanto.nicko.appearance.Appearance;
-import xyz.ineanto.nicko.language.Language;
-import xyz.ineanto.nicko.storage.PlayerDataStore;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-import java.util.UUID;
-
-public class NickoProfile implements Cloneable {
- public static final NickoProfile EMPTY_PROFILE = new NickoProfile(
- new Appearance(null, null),
- Language.ENGLISH,
- true,
- Collections.emptyList()
- );
-
- private static final Nicko instance = Nicko.getInstance();
- private static final PlayerDataStore dataStore = instance.getDataStore();
-
- private Appearance appearance;
- private Language language;
- private boolean randomSkin;
- private List favorites;
-
- public NickoProfile(Appearance appearance, Language language, boolean randomSkin, List favorites) {
- this.appearance = appearance;
- this.language = language;
- this.randomSkin = randomSkin;
- this.favorites = favorites;
- }
-
- public static Optional get(Player player) {
- return dataStore.getData(player.getUniqueId());
- }
-
- public static Optional get(UUID uuid) {
- return dataStore.getData(uuid);
- }
-
- public Appearance getAppearance() {
- return appearance;
- }
-
- public boolean hasData() {
- return appearance.name() != null || appearance.skin() != null;
- }
-
- public String getName() {
- return appearance.name();
- }
-
- public void setName(String name) {
- this.appearance = new Appearance(name, appearance.skin() == null ? null : appearance.skin());
- }
-
- public String getSkin() {
- return appearance.skin();
- }
-
- public void setSkin(String skin) {
- this.appearance = new Appearance(appearance.name() == null ? null : appearance.name(), skin);
- }
-
- public List getFavorites() {
- return favorites;
- }
-
- public void setFavorites(List favorites) {
- this.favorites = favorites;
- }
-
- public Language getLocale() {
- return language;
- }
-
- public void setLocale(Language language) {
- this.language = language;
- }
-
- public boolean isRandomSkin() {
- return randomSkin;
- }
-
- public void setRandomSkin(boolean randomSkin) {
- this.randomSkin = randomSkin;
- }
-
- @Override
- public NickoProfile clone() {
- Object o;
- try {
- o = super.clone();
- } catch (CloneNotSupportedException e) {
- throw new RuntimeException(e);
- }
- return (NickoProfile) o;
- }
-}
diff --git a/src/main/java/xyz/ineanto/nicko/prompt/Prompt.java b/src/main/java/xyz/ineanto/nicko/prompt/Prompt.java
deleted file mode 100644
index 5940993..0000000
--- a/src/main/java/xyz/ineanto/nicko/prompt/Prompt.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package xyz.ineanto.nicko.prompt;
-
-import org.bukkit.Sound;
-import org.bukkit.entity.Player;
-import xyz.ineanto.nicko.Nicko;
-import xyz.ineanto.nicko.appearance.ActionResult;
-import xyz.ineanto.nicko.appearance.AppearanceManager;
-import xyz.ineanto.nicko.language.LanguageKey;
-import xyz.ineanto.nicko.language.PlayerLanguage;
-import xyz.ineanto.nicko.profile.NickoProfile;
-import xyz.ineanto.nicko.storage.PlayerDataStore;
-
-import javax.annotation.Nullable;
-import java.util.Optional;
-
-public abstract class Prompt {
- private final Player player;
- private final AppearanceManager appearanceManager;
- private final NickoProfile profile;
- private final PlayerDataStore dataStore = Nicko.getInstance().getDataStore();
-
- protected final PlayerLanguage playerLanguage;
-
- public Prompt(Player player) {
- this.player = player;
- this.appearanceManager = new AppearanceManager(player);
- this.playerLanguage = new PlayerLanguage(player);
-
- final Optional optionalProfile = dataStore.getData(player.getUniqueId());
- this.profile = optionalProfile.orElse(NickoProfile.EMPTY_PROFILE.clone());
- }
-
- public abstract void displayNameThenSkinPrompt();
-
- public abstract void displaySkinPrompt();
-
- public abstract void displayNamePrompt();
-
- public void update(@Nullable String name, @Nullable String skin, boolean skinChange) {
- if (name != null && !name.isBlank()) {
- profile.setName(name);
- }
-
- if (skin != null && !skin.isBlank()) {
- profile.setSkin(skin);
- }
-
- dataStore.updateCache(player.getUniqueId(), profile);
-
- final ActionResult actionResult = appearanceManager.update(skinChange);
- if (!actionResult.isError()) {
- player.sendMessage(playerLanguage.translateWithWhoosh(LanguageKey.Event.Appearance.Set.OK));
- player.playSound(player.getLocation(), Sound.BLOCK_WOODEN_BUTTON_CLICK_ON, 1f, 1f);
- } else {
- player.sendMessage(
- playerLanguage.translateWithOops(
- LanguageKey.Event.Appearance.Set.ERROR,
- playerLanguage.translate(actionResult.getErrorKey(), false)
- ));
- player.playSound(player.getLocation(), Sound.BLOCK_ANVIL_PLACE, 1f, 1f);
- }
- }
-}
diff --git a/src/main/java/xyz/ineanto/nicko/prompt/PromptManager.java b/src/main/java/xyz/ineanto/nicko/prompt/PromptManager.java
deleted file mode 100644
index bbd5a9e..0000000
--- a/src/main/java/xyz/ineanto/nicko/prompt/PromptManager.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package xyz.ineanto.nicko.prompt;
-
-import org.bukkit.entity.Player;
-import xyz.ineanto.nicko.prompt.conversation.ConversationPrompt;
-
-public class PromptManager {
- private final Prompt prompt;
-
- public PromptManager(Player player) {
- this.prompt = new ConversationPrompt(player);
- }
-
- public void displayNameThenSkinPrompt() {
- prompt.displayNameThenSkinPrompt();
- }
-
- public void displaySkinPrompt() {
- prompt.displaySkinPrompt();
- }
-
- public void displayNamePromptThenUpdate() {
- prompt.displayNamePrompt();
- }
-}
\ No newline at end of file
diff --git a/src/main/java/xyz/ineanto/nicko/prompt/anvil/AnvilPrompt.java b/src/main/java/xyz/ineanto/nicko/prompt/anvil/AnvilPrompt.java
deleted file mode 100644
index 85e6d28..0000000
--- a/src/main/java/xyz/ineanto/nicko/prompt/anvil/AnvilPrompt.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package xyz.ineanto.nicko.prompt.anvil;
-
-import net.kyori.adventure.text.Component;
-import net.wesjd.anvilgui.AnvilGUI;
-import org.bukkit.Material;
-import org.bukkit.entity.Player;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.ItemMeta;
-import xyz.ineanto.nicko.Nicko;
-import xyz.ineanto.nicko.prompt.Prompt;
-import xyz.ineanto.nicko.language.LanguageKey;
-import xyz.ineanto.nicko.mojang.MojangUtils;
-
-import java.util.Collections;
-
-/**
- * This is currently unused, I'm waiting on AnvilGUI
- * to be compiled against Paper mappings.
- */
-// TODO (Ineanto, 16/05/2025): Do some validation on the inputs
-public class AnvilPrompt extends Prompt {
- private final Player player;
-
- private String name;
- private String skin;
-
- public AnvilPrompt(Player player) {
- super(player);
- this.player = player;
- }
-
- @Override
- public void displayNameThenSkinPrompt() {
- new AnvilGUI.Builder()
- .plugin(Nicko.getInstance())
- .itemLeft(getLeftItem(false))
- .interactableSlots(AnvilGUI.Slot.OUTPUT)
- .onClick((slot, snapshot) -> {
- if (slot == AnvilGUI.Slot.OUTPUT) {
- if (MojangUtils.isUsernameInvalid(snapshot.getText())) {
- return Collections.singletonList(AnvilGUI.ResponseAction.replaceInputText("Invalid username!"));
- } else {
- // Praying that it works. This is untested code!
- name = snapshot.getText();
- displaySkinPrompt();
- }
- }
- return Collections.emptyList();
- })
- .text("New name...").open(player);
- }
-
- @Override
- public void displaySkinPrompt() {
- new AnvilGUI.Builder()
- .plugin(Nicko.getInstance())
- .itemLeft(getLeftItem(true))
- .interactableSlots(AnvilGUI.Slot.OUTPUT)
- .onClick((slot, snapshot) -> {
- if (slot == AnvilGUI.Slot.OUTPUT) {
- if (MojangUtils.isUsernameInvalid(snapshot.getText())) {
- return Collections.singletonList(AnvilGUI.ResponseAction.replaceInputText("Invalid username!"));
- } else {
- skin = snapshot.getText();
- update(name == null ? null : name, skin, true);
- return Collections.singletonList(AnvilGUI.ResponseAction.close());
- }
- }
- return Collections.emptyList();
- })
- .text("New skin...").open(player);
- }
-
- @Override
- public void displayNamePrompt() {
- new AnvilGUI.Builder()
- .plugin(Nicko.getInstance())
- .itemLeft(getLeftItem(false))
- .interactableSlots(AnvilGUI.Slot.OUTPUT)
- .onClick((slot, snapshot) -> {
- if (slot == AnvilGUI.Slot.OUTPUT) {
- if (MojangUtils.isUsernameInvalid(snapshot.getText())) {
- return Collections.singletonList(AnvilGUI.ResponseAction.replaceInputText("Invalid username!"));
- } else {
- update(snapshot.getText(), null, false);
- return Collections.singletonList(AnvilGUI.ResponseAction.close());
- }
- }
- return Collections.emptyList();
- })
- .text("New name...").open(player);
- }
-
- private ItemStack getLeftItem(boolean skin) {
- final ItemStack item = new ItemStack(Material.PAPER);
- final ItemMeta meta = item.getItemMeta();
-
- if (meta != null) {
- meta.displayName(Component.text(playerLanguage.translate(skin ? LanguageKey.GUI.NEW_SKIN : LanguageKey.GUI.NEW_NAME, false)));
- }
-
- item.setItemMeta(meta);
- return item;
- }
-}
diff --git a/src/main/java/xyz/ineanto/nicko/prompt/conversation/ConversationPrompt.java b/src/main/java/xyz/ineanto/nicko/prompt/conversation/ConversationPrompt.java
deleted file mode 100644
index 701ce6c..0000000
--- a/src/main/java/xyz/ineanto/nicko/prompt/conversation/ConversationPrompt.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package xyz.ineanto.nicko.prompt.conversation;
-
-import org.bukkit.conversations.ConversationContext;
-import org.bukkit.conversations.ConversationFactory;
-import org.bukkit.conversations.StringPrompt;
-import org.bukkit.entity.Player;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import xyz.ineanto.nicko.Nicko;
-import xyz.ineanto.nicko.prompt.Prompt;
-import xyz.ineanto.nicko.language.LanguageKey;
-
-import java.util.Map;
-import java.util.Objects;
-
-public class ConversationPrompt extends Prompt {
- private final String changeBothTag = "changeBoth";
- private final Player player;
- private final ConversationFactory conversationFactory = new ConversationFactory(Nicko.getInstance())
- .withTimeout(30)
- .withModality(false)
- .withEscapeSequence("EXIT")
- .withLocalEcho(false)
- .thatExcludesNonPlayersWithMessage("Player only");
-
- private String name;
-
- public ConversationPrompt(Player player) {
- super(player);
- this.player = player;
- }
-
- @Override
- public void displayNameThenSkinPrompt() {
- conversationFactory
- .withFirstPrompt(new ChangeNameConversation())
- .withInitialSessionData(Map.of(changeBothTag, true))
- .buildConversation(player)
- .begin();
- }
-
- @Override
- public void displaySkinPrompt() {
- conversationFactory
- .withFirstPrompt(new ChangeSkinConversation())
- .buildConversation(player)
- .begin();
- }
-
- @Override
- public void displayNamePrompt() {
- conversationFactory
- .withFirstPrompt(new ChangeNameConversation())
- .buildConversation(player)
- .begin();
- }
-
- private class ChangeNameConversation extends StringPrompt {
- @Override
- public @NotNull String getPromptText(@NotNull ConversationContext context) {
- return playerLanguage.translate(LanguageKey.Event.Appearance.Set.CHAT_PROMPT_NAME, true);
- }
-
- @Override
- public @Nullable org.bukkit.conversations.Prompt acceptInput(@NotNull ConversationContext context, @Nullable String input) {
- if (Objects.equals(context.getSessionData(changeBothTag), true)) {
- name = input;
- return new ChangeSkinConversation();
- }
-
- update(input, null, false);
- return END_OF_CONVERSATION;
- }
- }
-
- private class ChangeSkinConversation extends StringPrompt {
- @Override
- public @NotNull String getPromptText(@NotNull ConversationContext context) {
- return playerLanguage.translate(LanguageKey.Event.Appearance.Set.CHAT_PROMPT_SKIN, true);
- }
-
- @Override
- public @Nullable org.bukkit.conversations.Prompt acceptInput(@NotNull ConversationContext context, @Nullable String input) {
- update(name != null ? name : null, input, true);
- name = null;
- return END_OF_CONVERSATION;
- }
- }
-}
diff --git a/src/main/java/xyz/ineanto/nicko/storage/PlayerDataStore.java b/src/main/java/xyz/ineanto/nicko/storage/PlayerDataStore.java
deleted file mode 100644
index 2ba648f..0000000
--- a/src/main/java/xyz/ineanto/nicko/storage/PlayerDataStore.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package xyz.ineanto.nicko.storage;
-
-import org.bukkit.entity.Player;
-import xyz.ineanto.nicko.appearance.ActionResult;
-import xyz.ineanto.nicko.config.Configuration;
-import xyz.ineanto.nicko.language.LanguageKey;
-import xyz.ineanto.nicko.mojang.MojangAPI;
-import xyz.ineanto.nicko.mojang.MojangUtils;
-import xyz.ineanto.nicko.profile.NickoProfile;
-import xyz.ineanto.nicko.storage.json.JSONStorage;
-import xyz.ineanto.nicko.storage.map.MapCache;
-import xyz.ineanto.nicko.storage.mariadb.MariaDBStorage;
-import xyz.ineanto.nicko.storage.mysql.MySQLStorage;
-import xyz.ineanto.nicko.storage.redis.RedisCache;
-
-import java.io.IOException;
-import java.util.Optional;
-import java.util.UUID;
-import java.util.concurrent.ExecutionException;
-
-public class PlayerDataStore {
- private final MojangAPI mojangAPI;
-
- private Storage storage;
- private Cache cache;
-
- public PlayerDataStore(MojangAPI mojangAPI, Configuration configuration) {
- this.mojangAPI = mojangAPI;
- this.storage = configuration.getSqlConfiguration().isEnabled() ?
- configuration.getSqlConfiguration().isMariadb() ? new MariaDBStorage(configuration) : new MySQLStorage(configuration)
- : new JSONStorage();
- this.cache = configuration.getRedisConfiguration().isEnabled() ? new RedisCache(configuration) : new MapCache();
- }
-
- public ActionResult updateCache(UUID uuid, NickoProfile profile) {
- if (storage.isError() || cache.isError()) {
- return ActionResult.error(LanguageKey.Error.CACHE);
- }
-
- getCache().cache(uuid, profile);
- return ActionResult.ok();
- }
-
- public Optional getData(UUID uuid) {
- if (storage.isError() || cache.isError()) {
- return Optional.empty();
- }
-
- if (cache.isCached(uuid)) {
- return cache.retrieve(uuid);
- } else if (storage.isStored(uuid)) {
- final Optional retrievedProfile = storage.retrieve(uuid);
- retrievedProfile.ifPresent(profile -> cache.cache(uuid, profile));
- return retrievedProfile;
- } else {
- final NickoProfile newProfile = NickoProfile.EMPTY_PROFILE.clone();
- cache.cache(uuid, newProfile);
- return Optional.of(newProfile);
- }
- }
-
- public Optional getOfflineData(String name) {
- if (storage.isError() || cache.isError()) {
- return Optional.empty();
- }
-
- try {
- final Optional uuidTrimmed = mojangAPI.getUUID(name);
- if (uuidTrimmed.isPresent()) {
- final UUID uuid = MojangUtils.fromTrimmed(uuidTrimmed.get());
- return getData(uuid);
- }
- return Optional.empty();
- } catch (IOException | ExecutionException e) {
- return Optional.empty();
- }
- }
-
- public ActionResult saveData(Player player) {
- if (storage.isError()) return ActionResult.error();
- if (cache.isError()) return ActionResult.error();
- if (!cache.isCached(player.getUniqueId())) return ActionResult.error();
-
- final Optional cachedProfile = cache.retrieve(player.getUniqueId());
- if (cachedProfile.isEmpty()) return ActionResult.error();
-
- cache.delete(player.getUniqueId());
- return storage.store(player.getUniqueId(), cachedProfile.get());
- }
-
- public Storage getStorage() {
- return storage;
- }
-
- public void setStorage(Storage storage) {
- this.storage = storage;
- }
-
- public Cache getCache() {
- return cache;
- }
-
- public void setCache(Cache cache) {
- this.cache = cache;
- }
-}
diff --git a/src/main/java/xyz/ineanto/nicko/storage/map/MapCache.java b/src/main/java/xyz/ineanto/nicko/storage/map/MapCache.java
deleted file mode 100644
index ebc3a88..0000000
--- a/src/main/java/xyz/ineanto/nicko/storage/map/MapCache.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package xyz.ineanto.nicko.storage.map;
-
-import xyz.ineanto.nicko.appearance.ActionResult;
-import xyz.ineanto.nicko.profile.NickoProfile;
-import xyz.ineanto.nicko.storage.Cache;
-import xyz.ineanto.nicko.storage.CacheProvider;
-
-import java.util.HashMap;
-import java.util.Optional;
-import java.util.UUID;
-
-public class MapCache extends Cache {
- private MapCacheProvider provider;
-
- @Override
- public CacheProvider getProvider() {
- if (provider == null) {
- provider = new MapCacheProvider();
- }
- return provider;
- }
-
- @Override
- public ActionResult cache(UUID uuid, NickoProfile profile) {
- final HashMap profiles = provider.getMap();
- profiles.put(uuid, profile);
- return ActionResult.ok();
- }
-
- @Override
- public boolean isCached(UUID uuid) {
- final HashMap profiles = provider.getMap();
- return profiles.containsKey(uuid);
- }
-
- @Override
- public Optional retrieve(UUID uuid) {
- final HashMap profiles = provider.getMap();
- if (isCached(uuid)) {
- return Optional.of(profiles.get(uuid));
- }
- return Optional.empty();
- }
-
- @Override
- public ActionResult delete(UUID uuid) {
- final HashMap profiles = provider.getMap();
- profiles.remove(uuid);
- return ActionResult.ok();
- }
-}
diff --git a/src/main/java/xyz/ineanto/nicko/storage/map/MapCacheProvider.java b/src/main/java/xyz/ineanto/nicko/storage/map/MapCacheProvider.java
deleted file mode 100644
index bfb85bd..0000000
--- a/src/main/java/xyz/ineanto/nicko/storage/map/MapCacheProvider.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package xyz.ineanto.nicko.storage.map;
-
-import xyz.ineanto.nicko.profile.NickoProfile;
-import xyz.ineanto.nicko.storage.CacheProvider;
-
-import java.util.HashMap;
-import java.util.UUID;
-
-public class MapCacheProvider implements CacheProvider {
- private HashMap profiles;
-
- @Override
- public boolean init() {
- if (profiles == null) {
- profiles = new HashMap<>();
- }
- return true;
- }
-
- @Override
- public boolean close() {
- return true;
- }
-
- public HashMap getMap() {
- return profiles;
- }
-}
diff --git a/src/main/java/xyz/ineanto/nicko/storage/mysql/MySQLStorage.java b/src/main/java/xyz/ineanto/nicko/storage/mysql/MySQLStorage.java
deleted file mode 100644
index ae74d5f..0000000
--- a/src/main/java/xyz/ineanto/nicko/storage/mysql/MySQLStorage.java
+++ /dev/null
@@ -1,152 +0,0 @@
-package xyz.ineanto.nicko.storage.mysql;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.reflect.TypeToken;
-import xyz.ineanto.nicko.appearance.ActionResult;
-import xyz.ineanto.nicko.appearance.Appearance;
-import xyz.ineanto.nicko.config.Configuration;
-import xyz.ineanto.nicko.language.Language;
-import xyz.ineanto.nicko.profile.NickoProfile;
-import xyz.ineanto.nicko.storage.Storage;
-
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-import java.util.UUID;
-import java.util.logging.Logger;
-
-public class MySQLStorage extends Storage {
- private final Logger logger = Logger.getLogger("SQLStorage");
- private final Configuration configuration;
- private final Gson gson = new GsonBuilder().serializeNulls().create();
-
- private MySQLStorageProvider provider;
-
- public MySQLStorage(Configuration configuration) {
- this.configuration = configuration;
- }
-
- @Override
- public MySQLStorageProvider getProvider() {
- if (provider == null) {
- provider = new MySQLStorageProvider(configuration);
- }
- return provider;
- }
-
- @Override
- public ActionResult store(UUID uuid, NickoProfile profile) {
- final Connection connection = getProvider().getConnection();
- if (connection == null) return ActionResult.error();
-
- try {
- final PreparedStatement statement = isStored(uuid) ?
- getUpdateStatement(connection, uuid, profile) : getInsertStatement(connection, uuid, profile);
- statement.executeUpdate();
- return ActionResult.ok();
- } catch (SQLException e) {
- logger.warning("Couldn't send SQL Request: " + e.getMessage());
- return ActionResult.error();
- }
- }
-
- @Override
- public boolean isStored(UUID uuid) {
- final Connection connection = getProvider().getConnection();
- if (connection == null) return false;
-
- try {
- final String sql = "SELECT uuid FROM nicko.DATA WHERE uuid = ?";
-
- final PreparedStatement statement = connection.prepareStatement(sql);
- statement.setString(1, uuid.toString());
-
- final ResultSet resultSet = statement.executeQuery();
- return resultSet.next();
- } catch (SQLException e) {
- logger.warning("Couldn't check if data is present: " + e.getMessage());
- return false;
- }
- }
-
- @Override
- public Optional retrieve(UUID uuid) {
- final Connection connection = getProvider().getConnection();
- if (connection == null) return Optional.empty();
- if (!isStored(uuid)) return Optional.empty();
-
- try {
- final String sql = "SELECT * FROM nicko.DATA WHERE uuid = ?";
-
- final PreparedStatement statement = connection.prepareStatement(sql);
- statement.setString(1, uuid.toString());
-
- final ResultSet resultSet = statement.executeQuery();
- String name = "";
- String skin = "";
- String locale = "";
- boolean randomSkin = false;
- List favorites = Collections.emptyList();
- while (resultSet.next()) {
- name = resultSet.getString("name");
- skin = resultSet.getString("skin");
- locale = resultSet.getString("locale");
- randomSkin = resultSet.getBoolean("randomskin");
- favorites = gson.fromJson(resultSet.getString("favorites"), new TypeToken>() { }.getType());
- }
-
- final NickoProfile profile = new NickoProfile(new Appearance(name, skin), Language.fromCode(locale), randomSkin, favorites);
- return Optional.of(profile);
- } catch (SQLException e) {
- logger.warning("Couldn't fetch profile: " + e.getMessage());
- return Optional.empty();
- }
- }
-
- @Override
- public ActionResult delete(UUID uuid) {
- final Connection connection = getProvider().getConnection();
- if (connection == null) return ActionResult.error();
-
- try {
- final String sql = "DELETE FROM nicko.DATA WHERE uuid = ?";
- final PreparedStatement statement = connection.prepareStatement(sql);
- statement.setString(1, uuid.toString());
- int rows = statement.executeUpdate();
- return (rows == 1 ? ActionResult.ok() : ActionResult.error());
- } catch (SQLException e) {
- logger.warning("Couldn't delete profile: " + e.getMessage());
- return ActionResult.error();
- }
- }
-
- private PreparedStatement getInsertStatement(Connection connection, UUID uuid, NickoProfile profile) throws SQLException {
- final String sql = "INSERT IGNORE INTO nicko.DATA (`uuid`, `name`, `skin`, `locale`, `randomskin`, `favorites`) VALUES (?, ?, ?, ?, ?, ?)";
- final PreparedStatement statement = connection.prepareStatement(sql);
- statement.setString(1, uuid.toString());
- statement.setString(2, profile.getName() == null ? null : profile.getName());
- statement.setString(3, profile.getSkin() == null ? null : profile.getSkin());
- statement.setString(4, profile.getLocale().getCode());
- statement.setBoolean(5, profile.isRandomSkin());
-
- // Ineanto, 08/06/2025: this will never fucking work
- statement.setString(6, gson.toJson(profile.getFavorites(), new TypeToken>() { }.getRawType()));
- return statement;
- }
-
- private PreparedStatement getUpdateStatement(Connection connection, UUID uuid, NickoProfile profile) throws SQLException {
- final String sql = "UPDATE nicko.DATA SET name = ?, skin = ?, locale = ?, randomskin = ? WHERE uuid = ?";
- final PreparedStatement statement = connection.prepareStatement(sql);
- statement.setString(1, profile.getName() == null ? null : profile.getName());
- statement.setString(2, profile.getSkin() == null ? null : profile.getSkin());
- statement.setString(3, profile.getLocale().getCode());
- statement.setBoolean(4, profile.isRandomSkin());
- statement.setString(5, uuid.toString());
- return statement;
- }
-}
diff --git a/src/main/java/xyz/ineanto/nicko/storage/mysql/MySQLStorageProvider.java b/src/main/java/xyz/ineanto/nicko/storage/mysql/MySQLStorageProvider.java
deleted file mode 100644
index 41faea2..0000000
--- a/src/main/java/xyz/ineanto/nicko/storage/mysql/MySQLStorageProvider.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package xyz.ineanto.nicko.storage.mysql;
-
-import com.mysql.cj.jdbc.MysqlDataSource;
-import xyz.ineanto.nicko.config.Configuration;
-import xyz.ineanto.nicko.config.DataSourceConfiguration;
-import xyz.ineanto.nicko.storage.StorageProvider;
-
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-import java.util.logging.Logger;
-
-public class MySQLStorageProvider implements StorageProvider {
- private final Logger logger = Logger.getLogger("MySQLStorageProvider");
- private final Configuration configuration;
-
- private Connection connection;
-
- private final String schemaName = "nicko";
-
- public MySQLStorageProvider(Configuration configuration) {
- this.configuration = configuration;
- }
-
- @Override
- public boolean init() {
- try {
- final MysqlDataSource dataSource = new MysqlDataSource();
- final DataSourceConfiguration sqlConfiguration = configuration.getSqlConfiguration();
- dataSource.setUrl("jdbc:mysql://" + sqlConfiguration.getAddress() + ":" + sqlConfiguration.getPort());
- dataSource.setUser(sqlConfiguration.getUsername());
- dataSource.setPassword(sqlConfiguration.getPassword());
- connection = dataSource.getConnection();
- connection.setAutoCommit(true);
- final boolean initialized = connection != null && !connection.isClosed();
-
- if (!initialized) return false;
-
- createDatabase();
- createTable();
- return true;
- } catch (SQLException e) {
- logger.severe("Couldn't establish a connection to the MySQL database: " + e.getMessage());
- return false;
- }
- }
-
- @Override
- public boolean close() {
- if (connection == null) { return true; }
- try {
- connection.close();
- return connection.isClosed();
- } catch (SQLException e) {
- return false;
- }
- }
-
- private void createTable() throws SQLException {
- final Connection connection = getConnection();
- final String query = "CREATE TABLE IF NOT EXISTS %s.DATA ".replace("%s", schemaName) +
- "(uuid varchar(36) NOT NULL," +
- "name varchar(16)," +
- "skin varchar(16)," +
- "locale char(2) NOT NULL," +
- "bungeecord boolean NOT NULL," +
- "PRIMARY KEY (uuid))";
-
- final PreparedStatement statement = connection.prepareStatement(query);
- statement.executeUpdate();
- }
-
- private void createDatabase() throws SQLException {
- final Connection connection = getConnection();
- final String query = "CREATE DATABASE IF NOT EXISTS %s".replace("%s", schemaName);
-
- final PreparedStatement statement = connection.prepareStatement(query);
- statement.executeUpdate();
- }
-
- public Connection getConnection() {
- return connection;
- }
-}
diff --git a/src/main/java/xyz/ineanto/nicko/storage/redis/RedisCache.java b/src/main/java/xyz/ineanto/nicko/storage/redis/RedisCache.java
deleted file mode 100644
index b40367e..0000000
--- a/src/main/java/xyz/ineanto/nicko/storage/redis/RedisCache.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package xyz.ineanto.nicko.storage.redis;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import redis.clients.jedis.Jedis;
-import redis.clients.jedis.exceptions.JedisException;
-import xyz.ineanto.nicko.appearance.ActionResult;
-import xyz.ineanto.nicko.config.Configuration;
-import xyz.ineanto.nicko.language.LanguageKey;
-import xyz.ineanto.nicko.profile.NickoProfile;
-import xyz.ineanto.nicko.storage.Cache;
-import xyz.ineanto.nicko.storage.CacheProvider;
-
-import java.util.Optional;
-import java.util.UUID;
-
-public class RedisCache extends Cache {
- private final Gson gson = new GsonBuilder()
- .serializeNulls()
- .setPrettyPrinting()
- .create();
- private final Configuration configuration;
- private RedisCacheProvider provider;
-
- public RedisCache(Configuration configuration) {
- this.configuration = configuration;
- }
-
- @Override
- public CacheProvider getProvider() {
- if (provider == null) {
- provider = new RedisCacheProvider(configuration);
- }
- return provider;
- }
-
- @Override
- public ActionResult cache(UUID uuid, NickoProfile profile) {
- try (Jedis jedis = provider.getJedis()) {
- jedis.set("nicko:" + uuid.toString(), gson.toJson(profile));
- return ActionResult.ok();
- } catch (JedisException exception) {
- return ActionResult.error(LanguageKey.Error.CACHE);
- }
- }
-
- @Override
- public boolean isCached(UUID uuid) {
- try (Jedis jedis = provider.getJedis()) {
- return jedis.exists("nicko:" + uuid.toString());
- } catch (JedisException exception) {
- return false;
- }
- }
-
- @Override
- public Optional retrieve(UUID uuid) {
- try (Jedis jedis = provider.getJedis()) {
- // 06/07/25: like, for real. what the f is that comment about...?
- // 08/29/23: what the fuck was I talking about?
- // old_todo (Ineanto, 05/20/23): Check if cached before because Jedis returns a bulk reply so this is unsafe
- final String data = jedis.get("nicko:" + uuid.toString());
- final NickoProfile profile = gson.fromJson(data, NickoProfile.class);
- return Optional.of(profile);
- } catch (JedisException exception) {
- return Optional.empty();
- }
- }
-
- @Override
- public ActionResult delete(UUID uuid) {
- try (Jedis jedis = provider.getJedis()) {
- jedis.del("nicko:" + uuid.toString());
- return ActionResult.ok();
- } catch (JedisException exception) {
- return ActionResult.error(LanguageKey.Error.CACHE);
- }
- }
-}
diff --git a/src/main/java/xyz/ineanto/nicko/storage/redis/RedisCacheProvider.java b/src/main/java/xyz/ineanto/nicko/storage/redis/RedisCacheProvider.java
deleted file mode 100644
index 7408326..0000000
--- a/src/main/java/xyz/ineanto/nicko/storage/redis/RedisCacheProvider.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package xyz.ineanto.nicko.storage.redis;
-
-import redis.clients.jedis.exceptions.JedisConnectionException;
-import xyz.ineanto.nicko.config.Configuration;
-import xyz.ineanto.nicko.config.DataSourceConfiguration;
-import xyz.ineanto.nicko.storage.CacheProvider;
-import redis.clients.jedis.Jedis;
-import redis.clients.jedis.JedisPool;
-
-public class RedisCacheProvider implements CacheProvider {
- private final Configuration configuration;
- private JedisPool pool;
-
- public RedisCacheProvider(Configuration configuration) {
- this.configuration = configuration;
- }
-
- @Override
- public boolean init() {
- final DataSourceConfiguration redisConfiguration = configuration.getRedisConfiguration();
- pool = new JedisPool(redisConfiguration.getAddress(), redisConfiguration.getPort());
- try {
- return !pool.isClosed() && pool.getResource() != null;
- } catch (JedisConnectionException exception) {
- return false;
- }
- }
-
- @Override
- public boolean close() {
- pool.close();
- return pool.isClosed();
- }
-
- public Jedis getJedis() {
- return pool.getResource();
- }
-}
diff --git a/src/main/java/xyz/ineanto/nicko/version/Version.java b/src/main/java/xyz/ineanto/nicko/version/Version.java
deleted file mode 100644
index 5b95ac0..0000000
--- a/src/main/java/xyz/ineanto/nicko/version/Version.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package xyz.ineanto.nicko.version;
-
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Comparator;
-
-public record Version(int major, int minor, int patch) implements Comparable {
- @Override
- public int compareTo(@NotNull Version otherVersion) {
- final Comparator comparator = Comparator
- .comparingInt(Version::major)
- .thenComparingInt(Version::minor)
- .thenComparingInt(Version::patch);
- return comparator.compare(this, otherVersion);
- }
-
- @Override
- public @NotNull String toString() {
- return major + "." + minor + "." + patch;
- }
-
- public static Version fromString(String versionString) {
- if (versionString == null || versionString.isEmpty()) { return new Version(0, 0, 0); }
- final String[] split = versionString.split("\\.");
- try {
- return new Version(Integer.parseInt(split[0]),
- Integer.parseInt(split[1]),
- Integer.parseInt(split[2]));
- } catch (NumberFormatException exception) {
- return new Version(0, 0, 0);
- }
- }
-}
\ No newline at end of file
diff --git a/src/main/resources/en.yml b/src/main/resources/en.yml
deleted file mode 100644
index afa9439..0000000
--- a/src/main/resources/en.yml
+++ /dev/null
@@ -1,175 +0,0 @@
-# Nicko ${version} - Language File:
-
-# Specifies the configuration version, don't change.
-version: "1.4.0"
-
-prefix: "NICKO"
-whoosh: "WHOOSH!"
-oops: "OOPS!"
-
-error:
- permission: "You're missing the permission to do that."
- invalid_username: "This is an invalid Minecraft username."
- mojang: "Something went wrong while fetching data from Mojang."
- cache: "Unable to get data from the cache."
-
-event:
- settings:
- error: "Wasn''t able to update your settings! ({0})"
- appearance:
- set:
- error: "Wasn''t able to apply your disguise! ({0})"
- ok: "You''re now disguised."
- chat_prompt_name: "Please enter your new name in chat (type \"EXIT\" to cancel)."
- chat_prompt_skin: "Please enter your new skin in chat (type \"EXIT\" to cancel)."
- restore:
- error: "Wasn''t able to apply the previous disguise! ({0})"
- ok: "Previous disguise restored."
- remove:
- error: "Wasn''t able to remove your disguise!."
- missing: "You''re not currently disguised."
- ok: "Undisguised successfully."
- admin:
- cache:
- invalidate_cache: "Cache purged."
- invalidate_entry: "{0} was purged."
- check:
- remove_skin: "Skin removed from player."
-
-gui:
- title:
- home: "Nicko"
- settings: "Settings"
- admin: "Administration"
- check: "Player Management"
- confirm: "Are you sure?"
- cache: "Cache Management"
- invalidate_skin: "Purge cache..."
- favorites: "Favorites"
-
- exit:
- name: "Exit"
- go_back:
- name: "Back"
- unavailable:
- name: "Unavailable"
- lore:
- - "This button is disabled."
- error:
- name: "Error!"
- lore:
- - "The item failed to load, but it might still work."
- loading:
- name: "Loading..."
- choice:
- confirm:
- name: "Confirm"
- choose:
- name: "Choose an option..."
- cancel:
- name: "Cancel"
- scroll_up:
- name: "Scroll up"
- lore:
- - "(You can't scroll any higher.)"
- scroll_down:
- name: "Scroll down"
- lore:
- - "(You can't scroll any further down.)"
- new_skin:
- name: "New skin..."
- new_name:
- name: "New name..."
- home:
- admin:
- name: "Administration panel"
- lore:
- - "Configure and manage Nicko."
- settings:
- name: "Settings"
- lore:
- - "Fine tune your experience with Nicko."
- change_name:
- name: "Change your nickname"
- change_skin:
- name: "Change your skin"
- change_both:
- name: "Change both"
- random_skin:
- name: "I feel lucky!"
- reset:
- name: "Reset appearance"
- lore:
- - "Completely remove your disguise."
- favorites:
- name: "Favorites"
- lore:
- - "List all your favorites appearances."
- admin:
- manage_cache:
- name: "Manage the skin cache..."
- lore:
- - "View and manage the skin cache."
- manage_player:
- name: "Inspect a player..."
- lore:
- - "See players' disguise information."
- check:
- name: "{0}"
- lore:
- - "Nicked: {1}"
- - "Name: {2}"
- - "Skin: {3}"
- - " "
- - "Click to remove skin!"
- cache:
- statistics:
- name: "Statistics"
- lore:
- - "Request count: {0}"
- - "Number of skin cached: {1}"
- - "Cache is cleared every 24 hours."
- invalidate_cache:
- name: "Invalidate cache"
- lore:
- - "NOT RECOMMENDED"
- - "Invalidate the entirety of the skin cache."
- - "This doesn't reset player's disguises."
- invalidate_skin:
- name: "Invalidate a skin..."
- lore:
- - "Select a specific skin to invalidate."
- - "Useful if a skin has been recently updated."
- entry:
- name: "{0}"
- lore:
- - "Click to invalidate..."
- settings:
- toggleable_button:
- lore:
- - "{0} Disabled"
- - "{1} Enabled"
- cycling_choices:
- lore:
- - "Cycle through the values"
- - "by left or right clicking."
- language:
- name: "Language"
- random_skin:
- name: "Random skin on login"
- favorites:
- add:
- name: "Add a favorite"
- lore:
- - "Add a new favorite appearance to the list."
- - "Hold SHIFT to add your current disguise!"
- remove:
- name: "Toggle deletion mode"
- lore:
- - "Clicking on any disguise as this mode is"
- - "active will remove it from your favorites."
- entry:
- name: "Favorite"
- lore:
- - "Name: {0}"
- - "Skin: {1}"
\ No newline at end of file
diff --git a/src/main/resources/fr.yml b/src/main/resources/fr.yml
deleted file mode 100644
index 109a887..0000000
--- a/src/main/resources/fr.yml
+++ /dev/null
@@ -1,177 +0,0 @@
-# Nicko ${version} - Fichier de langue:
-
-# Précise la version de la configuration, ne pas changer.
-version: "1.4.0"
-
-prefix: "NICKO"
-whoosh: "WHOOSH!"
-oops: "OOPS!"
-
-error:
- permission: "Vous n'avez pas la permission de faire cela."
- invalid_username: "Nom d'utilisateur Minecraft invalide."
- mojang: "Une erreur est surevenue en récupérant les information depuis Mojang."
- cache: "Impossible de récupérer les données depuis le cache."
-
-event:
- settings:
- error: "Impossible de mettre à jour vos paramètres ! ({0})"
- appearance:
- set:
- error: "Impossible d''appliquer votre déguisement ! ({0})"
- ok: "Déguisement appliqué avec succès."
- chat_prompt_name: "Veuillez entrer votre nouveau pseudo (saisissez \"EXIT\" pour arrêter)."
- chat_prompt_skin: "Veuillez entrer votre nouveau skin (saisissez \"EXIT\" pour arrêter)."
- restore:
- error: "Impossible d''appliquer le précédent déguisement ! ({0})"
- ok: "Votre précédent déguisement a été appliqué."
- remove:
- error: "Impossible de retirer votre déguisement."
- missing: "Vous n''avez pas de déguisement."
- ok: "Déguisement retiré."
- admin:
- cache:
- invalidate_cache: "Cache complet invalidé."
- invalidate_entry: "{0} a été invalidé."
- check:
- remove_skin: "Déguisement retiré au joueur."
-
-gui:
- title:
- home: "Nicko"
- settings: "Paramètres"
- admin: "Administration"
- check: "Gestion des Joueurs"
- confirm: "Êtes-vous sûr ?"
- cache: "Gestion du Cache"
- invalidate_skin: "Purge du cache..."
- favorites: "Favoris"
-
- exit:
- name: "Quitter"
- go_back:
- name: "Retour"
- unavailable:
- name: "Indisponible"
- lore:
- - "Ce boutton est désactivé."
- error:
- name: "Erreur !"
- lore:
- - "La texture de l'objet n'a pas chargé"
- - "correctement mais il fonctionne encore."
- loading:
- name: "Chargement..."
- choice:
- confirm:
- name: "Confirmer"
- choose:
- name: "Choisissez une option..."
- cancel:
- name: "Annuler"
- scroll_up:
- name: "Défiler vers le haut"
- lore:
- - "(Impossible de défiler plus haut.)"
- scroll_down:
- name: "Défiler vers le bas"
- lore:
- - "(Impossible de défiler plus bas.)"
- new_skin:
- name: "Nouveau skin..."
- new_name:
- name: "Nouveau nom..."
- home:
- admin:
- name: "Panel d'administration"
- lore:
- - "Configurez et gérez Nicko."
- settings:
- name: "Paramètres"
- lore:
- - "Gérez votre expérience avec Nicko."
- change_name:
- name: "Changer le pseudo"
- change_skin:
- name: "Changer le skin"
- change_both:
- name: "Changer les deux"
- random_skin:
- name: "Je me sens chanceux !"
- reset:
- name: "Réinitialiser l'apparence"
- lore:
- - "Supprime complètement votre déguisement."
- favorites:
- name: "Favoris"
- lore:
- - "Listez toutes vos apparences favorites."
- admin:
- manage_cache:
- name: "Gérer le cache de skin..."
- lore:
- - "Consultez et gérez le cache de skin."
- manage_player:
- name: "Vérifier un joueur..."
- lore:
- - "Vérifiez les informations de déguisement d'un joueur."
- check:
- name: "{0}"
- lore:
- - "Déguisé: {1}"
- - "Nom: {2}"
- - "Skin: {3}"
- - " "
- - "Cliquez pour retirer le skin !"
- cache:
- statistics:
- name: "Statistiques"
- lore:
- - "Nombre de requêtes: {0}"
- - "Nb. de skin dans le cache: {1}"
- - "Le cache est vidé toutes les 24 heures."
- invalidate_cache:
- name: "Purger le cache"
- lore:
- - "DÉCONSEILLÉ"
- - "Purge l'entièreté du cache des skin."
- - "Ne retire pas les déguisements des joueurs."
- invalidate_skin:
- name: "Invalider un skin..."
- lore:
- - "Sélectionnez une apparence spécifique à"
- - "invalider. Utile dans le cas où un skin"
- - "a récemment été mis à jour."
- entry:
- name: "{0}"
- lore:
- - "Cliquez pour invalider..."
- settings:
- toggleable_button:
- lore:
- - "{0} Désactivé"
- - "{1} Activé"
- cycling_choices:
- lore:
- - "Parcourez les valeurs"
- - "avec un clique gauche/droit."
- language:
- name: "Langage"
- random_skin:
- name: "Apparence aléatoire à la connexion"
- favorites:
- add:
- name: "Ajouter un favori"
- lore:
- - "Ajoute une nouvelle apparence favorite."
- - "Maintenez SHIFT pour ajouter votre apparence actuelle !"
- remove:
- name: "Activer la suppression"
- lore:
- - "Cliquer sur un déguisement lorsque le mode est"
- - "actif le supprimera de vos favoris."
- entry:
- name: "Favori"
- lore:
- - "Nom: {0}"
- - "Skin: {1}"
\ No newline at end of file
diff --git a/src/main/resources/names.txt b/src/main/resources/names.txt
deleted file mode 100644
index 0d54e92..0000000
--- a/src/main/resources/names.txt
+++ /dev/null
@@ -1,490 +0,0 @@
-w4nderlost
-TooParanoids
-Der_OG_31er
-9xxDaRkShAdOwxx9
-giiiaan_
-Jqstinnn
-Tillysboy92
-AlwaysCello
-SyndrexG0D
-Peypeycake
-ThePerjurer
-Tioe
-Elternbaum
-BarkersRover_16
-pebsso
-cyrus6950
-Bigest_guy
-RV0REU
-R379
-Shetell
-_HEAPASS_
-Iamaloner21
-TheFardoxGamerHD
-Flyboi43
-Cha0smusik
-kat00
-Infreat
-Crummymoofin
-MijnVriend
-momsrightkidney
-dmacrado
-Elephantman321
-ii_hamoudi_YT
-FaurePavane
-ambiezzz
-XD_Bandit695_XD
-Nabingo
-Cyl0re
-ku5
-SrAragon
-StarlightDream9
-CJ5370
-rainbees
-KeroTheWolf
-Andrews9722
-cursed_Assyrian
-yamateni
-ProgramEXE
-exprso
-harrypanda
-LookerMD
-migykins
-Wintrous
-ZzGaBi
-Flayber
-Grenixal
-maeve_wells
-Creeper10fr
-10Chairs
-2525lock
-Shqipe
-XenitsuZen
-Berno17_
-wolle1313
-HalfDogHalfCat1
-NachoGarcia
-popsicoal
-NemesiSevil2006
-AnywayOj
-Tanko12345
-Samdweck
-LYRECODE123
-Resulten
-SirBastii
-Maku056
-ItzArnizzz
-Brsh3620
-Masonita
-kapplanium
-shoezo
-Mansur203
-Waterboy15217
-redragonne
-ghko325
-HopePVP_tw7
-xtka
-NimwenxZ
-Hiro0408
-PanderaWz
-Shesu
-_Aniste_NY_
-Besceste
-3ee3
-ArcticGalaxy123
-snooze_mingo
-LizzyLomnh
-FaZeChulupa
-LineZeeK
-liabilaty
-BlackSheep1610
-Simif69
-Aficionado
-riekin
-XLuggas
-MathExams
-6fq
-Marveel
-lolme51
-TaioSayUwU
-Fonklift
-blvw
-Po1204
-Pierre_Rabbit
-mifimasters
-MrRidge1
-arnqen
-Nick_cage102
-Geo_9918
-SSShudder
-Nicolas_Mom
-WolfMatrix101
-frictionless_
-Gughik
-gold_dragon_4
-nealxero
-ClonedPickle
-SourWatermelonxX
-devilunion
-Daryifuny
-joaomarcos11
-Dekeef
-PadfootTheDog
-DarkScopez80
-flowers220
-Gaiiya
-The_Yeet_
-juuuuwu
-MrMafioz
-Surpasses
-TypicalOwen
-0lober
-Zerfixy
-Sunny3803b
-neostanley
-Creeper_Kart
-minestin
-Goldenfredster
-Vju
-MrArchI_YT
-Casper1709
-Backiii_
-DrCreate
-Nova_Lux1
-Jayvin_Blanco
-ShadowMan1770
-0KOPO40K
-Silk_Altermann69
-Alu____
-Honey_MilkExe112
-T0XEI
-CB_13
-Paragorn
-HaGiang
-Shivendra8i
-Mayflower47
-Not_Someguy
-raxx111bg
-IceyGlaceon
-grasseffect
-PoopTNTpvp
-codecyber
-Shrumpkin13
-Shqdown
-Cmartin82
-KTCXD_5p0tty
-rockesalt
-goldjeong
-TheRealAKD
-NamiSwaaan
-yaaratol
-Dikiy_Flexer
-PoLecker24
-_SakuraTree
-PikkOgP0rno
-HawksFang
-BlueWinterWolf
-hskmerk
-gurmaw
-Lunggor
-clashfield
-Zelaste
-ACommonMouse
-TJ_Mystery
-Dizzy3312
-Raindropsss
-minecraftxiaoju
-sachilovebbh
-Celina_LaZyCxt
-firered6
-55000000
-Illunarnati
-Jedidiah2003
-setomz1
-basically_e
-TommyGreif02
-Bongrip42069
-Coco_Keopi
-Lt_Colt
-Kuurotta
-GqmeKnight
-WinCo_Foods
-FKDLZ
-IanPumpkin
-tastywtf
-natedawg0
-ZQLFenyx
-GamerMaster110
-papajobi9
-Yucaroon
-Xion_69
-AirJaw
-funfun321234
-khalleesii
-Pozisch
-thorso15
-kyumisoup
-Leonqrd
-BmwDreamer
-TehRos
-pitplayer69
-_ve0
-Miss_Yuka
-I_am_a_Bucket
-nicolas_bean
-xHorizonGC
-RTX3060_
-Borec188
-c8to
-megan3groCENG
-ventriloquize
-galczin
-Scorch3dEarth3d
-nightstarLP
-VittyGam3r
-GLaDOS__
-hydrelo
-JustACarter
-MikeDropperPlay
-NorthernWest
-_Skelesam_
-ZX_Style
-Tamas_Boi
-taylub
-VyacheslavO_O
-trippyaubs
-udtpic
-Lunarglow
-Stoolman
-legendary_meow
-Loganii
-CaptainStain56
-FoofieGeto
-Judgeavapl
-OneBigDigger
-Sorem13
-Raisonneur
-IlkoalI
-Naxa
-craigbabyonebay
-NicholasG04
-UtopianCrisi
-CalamarPasGenti
-ryluh_
-Aceslimz
-Howardygh99927
-brandon257
-MarcoswildHD
-x_XSkylerX_x
-Bronco09
-That_Kookie_
-Danigtz
-Ricky_lol
-999keyt
-Thilow15
-Difesito
-ostehovl
-isacano_12
-big_esra
-secretbaguette
-MrCommunism
-Jekube
-GrandeMaster
-DrGrip
-TheArnek
-JacsMars
-Lliam14
-MrGameandWatch84
-Rinzap
-XrazzeD
-ukknown
-ZohanPrent
-Naspo
-Rajem
-VepiGHG
-matoureal
-BrianChen87
-Jrocky
-stivo999
-Des_cole
-ReqGames
-Kingja1912
-issssyy
-Apache424
-Nick_Zockt_
-Mr_Haider_10
-ValentineBun
-fedorPro228
-xTilz
-blockbuster02k
-4ck
-FrostedTree
-VegasTortoise
-ZBellaV12121
-paypales
-qDread
-itsRiven
-i8oreo
-_kimcream_
-Phisuss
-Oscargray
-Elsiff
-callofdutydog00
-BruhTheMoment
-Pazmaa
-MythicalOak
-komuchi33
-awf4
-Jacobsaurus21
-itsjohannaa
-Jello12
-Adrien183
-jajazzywazzy
-Jorjie22
-SuperBrawlr5788
-KaraageV
-_Hanime_tv
-Padilhao
-Tikkas
-ordinaryducky
-Mothytix95
-renopotouwu
-1000voices
-niclas05
-Felipstein
-DoutorBauer
-FireballPlaysMC
-vapelordsheep
-Aboain
-ImGrexy
-Aivokolo
-SuperAmazing101
-va75a77a
-_DawYans_
-AceT1223
-Livvyboo7
-Saaaaaaaaaaaaans
-okaychill
-AwesomeBro1122
-absolutesnek
-jogie5000
-curtainSenpai
-gabbyisaloser
-gamergurl6969
-ZeusDk
-FranaRibas
-Discoboss
-SYZ_1
-Nakoe
-FIU_Captive
-xSiFan_
-ilyDeathxz
-da_fipsi
-Lochy
-The_Lavie37
-Tonion
-vnvrchy
-xX0meg4Xx
-haohxtheone
-VtTronic
-xDaniGum
-tikkelill
-DatYoshi
-eyehamstewpit
-nicholas460_
-Memsly445
-nugunugu
-AndreSlayz
-jashik1
-Qweenoftheocean
-Coltable
-treblaclef
-Kisaxx
-69Dxddy69
-RaulCuh
-3Wheat
-_OscarTheGrouch
-oIsqk
-Blockbusterweng
-AntoineDegauss
-ValeIsTheBest
-SwaggyCrabby
-DieOfSanity
-SirenMC
-Jade_Jewel
-Tropic44
-666splendor
-TallnessTallness
-breadgang9827
-Muffin_Worlds
-DedicatedVeggie
-Gonzalox_7
-datrandomasian
-Chasemon01
-Nyavix
-Lonely_Summers
-_RoveN
-ok_kyro
-LN_hunter
-saharsabz
-Roselilianna
-Gadx
-xtytan
-RoRo_levosgien88
-Bowsesqe_21
-Bennett528
-TheShipSailsWest
-KaiserGaming
-Layna_Shinozaki
-OP_greatly
-D3rpTaco
-Loufink
-Jorlmungus
-Snichol1801
-Ludixeo
-Imoeto
-MarshallNebunu
-crazycrystals
-Parapatus
-HahaDani
-MrQuaring
-DonTurnt
-SailorRoberts101
-FluffieBear
-TripleThick
-KingSparta
-MummysHome
-Cooga3
-Technosista
-Youmerstudios
-SkyyRaine
-criss102
-mrfailt
-CraftingBasic
-qnxkdifh
-Igorex2k20
-LaLisette
-ReBoredGamer
-warlordwest
-ExoTemporal
-KingLonmc
-666Horus
-IslandCity2
-TheBigSavage1
-Trishke2003
-skyrowin
-Krissy3D
-AntonWTobias
-SaddyWasTaken
-Ahoy_Peko_Hao_Yo
-T4nTr1Ss
-aleciolike
-ninja_shenley
-Lordmord1337
-eatmypoopfather
-Ktanner
-The42OWeedGOD
-CooperBee
-_MikuMiku_
-althume
-Tr3bba93
\ No newline at end of file
diff --git a/src/main/resources/paper-plugin.yml b/src/main/resources/paper-plugin.yml
deleted file mode 100644
index f515c80..0000000
--- a/src/main/resources/paper-plugin.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-name: Nicko
-main: xyz.ineanto.nicko.Nicko
-loader: xyz.ineanto.nicko.loader.NickoPluginLoader
-version: ${version}
-author: Ineanto
-description: "The feature packed, next generation disguise plugin for Minecraft."
-api-version: "1.21"
-softdepend: [ PlaceholderAPI ]
-depend:
- - ProtocolLib
-
-dependencies:
- server:
- ProtocolLib:
- load: BEFORE
- join-classpath: true
-
-permissions:
- nicko.*:
- default: op
- children:
- - nicko.use
- nicko.use:
- default: false
\ No newline at end of file
diff --git a/v1_13_R1/pom.xml b/v1_13_R1/pom.xml
new file mode 100644
index 0000000..6aa987b
--- /dev/null
+++ b/v1_13_R1/pom.xml
@@ -0,0 +1,28 @@
+
+
+
+ nicko-parent
+ net.artelnatif
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ v1_13_R1
+ 1.0-SNAPSHOT
+
+
+
+ org.spigotmc
+ spigot
+ 1.13-R0.1-SNAPSHOT
+ provided
+
+
+ net.artelnatif
+ core
+ 1.0-SNAPSHOT
+
+
+
\ No newline at end of file
diff --git a/v1_13_R1/src/main/java/net/artelnatif/nicko/impl/v1_13_R1.java b/v1_13_R1/src/main/java/net/artelnatif/nicko/impl/v1_13_R1.java
new file mode 100644
index 0000000..013ddd4
--- /dev/null
+++ b/v1_13_R1/src/main/java/net/artelnatif/nicko/impl/v1_13_R1.java
@@ -0,0 +1,128 @@
+package net.artelnatif.nicko.impl;
+
+import com.google.common.collect.Lists;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import com.mojang.authlib.properties.PropertyMap;
+import net.artelnatif.nicko.NickoBukkit;
+import net.artelnatif.nicko.disguise.ActionResult;
+import net.artelnatif.nicko.disguise.NickoProfile;
+import net.artelnatif.nicko.mojang.MojangSkin;
+import net.minecraft.server.v1_13_R1.*;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_13_R1.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerTeleportEvent;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+
+public class v1_13_R1 implements Internals {
+ @Override
+ public void updateSelf(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final WorldServer worldServer = entityPlayer.getWorldServer();
+ final PacketPlayOutRespawn respawn = new PacketPlayOutRespawn(worldServer.dimension,
+ worldServer.getDifficulty(),
+ worldServer.worldData.getType(),
+ entityPlayer.playerInteractManager.getGameMode());
+
+ final boolean wasFlying = player.isFlying();
+ entityPlayer.playerConnection.sendPacket(respawn);
+ player.setFlying(wasFlying);
+ player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
+ player.updateInventory();
+ }
+
+ @Override
+ public void updateOthers(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final PacketPlayOutEntityDestroy destroy = new PacketPlayOutEntityDestroy(entityPlayer.getBukkitEntity().getEntityId());
+ final PacketPlayOutNamedEntitySpawn spawn = new PacketPlayOutNamedEntitySpawn(entityPlayer);
+
+ final DataWatcher dataWatcher = entityPlayer.getDataWatcher();
+ final DataWatcherObject displayedSkinPartDataWatcher = new DataWatcherObject<>(17, DataWatcherRegistry.a);
+ dataWatcher.set(displayedSkinPartDataWatcher, (byte) 0x7f);
+ final PacketPlayOutEntityMetadata entityMetadata = new PacketPlayOutEntityMetadata(entityPlayer.getBukkitEntity().getEntityId(), dataWatcher, true);
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ if (onlineEntityPlayer.getBukkitEntity().getUniqueId() != player.getUniqueId()) {
+ onlineEntityPlayer.playerConnection.sendPacket(destroy);
+ onlineEntityPlayer.playerConnection.sendPacket(spawn);
+ }
+ onlineEntityPlayer.playerConnection.sendPacket(entityMetadata);
+ });
+ }
+
+ @Override
+ public ActionResult updateProfile(Player player, NickoProfile profile, boolean skinChange, boolean reset) {
+ final boolean changeOnlyName = profile.getSkin() != null && !profile.getSkin().equalsIgnoreCase(player.getName());
+ final String profileName = profile.getName() == null ? player.getName() : profile.getName();
+
+ final CraftPlayer craftPlayer = (CraftPlayer) player;
+ final EntityPlayer entityPlayer = craftPlayer.getHandle();
+ final GameProfile gameProfile = new GameProfile(player.getUniqueId(), profileName);
+
+ if (skinChange || changeOnlyName) {
+ final ActionResult skinFetch = fetchSkinTextures(profile, reset);
+ if (!skinFetch.isError()) {
+ final MojangSkin skin = skinFetch.getResult();
+ final PropertyMap properties = gameProfile.getProperties();
+ properties.removeAll("textures");
+ properties.put("textures", new Property("textures", skin.getValue(), skin.getSignature()));
+ updateSelf(player);
+ }
+ }
+
+ final PacketPlayOutPlayerInfo remove = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, entityPlayer);
+ final PacketPlayOutPlayerInfo add = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER);
+ final IChatBaseComponent name = new ChatComponentText(profileName);
+
+ final Object infoData = yes(
+ add,
+ gameProfile,
+ entityPlayer.ping,
+ EnumGamemode.getById(player.getGameMode().ordinal()),
+ name
+ );
+ spoofPlayerInfoPacket(add, Lists.newArrayList(infoData));
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ onlineEntityPlayer.playerConnection.sendPacket(remove);
+ onlineEntityPlayer.playerConnection.sendPacket(add);
+ });
+ updateOthers(player);
+ return new ActionResult<>();
+ }
+
+ private void spoofPlayerInfoPacket(Object object, Object newValue) {
+ try {
+ final Field field = object.getClass().getDeclaredField("b");
+ field.setAccessible(true);
+ field.set(object, newValue);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ NickoBukkit.getInstance().getLogger().warning("Unable to spoof packet, that's bad! (" + e.getMessage() + ")");
+ }
+ }
+
+ public Object yes(PacketPlayOutPlayerInfo packet, GameProfile gameProfile, int ping, EnumGamemode gamemode, IChatBaseComponent name) {
+ try {
+ final Class> clazz = Class.forName("net.minecraft.server.v1_13_R1.PacketPlayOutPlayerInfo$PlayerInfoData");
+ final Constructor> infoConstructor = clazz.getDeclaredConstructor(
+ PacketPlayOutPlayerInfo.class,
+ GameProfile.class,
+ int.class,
+ EnumGamemode.class,
+ IChatBaseComponent.class
+ );
+ return infoConstructor.newInstance(packet, gameProfile, ping, gamemode, name);
+ } catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException | InstantiationException |
+ IllegalAccessException e) {
+ NickoBukkit.getInstance().getLogger().warning("Unable to instantiate PlayerInfoData, that's bad! (" + e.getMessage() + ")");
+ return null;
+ }
+ }
+}
diff --git a/v1_13_R2/pom.xml b/v1_13_R2/pom.xml
new file mode 100644
index 0000000..1e1606a
--- /dev/null
+++ b/v1_13_R2/pom.xml
@@ -0,0 +1,28 @@
+
+
+
+ nicko-parent
+ net.artelnatif
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ v1_13_R2
+ 1.0-SNAPSHOT
+
+
+
+ org.spigotmc
+ spigot
+ 1.13.2-R0.1-SNAPSHOT
+ provided
+
+
+ net.artelnatif
+ core
+ 1.0-SNAPSHOT
+
+
+
\ No newline at end of file
diff --git a/v1_13_R2/src/main/java/net/artelnatif/nicko/impl/v1_13_R2.java b/v1_13_R2/src/main/java/net/artelnatif/nicko/impl/v1_13_R2.java
new file mode 100644
index 0000000..ada42dc
--- /dev/null
+++ b/v1_13_R2/src/main/java/net/artelnatif/nicko/impl/v1_13_R2.java
@@ -0,0 +1,128 @@
+package net.artelnatif.nicko.impl;
+
+import com.google.common.collect.Lists;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import com.mojang.authlib.properties.PropertyMap;
+import net.artelnatif.nicko.NickoBukkit;
+import net.artelnatif.nicko.disguise.ActionResult;
+import net.artelnatif.nicko.disguise.NickoProfile;
+import net.artelnatif.nicko.mojang.MojangSkin;
+import net.minecraft.server.v1_13_R2.*;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerTeleportEvent;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+
+public class v1_13_R2 implements Internals {
+ @Override
+ public void updateSelf(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final WorldServer worldServer = entityPlayer.getWorldServer();
+ final PacketPlayOutRespawn respawn = new PacketPlayOutRespawn(worldServer.dimension,
+ worldServer.getDifficulty(),
+ worldServer.S(),
+ entityPlayer.playerInteractManager.getGameMode());
+
+ final boolean wasFlying = player.isFlying();
+ entityPlayer.playerConnection.sendPacket(respawn);
+ player.setFlying(wasFlying);
+ player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
+ player.updateInventory();
+ }
+
+ @Override
+ public void updateOthers(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final PacketPlayOutEntityDestroy destroy = new PacketPlayOutEntityDestroy(entityPlayer.getBukkitEntity().getEntityId());
+ final PacketPlayOutNamedEntitySpawn spawn = new PacketPlayOutNamedEntitySpawn(entityPlayer);
+
+ final DataWatcher dataWatcher = entityPlayer.getDataWatcher();
+ final DataWatcherObject displayedSkinPartDataWatcher = new DataWatcherObject<>(17, DataWatcherRegistry.a);
+ dataWatcher.set(displayedSkinPartDataWatcher, (byte) 0x7f);
+ final PacketPlayOutEntityMetadata entityMetadata = new PacketPlayOutEntityMetadata(entityPlayer.getBukkitEntity().getEntityId(), dataWatcher, true);
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ if (onlineEntityPlayer.getBukkitEntity().getUniqueId() != player.getUniqueId()) {
+ onlineEntityPlayer.playerConnection.sendPacket(destroy);
+ onlineEntityPlayer.playerConnection.sendPacket(spawn);
+ }
+ onlineEntityPlayer.playerConnection.sendPacket(entityMetadata);
+ });
+ }
+
+ @Override
+ public ActionResult updateProfile(Player player, NickoProfile profile, boolean skinChange, boolean reset) {
+ final boolean changeOnlyName = profile.getSkin() != null && !profile.getSkin().equalsIgnoreCase(player.getName());
+ final String profileName = profile.getName() == null ? player.getName() : profile.getName();
+
+ final CraftPlayer craftPlayer = (CraftPlayer) player;
+ final EntityPlayer entityPlayer = craftPlayer.getHandle();
+ final GameProfile gameProfile = new GameProfile(player.getUniqueId(), profileName);
+
+ if (skinChange || changeOnlyName) {
+ final ActionResult skinFetch = fetchSkinTextures(profile, reset);
+ if (!skinFetch.isError()) {
+ final MojangSkin skin = skinFetch.getResult();
+ final PropertyMap properties = gameProfile.getProperties();
+ properties.removeAll("textures");
+ properties.put("textures", new Property("textures", skin.getValue(), skin.getSignature()));
+ updateSelf(player);
+ }
+ }
+
+ final PacketPlayOutPlayerInfo remove = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, entityPlayer);
+ final PacketPlayOutPlayerInfo add = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER);
+ final IChatBaseComponent name = new ChatComponentText(profileName);
+
+ final Object infoData = yes(
+ add,
+ gameProfile,
+ entityPlayer.ping,
+ EnumGamemode.getById(player.getGameMode().ordinal()),
+ name
+ );
+ spoofPlayerInfoPacket(add, Lists.newArrayList(infoData));
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ onlineEntityPlayer.playerConnection.sendPacket(remove);
+ onlineEntityPlayer.playerConnection.sendPacket(add);
+ });
+ updateOthers(player);
+ return new ActionResult<>();
+ }
+
+ private void spoofPlayerInfoPacket(Object object, Object newValue) {
+ try {
+ final Field field = object.getClass().getDeclaredField("b");
+ field.setAccessible(true);
+ field.set(object, newValue);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ NickoBukkit.getInstance().getLogger().warning("Unable to spoof packet, that's bad! (" + e.getMessage() + ")");
+ }
+ }
+
+ public Object yes(PacketPlayOutPlayerInfo packet, GameProfile gameProfile, int ping, EnumGamemode gamemode, IChatBaseComponent name) {
+ try {
+ final Class> clazz = Class.forName("net.minecraft.server.v1_13_R2.PacketPlayOutPlayerInfo$PlayerInfoData");
+ final Constructor> infoConstructor = clazz.getDeclaredConstructor(
+ PacketPlayOutPlayerInfo.class,
+ GameProfile.class,
+ int.class,
+ EnumGamemode.class,
+ IChatBaseComponent.class
+ );
+ return infoConstructor.newInstance(packet, gameProfile, ping, gamemode, name);
+ } catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException | InstantiationException |
+ IllegalAccessException e) {
+ NickoBukkit.getInstance().getLogger().warning("Unable to instantiate PlayerInfoData, that's bad! (" + e.getMessage() + ")");
+ return null;
+ }
+ }
+}
diff --git a/v1_14_R1/pom.xml b/v1_14_R1/pom.xml
new file mode 100644
index 0000000..f69fa93
--- /dev/null
+++ b/v1_14_R1/pom.xml
@@ -0,0 +1,28 @@
+
+
+
+ nicko-parent
+ net.artelnatif
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ v1_14_R1
+ 1.0-SNAPSHOT
+
+
+
+ org.spigotmc
+ spigot
+ 1.14.4-R0.1-SNAPSHOT
+ provided
+
+
+ net.artelnatif
+ core
+ 1.0-SNAPSHOT
+
+
+
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/artelnatif/nicko/impl/v1_14_R1.java b/v1_14_R1/src/main/java/net/artelnatif/nicko/impl/v1_14_R1.java
new file mode 100644
index 0000000..8cb1887
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/artelnatif/nicko/impl/v1_14_R1.java
@@ -0,0 +1,126 @@
+package net.artelnatif.nicko.impl;
+
+import com.google.common.collect.Lists;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import com.mojang.authlib.properties.PropertyMap;
+import net.artelnatif.nicko.NickoBukkit;
+import net.artelnatif.nicko.disguise.ActionResult;
+import net.artelnatif.nicko.disguise.NickoProfile;
+import net.artelnatif.nicko.mojang.MojangSkin;
+import net.minecraft.server.v1_14_R1.*;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerTeleportEvent;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+
+public class v1_14_R1 implements Internals {
+ @Override
+ public void updateSelf(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final PacketPlayOutRespawn respawn = new PacketPlayOutRespawn(entityPlayer.getWorldServer().getWorldProvider().getDimensionManager(),
+ entityPlayer.getWorld().P(),
+ entityPlayer.playerInteractManager.getGameMode());
+
+ final boolean wasFlying = player.isFlying();
+ entityPlayer.playerConnection.sendPacket(respawn);
+ player.setFlying(wasFlying);
+ player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
+ player.updateInventory();
+ }
+
+ @Override
+ public void updateOthers(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final PacketPlayOutEntityDestroy destroy = new PacketPlayOutEntityDestroy(entityPlayer.getBukkitEntity().getEntityId());
+ final PacketPlayOutNamedEntitySpawn spawn = new PacketPlayOutNamedEntitySpawn(entityPlayer);
+
+ final DataWatcher dataWatcher = entityPlayer.getDataWatcher();
+ final DataWatcherObject displayedSkinPartDataWatcher = new DataWatcherObject<>(17, DataWatcherRegistry.a);
+ dataWatcher.set(displayedSkinPartDataWatcher, (byte) 0x7f);
+ final PacketPlayOutEntityMetadata entityMetadata = new PacketPlayOutEntityMetadata(entityPlayer.getBukkitEntity().getEntityId(), dataWatcher, true);
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ if (onlineEntityPlayer.getBukkitEntity().getUniqueId() != player.getUniqueId()) {
+ onlineEntityPlayer.playerConnection.sendPacket(destroy);
+ onlineEntityPlayer.playerConnection.sendPacket(spawn);
+ }
+ onlineEntityPlayer.playerConnection.sendPacket(entityMetadata);
+ });
+ }
+
+ @Override
+ public ActionResult updateProfile(Player player, NickoProfile profile, boolean skinChange, boolean reset) {
+ final boolean changeOnlyName = profile.getSkin() != null && !profile.getSkin().equalsIgnoreCase(player.getName());
+ final String profileName = profile.getName() == null ? player.getName() : profile.getName();
+
+ final CraftPlayer craftPlayer = (CraftPlayer) player;
+ final EntityPlayer entityPlayer = craftPlayer.getHandle();
+ final GameProfile gameProfile = new GameProfile(player.getUniqueId(), profileName);
+
+ if (skinChange || changeOnlyName) {
+ final ActionResult skinFetch = fetchSkinTextures(profile, reset);
+ if (!skinFetch.isError()) {
+ final MojangSkin skin = skinFetch.getResult();
+ final PropertyMap properties = gameProfile.getProperties();
+ properties.removeAll("textures");
+ properties.put("textures", new Property("textures", skin.getValue(), skin.getSignature()));
+ updateSelf(player);
+ }
+ }
+
+ final PacketPlayOutPlayerInfo remove = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, entityPlayer);
+ final PacketPlayOutPlayerInfo add = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER);
+ final IChatBaseComponent name = new ChatComponentText(profileName);
+
+ final Object infoData = yes(
+ add,
+ gameProfile,
+ entityPlayer.ping,
+ EnumGamemode.getById(player.getGameMode().ordinal()),
+ name
+ );
+ spoofPlayerInfoPacket(add, Lists.newArrayList(infoData));
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ onlineEntityPlayer.playerConnection.sendPacket(remove);
+ onlineEntityPlayer.playerConnection.sendPacket(add);
+ });
+ updateOthers(player);
+ return new ActionResult<>();
+ }
+
+ private void spoofPlayerInfoPacket(Object object, Object newValue) {
+ try {
+ final Field field = object.getClass().getDeclaredField("b");
+ field.setAccessible(true);
+ field.set(object, newValue);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ NickoBukkit.getInstance().getLogger().warning("Unable to spoof packet, that's bad! (" + e.getMessage() + ")");
+ }
+ }
+
+ public Object yes(PacketPlayOutPlayerInfo packet, GameProfile gameProfile, int ping, EnumGamemode gamemode, IChatBaseComponent name) {
+ try {
+ final Class> clazz = Class.forName("net.minecraft.server.v1_14_R1.PacketPlayOutPlayerInfo$PlayerInfoData");
+ final Constructor> infoConstructor = clazz.getDeclaredConstructor(
+ PacketPlayOutPlayerInfo.class,
+ GameProfile.class,
+ int.class,
+ EnumGamemode.class,
+ IChatBaseComponent.class
+ );
+ return infoConstructor.newInstance(packet, gameProfile, ping, gamemode, name);
+ } catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException | InstantiationException |
+ IllegalAccessException e) {
+ NickoBukkit.getInstance().getLogger().warning("Unable to instantiate PlayerInfoData, that's bad! (" + e.getMessage() + ")");
+ return null;
+ }
+ }
+}
diff --git a/v1_15_R1/pom.xml b/v1_15_R1/pom.xml
new file mode 100644
index 0000000..783358e
--- /dev/null
+++ b/v1_15_R1/pom.xml
@@ -0,0 +1,28 @@
+
+
+
+ nicko-parent
+ net.artelnatif
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ v1_15_R1
+ 1.0-SNAPSHOT
+
+
+
+ org.spigotmc
+ spigot
+ 1.15.2-R0.1-SNAPSHOT
+ provided
+
+
+ net.artelnatif
+ core
+ 1.0-SNAPSHOT
+
+
+
\ No newline at end of file
diff --git a/v1_15_R1/src/main/java/net/artelnatif/nicko/impl/v1_15_R1.java b/v1_15_R1/src/main/java/net/artelnatif/nicko/impl/v1_15_R1.java
new file mode 100644
index 0000000..1bffee0
--- /dev/null
+++ b/v1_15_R1/src/main/java/net/artelnatif/nicko/impl/v1_15_R1.java
@@ -0,0 +1,129 @@
+package net.artelnatif.nicko.impl;
+
+import com.google.common.collect.Lists;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import com.mojang.authlib.properties.PropertyMap;
+import net.artelnatif.nicko.NickoBukkit;
+import net.artelnatif.nicko.disguise.ActionResult;
+import net.artelnatif.nicko.disguise.NickoProfile;
+import net.artelnatif.nicko.mojang.MojangSkin;
+import net.minecraft.server.v1_15_R1.*;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
+import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerTeleportEvent;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+
+public class v1_15_R1 implements Internals {
+ @Override
+ public void updateSelf(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final CraftWorld world = entityPlayer.getWorld().getWorld();
+ final PacketPlayOutRespawn respawn = new PacketPlayOutRespawn(entityPlayer.getWorldServer().getWorldProvider().getDimensionManager(),
+ world.getSeed(),
+ entityPlayer.getWorld().P(),
+ entityPlayer.playerInteractManager.getGameMode());
+
+ final boolean wasFlying = player.isFlying();
+ entityPlayer.playerConnection.sendPacket(respawn);
+ player.setFlying(wasFlying);
+ player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
+ player.updateInventory();
+ }
+
+ @Override
+ public void updateOthers(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final PacketPlayOutEntityDestroy destroy = new PacketPlayOutEntityDestroy(entityPlayer.getBukkitEntity().getEntityId());
+ final PacketPlayOutNamedEntitySpawn spawn = new PacketPlayOutNamedEntitySpawn(entityPlayer);
+
+ final DataWatcher dataWatcher = entityPlayer.getDataWatcher();
+ final DataWatcherObject displayedSkinPartDataWatcher = new DataWatcherObject<>(17, DataWatcherRegistry.a);
+ dataWatcher.set(displayedSkinPartDataWatcher, (byte) 0x7f);
+ final PacketPlayOutEntityMetadata entityMetadata = new PacketPlayOutEntityMetadata(entityPlayer.getBukkitEntity().getEntityId(), dataWatcher, true);
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ if (onlineEntityPlayer.getBukkitEntity().getUniqueId() != player.getUniqueId()) {
+ onlineEntityPlayer.playerConnection.sendPacket(destroy);
+ onlineEntityPlayer.playerConnection.sendPacket(spawn);
+ }
+ onlineEntityPlayer.playerConnection.sendPacket(entityMetadata);
+ });
+ }
+
+ @Override
+ public ActionResult updateProfile(Player player, NickoProfile profile, boolean skinChange, boolean reset) {
+ final boolean changeOnlyName = profile.getSkin() != null && !profile.getSkin().equalsIgnoreCase(player.getName());
+ final String profileName = profile.getName() == null ? player.getName() : profile.getName();
+
+ final CraftPlayer craftPlayer = (CraftPlayer) player;
+ final EntityPlayer entityPlayer = craftPlayer.getHandle();
+ final GameProfile gameProfile = new GameProfile(player.getUniqueId(), profileName);
+
+ if (skinChange || changeOnlyName) {
+ final ActionResult skinFetch = fetchSkinTextures(profile, reset);
+ if (!skinFetch.isError()) {
+ final MojangSkin skin = skinFetch.getResult();
+ final PropertyMap properties = gameProfile.getProperties();
+ properties.removeAll("textures");
+ properties.put("textures", new Property("textures", skin.getValue(), skin.getSignature()));
+ updateSelf(player);
+ }
+ }
+
+ final PacketPlayOutPlayerInfo remove = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, entityPlayer);
+ final PacketPlayOutPlayerInfo add = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER);
+ final IChatBaseComponent name = new ChatComponentText(profileName);
+
+ final Object infoData = yes(
+ add,
+ gameProfile,
+ entityPlayer.ping,
+ EnumGamemode.getById(player.getGameMode().ordinal()),
+ name
+ );
+ spoofPlayerInfoPacket(add, Lists.newArrayList(infoData));
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ onlineEntityPlayer.playerConnection.sendPacket(remove);
+ onlineEntityPlayer.playerConnection.sendPacket(add);
+ });
+ updateOthers(player);
+ return new ActionResult<>();
+ }
+
+ private void spoofPlayerInfoPacket(Object object, Object newValue) {
+ try {
+ final Field field = object.getClass().getDeclaredField("b");
+ field.setAccessible(true);
+ field.set(object, newValue);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ NickoBukkit.getInstance().getLogger().warning("Unable to spoof packet, that's bad! (" + e.getMessage() + ")");
+ }
+ }
+
+ public Object yes(PacketPlayOutPlayerInfo packet, GameProfile gameProfile, int ping, EnumGamemode gamemode, IChatBaseComponent name) {
+ try {
+ final Class> clazz = Class.forName("net.minecraft.server.v1_15_R1.PacketPlayOutPlayerInfo$PlayerInfoData");
+ final Constructor> infoConstructor = clazz.getDeclaredConstructor(
+ PacketPlayOutPlayerInfo.class,
+ GameProfile.class,
+ int.class,
+ EnumGamemode.class,
+ IChatBaseComponent.class
+ );
+ return infoConstructor.newInstance(packet, gameProfile, ping, gamemode, name);
+ } catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException | InstantiationException |
+ IllegalAccessException e) {
+ NickoBukkit.getInstance().getLogger().warning("Unable to instantiate PlayerInfoData, that's bad! (" + e.getMessage() + ")");
+ return null;
+ }
+ }
+}
diff --git a/v1_16_R1/pom.xml b/v1_16_R1/pom.xml
new file mode 100644
index 0000000..032d146
--- /dev/null
+++ b/v1_16_R1/pom.xml
@@ -0,0 +1,28 @@
+
+
+
+ nicko-parent
+ net.artelnatif
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ v1_16_R1
+ 1.0-SNAPSHOT
+
+
+
+ org.spigotmc
+ spigot
+ 1.16.1-R0.1-SNAPSHOT
+ provided
+
+
+ net.artelnatif
+ core
+ 1.0-SNAPSHOT
+
+
+
\ No newline at end of file
diff --git a/v1_16_R1/src/main/java/net/artelnatif/nicko/impl/v1_16_R1.java b/v1_16_R1/src/main/java/net/artelnatif/nicko/impl/v1_16_R1.java
new file mode 100644
index 0000000..c7939c1
--- /dev/null
+++ b/v1_16_R1/src/main/java/net/artelnatif/nicko/impl/v1_16_R1.java
@@ -0,0 +1,132 @@
+package net.artelnatif.nicko.impl;
+
+import com.google.common.collect.Lists;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import com.mojang.authlib.properties.PropertyMap;
+import net.artelnatif.nicko.NickoBukkit;
+import net.artelnatif.nicko.disguise.ActionResult;
+import net.artelnatif.nicko.disguise.NickoProfile;
+import net.artelnatif.nicko.mojang.MojangSkin;
+import net.minecraft.server.v1_16_R1.*;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
+import org.bukkit.craftbukkit.v1_16_R1.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerTeleportEvent;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+
+public class v1_16_R1 implements Internals {
+ @Override
+ public void updateSelf(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final ResourceKey levelResourceKey = entityPlayer.getWorld().getDimensionKey();
+ final CraftWorld world = entityPlayer.getWorld().getWorld();
+ final PacketPlayOutRespawn respawn = new PacketPlayOutRespawn(entityPlayer.getWorld().getTypeKey(),
+ levelResourceKey, world.getSeed(),
+ entityPlayer.playerInteractManager.c(), entityPlayer.playerInteractManager.getGameMode(),
+ false,
+ false,
+ false);
+
+ final boolean wasFlying = player.isFlying();
+ entityPlayer.playerConnection.sendPacket(respawn);
+ player.setFlying(wasFlying);
+ player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
+ player.updateInventory();
+ }
+
+ @Override
+ public void updateOthers(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final PacketPlayOutEntityDestroy destroy = new PacketPlayOutEntityDestroy(entityPlayer.getBukkitEntity().getEntityId());
+ final PacketPlayOutNamedEntitySpawn spawn = new PacketPlayOutNamedEntitySpawn(entityPlayer);
+
+ final DataWatcher dataWatcher = entityPlayer.getDataWatcher();
+ final DataWatcherObject displayedSkinPartDataWatcher = new DataWatcherObject<>(17, DataWatcherRegistry.a);
+ dataWatcher.set(displayedSkinPartDataWatcher, (byte) 0x7f);
+ final PacketPlayOutEntityMetadata entityMetadata = new PacketPlayOutEntityMetadata(entityPlayer.getBukkitEntity().getEntityId(), dataWatcher, true);
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ if (onlineEntityPlayer.getBukkitEntity().getUniqueId() != player.getUniqueId()) {
+ onlineEntityPlayer.playerConnection.sendPacket(destroy);
+ onlineEntityPlayer.playerConnection.sendPacket(spawn);
+ }
+ onlineEntityPlayer.playerConnection.sendPacket(entityMetadata);
+ });
+ }
+
+ @Override
+ public ActionResult updateProfile(Player player, NickoProfile profile, boolean skinChange, boolean reset) {
+ final boolean changeOnlyName = profile.getSkin() != null && !profile.getSkin().equalsIgnoreCase(player.getName());
+ final String profileName = profile.getName() == null ? player.getName() : profile.getName();
+
+ final CraftPlayer craftPlayer = (CraftPlayer) player;
+ final EntityPlayer entityPlayer = craftPlayer.getHandle();
+ final GameProfile gameProfile = new GameProfile(player.getUniqueId(), profileName);
+
+ if (skinChange || changeOnlyName) {
+ final ActionResult skinFetch = fetchSkinTextures(profile, reset);
+ if (!skinFetch.isError()) {
+ final MojangSkin skin = skinFetch.getResult();
+ final PropertyMap properties = gameProfile.getProperties();
+ properties.removeAll("textures");
+ properties.put("textures", new Property("textures", skin.getValue(), skin.getSignature()));
+ updateSelf(player);
+ }
+ }
+
+ final PacketPlayOutPlayerInfo remove = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, entityPlayer);
+ final PacketPlayOutPlayerInfo add = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER);
+ final IChatBaseComponent name = new ChatComponentText(profileName);
+
+ final Object infoData = yes(
+ add,
+ gameProfile,
+ entityPlayer.ping,
+ EnumGamemode.getById(player.getGameMode().ordinal()),
+ name
+ );
+ spoofPlayerInfoPacket(add, Lists.newArrayList(infoData));
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ onlineEntityPlayer.playerConnection.sendPacket(remove);
+ onlineEntityPlayer.playerConnection.sendPacket(add);
+ });
+ updateOthers(player);
+ return new ActionResult<>();
+ }
+
+ private void spoofPlayerInfoPacket(Object object, Object newValue) {
+ try {
+ final Field field = object.getClass().getDeclaredField("b");
+ field.setAccessible(true);
+ field.set(object, newValue);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ NickoBukkit.getInstance().getLogger().warning("Unable to spoof packet, that's bad! (" + e.getMessage() + ")");
+ }
+ }
+
+ public Object yes(PacketPlayOutPlayerInfo packet, GameProfile gameProfile, int ping, EnumGamemode gamemode, IChatBaseComponent name) {
+ try {
+ final Class> clazz = Class.forName("net.minecraft.server.v1_16_R1.PacketPlayOutPlayerInfo$PlayerInfoData");
+ final Constructor> infoConstructor = clazz.getDeclaredConstructor(
+ PacketPlayOutPlayerInfo.class,
+ GameProfile.class,
+ int.class,
+ EnumGamemode.class,
+ IChatBaseComponent.class
+ );
+ return infoConstructor.newInstance(packet, gameProfile, ping, gamemode, name);
+ } catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException | InstantiationException |
+ IllegalAccessException e) {
+ NickoBukkit.getInstance().getLogger().warning("Unable to instantiate PlayerInfoData, that's bad! (" + e.getMessage() + ")");
+ return null;
+ }
+ }
+}
diff --git a/v1_16_R2/pom.xml b/v1_16_R2/pom.xml
new file mode 100644
index 0000000..658413d
--- /dev/null
+++ b/v1_16_R2/pom.xml
@@ -0,0 +1,28 @@
+
+
+
+ nicko-parent
+ net.artelnatif
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ v1_16_R2
+ 1.0-SNAPSHOT
+
+
+
+ org.spigotmc
+ spigot
+ 1.16.3-R0.1-SNAPSHOT
+ provided
+
+
+ net.artelnatif
+ core
+ 1.0-SNAPSHOT
+
+
+
\ No newline at end of file
diff --git a/v1_16_R2/src/main/java/net/artelnatif/nicko/impl/v1_16_R2.java b/v1_16_R2/src/main/java/net/artelnatif/nicko/impl/v1_16_R2.java
new file mode 100644
index 0000000..244970a
--- /dev/null
+++ b/v1_16_R2/src/main/java/net/artelnatif/nicko/impl/v1_16_R2.java
@@ -0,0 +1,132 @@
+package net.artelnatif.nicko.impl;
+
+import com.google.common.collect.Lists;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import com.mojang.authlib.properties.PropertyMap;
+import net.artelnatif.nicko.NickoBukkit;
+import net.artelnatif.nicko.disguise.ActionResult;
+import net.artelnatif.nicko.disguise.NickoProfile;
+import net.artelnatif.nicko.mojang.MojangSkin;
+import net.minecraft.server.v1_16_R2.*;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_16_R2.CraftWorld;
+import org.bukkit.craftbukkit.v1_16_R2.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerTeleportEvent;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+
+public class v1_16_R2 implements Internals {
+ @Override
+ public void updateSelf(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final ResourceKey levelResourceKey = entityPlayer.getWorld().getDimensionKey();
+ final CraftWorld world = entityPlayer.getWorld().getWorld();
+ final PacketPlayOutRespawn respawn = new PacketPlayOutRespawn(entityPlayer.getWorld().getDimensionManager(),
+ levelResourceKey, world.getSeed(),
+ entityPlayer.playerInteractManager.c(), entityPlayer.playerInteractManager.getGameMode(),
+ false,
+ false,
+ false);
+
+ final boolean wasFlying = player.isFlying();
+ entityPlayer.playerConnection.sendPacket(respawn);
+ player.setFlying(wasFlying);
+ player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
+ player.updateInventory();
+ }
+
+ @Override
+ public void updateOthers(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final PacketPlayOutEntityDestroy destroy = new PacketPlayOutEntityDestroy(entityPlayer.getBukkitEntity().getEntityId());
+ final PacketPlayOutNamedEntitySpawn spawn = new PacketPlayOutNamedEntitySpawn(entityPlayer);
+
+ final DataWatcher dataWatcher = entityPlayer.getDataWatcher();
+ final DataWatcherObject displayedSkinPartDataWatcher = new DataWatcherObject<>(17, DataWatcherRegistry.a);
+ dataWatcher.set(displayedSkinPartDataWatcher, (byte) 0x7f);
+ final PacketPlayOutEntityMetadata entityMetadata = new PacketPlayOutEntityMetadata(entityPlayer.getBukkitEntity().getEntityId(), dataWatcher, true);
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ if (onlineEntityPlayer.getBukkitEntity().getUniqueId() != player.getUniqueId()) {
+ onlineEntityPlayer.playerConnection.sendPacket(destroy);
+ onlineEntityPlayer.playerConnection.sendPacket(spawn);
+ }
+ onlineEntityPlayer.playerConnection.sendPacket(entityMetadata);
+ });
+ }
+
+ @Override
+ public ActionResult updateProfile(Player player, NickoProfile profile, boolean skinChange, boolean reset) {
+ final boolean changeOnlyName = profile.getSkin() != null && !profile.getSkin().equalsIgnoreCase(player.getName());
+ final String profileName = profile.getName() == null ? player.getName() : profile.getName();
+
+ final CraftPlayer craftPlayer = (CraftPlayer) player;
+ final EntityPlayer entityPlayer = craftPlayer.getHandle();
+ final GameProfile gameProfile = new GameProfile(player.getUniqueId(), profileName);
+
+ if (skinChange || changeOnlyName) {
+ final ActionResult skinFetch = fetchSkinTextures(profile, reset);
+ if (!skinFetch.isError()) {
+ final MojangSkin skin = skinFetch.getResult();
+ final PropertyMap properties = gameProfile.getProperties();
+ properties.removeAll("textures");
+ properties.put("textures", new Property("textures", skin.getValue(), skin.getSignature()));
+ updateSelf(player);
+ }
+ }
+
+ final PacketPlayOutPlayerInfo remove = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, entityPlayer);
+ final PacketPlayOutPlayerInfo add = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER);
+ final IChatBaseComponent name = new ChatComponentText(profileName);
+
+ final Object infoData = yes(
+ add,
+ gameProfile,
+ entityPlayer.ping,
+ EnumGamemode.getById(player.getGameMode().ordinal()),
+ name
+ );
+ spoofPlayerInfoPacket(add, Lists.newArrayList(infoData));
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ onlineEntityPlayer.playerConnection.sendPacket(remove);
+ onlineEntityPlayer.playerConnection.sendPacket(add);
+ });
+ updateOthers(player);
+ return new ActionResult<>();
+ }
+
+ private void spoofPlayerInfoPacket(Object object, Object newValue) {
+ try {
+ final Field field = object.getClass().getDeclaredField("b");
+ field.setAccessible(true);
+ field.set(object, newValue);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ NickoBukkit.getInstance().getLogger().warning("Unable to spoof packet, that's bad! (" + e.getMessage() + ")");
+ }
+ }
+
+ public Object yes(PacketPlayOutPlayerInfo packet, GameProfile gameProfile, int ping, EnumGamemode gamemode, IChatBaseComponent name) {
+ try {
+ final Class> clazz = Class.forName("net.minecraft.server.v1_16_R2.PacketPlayOutPlayerInfo$PlayerInfoData");
+ final Constructor> infoConstructor = clazz.getDeclaredConstructor(
+ PacketPlayOutPlayerInfo.class,
+ GameProfile.class,
+ int.class,
+ EnumGamemode.class,
+ IChatBaseComponent.class
+ );
+ return infoConstructor.newInstance(packet, gameProfile, ping, gamemode, name);
+ } catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException | InstantiationException |
+ IllegalAccessException e) {
+ NickoBukkit.getInstance().getLogger().warning("Unable to instantiate PlayerInfoData, that's bad! (" + e.getMessage() + ")");
+ return null;
+ }
+ }
+}
diff --git a/v1_16_R3/pom.xml b/v1_16_R3/pom.xml
new file mode 100644
index 0000000..055dbe2
--- /dev/null
+++ b/v1_16_R3/pom.xml
@@ -0,0 +1,28 @@
+
+
+
+ nicko-parent
+ net.artelnatif
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ v1_16_R3
+ 1.0-SNAPSHOT
+
+
+
+ org.spigotmc
+ spigot
+ 1.16.5-R0.1-SNAPSHOT
+ provided
+
+
+ net.artelnatif
+ core
+ 1.0-SNAPSHOT
+
+
+
\ No newline at end of file
diff --git a/v1_16_R3/src/main/java/net/artelnatif/nicko/impl/v1_16_R3.java b/v1_16_R3/src/main/java/net/artelnatif/nicko/impl/v1_16_R3.java
new file mode 100644
index 0000000..b0744ea
--- /dev/null
+++ b/v1_16_R3/src/main/java/net/artelnatif/nicko/impl/v1_16_R3.java
@@ -0,0 +1,136 @@
+package net.artelnatif.nicko.impl;
+
+import com.google.common.collect.Lists;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import com.mojang.authlib.properties.PropertyMap;
+import net.artelnatif.nicko.NickoBukkit;
+import net.artelnatif.nicko.disguise.ActionResult;
+import net.artelnatif.nicko.disguise.NickoProfile;
+import net.artelnatif.nicko.mojang.MojangSkin;
+import net.minecraft.server.v1_16_R3.*;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
+import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerTeleportEvent;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+
+public class v1_16_R3 implements Internals {
+ @Override
+ public void updateSelf(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final ResourceKey levelResourceKey = entityPlayer.getWorld().getDimensionKey();
+ final CraftWorld world = entityPlayer.getWorld().getWorld();
+ final PacketPlayOutRespawn respawn = new PacketPlayOutRespawn(entityPlayer.getWorld().getDimensionManager(),
+ levelResourceKey, world.getSeed(),
+ entityPlayer.playerInteractManager.c(), entityPlayer.playerInteractManager.getGameMode(),
+ false,
+ false,
+ false);
+
+ final boolean wasFlying = player.isFlying();
+ entityPlayer.playerConnection.sendPacket(respawn);
+ player.setFlying(wasFlying);
+ player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
+ player.updateInventory();
+ }
+
+ @Override
+ public void updateOthers(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final PacketPlayOutEntityDestroy destroy = new PacketPlayOutEntityDestroy(entityPlayer.getBukkitEntity().getEntityId());
+ final PacketPlayOutNamedEntitySpawn spawn = new PacketPlayOutNamedEntitySpawn(entityPlayer);
+
+ final DataWatcher dataWatcher = entityPlayer.getDataWatcher();
+ final DataWatcherObject displayedSkinPartDataWatcher = new DataWatcherObject<>(17, DataWatcherRegistry.a);
+ dataWatcher.set(displayedSkinPartDataWatcher, (byte) 0x7f);
+ final PacketPlayOutEntityMetadata entityMetadata = new PacketPlayOutEntityMetadata(entityPlayer.getBukkitEntity().getEntityId(), dataWatcher, true);
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ if (onlineEntityPlayer.getBukkitEntity().getUniqueId() != player.getUniqueId()) {
+ onlineEntityPlayer.playerConnection.sendPacket(destroy);
+ onlineEntityPlayer.playerConnection.sendPacket(spawn);
+ }
+ onlineEntityPlayer.playerConnection.sendPacket(entityMetadata);
+ });
+ }
+
+ @Override
+ public ActionResult updateProfile(Player player, NickoProfile profile, boolean skinChange, boolean reset) {
+ final boolean changeOnlyName = profile.getSkin() != null && !profile.getSkin().equalsIgnoreCase(player.getName());
+ final String profileName = profile.getName() == null ? player.getName() : profile.getName();
+
+ final CraftPlayer craftPlayer = (CraftPlayer) player;
+ final EntityPlayer entityPlayer = craftPlayer.getHandle();
+ final GameProfile gameProfile = new GameProfile(player.getUniqueId(), profileName);
+
+ if (skinChange || changeOnlyName) {
+ final ActionResult skinFetch = fetchSkinTextures(profile, reset);
+ if (!skinFetch.isError()) {
+ final MojangSkin skin = skinFetch.getResult();
+ final PropertyMap properties = gameProfile.getProperties();
+ properties.removeAll("textures");
+ properties.put("textures", new Property("textures", skin.getValue(), skin.getSignature()));
+ updateSelf(player);
+ }
+ }
+
+ final PacketPlayOutPlayerInfo remove = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, entityPlayer);
+ final PacketPlayOutPlayerInfo add = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER);
+ final IChatBaseComponent name = new ChatComponentText(profileName);
+
+ // ok so what the actual fuck
+ // the PlayerDataInfo inner class is NOT static
+ // thus the compiler can't access it when compiling??????
+ // i swear this is so dumb that I have to resort to doing this
+ final Object infoData = yes(
+ add,
+ gameProfile,
+ entityPlayer.ping,
+ EnumGamemode.getById(player.getGameMode().ordinal()),
+ name
+ );
+ spoofPlayerInfoPacket(add, Lists.newArrayList(infoData));
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ onlineEntityPlayer.playerConnection.sendPacket(remove);
+ onlineEntityPlayer.playerConnection.sendPacket(add);
+ });
+ updateOthers(player);
+ return new ActionResult<>();
+ }
+
+ private void spoofPlayerInfoPacket(Object object, Object newValue) {
+ try {
+ final Field field = object.getClass().getDeclaredField("b");
+ field.setAccessible(true);
+ field.set(object, newValue);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ NickoBukkit.getInstance().getLogger().warning("Unable to spoof packet, that's bad! (" + e.getMessage() + ")");
+ }
+ }
+
+ public Object yes(PacketPlayOutPlayerInfo packet, GameProfile gameProfile, int ping, EnumGamemode gamemode, IChatBaseComponent name) {
+ try {
+ final Class> clazz = Class.forName("net.minecraft.server.v1_16_R3.PacketPlayOutPlayerInfo$PlayerInfoData");
+ final Constructor> infoConstructor = clazz.getDeclaredConstructor(
+ PacketPlayOutPlayerInfo.class,
+ GameProfile.class,
+ int.class,
+ EnumGamemode.class,
+ IChatBaseComponent.class
+ );
+ return infoConstructor.newInstance(packet, gameProfile, ping, gamemode, name);
+ } catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException | InstantiationException |
+ IllegalAccessException e) {
+ NickoBukkit.getInstance().getLogger().warning("Unable to instantiate PlayerInfoData, that's bad! (" + e.getMessage() + ")");
+ return null;
+ }
+ }
+}
diff --git a/v1_17_R1/pom.xml b/v1_17_R1/pom.xml
new file mode 100644
index 0000000..7ca2642
--- /dev/null
+++ b/v1_17_R1/pom.xml
@@ -0,0 +1,28 @@
+
+
+
+ nicko-parent
+ net.artelnatif
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ v1_17_R1
+ 1.0-SNAPSHOT
+
+
+
+ org.spigotmc
+ spigot
+ 1.17.1-R0.1-SNAPSHOT
+ provided
+
+
+ net.artelnatif
+ core
+ 1.0-SNAPSHOT
+
+
+
\ No newline at end of file
diff --git a/v1_17_R1/src/main/java/net/artelnatif/nicko/impl/v1_17_R1.java b/v1_17_R1/src/main/java/net/artelnatif/nicko/impl/v1_17_R1.java
new file mode 100644
index 0000000..24cd2a0
--- /dev/null
+++ b/v1_17_R1/src/main/java/net/artelnatif/nicko/impl/v1_17_R1.java
@@ -0,0 +1,101 @@
+package net.artelnatif.nicko.impl;
+
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import com.mojang.authlib.properties.PropertyMap;
+import net.artelnatif.nicko.disguise.ActionResult;
+import net.artelnatif.nicko.disguise.NickoProfile;
+import net.artelnatif.nicko.mojang.MojangSkin;
+import net.minecraft.network.chat.IChatBaseComponent;
+import net.minecraft.network.protocol.game.*;
+import net.minecraft.network.syncher.DataWatcher;
+import net.minecraft.network.syncher.DataWatcherObject;
+import net.minecraft.network.syncher.DataWatcherRegistry;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.server.level.EntityPlayer;
+import net.minecraft.world.level.EnumGamemode;
+import net.minecraft.world.level.World;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_17_R1.CraftWorld;
+import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerTeleportEvent;
+
+public class v1_17_R1 implements Internals {
+ @Override
+ public void updateSelf(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final ResourceKey levelResourceKey = entityPlayer.getWorld().getDimensionKey();
+ final CraftWorld world = entityPlayer.getWorld().getWorld();
+ final PacketPlayOutRespawn respawn = new PacketPlayOutRespawn(entityPlayer.getWorld().getDimensionManager(),
+ levelResourceKey, world.getSeed(),
+ entityPlayer.c.getGamemode(), entityPlayer.d.c(),
+ false,
+ false,
+ false);
+
+ final boolean wasFlying = player.isFlying();
+ entityPlayer.b.sendPacket(respawn);
+ player.setFlying(wasFlying);
+ player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
+ player.updateInventory();
+ }
+
+ @Override
+ public void updateOthers(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final PacketPlayOutEntityDestroy destroy = new PacketPlayOutEntityDestroy(entityPlayer.getBukkitEntity().getEntityId());
+ final PacketPlayOutNamedEntitySpawn spawn = new PacketPlayOutNamedEntitySpawn(entityPlayer);
+
+ final DataWatcher dataWatcher = entityPlayer.getDataWatcher();
+ final DataWatcherObject displayedSkinPartDataWatcher = new DataWatcherObject<>(17, DataWatcherRegistry.a);
+ dataWatcher.set(displayedSkinPartDataWatcher, (byte) 0x7f);
+ final PacketPlayOutEntityMetadata entityMetadata = new PacketPlayOutEntityMetadata(entityPlayer.getBukkitEntity().getEntityId(), dataWatcher, true);
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ if (onlineEntityPlayer.getBukkitEntity().getUniqueId() != player.getUniqueId()) {
+ onlineEntityPlayer.b.sendPacket(destroy);
+ onlineEntityPlayer.b.sendPacket(spawn);
+ }
+ onlineEntityPlayer.b.sendPacket(entityMetadata);
+ });
+ }
+
+ @Override
+ public ActionResult updateProfile(Player player, NickoProfile profile, boolean skinChange, boolean reset) {
+ final boolean changeOnlyName = profile.getSkin() != null && !profile.getSkin().equalsIgnoreCase(player.getName());
+ final String profileName = profile.getName() == null ? player.getName() : profile.getName();
+
+ final CraftPlayer craftPlayer = (CraftPlayer) player;
+ final EntityPlayer entityPlayer = craftPlayer.getHandle();
+ final GameProfile gameProfile = new GameProfile(player.getUniqueId(), profileName);
+
+ if (skinChange || changeOnlyName) {
+ final ActionResult skinFetch = fetchSkinTextures(profile, reset);
+ if (!skinFetch.isError()) {
+ final MojangSkin skin = skinFetch.getResult();
+ final PropertyMap properties = gameProfile.getProperties();
+ properties.removeAll("textures");
+ properties.put("textures", new Property("textures", skin.getValue(), skin.getSignature()));
+ updateSelf(player);
+ }
+ }
+
+ final PacketPlayOutPlayerInfo remove = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.e, entityPlayer);
+ final PacketPlayOutPlayerInfo add = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.a);
+
+ add.b().clear();
+ add.b().add(new PacketPlayOutPlayerInfo.PlayerInfoData(gameProfile,
+ player.getPing(),
+ EnumGamemode.getById(player.getGameMode().ordinal()), IChatBaseComponent.a(profileName)));
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ onlineEntityPlayer.b.sendPacket(remove);
+ onlineEntityPlayer.b.sendPacket(add);
+ });
+ updateOthers(player);
+ return new ActionResult<>();
+ }
+}
diff --git a/v1_18_R1/pom.xml b/v1_18_R1/pom.xml
new file mode 100644
index 0000000..d842952
--- /dev/null
+++ b/v1_18_R1/pom.xml
@@ -0,0 +1,29 @@
+
+
+ 4.0.0
+
+
+ net.artelnatif
+ nicko-parent
+ 1.0-SNAPSHOT
+
+
+ v1_18_R1
+ 1.0-SNAPSHOT
+
+
+
+ org.spigotmc
+ spigot
+ 1.18.1-R0.1-SNAPSHOT
+ provided
+
+
+ net.artelnatif
+ core
+ 1.0-SNAPSHOT
+
+
+
\ No newline at end of file
diff --git a/v1_18_R1/src/main/java/net/artelnatif/nicko/impl/v1_18_R1.java b/v1_18_R1/src/main/java/net/artelnatif/nicko/impl/v1_18_R1.java
new file mode 100644
index 0000000..1f1b7b7
--- /dev/null
+++ b/v1_18_R1/src/main/java/net/artelnatif/nicko/impl/v1_18_R1.java
@@ -0,0 +1,103 @@
+package net.artelnatif.nicko.impl;
+
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import com.mojang.authlib.properties.PropertyMap;
+import net.artelnatif.nicko.disguise.ActionResult;
+import net.artelnatif.nicko.disguise.NickoProfile;
+import net.artelnatif.nicko.mojang.MojangSkin;
+import net.minecraft.network.chat.IChatBaseComponent;
+import net.minecraft.network.protocol.game.*;
+import net.minecraft.network.syncher.DataWatcher;
+import net.minecraft.network.syncher.DataWatcherObject;
+import net.minecraft.network.syncher.DataWatcherRegistry;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.server.level.EntityPlayer;
+import net.minecraft.world.level.EnumGamemode;
+import net.minecraft.world.level.World;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_18_R1.CraftWorld;
+import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerTeleportEvent;
+
+public class v1_18_R1 implements Internals {
+ @Override
+ public void updateSelf(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final ResourceKey levelResourceKey = entityPlayer.x().aa();
+ final CraftWorld world = entityPlayer.W().getWorld();
+ // again, wtf is that
+ // f*ck obfuscation
+ final PacketPlayOutRespawn respawn = new PacketPlayOutRespawn(entityPlayer.W().q_(),
+ levelResourceKey, world.getSeed(),
+ entityPlayer.d.b(), entityPlayer.d.c(),
+ false,
+ false,
+ false);
+
+ final boolean wasFlying = player.isFlying();
+ entityPlayer.b.a(respawn);
+ player.setFlying(wasFlying);
+ player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
+ player.updateInventory();
+ }
+
+ @Override
+ public void updateOthers(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final PacketPlayOutEntityDestroy destroy = new PacketPlayOutEntityDestroy(entityPlayer.getBukkitEntity().getEntityId());
+ final PacketPlayOutNamedEntitySpawn spawn = new PacketPlayOutNamedEntitySpawn(entityPlayer);
+
+ final DataWatcher dataWatcher = entityPlayer.ai();
+ final DataWatcherObject displayedSkinPartDataWatcher = new DataWatcherObject<>(17, DataWatcherRegistry.a);
+ dataWatcher.b(displayedSkinPartDataWatcher, (byte) 0x7f);
+ final PacketPlayOutEntityMetadata entityMetadata = new PacketPlayOutEntityMetadata(entityPlayer.getBukkitEntity().getEntityId(), dataWatcher, true);
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ if (onlineEntityPlayer.getBukkitEntity().getUniqueId() != player.getUniqueId()) {
+ onlineEntityPlayer.b.a(destroy);
+ onlineEntityPlayer.b.a(spawn);
+ }
+ onlineEntityPlayer.b.a(entityMetadata);
+ });
+ }
+
+ @Override
+ public ActionResult updateProfile(Player player, NickoProfile profile, boolean skinChange, boolean reset) {
+ final boolean changeOnlyName = profile.getSkin() != null && !profile.getSkin().equalsIgnoreCase(player.getName());
+ final String profileName = profile.getName() == null ? player.getName() : profile.getName();
+
+ final CraftPlayer craftPlayer = (CraftPlayer) player;
+ final EntityPlayer entityPlayer = craftPlayer.getHandle();
+ final GameProfile gameProfile = new GameProfile(player.getUniqueId(), profileName);
+
+ if (skinChange || changeOnlyName) {
+ final ActionResult skinFetch = fetchSkinTextures(profile, reset);
+ if (!skinFetch.isError()) {
+ final MojangSkin skin = skinFetch.getResult();
+ final PropertyMap properties = gameProfile.getProperties();
+ properties.removeAll("textures");
+ properties.put("textures", new Property("textures", skin.getValue(), skin.getSignature()));
+ updateSelf(player);
+ }
+ }
+
+ final PacketPlayOutPlayerInfo remove = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.e, entityPlayer);
+ final PacketPlayOutPlayerInfo add = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.a);
+
+ add.b().clear();
+ add.b().add(new PacketPlayOutPlayerInfo.PlayerInfoData(gameProfile,
+ player.getPing(),
+ EnumGamemode.a(player.getGameMode().ordinal()), IChatBaseComponent.a(profileName)));
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ onlineEntityPlayer.b.a(remove);
+ onlineEntityPlayer.b.a(add);
+ });
+ updateOthers(player);
+ return new ActionResult<>();
+ }
+}
diff --git a/v1_18_R2/pom.xml b/v1_18_R2/pom.xml
new file mode 100644
index 0000000..4eb30ad
--- /dev/null
+++ b/v1_18_R2/pom.xml
@@ -0,0 +1,29 @@
+
+
+ 4.0.0
+
+
+ net.artelnatif
+ nicko-parent
+ 1.0-SNAPSHOT
+
+
+ v1_18_R2
+ 1.0-SNAPSHOT
+
+
+
+ org.spigotmc
+ spigot
+ 1.18.2-R0.1-SNAPSHOT
+ provided
+
+
+ net.artelnatif
+ core
+ 1.0-SNAPSHOT
+
+
+
\ No newline at end of file
diff --git a/v1_18_R2/src/main/java/net/artelnatif/nicko/impl/v1_18_R2.java b/v1_18_R2/src/main/java/net/artelnatif/nicko/impl/v1_18_R2.java
new file mode 100644
index 0000000..1f085f6
--- /dev/null
+++ b/v1_18_R2/src/main/java/net/artelnatif/nicko/impl/v1_18_R2.java
@@ -0,0 +1,103 @@
+package net.artelnatif.nicko.impl;
+
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import com.mojang.authlib.properties.PropertyMap;
+import net.artelnatif.nicko.disguise.ActionResult;
+import net.artelnatif.nicko.disguise.NickoProfile;
+import net.artelnatif.nicko.mojang.MojangSkin;
+import net.minecraft.core.Holder;
+import net.minecraft.network.chat.IChatBaseComponent;
+import net.minecraft.network.protocol.game.*;
+import net.minecraft.network.syncher.DataWatcher;
+import net.minecraft.network.syncher.DataWatcherObject;
+import net.minecraft.network.syncher.DataWatcherRegistry;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.server.level.EntityPlayer;
+import net.minecraft.world.level.EnumGamemode;
+import net.minecraft.world.level.World;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_18_R2.CraftWorld;
+import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerTeleportEvent;
+
+public class v1_18_R2 implements Internals {
+ @Override
+ public void updateSelf(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final ResourceKey levelResourceKey = entityPlayer.x().aa();
+ final CraftWorld world = entityPlayer.s.getWorld();
+ // wtf is that ?
+ final PacketPlayOutRespawn respawn = new PacketPlayOutRespawn(Holder.a(entityPlayer.s.q_()),
+ levelResourceKey, world.getSeed(),
+ entityPlayer.d.b(), entityPlayer.d.c(),
+ false,
+ false,
+ false);
+
+ final boolean wasFlying = player.isFlying();
+ entityPlayer.b.a(respawn);
+ player.setFlying(wasFlying);
+ player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
+ player.updateInventory();
+ }
+
+ @Override
+ public void updateOthers(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final PacketPlayOutEntityDestroy destroy = new PacketPlayOutEntityDestroy(entityPlayer.getBukkitEntity().getEntityId());
+ final PacketPlayOutNamedEntitySpawn spawn = new PacketPlayOutNamedEntitySpawn(entityPlayer);
+
+ final DataWatcher dataWatcher = entityPlayer.ai();
+ final DataWatcherObject displayedSkinPartDataWatcher = new DataWatcherObject<>(17, DataWatcherRegistry.a);
+ dataWatcher.b(displayedSkinPartDataWatcher, (byte) 0x7f);
+ final PacketPlayOutEntityMetadata entityMetadata = new PacketPlayOutEntityMetadata(entityPlayer.getBukkitEntity().getEntityId(), dataWatcher, true);
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ if (onlineEntityPlayer.getBukkitEntity().getUniqueId() != player.getUniqueId()) {
+ onlineEntityPlayer.b.a(destroy);
+ onlineEntityPlayer.b.a(spawn);
+ }
+ onlineEntityPlayer.b.a(entityMetadata);
+ });
+ }
+
+ @Override
+ public ActionResult updateProfile(Player player, NickoProfile profile, boolean skinChange, boolean reset) {
+ final boolean changeOnlyName = profile.getSkin() != null && !profile.getSkin().equalsIgnoreCase(player.getName());
+ final String profileName = profile.getName() == null ? player.getName() : profile.getName();
+
+ final CraftPlayer craftPlayer = (CraftPlayer) player;
+ final EntityPlayer entityPlayer = craftPlayer.getHandle();
+ final GameProfile gameProfile = new GameProfile(player.getUniqueId(), profileName);
+
+ if (skinChange || changeOnlyName) {
+ final ActionResult skinFetch = fetchSkinTextures(profile, reset);
+ if (!skinFetch.isError()) {
+ final MojangSkin skin = skinFetch.getResult();
+ final PropertyMap properties = gameProfile.getProperties();
+ properties.removeAll("textures");
+ properties.put("textures", new Property("textures", skin.getValue(), skin.getSignature()));
+ updateSelf(player);
+ }
+ }
+
+ final PacketPlayOutPlayerInfo remove = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.e, entityPlayer);
+ final PacketPlayOutPlayerInfo add = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.a);
+
+ add.b().clear();
+ add.b().add(new PacketPlayOutPlayerInfo.PlayerInfoData(gameProfile,
+ player.getPing(),
+ EnumGamemode.a(player.getGameMode().ordinal()), IChatBaseComponent.a(profileName)));
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ onlineEntityPlayer.b.a(remove);
+ onlineEntityPlayer.b.a(add);
+ });
+ updateOthers(player);
+ return new ActionResult<>();
+ }
+}
\ No newline at end of file
diff --git a/v1_19_R1/pom.xml b/v1_19_R1/pom.xml
new file mode 100644
index 0000000..ccdb982
--- /dev/null
+++ b/v1_19_R1/pom.xml
@@ -0,0 +1,29 @@
+
+
+ 4.0.0
+
+
+ net.artelnatif
+ nicko-parent
+ 1.0-SNAPSHOT
+
+
+ v1_19_R1
+ 1.0-SNAPSHOT
+
+
+
+ org.spigotmc
+ spigot
+ 1.19.2-R0.1-SNAPSHOT
+ provided
+
+
+ net.artelnatif
+ core
+ 1.0-SNAPSHOT
+
+
+
\ No newline at end of file
diff --git a/v1_19_R1/src/main/java/net/artelnatif/nicko/impl/v1_19_R1.java b/v1_19_R1/src/main/java/net/artelnatif/nicko/impl/v1_19_R1.java
new file mode 100644
index 0000000..fe98d37
--- /dev/null
+++ b/v1_19_R1/src/main/java/net/artelnatif/nicko/impl/v1_19_R1.java
@@ -0,0 +1,107 @@
+package net.artelnatif.nicko.impl;
+
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import com.mojang.authlib.properties.PropertyMap;
+import net.artelnatif.nicko.disguise.ActionResult;
+import net.artelnatif.nicko.disguise.NickoProfile;
+import net.artelnatif.nicko.mojang.MojangSkin;
+import net.minecraft.network.chat.IChatBaseComponent;
+import net.minecraft.network.protocol.game.*;
+import net.minecraft.network.syncher.DataWatcher;
+import net.minecraft.network.syncher.DataWatcherObject;
+import net.minecraft.network.syncher.DataWatcherRegistry;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.server.level.EntityPlayer;
+import net.minecraft.world.entity.player.ProfilePublicKey;
+import net.minecraft.world.level.EnumGamemode;
+import net.minecraft.world.level.World;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerTeleportEvent;
+
+import java.util.Optional;
+
+public class v1_19_R1 implements Internals {
+ @Override
+ public void updateSelf(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final ResourceKey levelResourceKey = entityPlayer.x().ab();
+ final PacketPlayOutRespawn respawn = new PacketPlayOutRespawn(entityPlayer.x().Z(),
+ levelResourceKey, entityPlayer.s.getWorld().getSeed(),
+ entityPlayer.d.b(), entityPlayer.d.c(),
+ false,
+ false,
+ false,
+ Optional.empty());
+
+ final boolean wasFlying = player.isFlying();
+ entityPlayer.b.a(respawn);
+ player.setFlying(wasFlying);
+ player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
+ player.updateInventory();
+ }
+
+ @Override
+ public void updateOthers(Player player) {
+ final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ final PacketPlayOutEntityDestroy destroy = new PacketPlayOutEntityDestroy(entityPlayer.getBukkitEntity().getEntityId());
+ final PacketPlayOutNamedEntitySpawn spawn = new PacketPlayOutNamedEntitySpawn(entityPlayer);
+
+ final DataWatcher dataWatcher = entityPlayer.ai();
+ final DataWatcherObject displayedSkinPartDataWatcher = new DataWatcherObject<>(17, DataWatcherRegistry.a);
+ dataWatcher.b(displayedSkinPartDataWatcher, (byte) 0x7f);
+ final PacketPlayOutEntityMetadata entityMetadata = new PacketPlayOutEntityMetadata(entityPlayer.getBukkitEntity().getEntityId(), dataWatcher, true);
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ if (onlineEntityPlayer.getBukkitEntity().getUniqueId() != player.getUniqueId()) {
+ onlineEntityPlayer.b.a(destroy);
+ onlineEntityPlayer.b.a(spawn);
+ }
+ onlineEntityPlayer.b.a(entityMetadata);
+ });
+ }
+
+ @Override
+ public ActionResult updateProfile(Player player, NickoProfile profile, boolean skinChange, boolean reset) {
+ final boolean changeOnlyName = profile.getSkin() != null && !profile.getSkin().equalsIgnoreCase(player.getName());
+ final String profileName = profile.getName() == null ? player.getName() : profile.getName();
+
+ final CraftPlayer craftPlayer = (CraftPlayer) player;
+ final EntityPlayer entityPlayer = craftPlayer.getHandle();
+ final GameProfile gameProfile = new GameProfile(player.getUniqueId(), profileName);
+
+ if (skinChange || changeOnlyName) {
+ final ActionResult skinFetch = fetchSkinTextures(profile, reset);
+ if (!skinFetch.isError()) {
+ final MojangSkin skin = skinFetch.getResult();
+ final PropertyMap properties = gameProfile.getProperties();
+ properties.removeAll("textures");
+ properties.put("textures", new Property("textures", skin.getValue(), skin.getSignature()));
+ updateSelf(player);
+ }
+ }
+
+ final PacketPlayOutPlayerInfo add = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.a);
+ final PacketPlayOutPlayerInfo remove = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.e, entityPlayer);
+ // "It's a Surprise Tool That Will Help Us Later!"
+ final ProfilePublicKey.a key = remove.b().get(0).e();
+
+ add.b().clear();
+ add.b().add(new PacketPlayOutPlayerInfo.PlayerInfoData(gameProfile,
+ player.getPing(),
+ EnumGamemode.a(player.getGameMode().ordinal()),
+ IChatBaseComponent.a(profileName),
+ key)); // f mojang
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ onlineEntityPlayer.b.a(remove);
+ onlineEntityPlayer.b.a(add);
+ });
+ updateOthers(player);
+ return new ActionResult<>();
+ }
+}
diff --git a/v1_19_R2/pom.xml b/v1_19_R2/pom.xml
new file mode 100644
index 0000000..385efc4
--- /dev/null
+++ b/v1_19_R2/pom.xml
@@ -0,0 +1,68 @@
+
+
+ 4.0.0
+
+
+ net.artelnatif
+ nicko-parent
+ 1.0-SNAPSHOT
+
+
+ v1_19_R2
+ 1.0-SNAPSHOT
+
+
+
+
+ net.md-5
+ specialsource-maven-plugin
+ 1.2.4
+
+
+ package
+
+ remap
+
+ remap-obf
+
+ org.spigotmc:minecraft-server:1.19.3-R0.1-SNAPSHOT:txt:maps-mojang
+ true
+ org.spigotmc:spigot:1.19.3-R0.1-SNAPSHOT:jar:remapped-mojang
+ true
+ remapped-obf
+
+
+
+ package
+
+ remap
+
+ remap-spigot
+
+ ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar
+ org.spigotmc:minecraft-server:1.19.3-R0.1-SNAPSHOT:csrg:maps-spigot
+ org.spigotmc:spigot:1.19.3-R0.1-SNAPSHOT:jar:remapped-obf
+
+
+
+
+
+
+
+
+
+ org.spigotmc
+ spigot
+ 1.19.3-R0.1-SNAPSHOT
+ remapped-mojang
+ provided
+
+
+ net.artelnatif
+ core
+ 1.0-SNAPSHOT
+
+
+
\ No newline at end of file
diff --git a/v1_19_R2/src/main/java/net/artelnatif/nicko/impl/v1_19_R2.java b/v1_19_R2/src/main/java/net/artelnatif/nicko/impl/v1_19_R2.java
new file mode 100644
index 0000000..4059960
--- /dev/null
+++ b/v1_19_R2/src/main/java/net/artelnatif/nicko/impl/v1_19_R2.java
@@ -0,0 +1,132 @@
+package net.artelnatif.nicko.impl;
+
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import com.mojang.authlib.properties.PropertyMap;
+import net.artelnatif.nicko.NickoBukkit;
+import net.artelnatif.nicko.disguise.ActionResult;
+import net.artelnatif.nicko.disguise.NickoProfile;
+import net.artelnatif.nicko.mojang.MojangSkin;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.RemoteChatSession;
+import net.minecraft.network.protocol.game.*;
+import net.minecraft.network.syncher.EntityDataAccessor;
+import net.minecraft.network.syncher.EntityDataSerializers;
+import net.minecraft.network.syncher.SynchedEntityData;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.entity.player.ProfilePublicKey;
+import net.minecraft.world.level.Level;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerTeleportEvent;
+
+import java.lang.reflect.Field;
+import java.util.*;
+
+public class v1_19_R2 implements Internals {
+ @Override
+ public void updateSelf(Player player) {
+ final ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
+ final ServerLevel level = serverPlayer.getLevel();
+ final ResourceKey levelResourceKey = serverPlayer.getLevel().dimension();
+ final ClientboundRespawnPacket respawn = new ClientboundRespawnPacket(serverPlayer.level.dimensionTypeId(),
+ levelResourceKey, level.getWorld().getSeed(),
+ serverPlayer.gameMode.getGameModeForPlayer(), serverPlayer.gameMode.getPreviousGameModeForPlayer(),
+ level.isDebug(),
+ level.isFlat(),
+ (byte) 0x00,
+ Optional.empty());
+
+ final boolean wasFlying = player.isFlying();
+ serverPlayer.connection.send(respawn);
+ player.setFlying(wasFlying);
+ player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
+ player.updateInventory();
+ }
+
+ @Override
+ public void updateOthers(Player player) {
+ final ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
+ final ClientboundRemoveEntitiesPacket remove = new ClientboundRemoveEntitiesPacket(serverPlayer.getBukkitEntity().getEntityId());
+ final ClientboundAddEntityPacket add = new ClientboundAddEntityPacket(serverPlayer);
+
+ final SynchedEntityData entityData = serverPlayer.getEntityData();
+ final EntityDataAccessor skinPartAccessor = new EntityDataAccessor<>(17, EntityDataSerializers.BYTE);
+ entityData.set(skinPartAccessor, (byte) 0x7f);
+ final ClientboundSetEntityDataPacket entityMetadata = new ClientboundSetEntityDataPacket(serverPlayer.getBukkitEntity().getEntityId(), entityData.getNonDefaultValues());
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ final ServerPlayer onlineServerPlayer = ((CraftPlayer) online).getHandle();
+ if (onlineServerPlayer.getBukkitEntity().getUniqueId() != player.getUniqueId()) {
+ onlineServerPlayer.connection.send(remove);
+ onlineServerPlayer.connection.send(add);
+ }
+ onlineServerPlayer.connection.send(entityMetadata);
+ });
+ }
+
+ @Override
+ public ActionResult updateProfile(Player player, NickoProfile profile, boolean skinChange, boolean reset) {
+ final boolean changeOnlyName = profile.getSkin() != null && !profile.getSkin().equalsIgnoreCase(player.getName());
+ final String profileName = profile.getName() == null ? player.getName() : profile.getName();
+
+ final ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
+ final GameProfile gameProfile = new GameProfile(player.getUniqueId(), profileName);
+
+ if (skinChange || changeOnlyName) {
+ final ActionResult skinFetch = fetchSkinTextures(profile, reset);
+ if (!skinFetch.isError()) {
+ final MojangSkin skin = skinFetch.getResult();
+ final PropertyMap properties = gameProfile.getProperties();
+ properties.removeAll("textures");
+ properties.put("textures", new Property("textures", skin.getValue(), skin.getSignature()));
+ updateSelf(player);
+ }
+ }
+
+ final ClientboundPlayerInfoUpdatePacket init = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(Collections.singletonList(serverPlayer));
+ final ClientboundPlayerInfoRemovePacket remove = new ClientboundPlayerInfoRemovePacket(Collections.singletonList(player.getUniqueId()));
+
+ RemoteChatSession chatSession;
+ if (serverPlayer.getChatSession() == null) {
+ NickoBukkit.getInstance().getLogger().warning("Chat Session of " + serverPlayer.displayName + " is null!");
+ NickoBukkit.getInstance().getLogger().warning("If your server is in offline mode/under BungeeCord you can safely ignore this message.");
+ chatSession = null;
+ } else {
+ final UUID uuid = serverPlayer.getChatSession().sessionId();
+ final ProfilePublicKey ppk = serverPlayer.getChatSession().profilePublicKey();
+ chatSession = new RemoteChatSession(uuid, ppk);
+ }
+
+ spoofPlayerInfoPacket(init, Collections.singletonList(new ClientboundPlayerInfoUpdatePacket.Entry(
+ player.getUniqueId(),
+ gameProfile,
+ true,
+ serverPlayer.latency,
+ serverPlayer.gameMode.getGameModeForPlayer(),
+ Component.literal(profileName),
+ chatSession == null ? null : chatSession.asData()
+ )));
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ final ServerPlayer onlinePlayer = ((CraftPlayer) online).getHandle();
+ onlinePlayer.connection.send(remove);
+ onlinePlayer.connection.send(init);
+ });
+ updateOthers(player);
+ return new ActionResult<>();
+ }
+
+ private void spoofPlayerInfoPacket(Object object, Object newValue) {
+ try {
+ final Field field = object.getClass().getDeclaredField("b");
+ field.setAccessible(true);
+ field.set(object, newValue);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ NickoBukkit.getInstance().getLogger().warning("Unable to spoof packet, that's bad! (" + e.getMessage() + ")");
+ }
+ }
+}
diff --git a/v1_19_R3/pom.xml b/v1_19_R3/pom.xml
new file mode 100644
index 0000000..eefd19d
--- /dev/null
+++ b/v1_19_R3/pom.xml
@@ -0,0 +1,68 @@
+
+
+ 4.0.0
+
+
+ net.artelnatif
+ nicko-parent
+ 1.0-SNAPSHOT
+
+
+ v1_19_R3
+ 1.0-SNAPSHOT
+
+
+
+
+ net.md-5
+ specialsource-maven-plugin
+ 1.2.4
+
+
+ package
+
+ remap
+
+ remap-obf
+
+ org.spigotmc:minecraft-server:1.19.4-R0.1-SNAPSHOT:txt:maps-mojang
+ true
+ org.spigotmc:spigot:1.19.4-R0.1-SNAPSHOT:jar:remapped-mojang
+ true
+ remapped-obf
+
+
+
+ package
+
+ remap
+
+ remap-spigot
+
+ ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar
+ org.spigotmc:minecraft-server:1.19.4-R0.1-SNAPSHOT:csrg:maps-spigot
+ org.spigotmc:spigot:1.19.4-R0.1-SNAPSHOT:jar:remapped-obf
+
+
+
+
+
+
+
+
+
+ org.spigotmc
+ spigot
+ 1.19.4-R0.1-SNAPSHOT
+ remapped-mojang
+ provided
+
+
+ net.artelnatif
+ core
+ 1.0-SNAPSHOT
+
+
+
\ No newline at end of file
diff --git a/v1_19_R3/src/main/java/net/artelnatif/nicko/impl/v1_19_R3.java b/v1_19_R3/src/main/java/net/artelnatif/nicko/impl/v1_19_R3.java
new file mode 100644
index 0000000..d0ef0eb
--- /dev/null
+++ b/v1_19_R3/src/main/java/net/artelnatif/nicko/impl/v1_19_R3.java
@@ -0,0 +1,140 @@
+package net.artelnatif.nicko.impl;
+
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import com.mojang.authlib.properties.PropertyMap;
+import net.artelnatif.nicko.NickoBukkit;
+import net.artelnatif.nicko.disguise.ActionResult;
+import net.artelnatif.nicko.disguise.NickoProfile;
+import net.artelnatif.nicko.mojang.MojangSkin;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.RemoteChatSession;
+import net.minecraft.network.protocol.game.*;
+import net.minecraft.network.syncher.EntityDataAccessor;
+import net.minecraft.network.syncher.EntityDataSerializers;
+import net.minecraft.network.syncher.SynchedEntityData;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.entity.player.ProfilePublicKey;
+import net.minecraft.world.level.Level;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerTeleportEvent;
+
+import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.logging.Logger;
+
+public class v1_19_R3 implements Internals {
+ final Logger logger = Bukkit.getLogger();
+
+ @Override
+ public void updateSelf(Player player) {
+ final ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
+ final ServerLevel level = serverPlayer.getLevel();
+ final ResourceKey levelResourceKey = serverPlayer.getLevel().dimension();
+ final ClientboundRespawnPacket respawn = new ClientboundRespawnPacket(serverPlayer.level.dimensionTypeId(),
+ levelResourceKey, level.getWorld().getSeed(),
+ serverPlayer.gameMode.getGameModeForPlayer(), serverPlayer.gameMode.getPreviousGameModeForPlayer(),
+ level.isDebug(),
+ level.isFlat(),
+ (byte) 0x00,
+ Optional.empty());
+
+ final boolean wasFlying = player.isFlying();
+ serverPlayer.connection.send(respawn);
+ player.setFlying(wasFlying);
+ player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
+ player.updateInventory();
+ }
+
+ @Override
+ public void updateOthers(Player player) {
+ final ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
+
+ final ClientboundRemoveEntitiesPacket remove = new ClientboundRemoveEntitiesPacket(serverPlayer.getBukkitEntity().getEntityId());
+ final ClientboundAddEntityPacket add = new ClientboundAddEntityPacket(serverPlayer);
+
+ final SynchedEntityData entityData = serverPlayer.getEntityData();
+ final EntityDataAccessor skinPartAccessor = new EntityDataAccessor<>(17, EntityDataSerializers.BYTE);
+ entityData.set(skinPartAccessor, (byte) 0x7f);
+ final ClientboundSetEntityDataPacket entityMetadata = new ClientboundSetEntityDataPacket(serverPlayer.getBukkitEntity().getEntityId(), entityData.getNonDefaultValues());
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ final ServerPlayer onlineServerPlayer = ((CraftPlayer) online).getHandle();
+ if (onlineServerPlayer.getBukkitEntity().getUniqueId() != player.getUniqueId()) {
+ onlineServerPlayer.connection.send(remove);
+ onlineServerPlayer.connection.send(add);
+ }
+ onlineServerPlayer.connection.send(entityMetadata);
+ });
+ }
+
+ @Override
+ public ActionResult updateProfile(Player player, NickoProfile profile, boolean skinChange, boolean reset) {
+ final boolean changeOnlyName = profile.getSkin() != null && !profile.getSkin().equalsIgnoreCase(player.getName());
+ final String profileName = profile.getName() == null ? player.getName() : profile.getName();
+
+ final ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
+ final GameProfile gameProfile = new GameProfile(player.getUniqueId(), profileName);
+
+ if (skinChange || changeOnlyName) {
+ final ActionResult skinFetch = fetchSkinTextures(profile, reset);
+ if (!skinFetch.isError()) {
+ final MojangSkin skin = skinFetch.getResult();
+ final PropertyMap properties = gameProfile.getProperties();
+ properties.removeAll("textures");
+ properties.put("textures", new Property("textures", skin.getValue(), skin.getSignature()));
+ updateSelf(player);
+ }
+ }
+
+ final ClientboundPlayerInfoUpdatePacket init = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(Collections.singletonList(serverPlayer));
+ final ClientboundPlayerInfoRemovePacket remove = new ClientboundPlayerInfoRemovePacket(Collections.singletonList(player.getUniqueId()));
+
+ RemoteChatSession chatSession;
+ if (serverPlayer.getChatSession() == null) {
+ NickoBukkit.getInstance().getLogger().warning("Chat Session of " + serverPlayer.displayName + " is null!");
+ NickoBukkit.getInstance().getLogger().warning("If your server is in offline mode/under BungeeCord you can safely ignore this message.");
+ chatSession = null;
+ } else {
+ final UUID uuid = serverPlayer.getChatSession().sessionId();
+ final ProfilePublicKey ppk = serverPlayer.getChatSession().profilePublicKey();
+ chatSession = new RemoteChatSession(uuid, ppk);
+ }
+
+ spoofPlayerInfoPacket(init, Collections.singletonList(new ClientboundPlayerInfoUpdatePacket.Entry(
+ player.getUniqueId(),
+ gameProfile,
+ true,
+ serverPlayer.latency,
+ serverPlayer.gameMode.getGameModeForPlayer(),
+ Component.literal(profileName),
+ chatSession == null ? null : chatSession.asData()
+ )));
+
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ final ServerPlayer onlinePlayer = ((CraftPlayer) online).getHandle();
+ onlinePlayer.connection.send(remove);
+ onlinePlayer.connection.send(init);
+ });
+ // TODO: 3/17/23 Update signature to avoid duplicate for loop
+ updateOthers(player);
+ return new ActionResult<>();
+ }
+
+ private void spoofPlayerInfoPacket(Object object, Object newValue) {
+ try {
+ final Field field = object.getClass().getDeclaredField("b");
+ field.setAccessible(true);
+ field.set(object, newValue);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ NickoBukkit.getInstance().getLogger().warning("Unable to spoof packet, that's bad! (" + e.getMessage() + ")");
+ }
+ }
+}