rw-parser-ng 2.0.5 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,88 +1,88 @@
1
- # RenderWare Binary Stream Parser NG
2
-
3
- [![npm](https://img.shields.io/npm/v/rw-parser-ng.svg)](https://www.npmjs.com/package/rw-parser-ng)
4
- [![NPM](https://img.shields.io/npm/l/rw-parser-ng.svg)](https://github.com/DepsCian/rw-parser-ng/blob/master/LICENSE)
5
-
6
- Parses RenderWare files (`.dff`, `.txd`, `.ifp`) into a usable format.
7
-
8
- This is a fork of the original [rw-parser](https://github.com/Timic3/rw-parser) by Timic3, which is no longer active maintained. This version aims to continue development, fix bugs, and add new features.
9
-
10
- ## Features
11
-
12
- * **DFF (Model) Parsing:** Extracts geometry, materials, frames, and skinning data.
13
- * **TXD (Texture Dictionary) Parsing:** Extracts texture information, including name, resolution and pixel data.
14
- * **IFP (Animation) Parsing:** Extracts animation data, including bone names, keyframes, and timings.
15
- * **Cross-Platform:** Works in both Node.js and modern web browsers.
16
- * **TypeScript Support:** Fully typed for a better development experience.
17
-
18
- ## Installation
19
-
20
- Install `rw-parser-ng` using pnpm:
21
-
22
- ```bash
23
- pnpm install --save rw-parser-ng
24
- ```
25
-
26
- ## Usage
27
-
28
- ### ES6 Module
29
-
30
- ```javascript
31
- import { DffParser, TxdParser, IfpParser } from 'rw-parser-ng';
32
- import { readFileSync } from 'fs';
33
-
34
- // DFF
35
- const dffBuffer = readFileSync('path/to/your/model.dff');
36
- const dffParser = new DffParser(dffBuffer);
37
- const dffData = dffParser.parse();
38
- console.log(dffData);
39
-
40
- // TXD
41
- const txdBuffer = readFileSync('path/to/your/textures.txd');
42
- const txdParser = new TxdParser(txdBuffer);
43
- const txdData = txdParser.parse();
44
- console.log(txdData);
45
-
46
- // IFP
47
- const ifpBuffer = readFileSync('path/to/your/animation.ifp');
48
- const ifpParser = new IfpParser(ifpBuffer);
49
- const ifpData = ifpParser.parse();
50
- console.log(ifpData);
51
- ```
52
-
53
- ### Browser Usage
54
-
55
- This library can also be used in the browser. You will need a bundler like Webpack or Rollup to handle the Node.js `Buffer` dependency.
56
-
57
- ```javascript
58
- import { DffParser } from 'rw-parser-ng';
59
-
60
- async function parseDffFromUrl(url) {
61
- const response = await fetch(url);
62
- const arrayBuffer = await response.arrayBuffer();
63
- const buffer = Buffer.from(arrayBuffer); // Requires Buffer polyfill
64
-
65
- const dffParser = new DffParser(buffer);
66
- const dffData = dffParser.parse();
67
- console.log(dffData);
68
- }
69
-
70
- parseDffFromUrl('path/to/your/model.dff');
71
- ```
72
-
73
- ## Development
74
-
75
- 1. Clone the repository: `git clone https://github.com/DepsCian/rw-parser-ng.git`
76
- 2. Install dependencies: `pnpm install`
77
- 3. Build the project: `pnpm run build`
78
- 4. Run tests: `pnpm test`
79
-
80
- To watch for changes during development, use `pnpm run dev`.
81
-
82
- ## Contributing
83
-
84
- Contributions are welcome! Please feel free to open an issue or submit a pull request.
85
-
86
- ## License
87
-
88
- This project is licensed under the GPL-3.0 License. See the [LICENSE](LICENSE) file for details.
1
+ # RenderWare Binary Stream Parser NG
2
+
3
+ [![npm](https://img.shields.io/npm/v/rw-parser-ng.svg)](https://www.npmjs.com/package/rw-parser-ng)
4
+ [![NPM](https://img.shields.io/npm/l/rw-parser-ng.svg)](https://github.com/DepsCian/rw-parser-ng/blob/master/LICENSE)
5
+
6
+ Parses RenderWare files (`.dff`, `.txd`, `.ifp`) into a usable format.
7
+
8
+ This is a fork of the original [rw-parser](https://github.com/Timic3/rw-parser) by Timic3, which is no longer active maintained. This version aims to continue development, fix bugs, and add new features.
9
+
10
+ ## Features
11
+
12
+ * **DFF (Model) Parsing:** Extracts geometry, materials, frames, and skinning data.
13
+ * **TXD (Texture Dictionary) Parsing:** Extracts texture information, including name, resolution and pixel data.
14
+ * **IFP (Animation) Parsing:** Extracts animation data, including bone names, keyframes, and timings.
15
+ * **Cross-Platform:** Works in both Node.js and modern web browsers.
16
+ * **TypeScript Support:** Fully typed for a better development experience.
17
+
18
+ ## Installation
19
+
20
+ Install `rw-parser-ng` using pnpm:
21
+
22
+ ```bash
23
+ pnpm install --save rw-parser-ng
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ### ES6 Module
29
+
30
+ ```javascript
31
+ import { DffParser, TxdParser, IfpParser } from 'rw-parser-ng';
32
+ import { readFileSync } from 'fs';
33
+
34
+ // DFF
35
+ const dffBuffer = readFileSync('path/to/your/model.dff');
36
+ const dffParser = new DffParser(dffBuffer);
37
+ const dffData = dffParser.parse();
38
+ console.log(dffData);
39
+
40
+ // TXD
41
+ const txdBuffer = readFileSync('path/to/your/textures.txd');
42
+ const txdParser = new TxdParser(txdBuffer);
43
+ const txdData = txdParser.parse();
44
+ console.log(txdData);
45
+
46
+ // IFP
47
+ const ifpBuffer = readFileSync('path/to/your/animation.ifp');
48
+ const ifpParser = new IfpParser(ifpBuffer);
49
+ const ifpData = ifpParser.parse();
50
+ console.log(ifpData);
51
+ ```
52
+
53
+ ### Browser Usage
54
+
55
+ This library can also be used in the browser. You will need a bundler like Webpack or Rollup to handle the Node.js `Buffer` dependency.
56
+
57
+ ```javascript
58
+ import { DffParser } from 'rw-parser-ng';
59
+
60
+ async function parseDffFromUrl(url) {
61
+ const response = await fetch(url);
62
+ const arrayBuffer = await response.arrayBuffer();
63
+ const buffer = Buffer.from(arrayBuffer); // Requires Buffer polyfill
64
+
65
+ const dffParser = new DffParser(buffer);
66
+ const dffData = dffParser.parse();
67
+ console.log(dffData);
68
+ }
69
+
70
+ parseDffFromUrl('path/to/your/model.dff');
71
+ ```
72
+
73
+ ## Development
74
+
75
+ 1. Clone the repository: `git clone https://github.com/DepsCian/rw-parser-ng.git`
76
+ 2. Install dependencies: `pnpm install`
77
+ 3. Build the project: `pnpm run build`
78
+ 4. Run tests: `pnpm test`
79
+
80
+ To watch for changes during development, use `pnpm run dev`.
81
+
82
+ ## Contributing
83
+
84
+ Contributions are welcome! Please feel free to open an issue or submit a pull request.
85
+
86
+ ## License
87
+
88
+ This project is licensed under the GPL-3.0 License. See the [LICENSE](LICENSE) file for details.
@@ -23,6 +23,9 @@ var RwFile = /** @class */ (function (_super) {
23
23
  return _super.call(this, stream) || this;
24
24
  }
25
25
  RwFile.prototype.readSectionHeader = function () {
26
+ if (this.getPosition() + 12 > this.getSize()) {
27
+ throw new Error("Cannot read section header at offset ".concat(this.getPosition().toString(16), ": need 12 bytes but only ").concat(this.getSize() - this.getPosition(), " bytes remaining"));
28
+ }
26
29
  var sectionType = this.readUint32();
27
30
  var sectionSize = this.readUint32();
28
31
  var versionNumber = this.readUint32();
@@ -38,13 +38,24 @@ var DffParser = /** @class */ (function (_super) {
38
38
  var geometryList = null;
39
39
  var frameList = null;
40
40
  while (this.getPosition() < this.getSize()) {
41
- var header = this.readSectionHeader();
41
+ var header = void 0;
42
+ try {
43
+ header = this.readSectionHeader();
44
+ }
45
+ catch (error) {
46
+ console.warn("Failed to read section header at offset ".concat(this.getPosition().toString(16), ": ").concat(error instanceof Error ? error.message : error, ". Truncating file."));
47
+ break;
48
+ }
42
49
  if (header.sectionType === 0) {
43
50
  break;
44
51
  }
45
52
  if (header.sectionSize == 0) {
46
53
  continue;
47
54
  }
55
+ if (this.getPosition() + header.sectionSize > this.getSize()) {
56
+ console.warn("Section at offset ".concat(this.getPosition().toString(16), " claims size ").concat(header.sectionSize, " but only ").concat(this.getSize() - this.getPosition(), " bytes remaining. Truncating file."));
57
+ break;
58
+ }
48
59
  switch (header.sectionType) {
49
60
  case RwSections_1.RwSections.RwClump:
50
61
  // Multiple clumps are used in SA player models, so we should eventually support it
@@ -93,8 +104,11 @@ var DffParser = /** @class */ (function (_super) {
93
104
  if (!version || !versionNumber) {
94
105
  throw new RwParseError_1.RwParseStructureNotFoundError('version');
95
106
  }
107
+ if (!geometryList || !geometryList.geometries || geometryList.geometries.length === 0) {
108
+ throw new RwParseError_1.RwParseStructureNotFoundError('geometry list');
109
+ }
96
110
  var modelType = DffModelType_1.DffModelType.GENERIC;
97
- if (geometryList === null || geometryList === void 0 ? void 0 : geometryList.geometries.some(function (g) { return g.skin; })) {
111
+ if (geometryList.geometries.some(function (g) { return g.skin; })) {
98
112
  modelType = DffModelType_1.DffModelType.SKIN;
99
113
  }
100
114
  else if (dummies.some(function (d) { return d.toLowerCase().includes('wheel') || d.toLowerCase().includes('chassis'); })) {
@@ -71,6 +71,7 @@ var TxdParser = /** @class */ (function (_super) {
71
71
  var compressed = (compressionFlags & (1 << 3)) !== 0;
72
72
  var paletteType = (rasterFormat >> 13) & 3;
73
73
  var mipWidth = width;
74
+ var pixelFormat = rasterFormat & 0x0F00;
74
75
  var mipHeight = height;
75
76
  var mipmaps = [];
76
77
  var palette = (paletteType !== ImageFormatEnums_1.PaletteType.PALETTE_NONE ? this.readPalette(paletteType, depth) : new Uint8Array(0));
@@ -87,7 +88,7 @@ var TxdParser = /** @class */ (function (_super) {
87
88
  ImageFormatEnums_1.RasterFormat.RASTER_888,
88
89
  ImageFormatEnums_1.RasterFormat.RASTER_555
89
90
  ];
90
- var hasAlpha = ((platformId === ImageFormatEnums_1.PlatformType.D3D9 && alpha) || (platformId == ImageFormatEnums_1.PlatformType.D3D8 && !rasterFormatsWithoutAlpha.includes(rasterFormat)));
91
+ var hasAlpha = ((platformId === ImageFormatEnums_1.PlatformType.D3D9 && alpha) || (platformId == ImageFormatEnums_1.PlatformType.D3D8 && !rasterFormatsWithoutAlpha.includes(pixelFormat)));
91
92
  bitmap = Array.from(this.getBitmapWithPalette(paletteType, depth, hasAlpha, raster, palette, width, height));
92
93
  }
93
94
  else if (platformId === ImageFormatEnums_1.PlatformType.D3D8 && compressionFlags !== 0) {
@@ -97,7 +98,7 @@ var TxdParser = /** @class */ (function (_super) {
97
98
  bitmap = Array.from(this.getBitmapWithDXT(d3dFormat, raster, width, height));
98
99
  }
99
100
  else {
100
- bitmap = Array.from(this.getBitmapWithRasterFormat(rasterFormat, raster, width, height));
101
+ bitmap = Array.from(this.getBitmapWithRasterFormat(pixelFormat, raster, width, height));
101
102
  }
102
103
  mipmaps.push(bitmap);
103
104
  }
@@ -14,4 +14,5 @@ export declare class ByteStream {
14
14
  getPosition(): number;
15
15
  setPosition(position: number): void;
16
16
  skip(size: number): void;
17
+ dispose(): void;
17
18
  }
@@ -60,6 +60,10 @@ var ByteStream = /** @class */ (function () {
60
60
  ByteStream.prototype.skip = function (size) {
61
61
  this._cursor += size;
62
62
  };
63
+ ByteStream.prototype.dispose = function () {
64
+ this._stream = Buffer.alloc(0);
65
+ this._cursor = 0;
66
+ };
63
67
  return ByteStream;
64
68
  }());
65
69
  exports.ByteStream = ByteStream;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rw-parser-ng",
3
- "version": "2.0.5",
3
+ "version": "2.1.1",
4
4
  "description": "Parses RenderWare DFF, TXD and IFP files into usable format!",
5
5
  "author": {
6
6
  "name": "DepsCian",
@@ -46,6 +46,13 @@
46
46
  "ts-jest": "^29.4.0",
47
47
  "typescript": "^5.8.3"
48
48
  },
49
+ "scripts": {
50
+ "build": "tsc -p tsconfig.json",
51
+ "dev": "tsc -p tsconfig.json --watch",
52
+ "prepare": "npm run build",
53
+ "test": "jest",
54
+ "sort:models": "tsc && node lib/scripts/sort_models.js"
55
+ },
49
56
  "files": [
50
57
  "lib",
51
58
  "src",
@@ -53,11 +60,5 @@
53
60
  "README.md",
54
61
  "package.json",
55
62
  "tsconfig.json"
56
- ],
57
- "scripts": {
58
- "build": "tsc -p tsconfig.json",
59
- "dev": "tsc -p tsconfig.json --watch",
60
- "test": "jest",
61
- "sort:models": "tsc && node lib/scripts/sort_models.js"
62
- }
63
- }
63
+ ]
64
+ }
package/src/index.ts CHANGED
@@ -1,12 +1,12 @@
1
- export { ByteStream } from './utils/ByteStream';
2
- export { RwFile } from './renderware/RwFile';
3
- export { RwSections } from './renderware/RwSections';
4
-
5
- export * from './renderware/dff/DffParser';
6
- export * from './renderware/txd/TxdParser';
7
- export * from './renderware/ifp/IfpParser';
8
-
9
- export * from './renderware/dff/DffModelType';
10
- export * from './renderware/ifp/IfpData';
11
-
12
- export * from './renderware/common/types';
1
+ export { ByteStream } from './utils/ByteStream';
2
+ export { RwFile } from './renderware/RwFile';
3
+ export { RwSections } from './renderware/RwSections';
4
+
5
+ export * from './renderware/dff/DffParser';
6
+ export * from './renderware/txd/TxdParser';
7
+ export * from './renderware/ifp/IfpParser';
8
+
9
+ export * from './renderware/dff/DffModelType';
10
+ export * from './renderware/ifp/IfpData';
11
+
12
+ export * from './renderware/common/types';
@@ -1,22 +1,26 @@
1
- import { ByteStream } from "../utils/ByteStream";
2
-
3
- export interface RwSectionHeader {
4
- sectionType: number,
5
- sectionSize: number,
6
- versionNumber: number
7
- }
8
-
9
- export class RwFile extends ByteStream {
10
-
11
- constructor(stream: Buffer) {
12
- super(stream);
13
- }
14
-
15
- public readSectionHeader(): RwSectionHeader {
16
- const sectionType = this.readUint32();
17
- const sectionSize = this.readUint32();
18
- const versionNumber = this.readUint32();
19
-
20
- return { sectionType, sectionSize, versionNumber };
21
- }
22
- }
1
+ import { ByteStream } from "../utils/ByteStream";
2
+
3
+ export interface RwSectionHeader {
4
+ sectionType: number,
5
+ sectionSize: number,
6
+ versionNumber: number
7
+ }
8
+
9
+ export class RwFile extends ByteStream {
10
+
11
+ constructor(stream: Buffer) {
12
+ super(stream);
13
+ }
14
+
15
+ public readSectionHeader(): RwSectionHeader {
16
+ if (this.getPosition() + 12 > this.getSize()) {
17
+ throw new Error(`Cannot read section header at offset ${this.getPosition().toString(16)}: need 12 bytes but only ${this.getSize() - this.getPosition()} bytes remaining`);
18
+ }
19
+
20
+ const sectionType = this.readUint32();
21
+ const sectionSize = this.readUint32();
22
+ const versionNumber = this.readUint32();
23
+
24
+ return { sectionType, sectionSize, versionNumber };
25
+ }
26
+ }
@@ -1,27 +1,27 @@
1
- export enum RwSections {
2
- // Core
3
- RwStruct = 0x0001,
4
- RwString = 0x0002,
5
- RwExtension = 0x0003,
6
- RwTexture = 0x0006,
7
- RwMaterial = 0x0007,
8
- RwMaterialList = 0x0008,
9
- RwFrameList = 0x000E,
10
- RwGeometry = 0x000F,
11
- RwClump = 0x0010,
12
- RwAtomic = 0x0014,
13
- RwTextureNative = 0x0015,
14
- RwTextureDictionary = 0x0016,
15
- RwGeometryList = 0x001A,
16
- RwSkin = 0x116,
17
- RwAnim = 0x11E,
18
-
19
- // Toolkit
20
- RwMaterialEffectsPLG = 0x0120,
21
-
22
- // R* specific RW plugins
23
- RwReflectionMaterial = 0x0253F2FC,
24
- // This was renamed to RwNodeName from RwFrame to prevent confusion.
25
- // https://gtamods.com/wiki/Node_Name_(RW_Section)
26
- RwNodeName = 0x0253F2FE,
27
- }
1
+ export enum RwSections {
2
+ // Core
3
+ RwStruct = 0x0001,
4
+ RwString = 0x0002,
5
+ RwExtension = 0x0003,
6
+ RwTexture = 0x0006,
7
+ RwMaterial = 0x0007,
8
+ RwMaterialList = 0x0008,
9
+ RwFrameList = 0x000E,
10
+ RwGeometry = 0x000F,
11
+ RwClump = 0x0010,
12
+ RwAtomic = 0x0014,
13
+ RwTextureNative = 0x0015,
14
+ RwTextureDictionary = 0x0016,
15
+ RwGeometryList = 0x001A,
16
+ RwSkin = 0x116,
17
+ RwAnim = 0x11E,
18
+
19
+ // Toolkit
20
+ RwMaterialEffectsPLG = 0x0120,
21
+
22
+ // R* specific RW plugins
23
+ RwReflectionMaterial = 0x0253F2FC,
24
+ // This was renamed to RwNodeName from RwFrame to prevent confusion.
25
+ // https://gtamods.com/wiki/Node_Name_(RW_Section)
26
+ RwNodeName = 0x0253F2FE,
27
+ }
@@ -1,59 +1,59 @@
1
- export interface RwVector2 {
2
- x: number,
3
- y: number,
4
- }
5
-
6
- export interface RwVector3 {
7
- x: number,
8
- y: number,
9
- z: number,
10
- }
11
-
12
- export interface RwVector4 {
13
- x: number,
14
- y: number,
15
- z: number,
16
- t: number,
17
- }
18
-
19
- export interface RwQuaternion {
20
- x: number,
21
- y: number,
22
- z: number,
23
- w: number,
24
- }
25
-
26
- export interface RwMatrix3 {
27
- right: RwVector3,
28
- up: RwVector3,
29
- at: RwVector3,
30
- }
31
-
32
- export interface RwMatrix4 {
33
- right: RwVector4,
34
- up: RwVector4,
35
- at: RwVector4,
36
- transform: RwVector4,
37
- }
38
-
39
- export interface RwColor {
40
- r: number,
41
- g: number,
42
- b: number,
43
- a: number,
44
- }
45
-
46
- export interface RwTextureCoordinate {
47
- u: number,
48
- v: number,
49
- }
50
-
51
- export interface RwTriangle {
52
- vector: RwVector3,
53
- materialId: number,
54
- }
55
-
56
- export interface RwSphere {
57
- vector: RwVector3,
58
- radius: number,
1
+ export interface RwVector2 {
2
+ x: number,
3
+ y: number,
4
+ }
5
+
6
+ export interface RwVector3 {
7
+ x: number,
8
+ y: number,
9
+ z: number,
10
+ }
11
+
12
+ export interface RwVector4 {
13
+ x: number,
14
+ y: number,
15
+ z: number,
16
+ t: number,
17
+ }
18
+
19
+ export interface RwQuaternion {
20
+ x: number,
21
+ y: number,
22
+ z: number,
23
+ w: number,
24
+ }
25
+
26
+ export interface RwMatrix3 {
27
+ right: RwVector3,
28
+ up: RwVector3,
29
+ at: RwVector3,
30
+ }
31
+
32
+ export interface RwMatrix4 {
33
+ right: RwVector4,
34
+ up: RwVector4,
35
+ at: RwVector4,
36
+ transform: RwVector4,
37
+ }
38
+
39
+ export interface RwColor {
40
+ r: number,
41
+ g: number,
42
+ b: number,
43
+ a: number,
44
+ }
45
+
46
+ export interface RwTextureCoordinate {
47
+ u: number,
48
+ v: number,
49
+ }
50
+
51
+ export interface RwTriangle {
52
+ vector: RwVector3,
53
+ materialId: number,
54
+ }
55
+
56
+ export interface RwSphere {
57
+ vector: RwVector3,
58
+ radius: number,
59
59
  }
@@ -1,5 +1,5 @@
1
- export enum DffModelType {
2
- GENERIC,
3
- SKIN,
4
- VEHICLE,
1
+ export enum DffModelType {
2
+ GENERIC,
3
+ SKIN,
4
+ VEHICLE,
5
5
  }