You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Spigot 1.21.1中刷新玩家以更换皮肤?

解决1.21.1 Spigot服务器更换玩家皮肤的问题

你的问题出在数据包发送逻辑上:仅发送移除和添加玩家列表的数据包不足以让客户端刷新皮肤,且玩家信息更新的动作类型错误,导致皮肤未被重新加载。以下是修正方案:

核心问题分析

  1. ClientboundPlayerInfoRemovePacket会将玩家从客户端列表移除,而Action.ADD_PLAYER仅适用于添加新玩家,无法更新已有玩家的皮肤信息。
  2. 仅修改GameProfile的纹理属性后,客户端不会自动重新渲染玩家实体,必须触发实体的重新生成逻辑。

修正后的代码

@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) {
    String playerName = sender.getName();
    if (!(sender.hasPermission("northmclobbyutils.duckify")) && sender instanceof Player) {
        sender.sendMessage("§cYou do not have permission to use this command!");
        return true;
    }
    if (!(sender instanceof Player)) {
        playerName = "Console";
    }

    for (Player p : sender.getServer().getOnlinePlayers()) {
        CraftPlayer cp = (CraftPlayer) p;
        ServerPlayer sp = cp.getHandle();
        
        // 修改显示名称与GameProfile纹理
        sp.setCustomName(Component.literal("§6Duck"));
        PropertyMap pm = sp.getGameProfile().getProperties();
        pm.removeAll("textures");
        pm.put("textures", new Property("textures", 
            "ewogICJ0aW1lc3RhbXAiIDogMTczMTIxMzc0NTk1NywKICAicHJvZmlsZUlkIiA6ICI1OWJlOTUyY2EyNjc0OWE4OTM1YmQ5MGQxNmMyN2M4OCIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaGVQZW5zcGlubmV1ciIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS80MTlkNTQ3NTk3YTQ2NmM0MWY1YmI3YjE0Y2MyMTZmMTk2ZDNhZjI0YjJhYWQ3MWZjMjlkNWE4ZTlkY2RiZmY5IgogICAgfQogIH0KfQ==", 
            "D8GnL/k1kpQCuals0OqfQSGIqdUZA3akLfSH2UZpwIDfXGn6A3BQmMzpaMw63JxITiZOWruMkzbUtbLreP421kzvNKikkgmXVDIOpyLLc+WYfT+O2eZLAMKnf4/f/cWlnl05FDXeJqIpRyx9b463Uh9xam2zuqr5rHq9t0+/1DOnfew/sDEkJWjNUkUooaJBV+raAHTYmnWlEXCItmfkNJtfBVYN+OVE9w7aSJpC8rkC3bAtkdKFxMmzTuN93pIZBqUzVMwf68e7jAdGMaWiDKl6wptDm304dl2iwuDJeYWDdmKD01KdHZIva1HI/DiPEUTSoPaR7GF055mOp14/08kAkHJA63hQyH/6RE9J1YOolMjho9qlznZbSmjU1yIM7X8vPNuLDcCh0S1OjbraNFrtruzi1vY8nxViPMRVuulUWDtFftF3esQ52M4CsGmeZ8VP786zFc88c+SrezzALgI9TrFklQKl/oZZud8WfjCUnFal2MYdZSqXaMWoYw9QBss1AJABqaLFglVwRckcRVna48J35uFm9kI4aWZVx6WYOKgxqlSKQ1EbKnvVSSfxbZZeHS3u9+2jsIBFpishaFpOtdOKuGM0X6Dx8e+Q4ur4cmT5UV5Q1rLFJhEzxC+Turo2luu3xc63vGn9hUYjj2pCn5DM9vwHKnz6Ef49o1Q="));
        
        // 1. 发送玩家信息更新包,同步Profile(含皮肤)与显示名称
        sp.connection.send(new ClientboundPlayerInfoUpdatePacket(
            EnumSet.of(Action.UPDATE_PROFILE, Action.UPDATE_DISPLAY_NAME),
            sp
        ));
        
        // 2. 移除并重新生成玩家实体,触发客户端加载新皮肤
        sp.connection.send(new ClientboundRemoveEntitiesPacket(sp.getId()));
        sp.connection.send(new ClientboundAddPlayerPacket(sp));
        
        // 3. 发送位置与旋转包,避免玩家实体位置偏移
        sp.connection.send(new ClientboundMoveEntityPosPacket(sp.getId(), 
            (short) (sp.getX() * 4096), 
            (short) (sp.getY() * 4096), 
            (short) (sp.getZ() * 4096), 
            true
        ));
        sp.connection.send(new ClientboundMoveEntityRotPacket(sp.getId(), 
            (byte) ((sp.getYRot() * 256) / 360), 
            (byte) ((sp.getXRot() * 256) / 360), 
            true
        ));
    }
    
    sender.sendMessage("§aAll players have been duckified!");
    return true;
}

关键修正点

  • 使用EnumSet.of(Action.UPDATE_PROFILE, Action.UPDATE_DISPLAY_NAME)作为更新动作,让客户端同步玩家的GameProfile(含皮肤纹理)和显示名称,替代原有的移除后重新添加逻辑。
  • 发送ClientboundRemoveEntitiesPacket和ClientboundAddPlayerPacket:强制客户端先移除原实体,再加载更新后的实体,确保新皮肤被读取。
  • 补充位置与旋转数据包,防止玩家在客户端出现位置偏移问题。

额外注意事项

  • 若保留updatePlayerSkin方法,需确保它不会覆盖或重置GameProfile的纹理属性。
  • 玩家自身视角的皮肤更新可能需要额外发送ClientboundRespawnPacket,但上述代码已满足其他玩家看到更新后皮肤的需求。

内容的提问来源于stack exchange,提问作者Polarbaer007

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 08:59:51