arx-convert
Version:
Converts various Arx Fatalis formats to JSON or YAML and back
249 lines (176 loc) • 7.43 kB
Markdown
Converts various Arx Fatalis formats (DLF, FTS, LLF, AMB and FTL) to JSON/YAML and back
**IMPORTANT: Arx Fatalis files are partially compressed. See "compression" section for more info**
## Installation
`npm i arx-convert -g`
This will give you access to the following commands, both do the same:
- `arx-convert`
### Recommended requirements
node.js 18.0+ (because the lib uses prefix-only core modules)
It might work with older versions of node.js, but I haven't tested it there.
## Command-line API
`arx-convert <inputfile> --from=<format> --to=<format> --output=<outputfile> [--format] [--pretty] [--prettify]`
the inputfile and --output parameters can be omitted and then the code can be used in pipelines
`cat <inputfile> | arx-convert --from=<format> --to=<format> > <outputfile>`
the `<format>` parameter can be one of the following arx formats: `dlf`, `llf`, `fts`, `amb` or `ftl`
work in progress formats: `tea`
and it can also a data format for the other side: `json` and `yaml`(can also be spelled as `yml`)
prettifying the json output can be done by using any of the 3 parameters: `--format`, `--pretty` or `--prettify`
```sh
--version
-v
cat fast.fts.unpacked | arx-convert --from=fts --to=json --prettify > fast.fts.json
arx-convert level8.dlf.unpacked --from=dlf --to=json --output=level8.dlf.min.json
cat level8.dlf.min.json | arx-convert --from=json --to=dlf > level8.dlf.repacked
arx-convert fast.fts.json --from=json --to=fts --output=fast.fts.repacked
cat level8.dlf.unpacked | arx-convert --to=yaml --from=dlf > level8.dlf.yml
cat level8.dlf.yml | arx-convert --from=yaml --to=dlf > level8.dlf.repacked
```
The package is published as a commonjs lib and the files can be found in the `dist` folder, but only if you
install it via npm. If you downloaded the source files from github, then you need to transpile the typescript
files yourself using the `npm run build` command.
The built js files come with sourcemaps, which you can use by running your node.js file with the
[--enable-source-maps](https://nodejs.org/api/cli.html#--enable-source-maps) flag
```js
const fs = require('node:fs/promises')
const path = require('node:path')
const { FTS } = require('arx-convert')
;(async () => {
// reads an unpacked fts file into a buffer
const binary = await fs.readFile(path.resolve(__dirname, './fast.fts.unpacked'))
// converts the buffer into a json using the FTS converter
const json = FTS.load(binary)
// save as a minified json
await fs.writeFile(path.resolve(__dirname, './fast.fts.min.json'), JSON.stringify(json), 'utf8')
// save as a formatted json
await fs.writeFile(path.resolve(__dirname, './fast.fts.json'), JSON.stringify(json, null, '\t'), 'utf8')
})()
```
```ts
import fs from 'node:fs/promises'
import path from 'node:path'
import { DLF } from 'arx-convert'
import type { ArxDLF } from 'arx-convert/types'
;(async () => {
// reads an unpacked dlf file into a buffer
const binary = await fs.readFile(path.resolve(__dirname, './level1.dlf.unpacked'))
// converts the buffer into a json using the DLF converter
// optionally you can assign a type to the variable
const json: ArxDLF = DLF.load(binary)
// save as a minified json
await fs.writeFile(path.resolve(__dirname, './level1.dlf.min.json'), JSON.stringify(json), 'utf8')
// save as a formatted json
await fs.writeFile(path.resolve(__dirname, './level1.dlf.json'), JSON.stringify(json, null, '\t'), 'utf8')
})()
```
Some Arx Fatalis files are partially compressed with Stormlib Pkware and you need a separate
tool for unpacking/repacking: [node-pkware](https://www.npmjs.com/package/node-pkware)
Also, Arx Fatalis file headers are not constant in size, but there is a tool
that can give you the exact offset you need to pipe into node-pkware: [arx-header-size](https://www.npmjs.com/package/arx-header-size)
Install these tools by running
```sh
npm i node-pkware arx-header-size -g
```
```sh
arx-header-size level3.dlf --format=dlf
explode level3.dlf --offset=8520 --output=level3.dlf.unpacked
arx-convert level3.dlf.unpacked --from=dlf --to=yaml --output=level3.dlf.yml
```
```sh
arx-convert level3.dlf.yml --from=yaml --to=dlf --output=level3.dlf.repacked
implode level3.dlf.repacked --offset=8520 --binary --large --output=level3.dlf
```
```sh
if [ $
echo "missing filename, expected format: $0 <filename>"
exit 1
fi
INPUT=$1
INPUT_FORMAT=$( \
echo $INPUT \
| tr '[:upper:]' '[:lower:]' \
| tr '.' '\n' \
| tail -1 \
)
if [ $
OUTPUT_FORMAT=yml
else
OUTPUT_FORMAT=$2
fi
OFFSET=$(arx-header-size $INPUT --format=$INPUT_FORMAT)
if [[ $OFFSET == "not compressed" ]]; then
arx-convert $INPUT --from=$INPUT_FORMAT --to=$OUTPUT_FORMAT --pretty --output="$INPUT.$OUTPUT_FORMAT"
else
explode $INPUT --offset=$OFFSET | arx-convert --from=$INPUT_FORMAT --to=$OUTPUT_FORMAT --pretty --output="$INPUT.$OUTPUT_FORMAT"
fi
```
```sh
if [ $
echo "missing filename, expected format: $0 <filename>"
exit 1
fi
INPUT=$1
INPUT_FORMAT=$( \
echo $INPUT \
| tr '[:upper:]' '[:lower:]' \
| tr '.' '\n' \
| tail -1 \
)
OUTPUT_FORMAT=$( \
echo $INPUT \
| tr '[:upper:]' '[:lower:]' \
| tr '.' '\n' \
| tail -2 \
| head -1 \
)
arx-convert $INPUT --from=$INPUT_FORMAT --to=$OUTPUT_FORMAT --pretty --output="$INPUT.$OUTPUT_FORMAT.tmp"
OFFSET=$(arx-header-size $INPUT --format=$OUTPUT_FORMAT)
if [[ $OFFSET == "not compressed" ]]; then
mv "$INPUT.$OUTPUT_FORMAT.tmp" "$INPUT.$OUTPUT_FORMAT"
else
implode "$INPUT.$OUTPUT_FORMAT.tmp" --offset=$OFFSET --binary --large --output="$INPUT.$OUTPUT_FORMAT"
rm "$INPUT.$OUTPUT_FORMAT.tmp"
fi
```
`FTS.save()` now takes a 2nd parameter to control whether the given fts data should be marked as compressed
or uncompressed
- `FTS.save(ftsData, true)` -> fts files get compressed (true can be omitted as it is the **default** value)
- `FTS.save(ftsData, false)` -> marks the fts file as uncompressed, no pkware compression is required afterwards