From 2e2969c551f7c34146c69a91554f629bd9949648 Mon Sep 17 00:00:00 2001 From: q13x Date: Tue, 20 Dec 2022 18:26:35 -0800 Subject: [PATCH] Skins actually work now --- eaglerPacketDef.ts | 28 +-------------------------- eaglerSkin.ts | 48 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 39 insertions(+), 37 deletions(-) diff --git a/eaglerPacketDef.ts b/eaglerPacketDef.ts index 69fbb36..519f001 100644 --- a/eaglerPacketDef.ts +++ b/eaglerPacketDef.ts @@ -8,8 +8,7 @@ export enum EaglerPacketId { SKIN = 0x07, C_READY = 0x08, COMPLETE_HANDSHAKE = 0x09, - DISCONNECT = 0xff, - CUSTOM_PLAYER_LIST_ADD_PACKET = 0x38 + DISCONNECT = 0xff } export enum DisconnectReason { @@ -40,31 +39,6 @@ export type SkinCustom = [EaglerPacketId.SKIN, number, string, number, PrefixedS export type ClientReady = [EaglerPacketId.C_READY] export type Joined = [EaglerPacketId.COMPLETE_HANDSHAKE] export type Disconnect = [EaglerPacketId.DISCONNECT, number, string, DisconnectReason] -export type PlayerList = [ - EaglerPacketId.CUSTOM_PLAYER_LIST_ADD_PACKET, - UUID, 0xD6, 0x91, 0x9F, 0xD2, - /* username */ number, string, number, // 2nd number in string is 0x02, probably number of strings? - number, string, // string in this is "textures" - number, typeof PlayerListJson1, // base64 encoded string (see PlayerListJson1 for json contents) - number, typeof PlayerListBase64Str, // base64 encoded string () - number, string, // string is isEaglerPlayer - number, string, // boolean - 0x00, 0x01, 0x00, 0x00 // 256 -] -export const PlayerListJson1 = { - timestamp: null, // UNIX, in MS - profileId: '65a4a3d370cb49bbad67f10086f1c543', - profileName: 'lax1dude', - signatureRequired: true, - textures: { - SKIN: { - url: 'http://textures.minecraft.net/texture/d46393de83fbe165ab680a1821aad9f07d08b8196b2429fa046a15b61b129dc4' - } - } -} -export const PlayerListBase64Str = "¬X1eTQrruDPy+qp5pBNo+zIoPXGdhJKkhtPPgKIcBzgBDcp/CXhbcZong7886HSQyA2YMDL+muRgY+GLri+QH0wF5yZC5S1Nm8GrPPMScrWsgZRtyIv/cZnIQUtRAS4SQroup3M42s3blUjGjTfkjWTy5xxuHGaiXpgI1wAjsONfJebNLe+v3DvO2/7sbmMSQTEduODhF8J1QL44aiL5mAZFV+4XMzRVrs3wsIScwPaCSXqLRudn2tLRC5fylejnq5S9AHz17bDlwyWmMeG5djusM3ZVjYKfu3Bi/vEhG9eEyWhBxcDKilrXJ1ZwOeotwgwnafY4OLc18fS7w1LxHkedZLs/8gHZOpUQHcx2Kxhib5BOdRDMae+AuDRbR9Lk33txzYNlOS6drxHkpEyRwFTu7RYTQUIE+0Dljk4mZDqnTSd5ZDwb45FfYvm25nEu2r5hPj/UNUCAPTToNTCABWvWWuigVjt8pvATV05KPlzTl6bWqrLn822upkC3joP+H+GVR8TkdkGzyyjDbndt1hTXW+zIuB2og2oMuHAO5kI6JtEl26wk7eNYmBr4va6UpiEXAhYa10nRny+Fu9gHCHgMCW7n50+gK3IOAzxLt0QkrlYXgJI6uh5f125g/yMe7v5y49VpHwDcPkYBLcX0L9lxJh8EQem6ff8SLjcAwmdU=" - -// Afterwards, forward 0x01 (Join Game, Clientbound) and everything after that // EAGLERCRAFT SKIN PROTOCOL // All Eaglercraft skin networking is done through plugin channels under the channel name EAG|Skins-1.8. diff --git a/eaglerSkin.ts b/eaglerSkin.ts index bbb2caa..de7bf3a 100644 --- a/eaglerSkin.ts +++ b/eaglerSkin.ts @@ -92,8 +92,9 @@ export function encodeSSkinDl(uuid: string | Buffer, skin: Buffer, isFetched: bo // eaglercraft clients always expect a 16385 byte long byte array for the skin if (!isFetched) skin = skin.length !== 16384 ? skin.length < 16384 ? Buffer.concat([Buffer.alloc(16384 - skin.length), skin]) : skin.subarray(16383) : skin else skin = skin.length !== 16384 ? skin.length < 16384 ? Buffer.concat([skin, Buffer.alloc(16384 - skin.length)]) : skin.subarray(16383) : skin - const skinLen = encodeVarInt(skin.length), buff = Buffer.alloc(1 + 16 + 1 + skin.length) - buff.set([EaglerSkinPacketId.S_SKIN_DL, ...uuid, 0xff,...skin]) + const buff = Buffer.alloc(1 + 16 + 1 + skin.length) + if (!isFetched) buff.set([EaglerSkinPacketId.S_SKIN_DL,...uuid, 0xff,...skin]) + else buff.set([EaglerSkinPacketId.S_SKIN_DL, ...uuid, 0x00, ...skin]) return buff } @@ -120,21 +121,48 @@ export function encodeCSkinReq(uuid: string | Buffer, url: string): Buffer { return buff } -// TODO: fix broken custom skins +const SEG_SIZE = 3 -export async function fetchSkin(url: string): Promise { +function invert(buff: Buffer): Buffer { + let buffers: Buffer[] = [], i = 0 + const newBuffer = Buffer.alloc(buff.length) + while (true) { + if (i >= buff.length) + break + newBuffer.set(buff.subarray(i, i + 4).reverse(), i) + i += 4 + } + return newBuffer +} + +async function genRGBAEagler(buff: Buffer): Promise { + const r = await sharp(buff).extractChannel('red').raw({ depth: 'uchar' }).toBuffer() + const g = await sharp(buff).extractChannel('green').raw({ depth: 'uchar' }).toBuffer() + const b = await sharp(buff).extractChannel('blue').raw({ depth: 'uchar' }).toBuffer() + const a = await sharp(buff).ensureAlpha().extractChannel(3).toColorspace('b-w').raw({ depth: 'uchar' }).toBuffer() + const newBuff = Buffer.alloc(64 ** 2 * 4) + for (let i = 1; i < 64 ** 2; i++) { + const bytePos = i * 4 + newBuff[bytePos] = a[i] + newBuff[bytePos + 1] = b[i] + newBuff[bytePos + 2] = g[i] + newBuff[bytePos + 3] = r[i] + } + return newBuff +} + +async function toEaglerSkin(buff: Buffer): Promise { + return genRGBAEagler(buff) +} + +export async function fetchSkin(url: string, process?: boolean): Promise { return new Promise((res, rej) => { let body = [] request({ url: url, encoding: null }, (err, response, body) => { if (err) { rej(err) } else { - sharp(body) - .resize(64, 64) - .raw({ depth: 'char' }) - .toBuffer() - .then(res) - .catch(rej) + toEaglerSkin(body).then(buff => res(buff)) } }) })