From d7ed49f66807cc7663a42ac5d86d6ce1b2e1d424 Mon Sep 17 00:00:00 2001 From: aro Date: Sun, 22 Jan 2023 15:12:36 +0100 Subject: [PATCH] feat: 1.19.3 full support (chat, skin, name) --- .../net/artelnatif/nicko/impl/v1_19_R2.java | 62 +++++++++++-------- 1 file changed, 37 insertions(+), 25 deletions(-) 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 index dd22c27..0dd558c 100644 --- 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 @@ -10,6 +10,7 @@ import net.artelnatif.nicko.i18n.I18NDict; import net.artelnatif.nicko.mojang.MojangAPI; 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; @@ -17,19 +18,16 @@ 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.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.lang.reflect.Field; -import java.util.Collections; -import java.util.EnumSet; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.concurrent.ExecutionException; public class v1_19_R2 implements Internals { @@ -38,12 +36,9 @@ public class v1_19_R2 implements Internals { 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(), + levelResourceKey, level.getWorld().getSeed(), + serverPlayer.gameMode.getGameModeForPlayer(), serverPlayer.gameMode.getPreviousGameModeForPlayer(), level.isDebug(), level.isFlat(), (byte) 0x00, @@ -124,27 +119,33 @@ public class v1_19_R2 implements Internals { final ClientboundPlayerInfoUpdatePacket init = new ClientboundPlayerInfoUpdatePacket( EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, + ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED), Collections.singletonList(serverPlayer)); - Field field; - try { - field = init.getClass().getDeclaredField("b"); - field.setAccessible(true); - field.set(init, List.of(new ClientboundPlayerInfoUpdatePacket.Entry( - player.getUniqueId(), - gameProfile, - true, - serverPlayer.latency, - serverPlayer.gameMode.getGameModeForPlayer(), - Component.literal(profileName), - serverPlayer.getChatSession().asData() - ))); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new RuntimeException(e); + if (serverPlayer.getChatSession() == null) { + NickoBukkit.getInstance().getLogger().warning("Chat Session of " + serverPlayer.displayName + " is undefined." + + "Nicko might fail at changing skins or might throw an error." + + "Worse however, the player might get kicked when chatting." + + "This is pretty rare however and this" + + "warning can be safely ignored in most cases."); } + final UUID uuid = serverPlayer.getChatSession().sessionId(); + final ProfilePublicKey ppk = serverPlayer.getChatSession().profilePublicKey(); + final RemoteChatSession newChatSession = new RemoteChatSession(uuid, ppk); + + spoofPlayerInfoPacket(init, List.of(new ClientboundPlayerInfoUpdatePacket.Entry( + player.getUniqueId(), + gameProfile, + true, + serverPlayer.latency, + serverPlayer.gameMode.getGameModeForPlayer(), + Component.literal(profileName), + newChatSession.asData() + ))); + Bukkit.getOnlinePlayers().forEach(online -> { final ServerPlayer onlinePlayer = ((CraftPlayer) online).getHandle(); onlinePlayer.connection.send(remove); @@ -153,4 +154,15 @@ public class v1_19_R2 implements Internals { 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) { + // TODO: 1/22/23 Throw nice error + throw new RuntimeException(e); + } + } }