import { createWriter, Endian } from "bufferstuff"; import { FunkyArray } from "../funkyArray"; import { MetadataFieldType } from "./enums/MetadataFieldType"; export class MetadataEntry { public type:MetadataFieldType; public value:number|string; public constructor(type:MetadataFieldType, value:number|string) { this.type = type; this.value = value; } } export class MetadataWriter { // https://wiki.vg/index.php?title=Protocol&oldid=488#Entity_Metadata_.280x28.29 private entries:FunkyArray; // TODO: Extend with Item and Vector types public constructor() { this.entries = new FunkyArray(); } public addMetadataEntry(identifier:number, entry:MetadataEntry) { this.entries.set(identifier, entry); } private calculateBufferSize() { let size = this.entries.length + 1; // Type/Identifiers + Stream end magic this.entries.forEach(entry => { switch (entry.type) { case MetadataFieldType.Byte: size += 1; break; case MetadataFieldType.Short: size += 2; break; case MetadataFieldType.Int: size += 4; break; case MetadataFieldType.Float: size += 4; break; case MetadataFieldType.String: if (typeof(entry.value) === "string") { size += 2 + entry.value.length * 2; break; } else { throw "Non-string value assigned to a String MetadataEntry"; } } }) return size; } public writeBuffer() { const writer = createWriter(Endian.BE, this.calculateBufferSize()); for (const key of this.entries.keys) { const entry = this.entries.get(key); if (entry instanceof MetadataEntry) { writer.writeByte((entry.type << 5 | key & 0x1f) & 0xff); if (typeof(entry.value) === "number") { switch (entry.type) { case MetadataFieldType.Byte: writer.writeByte(entry.value); break; case MetadataFieldType.Short: writer.writeShort(entry.value); break; case MetadataFieldType.Int: writer.writeInt(entry.value); break; case MetadataFieldType.Float: writer.writeFloat(entry.value); break; } } else if (typeof(entry.value) === "string") { writer.writeString16(entry.value); } } } // Metadata end magic writer.writeByte(0x7F); return writer.toBuffer(); } }