'use strict';
const OsuBuffer = require('osu-buffer');
class Writer {
/**
* @param {Buffer|OsuBuffer|undefined} input
*/
constructor(input) {
this.buffer = OsuBuffer.from((input instanceof Buffer || input instanceof OsuBuffer) ? input : []);
}
/**
* Writes a set of data to a buffer
* @param {Object} o
* @param {String} o.type
* @param {Object|Array|String|Number|Boolean|Null} o.data
* @param {Boolean?} o.nullable
* @return {Buffer}
*/
Write(o) {
let buff = new OsuBuffer();
switch (o.type) {
case 'int8':
buff.WriteInt8(o.data);
break;
case 'uint8':
buff.WriteUInt8(o.data);
break;
case 'int16':
buff.WriteInt16(o.data);
break;
case 'uint16':
buff.WriteUInt16(o.data);
break;
case 'int32':
buff.WriteInt32(o.data);
break;
case 'uint32':
buff.WriteUInt32(o.data);
break;
case 'int64':
buff.WriteInt64(o.data);
break;
case 'uint64':
buff.WriteUInt64(o.data);
break;
case 'string':
buff.WriteOsuString(o.data, o.nullable);
break;
case 'float':
buff.WriteFloat(o.data);
break;
case 'double':
buff.WriteDouble(o.data);
break;
case 'boolean':
buff.WriteBoolean(o.data);
break;
case 'byte':
buff.WriteByte(o.data);
break;
case 'int32array': {
buff.WriteInt16(o.data.length);
for (let i = 0; i < o.data.length; i++) {
buff.WriteInt32(o.data[i]);
}
break;
}
case 'replayframes': {
buff.WriteUInt16(o.data.length);
for (let i = 0; i < o.data.length; i++) {
buff.WriteByte(o.data[i].buttonState)
.WriteByte(o.data[i].bt)
.WriteFloat(o.data[i].mouseX)
.WriteFloat(o.data[i].mouseY)
.WriteInt32(o.data[i].time);
}
break;
}
case 'scoreframe':
buff.WriteInt32(o.data.time)
.WriteByte(o.data.id)
.WriteUInt16(o.data.count300)
.WriteUInt16(o.data.count100)
.WriteUInt16(o.data.count50)
.WriteUInt16(o.data.countGeki)
.WriteUInt16(o.data.countKatu)
.WriteUInt16(o.data.countMiss)
.WriteInt32(o.data.totalScore)
.WriteUInt16(o.data.maxCombo)
.WriteUInt16(o.data.currentCombo)
.WriteBoolean(o.data.perfect)
.WriteByte(o.data.currentHp)
.WriteByte(o.data.tagByte)
.WriteBoolean(o.data.usingScoreV2);
if (o.data.usingScoreV2) {
buff.WriteDouble(o.data.comboPortion)
.WriteDouble(o.data.bonusPortion);
}
break;
case 'multislots': {
for (let a = 0; a < 16; a++) {
buff.WriteByte(o[a].status);
}
for (let b = 0; b < 16; b++) {
buff.WriteByte(o[b].team);
}
for (let c = 0; c < 16; c++) {
if ((o[c].status & (4 | 8 | 16 | 32 | 64)) > 0) {
buff.WriteInt32(o[c].playerId);
}
}
break;
}
/*
* !!!!!!!!!!!!!!!!WARNING!!!!!!!!!!!!!!!!
* This is only for multiplayer stuff, will break anything if you use it elsewhere
*/
case 'multislotmods': {
if ((o['specialModes'] & 1) > 0) {
for (let i = 0; i < 16; i++) {
buff.WriteUInt32(o[item.name][i].mods);
}
}
break;
}
}
return buff.buffer;
}
/**
* Marshal's a packet to a buffer from a layout
* @param {Object|Number|String|Boolean|Array|Null} data
* @param {Array|Object} layout
* @return {Buffer}
*/
MarshalPacket(data = null, layout = []) {
let buff = new OsuBuffer();
if (layout instanceof Array) {
layout.forEach(item => {
buff.WriteBuffer(this.Write({
data: data[item.name],
type: item.type,
nullable: item.nullable || false
}));
});
} else if (layout instanceof Object) {
buff.WriteBuffer(this.Write({
data: data,
type: layout.type,
nullable: layout.nullable || false
}));
}
return buff.buffer;
}
/**
* Writes the packet to the buffer and returns self
* @param packet
* @return {Writer}
*/
WritePacket(packet) {
this.buffer.WriteInt16(packet.id)
.WriteBoolean(false)
.WriteUInt32(packet.data.length)
.WriteBuffer(packet.data);
return this;
}
/**
* Returns a buffer
* @return {Buffer}
*/
get toBuffer() {
return this.buffer.buffer;
}
}
module.exports = Writer;