diff --git a/dist/pom.xml b/dist/pom.xml
index 2b838e5..0384c21 100644
--- a/dist/pom.xml
+++ b/dist/pom.xml
@@ -46,6 +46,11 @@
nicko-core
${project.parent.version}
+
+ net.artelnatif
+ nicko-v1_17_R1
+ ${project.parent.version}
+
net.artelnatif
nicko-v1_18_R1
diff --git a/pom.xml b/pom.xml
index b7e4c1a..e83a403 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,8 +14,9 @@
nicko-core
dist
v1_18_R2
- v1_18_R1
+ net.artelnatif.nicko.impl.v1_17_R1
v1_19_R1
+ v1_17_R1
diff --git a/v1_17_R1/pom.xml b/v1_17_R1/pom.xml
index 81bd102..2fb37e9 100644
--- a/v1_17_R1/pom.xml
+++ b/v1_17_R1/pom.xml
@@ -9,12 +9,20 @@
4.0.0
- v1_17_R1
-
-
- 17
- 17
- UTF-8
-
+ nicko-v1_17_R1
+ 1.0-SNAPSHOT
+
+
+ org.spigotmc
+ spigot
+ 1.17.1-R0.1-SNAPSHOT
+ provided
+
+
+ net.artelnatif
+ nicko-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..16c632b
--- /dev/null
+++ b/v1_17_R1/src/main/java/net/artelnatif/nicko/impl/v1_17_R1.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.NickoProfile;
+import net.artelnatif.nicko.disguise.UpdateResult;
+import net.artelnatif.nicko.i18n.I18NDict;
+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;
+import org.bukkit.inventory.ItemStack;
+
+import java.io.IOException;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+
+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();
+ final ItemStack itemOnCursor = player.getItemOnCursor();
+ entityPlayer.b.sendPacket(respawn);
+ player.setFlying(wasFlying);
+ player.setItemOnCursor(itemOnCursor);
+ 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);
+
+ /*
+ BIT MASKS:
+ 0x01 Cape enabled
+ 0x02 Jacket enabled
+ 0x04 Left sleeve enabled
+ 0x08 Right sleeve enabled
+ 0x10 Left pants leg enabled
+ 0x20 Right pants leg enabled
+ 0x40 Hat enabled
+ */
+ final DataWatcher dataWatcher = entityPlayer.getDataWatcher();
+ final DataWatcherObject displayedSkinPartDataWatcher = new DataWatcherObject<>(17, DataWatcherRegistry.a);
+ dataWatcher.set(displayedSkinPartDataWatcher, (byte) 0x7f); // 127, all masks combined
+ 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 UpdateResult updateProfile(Player player, NickoProfile profile, boolean skinChange) {
+ final CraftPlayer craftPlayer = (CraftPlayer) player;
+ final EntityPlayer entityPlayer = craftPlayer.getHandle();
+ Optional skin;
+
+ final PacketPlayOutPlayerInfo remove = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.e, entityPlayer);
+ entityPlayer.b.sendPacket(remove);
+
+ final PacketPlayOutPlayerInfo add = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.a);
+ final GameProfile gameProfile = new GameProfile(player.getUniqueId(), profile.getName());
+
+ if (skinChange) {
+ try {
+ final Optional uuid = NickoBukkit.getInstance().getMojangAPI().getUUID(profile.getSkin());
+ if (uuid.isPresent()) {
+ skin = NickoBukkit.getInstance().getMojangAPI().getSkin(uuid.get());
+ if (skin.isPresent()) {
+ final PropertyMap properties = gameProfile.getProperties();
+ properties.put("textures", new Property("textures", skin.get().value(), skin.get().signature()));
+ updateSelf(player);
+ } else {
+ return new UpdateResult(I18NDict.Error.SKIN_FAIL_MOJANG);
+ }
+ } else {
+ return new UpdateResult(I18NDict.Error.NAME_FAIL_MOJANG);
+ }
+ } catch (ExecutionException e) {
+ return new UpdateResult(I18NDict.Error.SKIN_FAIL_CACHE);
+ } catch (IOException e) {
+ return new UpdateResult(I18NDict.Error.UNEXPECTED_ERROR);
+ }
+ }
+
+ add.b().clear();
+ add.b().add(new PacketPlayOutPlayerInfo.PlayerInfoData(gameProfile,
+ player.getPing(),
+ EnumGamemode.getById(player.getGameMode().ordinal()), IChatBaseComponent.a(profile.getName())));
+ entityPlayer.b.sendPacket(add);
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ onlineEntityPlayer.b.sendPacket(remove);
+ onlineEntityPlayer.b.sendPacket(add);
+ });
+ updateOthers(player);
+ return new UpdateResult();
+ }
+}