diff --git a/dist/dependency-reduced-pom.xml b/dist/dependency-reduced-pom.xml
index 9ac078f..abcb5d0 100644
--- a/dist/dependency-reduced-pom.xml
+++ b/dist/dependency-reduced-pom.xml
@@ -31,6 +31,39 @@
+
+ net.md-5
+ specialsource-maven-plugin
+ 1.2.4
+
+
+ remap-obf
+ package
+
+ remap
+
+
+ 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
+
+
+
+ remap-spigot
+ package
+
+ remap
+
+
+ ${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
+
+
+
+
diff --git a/dist/pom.xml b/dist/pom.xml
index 0384c21..d81b2f5 100644
--- a/dist/pom.xml
+++ b/dist/pom.xml
@@ -37,6 +37,39 @@
+
+ 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
+
+
+
+
@@ -66,7 +99,10 @@
nicko-v1_19_R1
${project.parent.version}
+
+ net.artelnatif
+ nicko-v1_19_R2
+ ${project.parent.version}
+
-
-
\ No newline at end of file
diff --git a/nicko-core/pom.xml b/nicko-core/pom.xml
index b673d55..0917b60 100644
--- a/nicko-core/pom.xml
+++ b/nicko-core/pom.xml
@@ -71,7 +71,7 @@
de.studiocode.invui
InvUI
- 0.8.2
+ 0.10.2
diff --git a/pom.xml b/pom.xml
index 6cc51a1..31e0c49 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,6 +17,7 @@
v1_18_R1
v1_18_R2
v1_19_R1
+ v1_19_R2
diff --git a/v1_19_R2/pom.xml b/v1_19_R2/pom.xml
new file mode 100644
index 0000000..ee71c1d
--- /dev/null
+++ b/v1_19_R2/pom.xml
@@ -0,0 +1,30 @@
+
+
+ 4.0.0
+
+
+ net.artelnatif
+ nicko-parent
+ 1.0-SNAPSHOT
+
+
+ nicko-v1_19_R2
+ 1.0-SNAPSHOT
+
+
+
+ org.spigotmc
+ spigot
+ 1.19.3-R0.1-SNAPSHOT
+ remapped-mojang
+ provided
+
+
+ net.artelnatif
+ nicko-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..9448bfb
--- /dev/null
+++ b/v1_19_R2/src/main/java/net/artelnatif/nicko/impl/v1_19_R2.java
@@ -0,0 +1,134 @@
+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.i18n.I18NDict;
+import net.artelnatif.nicko.mojang.MojangAPI;
+import net.artelnatif.nicko.mojang.MojangSkin;
+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.level.Level;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
+import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerTeleportEvent;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+
+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 CraftWorld world = level.getWorld();
+ // last boolean is: "has death location" attribute, if true, the optional contains the death dimension and position.
+ // with the boolean being false, we don't need to provide a value, and thus we return an empty optional.
+ final ClientboundRespawnPacket respawn = new ClientboundRespawnPacket(serverPlayer.level.dimensionTypeId(),
+ levelResourceKey, world.getSeed(),
+ serverPlayer.gameMode.getPreviousGameModeForPlayer(), serverPlayer.gameMode.getGameModeForPlayer(),
+ 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);
+
+ /*
+ 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 SynchedEntityData entityData = serverPlayer.getEntityData();
+ final EntityDataAccessor skinPartAccessor = new EntityDataAccessor<>(17, EntityDataSerializers.BYTE);
+ entityData.set(skinPartAccessor, (byte) 0x7f); // 127, all masks combined
+ final ClientboundSetEntityDataPacket entityMetadata = new ClientboundSetEntityDataPacket(serverPlayer.getBukkitEntity().getEntityId(), entityData.getNonDefaultValues());
+
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ 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();
+ Optional skin;
+
+ final ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
+ final GameProfile gameProfile = serverPlayer.getGameProfile();
+
+ final ClientboundPlayerInfoRemovePacket remove = new ClientboundPlayerInfoRemovePacket(List.of(player.getUniqueId()));
+ // TODO: 1/20/23 Sets Gamemode to Survival but keeps the flying? Visual effect only?
+ final ClientboundPlayerInfoUpdatePacket init = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(serverPlayer));
+
+
+ if (skinChange || changeOnlyName) {
+ try {
+ final MojangAPI mojang = NickoBukkit.getInstance().getMojangAPI();
+ final Optional uuid = mojang.getUUID(profile.getSkin());
+ if (uuid.isPresent()) {
+ skin = (reset ? mojang.getSkinWithoutCaching(uuid.get()) : mojang.getSkin(uuid.get()));
+ if (skin.isPresent()) {
+ final PropertyMap properties = gameProfile.getProperties();
+ properties.removeAll("textures");
+ properties.put("textures", new Property("textures", skin.get().value(), skin.get().signature()));
+ updateSelf(player);
+ } else {
+ return new ActionResult(I18NDict.Error.SKIN_FAIL_MOJANG);
+ }
+ } else {
+ return new ActionResult(I18NDict.Error.NAME_FAIL_MOJANG);
+ }
+ } catch (ExecutionException e) {
+ return new ActionResult(I18NDict.Error.SKIN_FAIL_CACHE);
+ } catch (IOException e) {
+ return new ActionResult(I18NDict.Error.NAME_FAIL_MOJANG);
+ }
+ }
+
+ serverPlayer.connection.send(remove);
+ serverPlayer.connection.send(init);
+ Bukkit.getOnlinePlayers().forEach(online -> {
+ ServerPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle();
+ onlineEntityPlayer.connection.send(remove);
+ onlineEntityPlayer.connection.send(init);
+ });
+ updateOthers(player);
+ return new ActionResult();
+ }
+}