Lib39/common/src/main/java/top/r3944realms/lib39/util/GameProfileHelper.java

342 lines
11 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package top.r3944realms.lib39.util;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.PlayerInfo;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.resources.DefaultPlayerSkin;
import net.minecraft.core.component.DataComponents;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.ResolvableProfile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.util.nbt.NBTReader;
import top.r3944realms.lib39.util.nbt.NBTWriter;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Collection;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
/**
* The type GameProfile helper.
*/
public class GameProfileHelper {
/**
* Client Only Class
*/
public static class ClientOpt implements IClientOnly {
/**
* Resolve skin texture resource location.
*
* @param gameProfile the game profile
* @return the resource location
*/
public static @NotNull ResourceLocation resolveSkinTexture(@NotNull GameProfile gameProfile) {
return IClientOnly.check(() ->
Minecraft.getInstance().getSkinManager()
.getInsecureSkin(gameProfile)).texture();
}
/**
* Gets skin texture.
*
* @param gameProfile the game profile
* @return the skin texture
*/
public static ResourceLocation getSkinTexture(@Nullable GameProfile gameProfile) {
return IClientOnly.check(() -> {
if (gameProfile == null) {
return Lib39.mrl("textures/entity/player/wide/steve.png");
}
return resolveSkinTexture(gameProfile);
});
}
/**
* Has slim arms client boolean.
*
* @param player the player
* @return the boolean
*/
public static boolean hasSlimArmsClient(Player player) {
return IClientOnly.check(() -> {
if (player instanceof AbstractClientPlayer clientPlayer) {
PlayerInfo playerInfo = Objects.requireNonNull(Minecraft.getInstance()
.getConnection())
.getPlayerInfo(clientPlayer.getUUID());
return playerInfo != null && "slim".equals(playerInfo.getSkin().model().id());
}
return false;
});
}
/**
* Gets skin model name.
*
* @param player the player
* @return the skin model name
*/
public static @NotNull String getSkinModelName(@NotNull Player player) {
return IClientOnly.check(() -> {
if (player.level().isClientSide && player instanceof AbstractClientPlayer) {
PlayerInfo info = Objects.requireNonNull(Minecraft.getInstance().getConnection())
.getPlayerInfo(player.getUUID());
return info != null ? info.getSkin().model().id() : "default";
}
return "default";
});
}
}
/**
* The constant TAG_OWN_PROFILE.
*/
public static final String TAG_OWN_PROFILE = "OwnerProfile";
/**
* Gets skin texture.
*
* @param gameProfile the game profile
* @return the skin texture
*/
public static ResourceLocation getSkinTexture(@Nullable GameProfile gameProfile) {
return ClientOpt.getSkinTexture(gameProfile);
}
/**
* Resolve skin texture resource location.
*
* @param gameProfile the game profile
* @return the resource location
*/
public static @NotNull ResourceLocation resolveSkinTexture(@NotNull GameProfile gameProfile) {
return ClientOpt.resolveSkinTexture(gameProfile);
}
/**
* Has slim arms boolean.
*
* @param player the player
* @return the boolean
*/
public static boolean hasSlimArms(@NotNull Player player) {
if (player.level().isClientSide) {
return hasSlimArmsClient(player);
} else {
return hasSlimArmsServer(player);
}
}
private static boolean hasSlimArmsClient(Player player) {
return ClientOpt.hasSlimArmsClient(player);
}
// 服务器端判断
private static boolean hasSlimArmsServer(@NotNull Player player) {
GameProfile profile = player.getGameProfile();
for (Property property : profile.getProperties().get("textures")) {
try {
String json = new String(Base64.getDecoder().decode(property.value()));
JsonObject obj = JsonParser.parseString(json).getAsJsonObject();
JsonObject textures = obj.getAsJsonObject("textures");
JsonObject skin = textures.getAsJsonObject("SKIN");
if (skin.has("metadata")) {
JsonObject metadata = skin.getAsJsonObject("metadata");
if (metadata.has("model")) {
return "slim".equals(metadata.get("model").getAsString());
}
}
} catch (Exception e) {
// 解析失败,使用默认
}
}
return false;
}
/**
* Gets skin model name.
*
* @param player the player
* @return the skin model name
*/
public static @NotNull String getSkinModelName(@NotNull Player player) {
return ClientOpt.getSkinModelName(player);
}
/**
* 判断玩家是否为纤细手臂Alex模型
*
* @param profile 玩家的GameProfile
* @return true =纤细手臂false=正常手臂
*/
public static boolean isSlimArms(GameProfile profile) {
if (profile == null) {
return false;
}
// 获取textures属性
Collection<Property> textures = profile.getProperties().get("textures");
if (textures.isEmpty()) {
return false; // 没有皮肤数据,使用默认
}
// 获取第一个texture属性通常是皮肤
Property textureProperty = textures.iterator().next();
String value = textureProperty.value();
try {
return isSlimFromTextureData(value);
} catch (Exception e) {
// 解析失败,使用默认
return false;
}
}
/**
* 从Base64编码的皮肤数据判断
* @param encodedTexture Base64编码的皮肤数据
* @return true=纤细手臂
*/
private static boolean isSlimFromTextureData(String encodedTexture) {
if (encodedTexture == null || encodedTexture.isEmpty()) {
return false;
}
try {
// 1. Base64解码
byte[] decodedBytes = Base64.getDecoder().decode(encodedTexture);
String jsonString = new String(decodedBytes, StandardCharsets.UTF_8);
// 2. 解析JSON
JsonObject root = JsonParser.parseString(jsonString).getAsJsonObject();
// 3. 导航到textures -> SKIN
JsonObject textures = root.getAsJsonObject("textures");
if (textures == null) {
return false;
}
JsonObject skin = textures.getAsJsonObject("SKIN");
if (skin == null) {
return false;
}
// 4. 检查metadata -> model
JsonObject metadata = skin.getAsJsonObject("metadata");
if (metadata == null) {
return false; // 没有metadata使用默认
}
String model = metadata.get("model").getAsString();
return "slim".equals(model);
} catch (Exception e) {
// 解析过程中出现任何错误,返回默认值
return false;
}
}
/**
* 获取皮肤模型名称
*
* @param profile GameProfile
* @return "slim" 或 "default"
*/
public static String getSkinModelName(GameProfile profile) {
if (profile == null) {
return "default";
}
Collection<Property> textures = profile.getProperties().get("textures");
if (textures.isEmpty()) {
return "default";
}
Property textureProperty = textures.iterator().next();
String value = textureProperty.value();
try {
byte[] decodedBytes = Base64.getDecoder().decode(value);
String jsonString = new String(decodedBytes, StandardCharsets.UTF_8);
JsonObject root = JsonParser.parseString(jsonString).getAsJsonObject();
JsonObject texturesObj = root.getAsJsonObject("textures");
JsonObject skin = texturesObj.getAsJsonObject("SKIN");
if (skin.has("metadata")) {
JsonObject metadata = skin.getAsJsonObject("metadata");
if (metadata.has("model")) {
return metadata.get("model").getAsString();
}
}
} catch (Exception e) {
// 忽略错误
}
return "default";
}
/**
* 从ItemStack的组件中读取GameProfile
*
* @param stack the stack
* @return the profile from item stack
*/
@Nullable
public static GameProfile getProfileFromItemStack(ItemStack stack) {
if (stack.isEmpty()) {
return null;
}
if (stack.isEmpty()) return null;
ResolvableProfile profile = stack.get(DataComponents.PROFILE);
return profile != null ? profile.gameProfile() : null;
}
/**
* 将GameProfile保存到ItemStack的组件
*
* @param stack the stack
* @param profile the profile
*/
public static void saveProfileToItemStack(@NotNull ItemStack stack, @Nullable GameProfile profile) {
if (stack.isEmpty()) return;
if (profile == null) {
stack.remove(DataComponents.PROFILE);
} else {
stack.set(DataComponents.PROFILE, new ResolvableProfile(profile));
}
}
/**
* 检查ItemStack是否有保存的皮肤数据
*
* @param stack the stack
* @return the boolean
*/
public static boolean hasProfileData(@NotNull ItemStack stack) {
if (stack.isEmpty()) {
return false;
}
return !stack.isEmpty() && stack.has(DataComponents.PROFILE);
}
}