Skip to content

Instantly share code, notes, and snippets.

@nathanfranke
Created February 27, 2022 09:37
Show Gist options
  • Save nathanfranke/2d02ceec740ad0599d4c2a19883ed42e to your computer and use it in GitHub Desktop.
Save nathanfranke/2d02ceec740ad0599d4c2a19883ed42e to your computer and use it in GitHub Desktop.
Seamless Name, UUID, and Skin Disguise on Paper 1.18 (ProtocolLib)
package me.nathanfranke.nickplugin
import com.comphenix.protocol.PacketType
import com.comphenix.protocol.ProtocolLibrary
import com.comphenix.protocol.events.PacketAdapter
import com.comphenix.protocol.events.PacketContainer
import com.comphenix.protocol.events.PacketEvent
import com.comphenix.protocol.wrappers.EnumWrappers
import com.comphenix.protocol.wrappers.PlayerInfoData
import com.comphenix.protocol.wrappers.WrappedChatComponent
import com.comphenix.protocol.wrappers.WrappedGameProfile
import com.comphenix.protocol.wrappers.WrappedSignedProperty
import com.destroystokyo.paper.profile.PlayerProfile
import org.bukkit.command.Command
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.plugin.java.JavaPlugin
import java.util.UUID
@Suppress("UNUSED")
class NickPlugin : JavaPlugin(), Listener {
private val names = mutableMapOf<UUID, String>()
override fun onEnable() {
ProtocolLibrary.getProtocolManager().addPacketListener(
object : PacketAdapter(this, PacketType.Play.Server.NAMED_ENTITY_SPAWN) {
override fun onPacketSending(event: PacketEvent) {
val uuid = event.packet.uuiDs.read(0)
val profile = getEffectiveProfile(server.getPlayer(uuid)!!)
event.packet.uuiDs.write(0, profile.id)
}
},
)
ProtocolLibrary.getProtocolManager().addPacketListener(
object : PacketAdapter(this, PacketType.Play.Server.PLAYER_INFO) {
override fun onPacketSending(event: PacketEvent) {
val dataList = event.packet.playerInfoDataLists.read(0)
for (i in dataList.indices) {
val data = dataList[i]
val player = server.getPlayer(data.profile.uuid) ?: continue
val profile = getEffectiveProfile(player)
val wrappedProfile = if (event.player == player) {
WrappedGameProfile(player.uniqueId, profile.name)
} else {
WrappedGameProfile(profile.id, profile.name)
}
for (property in profile.properties) {
wrappedProfile.properties.put(
property.name,
WrappedSignedProperty(
property.name,
property.value,
property.signature,
),
)
}
dataList[i] = PlayerInfoData(
wrappedProfile,
data.latency,
data.gameMode,
WrappedChatComponent.fromText(wrappedProfile.name),
)
}
event.packet.playerInfoDataLists.write(0, dataList)
Unit
}
},
)
server.pluginManager.registerEvents(this, this)
}
private fun getOfflineProfile(name: String) =
server.createProfile(UUID.nameUUIDFromBytes("OfflinePlayer:$name".toByteArray()), name)
private fun getEffectiveProfile(player: Player): PlayerProfile {
val effectiveName = names.getOrDefault(player.uniqueId, player.name)
val profile = server.createProfile(effectiveName)
profile.complete()
profile.id ?: return getOfflineProfile(effectiveName)
return profile
}
private fun nick(player: Player, name: String) {
names[player.uniqueId] = name
refresh(player)
}
private val playerPreviousIdentities = mutableMapOf<Player, WrappedGameProfile>()
private fun refresh(player: Player) {
// REMOVE PLAYER FOR OTHERS
run {
val previous = playerPreviousIdentities.remove(player)
?: WrappedGameProfile(player.uniqueId, player.name)
val profile = getEffectiveProfile(player)
playerPreviousIdentities[player] = WrappedGameProfile(profile.id, profile.name)
val packet = PacketContainer(PacketType.Play.Server.PLAYER_INFO)
packet.playerInfoAction.write(0, EnumWrappers.PlayerInfoAction.REMOVE_PLAYER)
packet.playerInfoDataLists.write(
0,
listOf(
PlayerInfoData(
previous,
0,
EnumWrappers.NativeGameMode.SURVIVAL,
null,
),
),
)
for (p in server.onlinePlayers) {
if (p != player) {
ProtocolLibrary.getProtocolManager().sendServerPacket(p, packet.deepClone(), false)
}
}
}
// REMOVE PLAYER FOR SELF
run {
val packet = PacketContainer(PacketType.Play.Server.PLAYER_INFO)
packet.playerInfoAction.write(0, EnumWrappers.PlayerInfoAction.REMOVE_PLAYER)
packet.playerInfoDataLists.write(
0,
listOf(
PlayerInfoData(
WrappedGameProfile(player.uniqueId, player.name),
0,
EnumWrappers.NativeGameMode.SURVIVAL,
null,
),
),
)
ProtocolLibrary.getProtocolManager().sendServerPacket(player, packet, false)
}
// ADD PLAYER FOR EVERYONE
run {
val packet = PacketContainer(PacketType.Play.Server.PLAYER_INFO)
packet.playerInfoAction.write(0, EnumWrappers.PlayerInfoAction.ADD_PLAYER)
packet.playerInfoDataLists.write(
0,
listOf(
PlayerInfoData(
WrappedGameProfile(player.uniqueId, player.name),
player.ping,
EnumWrappers.NativeGameMode.fromBukkit(player.gameMode),
WrappedChatComponent.fromText(player.name),
),
),
)
for (p in server.onlinePlayers) {
ProtocolLibrary.getProtocolManager().sendServerPacket(p, packet.deepClone())
}
}
// RESPAWN FOR SELF
run {
server.worlds.firstOrNull { it != player.world }?.let {
val location = player.location
player.teleport(it.spawnLocation)
player.teleport(location)
}
}
for (p in server.onlinePlayers) {
p.hidePlayer(this, player)
p.showPlayer(this, player)
}
}
@EventHandler
fun onPlayerJoin(event: PlayerJoinEvent) {
refresh(event.player)
}
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
if (command.name == "nick") {
if (sender !is Player) {
sender.sendMessage("You must be a player to execute this command.")
return true
}
if (args.isEmpty()) {
sender.sendMessage("Please specify a nickname to use.")
return true
}
nick(sender, args.first())
return true
}
return false
}
}
@nathanfranke
Copy link
Author

disguise.mp4

@UnknownKriodluk
Copy link

UnknownKriodluk commented Feb 12, 2024

[14:08:35 ERROR]: [NickColor] Unhandled exception occurred in onPacketSending(PacketEvent) for NickColor
java.lang.NullPointerException: Cannot invoke "com.comphenix.protocol.wrappers.PlayerInfoData.getProfile()" because "data" is null
        at me.unknkriod.NickPlugin$onEnable$2.onPacketSending(Main.kt:43) ~[untitled2-1.0-SNAPSHOT.jar:?]
        at com.comphenix.protocol.injector.SortedPacketListenerList.invokeSendingListener(SortedPacketListenerList.java:219) ~[ProtocolLib.jar:?]
        at com.comphenix.protocol.injector.SortedPacketListenerList.invokeUnpackedPacketSending(SortedPacketListenerList.java:204) ~[ProtocolLib.jar:?]
        at com.comphenix.protocol.injector.SortedPacketListenerList.invokePacketSending(SortedPacketListenerList.java:149) ~[ProtocolLib.jar:?]
        at com.comphenix.protocol.injector.SortedPacketListenerList.invokePacketSending(SortedPacketListenerList.java:139) ~[ProtocolLib.jar:?]
        at com.comphenix.protocol.injector.PacketFilterManager.postPacketToListeners(PacketFilterManager.java:553) ~[ProtocolLib.jar:?]
        at com.comphenix.protocol.injector.PacketFilterManager.invokePacketSending(PacketFilterManager.java:526) ~[ProtocolLib.jar:?]
        at com.comphenix.protocol.injector.netty.manager.NetworkManagerInjector.onPacketSending(NetworkManagerInjector.java:100) ~[ProtocolLib.jar:?]
        at com.comphenix.protocol.injector.netty.channel.NettyChannelInjector.processOutbound(NettyChannelInjector.java:553) ~[ProtocolLib.jar:?]
        at com.comphenix.protocol.injector.netty.channel.NettyChannelInjector$2.doProxyRunnable(NettyChannelInjector.java:456) ~[ProtocolLib.jar:?]
        at com.comphenix.protocol.injector.netty.channel.NettyEventLoopProxy.proxyRunnable(NettyEventLoopProxy.java:43) ~[ProtocolLib.jar:?]
        at com.comphenix.protocol.injector.netty.channel.NettyEventLoopProxy.execute(NettyEventLoopProxy.java:252) ~[ProtocolLib.jar:?]
        at net.minecraft.network.Connection.sendPacket(Connection.java:432) ~[?:?]
        at net.minecraft.network.Connection.send(Connection.java:392) ~[?:?]
        at net.minecraft.server.network.ServerCommonPacketListenerImpl.send(ServerCommonPacketListenerImpl.java:242) ~[paper-1.20.2.jar:git-Paper-318]
        at net.minecraft.server.network.ServerCommonPacketListenerImpl.send(ServerCommonPacketListenerImpl.java:227) ~[paper-1.20.2.jar:git-Paper-318]
        at net.minecraft.server.players.PlayerList.tick(PlayerList.java:1020) ~[paper-1.20.2.jar:git-Paper-318]
        at net.minecraft.server.MinecraftServer.tickChildren(MinecraftServer.java:1582) ~[paper-1.20.2.jar:git-Paper-318]
        at net.minecraft.server.dedicated.DedicatedServer.tickChildren(DedicatedServer.java:446) ~[paper-1.20.2.jar:git-Paper-318]
        at net.minecraft.server.MinecraftServer.tickServer(MinecraftServer.java:1379) ~[paper-1.20.2.jar:git-Paper-318]
        at net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:1156) ~[paper-1.20.2.jar:git-Paper-318]
        at net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:315) ~[paper-1.20.2.jar:git-Paper-318]
        at java.lang.Thread.run(Thread.java:833) ~[?:?]
[14:08:35 ERROR]: Parameters:
  net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket@74b23de8[
    a=[UPDATE_LATENCY]
    b=[b[profileId=......................................................., profile=com.mojang.authlib.GameProfile@470d99c2[id=..........................................,name=...............,properties={textures=[Property[name=textures, value=..................................................]]}], listed=true, latency=0, gameMode=SURVIVAL, displayName=io.papermc.paper.adventure.AdventureComponent@216c894f, chatSession=null]]
  ]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment