import Color from "color"; import { encrypt } from "@3t/romulus"; import { DEFAULT_KEY, MessageTypes } from "../common"; import { numberToUint16BE } from "../utilities/number"; import { SmartBuffer } from "../utilities/smart-buffer"; import { packOutgoingPacket } from "./packet"; const MESSAGE_TYPE = numberToUint16BE(MessageTypes.UserDataRequest); export interface UserDataRequestMessage { username: string; colour: Color; clientId: string; } /** * Create an outgoing user data request (0x0002) packet. * @param properties The properties for the message. * @param key The key to encrypt the data with. * @returns An outgoing user data request (0x0002) packet. */ export function packUserDataRequestMessage( properties: UserDataRequestMessage, key: Uint8Array = DEFAULT_KEY, ): Uint8Array { const encoder = new TextEncoder(); // Prepare data in correct format. const username = encoder.encode(properties.username); const usernameLength = numberToUint16BE(username.length); const colour = new Uint8Array(properties.colour.array()); const clientId = encoder.encode(properties.clientId); const clientIdLength = numberToUint16BE(clientId.length); // Pack data. const packedData = new SmartBuffer(); packedData.writeBytes(usernameLength); packedData.writeBytes(username); packedData.pad(32 - username.length); packedData.writeBytes(colour); packedData.writeBytes(clientIdLength); packedData.writeBytes(clientId); packedData.pad(32 - clientId.length); // Encrypt the data. const data = encrypt(packedData.data, MESSAGE_TYPE, key); return packOutgoingPacket({ messageType: MESSAGE_TYPE, data: data, }); } /** * Unpack the decrypted data section of an incoming user data request (0x0002) message. * @param data The decrypted data section of an incoming user data request (0x0002) message. * @returns An unpacked user data request (0x0002) message. */ export function unpackUserDataRequestMessage( data: Uint8Array, ): UserDataRequestMessage { // Unpack and read data in correct format. const packedData = SmartBuffer.from(Array.from(data)); const usernameLength = packedData.readUInt16(); const username = packedData.readBytes(usernameLength); packedData.cursor = 34; const colour = packedData.readBytes(3); const clientIdLength = packedData.readUInt16(); const clientId = packedData.readBytes(clientIdLength); const decoder = new TextDecoder(); // Return data in correct format. return { username: decoder.decode(username), colour: Color.rgb(colour), clientId: decoder.decode(clientId), }; }