Skip to content

Commit

Permalink
Add a serialiser for room header 🛰️.
Browse files Browse the repository at this point in the history
  • Loading branch information
gmarty committed Apr 30, 2024
1 parent 4f90163 commit bb1245e
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 50 deletions.
56 changes: 6 additions & 50 deletions src/lib/parser/parseRooms.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import Parser from './parser.js';
import parseRoomHeader from './room/parseRoomHeader.js';

const assert = console.assert;

const parseRooms = (arrayBuffer, i = 0, offset = 0, characters = {}) => {
const parser = new Parser(arrayBuffer);
const metadata = {
id: i,
offset,
Expand All @@ -14,50 +14,13 @@ const parseRooms = (arrayBuffer, i = 0, offset = 0, characters = {}) => {
return { metadata };
}

const chunkSize = parser.getUint16(); // Room res size
const header = parseRoomHeader(arrayBuffer.slice(0, 0x1c));

assert(
chunkSize === arrayBuffer.byteLength,
header.chunkSize === arrayBuffer.byteLength,
'Room res size flag does not match chunk size.',
);

const unk1 = parser.getUint8();
const unk2 = parser.getUint8();

assert(unk1 === 0, 'Unknown 1 is not 0.');

const width = parser.getUint16(); // Room width
const height = parser.getUint16(); // Room height

assert(width === 28 || width === 60, 'Room width is not 28 or 60.');
assert(height === 16, 'Room height is not 16.');

const unk3 = parser.getUint16(); // Number objects in room (unused?)

assert(unk3 === 0, 'Unknown 3 is not 0.');

const nametableOffs = parser.getUint16(); // Gfx background tileset offset
const attrOffs = parser.getUint16(); // Gfx background attr offset
const maskOffs = parser.getUint16(); // Gfx mask offset

const unk4 = parser.getUint16(); // charMap offset
const unk5 = parser.getUint16(); // picMap offset

assert(unk4 === unk5, 'The values of unknown 4 and 5 do not match.');

const objectsNum = parser.getUint8();

assert(objectsNum < 57, 'There are more than 56 objects in room.');

const boxOffs = parser.getUint8();
const soundsNum = parser.getUint8();

assert(soundsNum === 0, 'The number of sounds is not 0.');

const scriptsNum = parser.getUint8();
const excdOffs = parser.getUint16(); // Exit script (EXCD) offset
const encdOffs = parser.getUint16(); // Entry script (ENCD) offset

let map = [
{
type: 'header',
Expand All @@ -66,25 +29,18 @@ const parseRooms = (arrayBuffer, i = 0, offset = 0, characters = {}) => {
},
];

const header = {
const {
chunkSize,
unk1,
unk2,
width,
height,
unk3,
nametableOffs,
attrOffs,
maskOffs,
unk4,
unk5,
objectsNum,
boxOffs,
soundsNum,
scriptsNum,
excdOffs,
encdOffs,
};
} = header;

const objectImages = [];
const objects = [];
const boxes = [];
Expand Down
68 changes: 68 additions & 0 deletions src/lib/parser/room/parseRoomHeader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import Parser from '../parser.js';

const assert = console.assert;

const parseRoomHeader = (arrayBuffer) => {
const parser = new Parser(arrayBuffer);

const chunkSize = parser.getUint16(); // Room res size

const unk1 = parser.getUint8();
const unk2 = parser.getUint8();

assert(unk1 === 0, 'Unknown 1 is not 0.');

const width = parser.getUint16(); // Room width
const height = parser.getUint16(); // Room height

assert(width === 28 || width === 60, 'Room width is not 28 or 60.');
assert(height === 16, 'Room height is not 16.');

const unk3 = parser.getUint16(); // Number objects in room (unused?)

assert(unk3 === 0, 'Unknown 3 is not 0.');

const nametableOffs = parser.getUint16(); // Gfx background tileset offset
const attrOffs = parser.getUint16(); // Gfx background attr offset
const maskOffs = parser.getUint16(); // Gfx mask offset

const unk4 = parser.getUint16(); // charMap offset
const unk5 = parser.getUint16(); // picMap offset

assert(unk4 === unk5, 'The values of unknown 4 and 5 do not match.');

const objectsNum = parser.getUint8();

assert(objectsNum < 57, 'There are more than 56 objects in room.');

const boxOffs = parser.getUint8();
const soundsNum = parser.getUint8();

assert(soundsNum === 0, 'The number of sounds is not 0.');

const scriptsNum = parser.getUint8();
const excdOffs = parser.getUint16(); // Exit script (EXCD) offset
const encdOffs = parser.getUint16(); // Entry script (ENCD) offset

return {
chunkSize,
unk1,
unk2,
width,
height,
unk3,
nametableOffs,
attrOffs,
maskOffs,
unk4,
unk5,
objectsNum,
boxOffs,
soundsNum,
scriptsNum,
excdOffs,
encdOffs,
};
};

export default parseRoomHeader;
38 changes: 38 additions & 0 deletions src/lib/serialiser/room/serialiseRoomHeader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Serialiser from '../serialiser.js';

const serialiseRoomHeader = (header) => {
const serialiser = new Serialiser();

// @todo Move the writing of chunk size outside of this code,
// to the end of the serialisation.
serialiser.setUint16(header.chunkSize);

serialiser.setUint8(header.unk1);
serialiser.setUint8(header.unk2);

serialiser.setUint16(header.width);
serialiser.setUint16(header.height);

serialiser.setUint16(); // 0x00

serialiser.setUint16(header.nametableOffs);
serialiser.setUint16(header.attrOffs);
serialiser.setUint16(header.maskOffs);

serialiser.setUint16(header.unk4);
serialiser.setUint16(header.unk5);

// @todo Update the value of objectsNum after the serialisation.
serialiser.setUint8(header.objectsNum);

serialiser.setUint8(header.boxOffs);
serialiser.setUint8(header.soundsNum);

serialiser.setUint8(header.scriptsNum);
serialiser.setUint16(header.excdOffs);
serialiser.setUint16(header.encdOffs);

return serialiser.buffer;
};

export default serialiseRoomHeader;
6 changes: 6 additions & 0 deletions src/lib/serialiser/serialiser.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ class Serialiser {
this.#view.setUint8(this.#ptr++, value);
}

setUint16(value = 0x00) {
this.#view.buffer.resize(this.#ptr + 2);
this.#view.setUint16(this.#ptr, value, true);
this.#ptr += 2;
}

setString(str) {
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt#looping_with_codepointat
for (let codePoint of str) {
Expand Down
33 changes: 33 additions & 0 deletions test/parseRoomHeader.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import parseRoomHeader from '../src/lib/parser/room/parseRoomHeader.js';
import serialiseRoomHeader from '../src/lib/serialiser/room/serialiseRoomHeader.js';

const roomHeaderBuffer = () => {
const array = [
0x0c, 0x0d, 0x00, 0x24, 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x01,
0xc5, 0x03, 0xfa, 0x03, 0x2d, 0x00, 0x2d, 0x00, 0x14, 0x6d, 0x00, 0x01,
0xca, 0x0c, 0xfb, 0x0c,
];
const buffer = new ArrayBuffer(array.length);
const view = new DataView(buffer);
array.forEach((v, i) => view.setUint8(i, v));
return buffer;
};

describe('parseRoomHeader', () => {
it('should return a non empty object.', () => {
const header = parseRoomHeader(roomHeaderBuffer());

assert.equal(typeof header, 'object');
assert.ok(Object.keys(header).length > 0);
});

it('should be the inverse of serialiseRoomHeader.', () => {
const initialBuffer = roomHeaderBuffer();
const header = parseRoomHeader(initialBuffer);
const buffer = serialiseRoomHeader(header);

assert.deepEqual(initialBuffer, buffer);
});
});
47 changes: 47 additions & 0 deletions test/serialiseRoomHeader.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import serialiseRoomHeader from '../src/lib/serialiser/room/serialiseRoomHeader.js';
import parseRoomHeader from '../src/lib/parser/room/parseRoomHeader.js';

const roomHeader = {
header: {
chunkSize: 3340,
unk1: 0,
unk2: 36,
width: 60,
height: 16,
unk3: 0,
nametableOffs: 272,
attrOffs: 965,
maskOffs: 1018,
unk4: 45,
unk5: 45,
objectsNum: 20,
boxOffs: 109,
soundsNum: 0,
scriptsNum: 1,
excdOffs: 3274,
encdOffs: 3323,
},
};

describe('serialiseRoomHeader', () => {
it('should return an instance of ArrayBuffer.', () => {
const buffer = serialiseRoomHeader(roomHeader.header);
assert.ok(buffer instanceof ArrayBuffer);
});

it('should serialise a room header.', () => {
const buffer = serialiseRoomHeader(roomHeader.header);
const view = new DataView(buffer);

assert.equal(view.getUint8(2), 0x00);
});

it('should be the inverse of parseRoomHeader.', () => {
const buffer = serialiseRoomHeader(roomHeader.header);
const header = parseRoomHeader(buffer);

assert.deepEqual(roomHeader.header, header);
});
});

0 comments on commit bb1245e

Please sign in to comment.