diff --git a/backend/trackmania-replays/gbx-replay.js b/backend/trackmania-replays/gbx-replay.js index bc1bc20..0137f18 100644 --- a/backend/trackmania-replays/gbx-replay.js +++ b/backend/trackmania-replays/gbx-replay.js @@ -4,6 +4,14 @@ class gbxReplay { HEADER_OFFSET = 21; UNASSIGNED = 0xFFFFFFFF; + mapUID = ""; + environment = ""; + author = ""; + bestTime = this.UNASSIGNED; + gamerHandle = "" + login = "" + titleId = "" + calcChunkOffset(num) { return (((num) * 8) + this.HEADER_OFFSET) } @@ -13,47 +21,70 @@ class gbxReplay { isUnassigned(id) {return ((id) == this.UNASSIGNED)} getIndex(id) {return ((id) & 0x3FFFFFFF)} - readIdentifier(buff, idList, outString, stringLen) - { - if ( idList.version < 3 ) { - idList.version = buff.readUInt32(); - } - - let id = buff.readUInt32(); - if(this.isUnassigned(id)) { - return; - } - - if(this.isNumber(id)){ - console.log("number") - } - - if(idList.version == 2) { - outString = buff.readString(stringLen) - console.log(outString) - } - - if(this.isString(id) && this.getIndex(id) == 0) { - outString = buff.readString(stringLen) - - console.log(outString) - } - } - parseReplayChunk(buff, chunkInfo) { buff.seek(0+chunkInfo.dwOffset); let version = buff.readUInt32(); let isVSK = version >= 9999 ? true : false; - let idList = { version: 0, index: 0, list:[[]]} + let idList = { version: 0, index: 0, list:[]} if( chunkInfo.dwSize <= 4) { return; } - if((!isVSK && version >= 3) || (isVSK && version >= 10000)) { - let outString = ""; - this.readIdentifier(buff, idList, outString, 512); + if((!isVSK && version >= 3) || (isVSK && version >= 10000)) + { + let result = this.readIdentifier(buff, idList); + if(result.read > 0) + { + this.mapUID = result.str; + console.log("MapUID:\t " + this.mapUID) + } + + result = this.readIdentifier(buff, idList); + if(result.read > 0) + { + this.environment = result.str; + console.log("Environ:\t " + this.environment) + } + + result = this.readIdentifier(buff, idList) + if (result.read > 0) + { + this.author = result.str; + console.log("Author:\t " + this.author) + } + + this.bestTime = buff.readUInt32(); + console.log("BestTime:\t " + this.bestTime); + + result = buff.readNadeoString(); + if (result.read > 0) + { + this.gamerHandle = result.str; + console.log("Gamer Handle:\t " + this.gamerHandle) + } + + if((!isVSK && version >= 6) || (isVSK && version >= 10000)) + { + result = buff.readNadeoString(); + if (result.read > 0) + { + this.login = result.str; + console.log("Login:\t " + this.login) + } + + if((!isVSK && version >= 8) || (isVSK && version >= 10000)) + { + buff.seek(buff.readPos+1); + result = this.readIdentifier(buff, idList) + if (result.read > 0) + { + this.titleId = result.str; + console.log("titleId:\t " + this.titleId) + } + } + } } } @@ -133,7 +164,214 @@ class gbxReplay { } } - + readIdentifier(buff, idList) + { + if ( idList.version < 3 ) + { + idList.version = buff.readUInt32(); + + if (idList.version < 2) + { + return {read:-1, str:""}; + } + } + + let id = buff.readUInt32(); + if(this.isUnassigned(id)) + { + return {read:0, str:""}; + } + + if(this.isNumber(id)) + { + return this.getCollectionString(id); + } + + if(idList.version == 2) + { + return buff.readNadeoString(); + } + + if(this.isString(id) && this.getIndex(id) == 0) + { + let result = buff.readNadeoString(); + + if (result.read > 0 && idList.index < 8) + { + idList.list[idList.index] = result.str; + idList.index++; + } + + return result; + } + + let index = this.getIndex(id); + if( index == 0 || index > 8) + { + return {read:0, str:""}; + } + + let latest = idList.list[idList.index-1]; + return {read:latest.length, str:latest}; + } + + getCollectionString(id) + { + let outString = "" + switch (id) + { + case 0: // Speed + outString = "Desert"; + break; + case 1: // Alpine + outString = "Snow"; + break; + case 2: // Rally + outString = "Rally"; + break; + case 3: // Island + outString = "Island"; + break; + case 4: // Bay + outString = "Bay"; + break; + case 5: // Coast + outString = "Coast"; + break; + case 6: // StadiumMP4 + outString = "Stadium"; + break; + case 7: // Basic + outString = "Basic"; + break; + case 8: // Plain + outString = "Plain"; + break; + case 9: // Moon + outString = "Moon"; + break; + case 10: // Toy + outString = "Toy"; + break; + case 11: // Valley + outString = "Valley"; + break; + case 12: // Canyon + outString = "Canyon"; + break; + case 13: // Lagoon + outString = "Lagoon"; + break; + case 14: // Deprecated_Arena + outString = "Arena"; + break; + case 15: // TMTest8 + outString = "TMTest8"; + break; + case 16: // TMTest9 + outString = "TMTest9"; + break; + case 17: // TMCommon + outString = "TMCommon"; + break; + case 18: // Canyon4 + outString = "Canyon4"; + break; + case 19: // Canyon256 + outString = "Canyon256"; + break; + case 20: // Valley4 + outString = "Valley4"; + break; + case 21: // Valley256 + outString = "Valley256"; + break; + case 22: // Lagoon4 + outString = "Lagoon4"; + break; + case 23: // Lagoon256 + outString = "Lagoon256"; + break; + case 24: // Stadium4 + outString = "Stadium4"; + break; + case 25: // Stadium256 + outString = "Stadium256"; + break; + case 26: // Stadium + outString = "Stadium"; + break; + case 27: // Voxel + outString = "Voxel"; + break; + case 100: // History + outString = "History"; + break; + case 101: // Society + outString = "Society"; + break; + case 102: // Galaxy + outString = "Galaxy"; + break; + case 103: // QMTest1 + outString = "QMTest1"; + break; + case 104: // QMTest2 + outString = "QMTest2"; + break; + case 105: // QMTest3 + outString = "QMTest3"; + break; + case 200: // Gothic + outString = "Gothic"; + break; + case 201: // Paris + outString = "Paris"; + break; + case 202: // Storm + outString = "Storm"; + break; + case 203: // Cryo + outString = "Cryo"; + break; + case 204: // Meteor + outString = "Meteor"; + break; + case 205: // Meteor4 + outString = "Meteor4"; + break; + case 206: // Meteor256 + outString = "Meteor256"; + break; + case 207: // SMTest3 + outString = "SMTest3"; + break; + case 299: // SMCommon + outString = "SMCommon"; + break; + case 10000: // Vehicles + outString = "Vehicles"; + break; + case 10001: // Orbital + outString = "Orbital"; + break; + case 10002: // Actors + outString = "Actors"; + break; + case 10003: // Common + outString = "Common"; + break; + case UNASSIGNED: + outString = "_Unassigned"; + break; + default: + { + return {read:0, str:""}; + } + } + + return {read:outString.length, str:outString} + } } module.exports = gbxReplay; \ No newline at end of file diff --git a/backend/utilities/AdvancableBuffer.js b/backend/utilities/AdvancableBuffer.js index d345c3a..605e51b 100644 --- a/backend/utilities/AdvancableBuffer.js +++ b/backend/utilities/AdvancableBuffer.js @@ -48,6 +48,23 @@ class Advancablebuffer { let sub = this.internalBuffer.subarray(this.readPos, this.readPos+=length); return sub; } + + readNadeoString() + { + let length = this.readUInt32() + if(length >= 0xFFFF) + { + return {read:-1, str:""}; + } + + if (length == 0) + { + return {read:0, str:""}; + } + + let outString = this.readString(length); + return {read:outString.length, str:outString}; + } } module.exports = Advancablebuffer; \ No newline at end of file