|
|
@ -4,6 +4,14 @@ class gbxReplay { |
|
|
HEADER_OFFSET = 21; |
|
|
HEADER_OFFSET = 21; |
|
|
UNASSIGNED = 0xFFFFFFFF; |
|
|
UNASSIGNED = 0xFFFFFFFF; |
|
|
|
|
|
|
|
|
|
|
|
mapUID = ""; |
|
|
|
|
|
environment = ""; |
|
|
|
|
|
author = ""; |
|
|
|
|
|
bestTime = this.UNASSIGNED; |
|
|
|
|
|
gamerHandle = "" |
|
|
|
|
|
login = "" |
|
|
|
|
|
titleId = "" |
|
|
|
|
|
|
|
|
calcChunkOffset(num) { |
|
|
calcChunkOffset(num) { |
|
|
return (((num) * 8) + this.HEADER_OFFSET) |
|
|
return (((num) * 8) + this.HEADER_OFFSET) |
|
|
} |
|
|
} |
|
|
@ -13,47 +21,70 @@ class gbxReplay { |
|
|
isUnassigned(id) {return ((id) == this.UNASSIGNED)} |
|
|
isUnassigned(id) {return ((id) == this.UNASSIGNED)} |
|
|
getIndex(id) {return ((id) & 0x3FFFFFFF)} |
|
|
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) { |
|
|
parseReplayChunk(buff, chunkInfo) { |
|
|
buff.seek(0+chunkInfo.dwOffset); |
|
|
buff.seek(0+chunkInfo.dwOffset); |
|
|
let version = buff.readUInt32(); |
|
|
let version = buff.readUInt32(); |
|
|
let isVSK = version >= 9999 ? true : false; |
|
|
let isVSK = version >= 9999 ? true : false; |
|
|
|
|
|
|
|
|
let idList = { version: 0, index: 0, list:[[]]} |
|
|
let idList = { version: 0, index: 0, list:[]} |
|
|
|
|
|
|
|
|
if( chunkInfo.dwSize <= 4) { |
|
|
if( chunkInfo.dwSize <= 4) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if((!isVSK && version >= 3) || (isVSK && version >= 10000)) { |
|
|
if((!isVSK && version >= 3) || (isVSK && version >= 10000)) |
|
|
let outString = ""; |
|
|
{ |
|
|
this.readIdentifier(buff, idList, outString, 512); |
|
|
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; |
|
|
module.exports = gbxReplay; |