Omnibus's picture
Upload 131 files
4ee4376
import * as CONST from '../constants';
import * as segmentHandlers from './segmentHandlers/';
import { bytesToAscii } from './segmentHandlers/common';
export default class sc2 {
import (buffer) {
let size = CONST.MAP_SIZE;
let x = 0;
let y = 0;
let map = {
cells: [],
_segmentData: {}
};
for (let i = 0; i < size * size; i++) {
map.cells.push({ x: x, y: y, _segmentData: {} });
if (y === 127) {
y = 0;
x += 1;
} else {
y += 1;
}
}
// iterate through each data segment and parse
let bytes = buffer.subarray(12);
let segments = this.splitSegments(bytes);
Object.keys(segments).sort().forEach((title) => {
let type = title;
// handle special case for scenario
// text sections
if (title.startsWith('TEXT'))
type = 'TEXT';
let handler = segmentHandlers[type];
if (handler)
handler(segments[title], map);
else
console.log('Unknown Segment:',type);
});
// city metadata
map.info = {
name: map._segmentData.CNAM.text || 'Default',
height: size,
width: size,
rotation: map._segmentData.MISC.rotation,
waterLevel: map._segmentData.MISC.globalSeaLevel,
};
// populate data cells
for (let i = 0; i < map.cells.length; i++) {
let cell = map.cells[i];
let data = cell._segmentData;
cell.tiles = { _list: [] };
if (data.XTER.terrain) cell.tiles._list.push({ id: data.XTER.terrain, type: CONST.T_TERRAIN });
if (data.XTER.water) cell.tiles._list.push({ id: data.XTER.water, type: CONST.T_WATER });
if (cell.x == 0 || cell.x == 127 || cell.y == 0 || cell.y == 127)
if (data.XTER.terrain) cell.tiles._list.push({ id: data.XTER.terrain, type: CONST.T_EDGE });
//if (data.XTER.terrain) cell.tiles._list.push({ id: data.XTER.terrain, type: CONST.T_HEIGHTMAP });
//if (data.XZON.zone) cell.tiles._list.push({ id: data.XZON.zone, type: CONST.T_ZONE });
if (data.XBLD.id != 0) cell.tiles._list.push(data.XBLD);
//if (data.XUND.subway) cell.tiles._list.push({ id: data.XUND.subway, type: CONST.T_SUBWAY });
//if (data.XUND.pipes) cell.tiles._list.push({ id: data.XUND.pipes, type: CONST.T_PIPES });
cell.corners = {
left: data.XZON.left,
top: data.XZON.top,
bottom: data.XZON.bottom,
right: data.XZON.right,
none: data.XZON.none,
};
cell.zone = {
id: data.XZON.zone,
type: data.XZON.zoneType,
};
cell.z = data.ALTM.altitude;
cell.rotate = data.XBIT.rotate;
cell.power = {
wired: data.XBIT.wired,
powered: data.XBIT.powered,
};
cell.pipes = {
piped: data.XBIT.piped,
watered: data.XBIT.watered,
};
cell.water = {
type: data.XTER.type,
covered: data.XBIT.waterCovered,
salt: data.XBIT.saltWater,
};
map.cells[i] = cell;
}
return map;
}
splitSegments (bytes) {
let segments = {};
while (bytes.length > 0) {
let title = bytesToAscii(bytes.subarray(0x00, 0x04));
let length = new DataView(bytes.subarray(0x04, 0x08).buffer).getUint32(bytes.subarray(0x04, 0x08).byteOffset);
let contents = bytes.subarray(0x08, 0x08 + length);
if (!['ALTM','CNAM','TEXT','PICT','SCEN','TMPL'].includes(title))
contents = this.decompressSegment(contents);
// can have multilpe TEXT segments
if (title == 'TEXT') {
let type = bytes.subarray(0x08, 0x09);
if (type == 0x80)
title = 'TEXT_1';
else if (type == 0x81)
title = 'TEXT_2';
}
segments[title] = contents;
bytes = bytes.subarray(0x08 + length);
}
return segments;
}
decompressSegment (bytes) {
let output = [];
let dataCount = 0;
for (let i = 0; i < bytes.length; i++) {
if (dataCount > 0) {
output.push(bytes[i]);
dataCount -= 1;
continue;
}
// data bytes
if (bytes[i] < 128) {
dataCount = bytes[i];
// run-length encoded byte
} else {
let repeatCount = bytes[i] - 127;
let repeated = bytes[i + 1];
for (let i = 0; i < repeatCount; i++)
output.push(repeated);
// skip the next byte
i += 1;
}
}
return Uint8Array.from(output);
}
}