Skip to content

Commit

Permalink
implements full player uuid rewrite
Browse files Browse the repository at this point in the history
  • Loading branch information
Fallen-Breath committed Jun 23, 2024
1 parent 7af5538 commit ef2e4e8
Show file tree
Hide file tree
Showing 13 changed files with 425 additions and 27 deletions.
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ A list of small tweaks I made:
- The proxy setting is in the `auth-proxy` section in `velocity.toml`, of course you know how to fill it
- Supported proxy types: `socks4`, `socks5`, `http`
- If enabled, velocity will firstly try authenticating with the given proxy, if failed it will try again without the proxy
- Implement UUID rewrite for TabList packets, like what bungeecord does
- So `online-mode=true` on velocity + `online-mode=false` on backend mc servers + `player-info-forwarding-mode=none` can correctly work
- Implement player UUID rewrite, like what bungeecord does.
Make setup with online velocity + offline Minecraft server work correctly
(`online-mode=true` on velocity + `online-mode=false` on backend mc servers + `player-info-forwarding-mode=none`)
- TabList packets rewrite
- Affects `LegacyPlayerListItemPacket`, `UpsertPlayerInfoPacket`, `RemovePlayerInfoPacket` packets
- Rewrites player UUIDs inside those packets to their UUIDs in the velocity server
- Entity packets rewrite
- Rewrites player UUIDs inside player creation packets and spectator teleport packets, to their UUIDs in the velocity server

# Velocity

Expand Down
8 changes: 8 additions & 0 deletions api/src/main/java/com/velocitypowered/api/proxy/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ public interface Player extends
*/
UUID getUniqueId();

// [fallen's fork] player uuid rewrite: store offline uuid for reuse
/**
* Returns the player's offline UUID.
*
* @return the UUID
*/
UUID getOfflineUuid();

/**
* Returns the server that the player is currently connected to.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@
import com.velocitypowered.proxy.protocol.packet.title.TitleSubtitlePacket;
import com.velocitypowered.proxy.protocol.packet.title.TitleTextPacket;
import com.velocitypowered.proxy.protocol.packet.title.TitleTimesPacket;
import com.velocitypowered.proxy.protocol.packet.uuidrewrite.UrSpawnEntityS2CPacket;
import com.velocitypowered.proxy.protocol.packet.uuidrewrite.UrSpawnPlayerS2CPacket;
import com.velocitypowered.proxy.protocol.packet.uuidrewrite.UrSpectatorTeleportC2SPacket;
import io.netty.buffer.ByteBuf;

/**
Expand Down Expand Up @@ -309,6 +312,20 @@ default boolean handle(ActiveFeaturesPacket packet) {
return false;
}

// [fallen's fork] player uuid rewrite - entity packet
default boolean handle(UrSpawnPlayerS2CPacket packet) {
return false;
}

default boolean handle(UrSpawnEntityS2CPacket packet) {
return false;
}

default boolean handle(UrSpectatorTeleportC2SPacket packet) {
return false;
}
// [fallen's fork] ends

default boolean handle(FinishedUpdatePacket packet) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@
import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfoPacket;
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
import com.velocitypowered.proxy.protocol.packet.config.StartUpdatePacket;
import com.velocitypowered.proxy.protocol.packet.uuidrewrite.EntityPacketUuidRewriter;
import com.velocitypowered.proxy.protocol.packet.uuidrewrite.UrSpawnEntityS2CPacket;
import com.velocitypowered.proxy.protocol.packet.uuidrewrite.UrSpawnPlayerS2CPacket;
import com.velocitypowered.proxy.protocol.util.PluginMessageUtil;
import com.velocitypowered.proxy.tablist.TabListUuidRewriter;
import io.netty.buffer.ByteBuf;
Expand Down Expand Up @@ -322,31 +325,45 @@ public boolean handle(TabCompleteResponsePacket packet) {

@Override
public boolean handle(LegacyPlayerListItemPacket packet) {
// [fallen's fork] tab list entry uuid rewrite: impl
TabListUuidRewriter.rewrite(serverConn.getPlayer(), packet);
// [fallen's fork] player uuid rewrite - tab list entry: impl
TabListUuidRewriter.rewrite(server, packet);

serverConn.getPlayer().getTabList().processLegacy(packet);
return false;
}

@Override
public boolean handle(UpsertPlayerInfoPacket packet) {
// [fallen's fork] tab list entry uuid rewrite: impl
TabListUuidRewriter.rewrite(serverConn.getPlayer(), packet);
// [fallen's fork] player uuid rewrite - tab list entry: impl
TabListUuidRewriter.rewrite(server, packet);

serverConn.getPlayer().getTabList().processUpdate(packet);
return false;
}

@Override
public boolean handle(RemovePlayerInfoPacket packet) {
// [fallen's fork] tab list entry uuid rewrite: impl
TabListUuidRewriter.rewrite(serverConn.getPlayer(), packet);
// [fallen's fork] player uuid rewrite - tab list entry: impl
TabListUuidRewriter.rewrite(server, packet);

serverConn.getPlayer().getTabList().processRemove(packet);
return false;
}

// [fallen's fork] player uuid rewrite - entity packet
@Override
public boolean handle(UrSpawnPlayerS2CPacket packet) {
EntityPacketUuidRewriter.rewriteS2C(server, serverConn.getPlayer(), packet);
return false;
}

@Override
public boolean handle(UrSpawnEntityS2CPacket packet) {
EntityPacketUuidRewriter.rewriteS2C(server, serverConn.getPlayer(), packet);
return false;
}
// [fallen's fork] ends

@Override
public boolean handle(AvailableCommandsPacket commands) {
RootCommandNode<CommandSource> rootNode = commands.getRootNode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@
import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerCommandPacket;
import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdatePacket;
import com.velocitypowered.proxy.protocol.packet.title.GenericTitlePacket;
import com.velocitypowered.proxy.protocol.packet.uuidrewrite.EntityPacketUuidRewriter;
import com.velocitypowered.proxy.protocol.packet.uuidrewrite.UrSpectatorTeleportC2SPacket;
import com.velocitypowered.proxy.protocol.util.PluginMessageUtil;
import com.velocitypowered.proxy.util.CharacterUtil;
import io.netty.buffer.ByteBuf;
Expand Down Expand Up @@ -402,6 +404,14 @@ public boolean handle(ResourcePackResponsePacket packet) {
packet.getStatus()));
}

// [fallen's fork] player uuid rewrite - entity packet
@Override
public boolean handle(UrSpectatorTeleportC2SPacket packet) {
EntityPacketUuidRewriter.rewriteC2S(server, player, packet);
return false;
}
// [fallen's fork] ends

@Override
public boolean handle(FinishedUpdatePacket packet) {
// Complete client switch
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
private final ChatQueue chatQueue;
private final ChatBuilderFactory chatBuilderFactory;

// [fallen's fork] tab list entry uuid rewrite: store offline uuid for reuse
// [fallen's fork] player uuid rewrite: store offline uuid for reuse
private final UUID offlineUuid;

ConnectedPlayer(VelocityServer server, GameProfile profile, MinecraftConnection connection,
Expand All @@ -214,7 +214,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
this.chatBuilderFactory = new ChatBuilderFactory(this.getProtocolVersion());
this.resourcePackHandler = ResourcePackHandler.create(this, server);

// [fallen's fork] tab list entry uuid rewrite: store offline uuid for reuse
// [fallen's fork] player uuid rewrite: store offline uuid for reuse
this.offlineUuid = UuidUtils.generateOfflinePlayerUuid(this.getUsername());
}

Expand Down Expand Up @@ -267,7 +267,8 @@ public UUID getUniqueId() {
return profile.getId();
}

// [fallen's fork] tab list entry uuid rewrite: store offline uuid for reuse
// [fallen's fork] player uuid rewrite: store offline uuid for reuse
@Override
public UUID getOfflineUuid() {
return offlineUuid;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@
import com.velocitypowered.proxy.protocol.packet.title.TitleSubtitlePacket;
import com.velocitypowered.proxy.protocol.packet.title.TitleTextPacket;
import com.velocitypowered.proxy.protocol.packet.title.TitleTimesPacket;
import com.velocitypowered.proxy.protocol.packet.uuidrewrite.UrSpawnEntityS2CPacket;
import com.velocitypowered.proxy.protocol.packet.uuidrewrite.UrSpawnPlayerS2CPacket;
import com.velocitypowered.proxy.protocol.packet.uuidrewrite.UrSpectatorTeleportC2SPacket;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import io.netty.util.collection.IntObjectHashMap;
import io.netty.util.collection.IntObjectMap;
Expand Down Expand Up @@ -670,6 +673,30 @@ public enum StateRegistry {
map(0x7A, MINECRAFT_1_21, false));
clientbound.register(ClientboundServerLinksPacket.class, ClientboundServerLinksPacket::new,
map(0x7B, MINECRAFT_1_21, false));

// [fallen's fork] player uuid rewrite - entity packet
clientbound.register(UrSpawnPlayerS2CPacket.class, UrSpawnPlayerS2CPacket::new,
map(0x05, MINECRAFT_1_8, false),
map(0x04, MINECRAFT_1_16, false),
map(0x02, MINECRAFT_1_19, false),
map(0x03, MINECRAFT_1_19_4, false),
map(-1, MINECRAFT_1_20_2, false));
clientbound.register(UrSpawnEntityS2CPacket.class, UrSpawnEntityS2CPacket::new,
map(0x01, MINECRAFT_1_20_2, false));
serverbound.register(UrSpectatorTeleportC2SPacket.class, UrSpectatorTeleportC2SPacket::new,
map(0x18, MINECRAFT_1_8, false),
map(0x1B, MINECRAFT_1_9, false),
map(0x1E, MINECRAFT_1_12, false),
map(0x28, MINECRAFT_1_13, false),
map(0x2B, MINECRAFT_1_14, false),
map(0x2C, MINECRAFT_1_16, false),
map(0x2D, MINECRAFT_1_16_2, false),
map(0x2F, MINECRAFT_1_19, false),
map(0x30, MINECRAFT_1_19_1, false),
map(0x33, MINECRAFT_1_20_2, false),
map(0x34, MINECRAFT_1_20_3, false),
map(0x37, MINECRAFT_1_20_5, false));
// [fallen's fork] ends
}
},
LOGIN {
Expand Down Expand Up @@ -804,6 +831,11 @@ <P extends MinecraftPacket> void register(Class<P> clazz, Supplier<P> packetSupp
"Next mapping version (%s) should be lower then current (%s)", to, from));
}

// [fallen's fork] support skipping id=-1
if (current.id == -1) {
break;
}

for (ProtocolVersion protocol : EnumSet.range(from, to)) {
if (protocol == to && next != current) {
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright (C) 2024 Velocity Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.velocitypowered.proxy.protocol.packet.uuidrewrite;

import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.config.PlayerInfoForwarding;

import java.util.UUID;
import java.util.function.Function;

public class EntityPacketUuidRewriter {

public static void rewriteS2C(VelocityServer server, Player connectionPlayer, PacketToRewriteEntityUuid packet) {
rewrite(server, connectionPlayer, packet, Player::getOfflineUuid, Player::getUniqueId);
}

public static void rewriteC2S(VelocityServer server, Player connectionPlayer, PacketToRewriteEntityUuid packet) {
rewrite(server, connectionPlayer, packet, Player::getUniqueId, Player::getOfflineUuid);
}

private static void rewrite(VelocityServer server, Player connectionPlayer, PacketToRewriteEntityUuid packet,
Function<Player, UUID> uuidFrom, Function<Player, UUID> uuidTo) {
var config = server.getConfiguration();
if (!(config.isOnlineMode() && config.getPlayerInfoForwardingMode() == PlayerInfoForwarding.NONE)) {
return;
}
if (!packet.isPlayer()) {
return;
}
UUID uuid = packet.getEntityUuid();
if (uuid == null) {
return;
}

// FIXME: inefficient implementation using for loop. Replace it with map lookup?
for (Player player : server.getAllPlayers()) {
if (uuidFrom.apply(player).equals(uuid)) {
UUID newUuid = uuidTo.apply(player);
if (!newUuid.equals(uuid)) {
packet.setEntityUuid(newUuid);
}
break;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2024 Velocity Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.velocitypowered.proxy.protocol.packet.uuidrewrite;

import java.util.UUID;

public interface PacketToRewriteEntityUuid {

boolean isPlayer();

UUID getEntityUuid();

void setEntityUuid(UUID entityUuid);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright (C) 2024 Velocity Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.velocitypowered.proxy.protocol.packet.uuidrewrite;

import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import io.netty.buffer.ByteBuf;

import java.util.UUID;

// [fallen's fork] player uuid rewrite - entity packet
public class UrSpawnEntityS2CPacket implements MinecraftPacket, PacketToRewriteEntityUuid {

private int entityId;
private UUID entityUuid;
private int entityType;
private byte[] remainingBuf;

@Override
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
this.entityId = ProtocolUtils.readVarInt(buf);
this.entityUuid = ProtocolUtils.readUuid(buf);
this.entityType = ProtocolUtils.readVarInt(buf);
this.remainingBuf = new byte[buf.readableBytes()];
buf.readBytes(this.remainingBuf);
}

@Override
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
ProtocolUtils.writeVarInt(buf, this.entityId);
ProtocolUtils.writeUuid(buf, this.entityUuid);
ProtocolUtils.writeVarInt(buf, this.entityType);
buf.writeBytes(this.remainingBuf);
}

@Override
public boolean handle(MinecraftSessionHandler handler) {
return handler.handle(this);
}

@Override
public boolean isPlayer() {
// https://wiki.vg/Entity_metadata#Mobs
int playerEntityType = 122; // mc1.20.2
return this.entityType == playerEntityType;
}

@Override
public UUID getEntityUuid() {
return this.entityUuid;
}

@Override
public void setEntityUuid(UUID entityUuid) {
this.entityUuid = entityUuid;
}
}
Loading

0 comments on commit ef2e4e8

Please sign in to comment.