feat: 1.19.3 full support (chat, skin, name)
This commit is contained in:
parent
ed1ffc472e
commit
d7ed49f668
1 changed files with 37 additions and 25 deletions
|
@ -10,6 +10,7 @@ import net.artelnatif.nicko.i18n.I18NDict;
|
||||||
import net.artelnatif.nicko.mojang.MojangAPI;
|
import net.artelnatif.nicko.mojang.MojangAPI;
|
||||||
import net.artelnatif.nicko.mojang.MojangSkin;
|
import net.artelnatif.nicko.mojang.MojangSkin;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.chat.RemoteChatSession;
|
||||||
import net.minecraft.network.protocol.game.*;
|
import net.minecraft.network.protocol.game.*;
|
||||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||||
|
@ -17,19 +18,16 @@ import net.minecraft.network.syncher.SynchedEntityData;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.player.ProfilePublicKey;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
|
|
||||||
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer;
|
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Collections;
|
import java.util.*;
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
public class v1_19_R2 implements Internals {
|
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 ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
|
||||||
final ServerLevel level = serverPlayer.getLevel();
|
final ServerLevel level = serverPlayer.getLevel();
|
||||||
final ResourceKey<Level> levelResourceKey = serverPlayer.getLevel().dimension();
|
final ResourceKey<Level> 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(),
|
final ClientboundRespawnPacket respawn = new ClientboundRespawnPacket(serverPlayer.level.dimensionTypeId(),
|
||||||
levelResourceKey, world.getSeed(),
|
levelResourceKey, level.getWorld().getSeed(),
|
||||||
serverPlayer.gameMode.getPreviousGameModeForPlayer(), serverPlayer.gameMode.getGameModeForPlayer(),
|
serverPlayer.gameMode.getGameModeForPlayer(), serverPlayer.gameMode.getPreviousGameModeForPlayer(),
|
||||||
level.isDebug(),
|
level.isDebug(),
|
||||||
level.isFlat(),
|
level.isFlat(),
|
||||||
(byte) 0x00,
|
(byte) 0x00,
|
||||||
|
@ -124,26 +119,32 @@ public class v1_19_R2 implements Internals {
|
||||||
|
|
||||||
final ClientboundPlayerInfoUpdatePacket init = new ClientboundPlayerInfoUpdatePacket(
|
final ClientboundPlayerInfoUpdatePacket init = new ClientboundPlayerInfoUpdatePacket(
|
||||||
EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER,
|
EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER,
|
||||||
|
ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT,
|
||||||
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY,
|
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY,
|
||||||
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED),
|
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED),
|
||||||
Collections.singletonList(serverPlayer));
|
Collections.singletonList(serverPlayer));
|
||||||
|
|
||||||
Field field;
|
if (serverPlayer.getChatSession() == null) {
|
||||||
try {
|
NickoBukkit.getInstance().getLogger().warning("Chat Session of " + serverPlayer.displayName + " is undefined." +
|
||||||
field = init.getClass().getDeclaredField("b");
|
"Nicko might fail at changing skins or might throw an error." +
|
||||||
field.setAccessible(true);
|
"Worse however, the player might get kicked when chatting." +
|
||||||
field.set(init, List.of(new ClientboundPlayerInfoUpdatePacket.Entry(
|
"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(),
|
player.getUniqueId(),
|
||||||
gameProfile,
|
gameProfile,
|
||||||
true,
|
true,
|
||||||
serverPlayer.latency,
|
serverPlayer.latency,
|
||||||
serverPlayer.gameMode.getGameModeForPlayer(),
|
serverPlayer.gameMode.getGameModeForPlayer(),
|
||||||
Component.literal(profileName),
|
Component.literal(profileName),
|
||||||
serverPlayer.getChatSession().asData()
|
newChatSession.asData()
|
||||||
)));
|
)));
|
||||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
Bukkit.getOnlinePlayers().forEach(online -> {
|
Bukkit.getOnlinePlayers().forEach(online -> {
|
||||||
final ServerPlayer onlinePlayer = ((CraftPlayer) online).getHandle();
|
final ServerPlayer onlinePlayer = ((CraftPlayer) online).getHandle();
|
||||||
|
@ -153,4 +154,15 @@ public class v1_19_R2 implements Internals {
|
||||||
updateOthers(player);
|
updateOthers(player);
|
||||||
return new ActionResult();
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue