diff --git a/prismarine-viewer/viewer/lib/entities.ts b/prismarine-viewer/viewer/lib/entities.ts index efc80b5d..5e7a96bf 100644 --- a/prismarine-viewer/viewer/lib/entities.ts +++ b/prismarine-viewer/viewer/lib/entities.ts @@ -276,8 +276,20 @@ export class Entities extends EventEmitter { // fixme workaround defaultSteveTexture + usernamePerSkinUrlsCache = {} as Record + // true means use default skin url updatePlayerSkin (entityId: string | number, username: string | undefined, skinUrl: string | true, capeUrl: string | true | undefined = undefined) { + if (username) { + if (typeof skinUrl === 'string' || typeof capeUrl === 'string') this.usernamePerSkinUrlsCache[username] = {} + if (typeof skinUrl === 'string') this.usernamePerSkinUrlsCache[username].skinUrl = skinUrl + if (typeof capeUrl === 'string') this.usernamePerSkinUrlsCache[username].capeUrl = capeUrl + if (skinUrl === true) { + skinUrl = this.usernamePerSkinUrlsCache[username]?.skinUrl ?? skinUrl + } + capeUrl ??= this.usernamePerSkinUrlsCache[username]?.capeUrl + } + let playerObject = this.getPlayerObject(entityId) if (!playerObject) return // const username = this.entities[entityId].username diff --git a/src/entities.ts b/src/entities.ts index 26641f5a..4e3a73fb 100644 --- a/src/entities.ts +++ b/src/entities.ts @@ -153,4 +153,32 @@ customEvents.on('gameLoaded', () => { watchValue(options, o => { viewer.entities.setDebugMode(o.showChunkBorders ? 'basic' : 'none') }) + + // Texture override from packet properties + bot._client.on('player_info', (packet) => { + for (const player of packet.data) { + const textureProperty = player.properties?.find(prop => prop.name === 'textures') + if (textureProperty) { + try { + const textureData = JSON.parse(Buffer.from(textureProperty.value, 'base64').toString()) + const skinUrl = textureData.textures?.SKIN?.url + const capeUrl = textureData.textures?.CAPE?.url + + // Find entity with matching UUID and update skin + let entityId = '' + for (const [entId, entity] of Object.entries(bot.entities)) { + if (entity.uuid === player.UUID) { + entityId = entId + break + } + } + // even if not found, still record to cache + viewer.entities.updatePlayerSkin(entityId, player.name, skinUrl, capeUrl) + } catch (err) { + console.error('Error decoding player texture:', err) + } + } + } + + }) }) diff --git a/src/generatedServerPackets.ts b/src/generatedServerPackets.ts index 1c7ffa9e..3b3ce018 100644 --- a/src/generatedServerPackets.ts +++ b/src/generatedServerPackets.ts @@ -6,14 +6,7 @@ export interface ClientOnMap { } | /** 1.12.2 */ { keepAliveId: bigint; }; - login: /** 1.7 */ { - entityId: number; - gameMode: number; - dimension: number; - difficulty: number; - maxPlayers: number; - levelType: string; - } | /** 1.8 */ { + login:/** 1.8 */ { entityId: number; gameMode: number; dimension: number; @@ -148,9 +141,7 @@ export interface ClientOnMap { entityId: number; equipments: any; }; - spawn_position: /** 1.7 */ { - location: any; - } | /** 1.8 */ { + spawn_position:/** 1.8 */ { location: { x: number, y: number, z: number }; } | /** 1.17 */ { location: { x: number, y: number, z: number }; @@ -215,14 +206,7 @@ export interface ClientOnMap { death: any; portalCooldown: number; }; - position: /** 1.7 */ { - x: number; - y: number; - z: number; - yaw: number; - pitch: number; - onGround: boolean; - } | /** 1.8 */ { + position: /** 1.8 */ { x: number; y: number; z: number; @@ -905,11 +889,7 @@ export interface ClientOnMap { statistics: /** 1.7 */ { entries: any; }; - player_info: /** 1.7 */ { - playerName: string; - online: boolean; - ping: number; - } | /** 1.8 */ { + player_info: /** 1.8 */ { action: number; data: any; }; @@ -926,22 +906,13 @@ export interface ClientOnMap { length: number; matches: any; }; - scoreboard_objective: /** 1.7 */ { - name: string; - displayText: string; - action: number; - } | /** 1.8 */ { + scoreboard_objective:/** 1.8 */ { name: string; action: number; displayText: any; type: any; }; - scoreboard_score: /** 1.7 */ { - itemName: string; - action: number; - scoreName: any; - value: any; - } | /** 1.8 */ { + scoreboard_score:/** 1.8 */ { itemName: string; action: number; scoreName: string;