valence-rs/valence

Custom skins for NPC Player entities

dyc3 opened this issue · 8 comments

dyc3 commented

Describe the problem related to your feature request.

It's common to have custom NPCs on minigame servers with custom skins.

What solution would you like?

There should be an optional component that you can attach to a Player entity to change it's texture.

What alternative(s) have you considered?

None

Additional context

Apparently, this is possible in Bukkit by setting the textures property on GameProfile. I haven't found a good specific code example yet other than this forum post.

rj00a commented

The player list entry archetype uses the Properties component to hold the properties from the game profile. If you add textures to the player list entry for the fake player I think it should work.

The value of the textures property is a base64 blob of JSON. You can get some from MineSkin.org. You'll also need the signature.

It's worth testing if any of this is functioning correctly. Time for a new example?

dyc3 commented

A new example would be good, unless we can work it into another large example similar to parkour or ctf.

Bafbi commented

I'm not really fond of having examples for literally every little thing, I think we can just demonstrate it on an existing example that uses an entity and we could having a mapping of certain feature to certain example if someone search something

The player list entry archetype uses the Properties component to hold the properties from the game profile. If you add textures to the player list entry for the fake player I think it should work.

The value of the textures property is a base64 blob of JSON. You can get some from MineSkin.org. You'll also need the signature.

It's worth testing if any of this is functioning correctly. Time for a new example?

We can't access the GameProfile struct though

dyc3 commented

He's talking about this component:

pub struct Properties(pub Vec<Property>);
impl Properties {
/// Finds the property with the name "textures".
pub fn textures(&self) -> Option<&Property> {
self.0.iter().find(|prop| prop.name == "textures")
}
/// Finds the property with the name "textures".
pub fn textures_mut(&mut self) -> Option<&mut Property> {
self.0.iter_mut().find(|prop| prop.name == "textures")
}
}

dyc3 commented

I was able to get a custom skin on a player entity, but it's unclear to me where the signature comes from, and whether or not it's required.

In the base64, there's a field called signatureRequired that would imply you could make it optional, but setting it to false does not work.

{
  "timestamp" : 1691706573156,
  "profileId" : "e88274eb3f514d60bc1ad95481218303",
  "profileName" : "AnimalTheGamer",
  "signatureRequired" : true,
  "textures" : {
    "SKIN" : {
      "url" : "http://textures.minecraft.net/texture/1de2c83f8f4fb38069f55f52e4f8ee5f0867229ead91b7e79def754b70ea9433",
      "metadata" : {
        "model" : "slim"
      }
    }
  }
}
Bafbi commented

@dyc3 https://wiki.vg/Mojang_API#UUID_to_Profile_and_Skin.2FCape
It doesn't even seems to be the default to have it signed

dyc3 commented

From my experimenting, it appears that by default, the notchian Minecraft client always verifies the signatures of player skins. I think what mineskin.org is doing is requesting a skin change for some minecraft account, and then letting mojang sign the texture, and returning those values back to the end user. I think mojang will keep the skin in their CDNs even after another skin change? That part is somewhat unclear.