genie-drs v3.2.0
genie-drs
Genie Engine DRS file reader/writer for Node.js and the browser
.DRS files are archive files used in the Age of Empires 1 and 2 and Star Wars: Galactic Battlegrounds games. A format specification is available in the openage project.
Usage Example
Read a palette file and a unit graphic from the Age of Empires 2 data files:
var DRS = require('genie-drs')
var Palette = require('jascpal')
var SLP = require('genie-slp')
var PNG = require('pngjs').PNG
// using Age of Empires 2 files
var int = DRS('interfac.drs')
, gra = DRS('graphics.drs')
// id 50500 is the main in-game palette.
int.readFile(50500, function (err, buffer) {
if (err) throw err
var palette = Palette(buffer)
int.close()
onpalette(palette)
})
function onpalette (palette) {
// 3088 is the 'Champion Dying' graphic.
gra.readFile(3088, function (err, buffer) {
if (err) throw err
var slp = SLP(buffer)
onslp(palette, slp)
})
}
function onslp (palette, slp) {
var frame = slp.renderFrame(1, palette, { player: 1, drawOutline: false })
var png = new PNG({
width: frame.width,
height: frame.height
})
png.data = Buffer.from(frame.data.buffer)
png.pack().pipe(fs.createWriteStream('champion-dying.png'))
}
Create a new DRS file:
var DRS = require('genie-drs')
var after = require('after')
var drs = DRS()
var cb = after(3, onfinish)
fs.createReadStream('./somefile.slp').pipe(drs.createWriteStream('slp ', 1, cb))
fs.createReadStream('./bgm.wav').pipe(drs.createWriteStream('wav ', 2, cb))
fs.createReadStream('./palette.pal').pipe(drs.createWriteStream('bina', 3, cb))
function onfinish () {
drs.archive().pipe(fs.createWriteStream('./archive.drs'))
}
API
DRS([options])
Create a new DRS file. Options can be:
isSWGB
- Whether this is a file for Star Wars: Galactic Battlegrounds. Defaultfalse
.copyright
- Copyright string to use, uses the Age of Empires or Star Wars: Galactic Battlegrounds string by default. This should be exactly 40 characters long for DRS files intended for AoE and exactly 60 characters long for DRS files for SWGB.fileVersion
- Version number as a 4-character string, default '1.00'.fileType
- File type as a 12-character string, pad with NUL bytes. Default 'tribe\0\0\0\0\0\0\0' like in Age of Empires 2 files.
DRS(filename: string)
Node only!
Creates a new DRS instance for the .DRS file filename
.
DRS(blob: Blob)
Browser only!
Creates a new DRS instance for the given Blob instance.
DRS#read(callback)
Reads the DRS table headers.
This only needs to be called manually if getFiles()
or getSize()
is used.
Otherwise, genie-drs
will call it automatically when necessary.
DRS#getSize(): number
Returns the size of the DRS file. Includes any unsaved modifications. Won't work if the file hasn't been .read()
yet.
DRS#getFiles(): Array<{id, type, size, offset}>
Returns an array of all the file entries in this DRS file. Format:
{ id: Number // internal file ID
, type: String // 4-character, space-padded type of file: "wav ", "slp ", "bina"
, size: Number // file size in bytes
, offset: Number // file offset in the main DRS, in bytes
}
Won't work if the file hasn't been .read()
yet.
DRS#getFile(id: number): { id, type, size, offset }
Finds one file entry by its file ID. See DRS#getFiles()
DRS#putFile(type: string, id: number, buffer: Buffer, callback)
Replaces one file in the DRS.
type
is the file type, i.e. the table in which to store the file.
If a file type is given for which a table does not exist, a new table is created.
id
is the new file ID.
buffer
is a Buffer or string with the new file contents.
DRS#readFile(id: number[, options], callback)
Reads a file's contents for ID id
. The callback gets an err
and a Buffer
containing the file contents.
Optionally, provide an options
object to read only part of the file:
start
- Byte offset inside the file to start reading at.end
- Byte offset inside the file to stop reading at.
DRS#createReadStream(id: number[, options]): Readable
Returns a Readable stream of the file contents for file ID id
.
The returned stream also emits a meta
event with information about the file, like in getFiles()
.
Optionally, provide an options
object to read only part of the file:
start
- Byte offset inside the file to start reading at.end
- Byte offset inside the file to stop reading at.
DRS#createWriteStream(type: string, id: number): Writable
Returns a stream, stuff that is written to it will be saved in the DRS file.
Note that this method works in-memory, use the archive()
method to flush changes back to disk.
The returned stream emits a meta
event with information about the new file, like in getFiles()
.
type
is the file type, i.e. the table in which to store the file.
If a file type is given for which a table does not exist, a new table is created.
id
is the new file ID.
DRS#archive(): Readable
Returns the entire DRS file as a stream.
If the DRS instance was initialized from an existing DRS file, this method may attempt to read data from that file--it's not safe to pipe the stream straight back to the original DRS file.
If that is necessary, use a module like fs-write-stream-atomic
, which will not touch the initial file until everything has been read.
var createWriteStream = require('fs-write-stream-atomic')
var drs = DRS('./archive.drs')
fs.createReadStream('./custom-palette.pal')
.pipe(drs.createWriteStream('bina', 50501))
.on('finish', onfinish)
function onfinish () {
drs.archive().pipe(createWriteStream('./archive.drs'))
}