Created
February 27, 2022 09:37
-
-
Save nathanfranke/2d02ceec740ad0599d4c2a19883ed42e to your computer and use it in GitHub Desktop.
Seamless Name, UUID, and Skin Disguise on Paper 1.18 (ProtocolLib)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} |
[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
disguise.mp4