const messages = require('./msg_template.json'); const path = require('path'); const fs = require('fs'); messages.forEach((message) => { let classString = '// This file has been automatically generated by writePacketClasses.js\n\n'; //First import required classes let uuid = false; let ipaddr = false; let vector3 = false; let vector4 = false; let long = false; let quaternion = false; message.blocks.forEach((block) => { block.params.forEach((param) => { switch(param.type) { case 'BOOL': case 'U32': case 'S32': case 'S8': case 'U8': case 'U16': case 'S16': case 'F32': case 'F64': case "IPPORT": case "Fixed": case 'Variable': break; case "LLVector3d": vector3 = true; break; case "LLVector3": vector3 = true; break; case "LLVector4": vector4 = true; break; case "LLQuaternion": quaternion = true; break; case "LLUUID": uuid = true; break; case "IPADDR": ipaddr = true; break; case "U64": long = true; break; default: console.log("UNKNOWN TYPE: "+param.type); } }); }); if (uuid) { classString += 'import {UUID} from \'../UUID\';\n' } if (ipaddr) { classString += 'import {IPAddress} from \'../IPAddress\';\n' } if (vector3) { classString += 'import {Vector3} from \'../Vector3\';\n' } if (vector4) { classString += 'import {Vector4} from \'../Vector4\';\n' } if (long) { classString += 'import Long = require(\'long\');\n' } if (quaternion) { classString += 'import {Quaternion} from \'../Quaternion\';\n' } classString += 'import {MessageFlags} from \'../../enums/MessageFlags\';\n' + 'import {Packet} from \'../Packet\';\n\n'; classString += 'export class ' + message.name + 'Packet implements Packet\n'; classString += '{\n'; classString += ' name = \''+message.name+'\';\n'; let flags = []; message.flags.forEach((flag) => { switch(flag.toUpperCase()) { case 'TRUSTED': flags.push('MessageFlags.Trusted'); break; case 'UDPDEPRECATED': case 'DEPRECATED': flags.push('MessageFlags.Deprecated'); break; case 'ZEROCODED': flags.push('MessageFlags.Zerocoded'); break; case 'UNENCODED': break; case 'NOTTRUSTED': break; case 'UDPBLACKLISTED': flags.push('MessageFlags.Blacklisted'); break; default: console.log("UNKNOWN FLAG: "+flag); break; } }); let id = parseInt(message.id); switch(message.frequency) { case 'Low': id += 4294901760; flags.push('MessageFlags.FrequencyLow'); break; case 'Medium': id += 65280; flags.push('MessageFlags.FrequencyMedium'); break; case 'Fixed': flags.push('MessageFlags.FrequencyFixed'); break; case 'High': flags.push('MessageFlags.FrequencyHigh'); break; default: console.log("UNKNOWN FREQUENCY: "+message.frequency); break; } classString += ' flags = ' + flags.join(' | ')+';\n'; classString += ' id = ' + id+';\n'; classString += '\n'; let messageFixedSize = 0; let messageVariableSize = []; let calcVarVar = false; message.blocks.forEach((block) => { classString += ' '+block.name+': {\n'; let blockFixedSize = 0; let blockVariableSize = []; block.params.forEach((param) => { classString += ' '+param.name+': '; let jstype = 'string'; switch(param.type) { case 'LLUUID': jstype = 'UUID'; blockFixedSize += 16; break; case 'F32': case 'S32': case 'U32': blockFixedSize += 4; jstype = 'number'; break; case 'IPPORT': case 'S16': case 'U16': blockFixedSize += 2; jstype = 'number'; break; case 'U64': case 'S64': jstype = 'Long'; blockFixedSize += 8; break; case 'F64': blockFixedSize += 8; jstype = 'number'; break; case 'S8': case 'U8': blockFixedSize += 1; jstype = 'number'; break; case 'BOOL': blockFixedSize += 1; jstype = 'boolean'; break; case 'Variable': jstype = 'string'; if (block.type === 'Single') { blockVariableSize.push('this.' + block.name + '[\'' + param.name + '\'].length + ' + param.size); } else { //Variable parameter in variable or multi block - tricky edge case blockVariableSize.push('this.calculateVarVarSize(this.'+block.name+', \''+param.name+'\', '+param.size+')') calcVarVar = true; } break; case 'LLVector4': blockFixedSize += 16; jstype = 'Vector4'; break; case 'LLQuaternion': // because it's always a unit quaternion, transmitted in messages as a triplet of floats, 12 bytes wide (represented in memory as a quad of floats, 16 bytes wide) blockFixedSize += 12; jstype = 'Quaternion'; break; case 'LLVector3d': blockFixedSize += 24; jstype = 'Vector3'; break; case 'LLVector3': blockFixedSize += 12; jstype = 'Vector3'; break; case 'IPADDR': blockFixedSize += 4; jstype = 'IPAddress'; break; case 'Fixed': blockFixedSize += parseInt(param.size); jstype = 'Buffer'; break; default: console.log('Unknown type: '+param.type); } classString += jstype + ';\n'; }); if (block.type === 'Single') { messageFixedSize += blockFixedSize; if (blockVariableSize.length > 0) { messageVariableSize.push('(' + blockVariableSize.join(' + ') + ')'); } } else if (block.type === 'Multiple') { messageFixedSize += blockFixedSize * block.count; if (blockVariableSize.length > 0) { messageVariableSize.push('((' + blockVariableSize.join(' + ') + ') * ' + block.count + ')'); } } else if (block.type === 'Variable') { messageFixedSize += 1; //variable block starts with a U8 if (blockFixedSize > 0) { blockVariableSize.push(blockFixedSize); } if (blockVariableSize.length > 0) { messageVariableSize.push('((' + blockVariableSize.join(' + ') + ') * this.' + block.name + '.length)'); } } switch(block.type) { case 'Single': classString += ' };\n'; break; case 'Variable': case 'Multiple': classString += ' }[];\n'; break; default: console.log("Unknown type: "+block.type); } }); classString+='\n'; classString+=' getSize(): number\n'; classString+=' {\n'; if (messageFixedSize > 0) { messageVariableSize.push(messageFixedSize); } if (messageVariableSize.length === 0) { classString += ' return 0;\n'; } else { classString += ' return ' + messageVariableSize.join(' + ') + ';\n'; } classString+=' }\n'; classString+='\n'; if (calcVarVar) { classString+=' calculateVarVarSize(block: object[], paramName: string, extraPerVar: number): number\n' + ' {\n' + ' let size = 0;\n' + ' block.forEach((bl: any) =>\n' + ' {\n' + ' size += bl[paramName].length + extraPerVar;\n' + ' });\n' + ' return size;\n' + ' }\n\n'; } classString += '}\n'; const p = path.join(__dirname+'/../lib/classes/packets/'+message.name+'.ts'); fs.writeFile(p, classString, (err) => { }); });