You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

377 lines
11 KiB

class gbxReplay {
CHUNKS_OFFSET = 17;
HEADER_OFFSET = 21;
UNASSIGNED = 0xFFFFFFFF;
mapUID = "";
environment = "";
author = "";
bestTime = this.UNASSIGNED;
gamerHandle = ""
login = ""
titleId = ""
calcChunkOffset(num) {
return (((num) * 8) + this.HEADER_OFFSET)
}
isNumber(id) { return (((id) & 0xC0000000) == 0)}
isString(id) { return (((id) & 0xC0000000) != 0)}
isUnassigned(id) {return ((id) == this.UNASSIGNED)}
getIndex(id) {return ((id) & 0x3FFFFFFF)}
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:[]}
if( chunkInfo.dwSize <= 4) {
return;
}
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)
}
}
}
}
}
parseAuthorChunk(buff, chunkInfo) {
}
parseCommunityChunk(buff, chunkInfo) {
}
parse(buff)
{
buff.seek(0+this.CHUNKS_OFFSET);
let numChunks = buff.readUInt32();
if(numChunks == 0) {
return true;
}
else if (numChunks > 0xff) {
return false;
}
let chunkId, chunkSize = 0;
let chunkOffset = this.calcChunkOffset(numChunks)
let chunkVersion = {}
let chunkCommunity = {}
let chunkAuthor = {}
for (let counter = 1; counter <= numChunks; counter++) {
chunkId = buff.readUInt32();
chunkSize = buff.readUInt32();
chunkSize &= 0x7FFFFFFF;
switch (chunkId){
case 0x03093000: // (TM)
case 0x2403F000: // (VSK, TM)
chunkVersion.dwId = chunkId;
chunkVersion.dwSize = chunkSize;
chunkVersion.dwOffset = chunkOffset;
chunkOffset += chunkSize;
break;
case 0x03093001: // (TM)
case 0x2403F001: // (VSK, TM)
chunkCommunity.dwId = chunkId;
chunkCommunity.dwSize = chunkSize;
chunkCommunity.dwOffset = chunkOffset;
chunkOffset += chunkSize;
//OutputTextFmt(hwndCtl, szOutput, _countof(szOutput), g_szChunk, dwCouter, dwChunkId, dwChunkSize);
break;
case 0x03093002: // (MP)
chunkAuthor.dwId = chunkId;
chunkAuthor.dwSize = chunkSize;
chunkAuthor.dwOffset = chunkOffset;
chunkOffset += chunkSize;
//OutputTextFmt(hwndCtl, szOutput, _countof(szOutput), g_szChunk, dwCouter, dwChunkId, dwChunkSize);
break;
default:
chunkOffset += chunkSize;
//OutputTextFmt(hwndCtl, szOutput, _countof(szOutput), g_szChunk, dwCouter, dwChunkId, dwChunkSize);
}
}
if (chunkVersion.dwSize > 0) {
this.parseReplayChunk(buff, chunkVersion);
}
if (chunkCommunity.dwSize > 0) {
this.parseCommunityChunk(buff, chunkCommunity);
}
if (chunkAuthor.dwSize > 0) {
this.parseAuthorChunk(buff, chunkAuthor);
}
}
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;