1
0
mirror of https://github.com/GeyserMC/Geyser.git synced 2025-12-19 14:59:27 +00:00

Translate custom skull items if the profile is resolved

This commit is contained in:
Eclipse
2025-09-24 07:07:33 +00:00
parent 1df98f961a
commit 19665f5836
3 changed files with 33 additions and 25 deletions

View File

@@ -31,7 +31,6 @@ import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.protocol.bedrock.data.Ability;
import org.cloudburstmc.protocol.bedrock.data.AbilityLayer;
import org.cloudburstmc.protocol.bedrock.data.GameType;
@@ -180,8 +179,8 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity {
this.initializeMetadata();
// Explicitly reset all metadata not handled by initializeMetadata
setParrot(null, true);
setParrot(null, false);
setParrot(OptionalInt.empty(), true);
setParrot(OptionalInt.empty(), false);
}
public void sendPlayer() {

View File

@@ -30,9 +30,11 @@ import org.geysermc.geyser.item.TooltipOptions;
import org.geysermc.geyser.item.components.Rarity;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.skin.SkinManager;
import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
import org.geysermc.mcprotocollib.auth.GameProfile;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.ResolvableProfile;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
@@ -49,21 +51,25 @@ public class PlayerHeadItem extends BlockItem {
// Use the correct color, determined by the rarity of the item
char rarity = Rarity.fromId(components.getOrDefault(DataComponentTypes.RARITY, Rarity.COMMON.ordinal())).getColor();
// Ideally we'd resolve the profile here and show the resolved name if it's a dynamic profile
// but, resolving is done async, which isn't really possible here
// TODO FIXME 1.21.9? also see comment in ItemTranslator
ResolvableProfile profile = components.get(DataComponentTypes.PROFILE);
if (profile != null) {
String name = profile.getProfile().getName();
if (name != null) {
// Add correct name of player skull
String displayName = ChatColor.RESET + ChatColor.ESCAPE + rarity +
// Ideally we'd update the item once the profile is resolved,
// but there's no good way of doing this as we don't know where the item is in an inventory after we have translated it
// So, we request a resolve here, and if the profile has already been resolved it will be returned instantly from cache.
// If not, the next time the item will be translated the profile will probably have been resolved
GameProfile resolved = SkinManager.resolveProfile(profile).getNow(null);
if (resolved != null) {
String name = resolved.getName();
if (name != null) {
// Add correct name of player skull
String displayName = ChatColor.RESET + ChatColor.ESCAPE + rarity +
MinecraftLocale.getLocaleString("block.minecraft.player_head.named", session.locale()).replace("%s", name);
builder.setCustomName(displayName);
} else {
// No name found so default to "Player Head"
builder.setCustomName(ChatColor.RESET + ChatColor.ESCAPE + rarity +
builder.setCustomName(displayName);
} else {
// No name found so default to "Player Head"
builder.setCustomName(ChatColor.RESET + ChatColor.ESCAPE + rarity +
MinecraftLocale.getLocaleString("block.minecraft.player_head", session.locale()));
}
}
}
}

View File

@@ -38,6 +38,7 @@ import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.block.custom.CustomBlockData;
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
import org.geysermc.geyser.inventory.GeyserItemStack;
@@ -53,11 +54,13 @@ import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.type.CustomSkull;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.skin.SkinManager;
import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.InventoryUtils;
import org.geysermc.geyser.util.MinecraftKey;
import org.geysermc.mcprotocollib.auth.GameProfile;
import org.geysermc.mcprotocollib.protocol.data.game.entity.Effect;
import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeType;
import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.ModifierOperation;
@@ -625,32 +628,32 @@ public final class ItemTranslator {
return null;
}
// TODO FIXME 1.21.9 - maybe if dynamic first send vanilla player head, then once resolved resend the proper player head??
// TODO could also work with the head name (see PlayerHeadItem)
/*
Map<TextureType, Texture> textures;
// Ideally we'd update the item once the profile has been resolved, but this isn't really possible,
// also see comments in PlayerHeadItem for full explanation
GameProfile resolved = SkinManager.resolveProfile(profile).getNow(null);
if (resolved == null) {
return null;
}
Map<GameProfile.TextureType, GameProfile.Texture> textures;
try {
textures = profile.getTextures(false);
textures = resolved.getTextures(false);
} catch (IllegalStateException e) {
GeyserImpl.getInstance().getLogger().debug("Could not decode player head from profile %s, got: %s".formatted(profile, e.getMessage()));
GeyserImpl.getInstance().getLogger().debug("Could not decode player head from profile %s, got: %s".formatted(resolved, e.getMessage()));
return null;
}
if (textures == null || textures.isEmpty()) {
// TODO the java client looks up the texture properties here and updates the item
return null;
}
Texture skinTexture = textures.get(TextureType.SKIN);
GameProfile.Texture skinTexture = textures.get(GameProfile.TextureType.SKIN);
if (skinTexture == null) {
return null;
}
String skinHash = skinTexture.getURL().substring(skinTexture.getURL().lastIndexOf('/') + 1);
return BlockRegistries.CUSTOM_SKULLS.get(skinHash);
*/
return null;
}
private static void translatePlayerHead(GeyserSession session, ResolvableProfile profile, ItemData.Builder builder) {