Compare commits

..

252 Commits

Author SHA1 Message Date
Jan
da90bbd356
Merge pull request #412 from Laupetin/chore/better-build-scripts
chore: replace x64 build scripts with generic ones
2025-04-20 17:54:29 +02:00
Jan
13b07c0fe4
chore: replace x64 build scripts with generic ones 2025-04-20 17:30:55 +02:00
Jan
38d948ebdd
Merge pull request #408 from Laupetin/refactor/zcg-code-style
refactor: zcg code style
2025-04-20 13:51:43 +02:00
Jan
9f8a933277
chore: update ZoneCodeGenerator code style 2025-04-20 09:45:37 +02:00
Jan
9f738da517
chore: remove duplicated alignment utility method 2025-04-20 09:45:36 +02:00
Jan
785cf8c025
chore: update code style in ZoneCodeGenerator entrypoint 2025-04-20 09:45:32 +02:00
Jan
0f3ee1fa79
Merge pull request #407 from Laupetin/dependabot/submodules/thirdparty/eigen-33f5f59
chore(deps): bump thirdparty/eigen from `11fd34c` to `33f5f59`
2025-04-19 11:54:54 +02:00
Jan
c8cd6826c1
Merge pull request #406 from Laupetin/dependabot/submodules/thirdparty/json-c67d538
chore(deps): bump thirdparty/json from `7ddea26` to `c67d538`
2025-04-19 11:54:41 +02:00
Jan
5afc24fd89
Merge pull request #405 from Laupetin/dependabot/submodules/thirdparty/catch2-4c8671c
chore(deps): bump thirdparty/catch2 from `2b60af8` to `4c8671c`
2025-04-19 11:54:28 +02:00
dependabot[bot]
598abe095b
chore(deps): bump thirdparty/eigen from 11fd34c to 33f5f59
Bumps [thirdparty/eigen](https://gitlab.com/libeigen/eigen) from `11fd34c` to `33f5f59`.
- [Release notes](https://gitlab.com/libeigen/eigen/tags)
- [Commits](11fd34cc1c...33f5f59614)

---
updated-dependencies:
- dependency-name: thirdparty/eigen
  dependency-version: 33f5f596143d0fce32316ec6fa4bd9f23b4dd9d2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-18 22:43:27 +00:00
dependabot[bot]
d6eee273ff
chore(deps): bump thirdparty/json from 7ddea26 to c67d538
Bumps [thirdparty/json](https://github.com/nlohmann/json) from `7ddea26` to `c67d538`.
- [Release notes](https://github.com/nlohmann/json/releases)
- [Commits](7ddea2686f...c67d538274)

---
updated-dependencies:
- dependency-name: thirdparty/json
  dependency-version: c67d538274502163b55e8fb54b5c27c17764722d
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-18 22:43:25 +00:00
dependabot[bot]
7edbe7378b
chore(deps): bump thirdparty/catch2 from 2b60af8 to 4c8671c
Bumps [thirdparty/catch2](https://github.com/catchorg/Catch2) from `2b60af8` to `4c8671c`.
- [Release notes](https://github.com/catchorg/Catch2/releases)
- [Commits](2b60af89e2...4c8671cfbb)

---
updated-dependencies:
- dependency-name: thirdparty/catch2
  dependency-version: 4c8671cfbbf0019d3827305d4d1c82a74eeb029a
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-18 22:43:23 +00:00
Jan
b83bafb0f8
Merge pull request #403 from Laupetin/dependabot/submodules/thirdparty/catch2-2b60af8
chore(deps): bump thirdparty/catch2 from `76f70b1` to `2b60af8`
2025-04-12 23:24:00 +02:00
Jan
e750e3ffd9
Merge pull request #402 from Laupetin/dependabot/submodules/thirdparty/json-7ddea26
chore(deps): bump thirdparty/json from `11aa5f9` to `7ddea26`
2025-04-12 23:23:44 +02:00
Jan
d5b6c6e9c2
Merge pull request #401 from Laupetin/dependabot/submodules/thirdparty/eigen-11fd34c
chore(deps): bump thirdparty/eigen from `b860042` to `11fd34c`
2025-04-12 23:23:32 +02:00
dependabot[bot]
d6c1ef775e
chore(deps): bump thirdparty/catch2 from 76f70b1 to 2b60af8
Bumps [thirdparty/catch2](https://github.com/catchorg/Catch2) from `76f70b1` to `2b60af8`.
- [Release notes](https://github.com/catchorg/Catch2/releases)
- [Commits](76f70b1403...2b60af89e2)

---
updated-dependencies:
- dependency-name: thirdparty/catch2
  dependency-version: 2b60af89e23d28eefc081bc930831ee9d45ea58b
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-11 22:49:13 +00:00
dependabot[bot]
c05d4ea34e
chore(deps): bump thirdparty/json from 11aa5f9 to 7ddea26
Bumps [thirdparty/json](https://github.com/nlohmann/json) from `11aa5f9` to `7ddea26`.
- [Release notes](https://github.com/nlohmann/json/releases)
- [Commits](11aa5f944d...7ddea2686f)

---
updated-dependencies:
- dependency-name: thirdparty/json
  dependency-version: 7ddea2686f091ea77a3f731ab74c59535db9f684
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-11 22:49:10 +00:00
dependabot[bot]
b2d9bf416d
chore(deps): bump thirdparty/eigen from b860042 to 11fd34c
Bumps [thirdparty/eigen](https://gitlab.com/libeigen/eigen) from `b860042` to `11fd34c`.
- [Release notes](https://gitlab.com/libeigen/eigen/tags)
- [Commits](b860042263...11fd34cc1c)

---
updated-dependencies:
- dependency-name: thirdparty/eigen
  dependency-version: 11fd34cc1c398f2c2311339ed3b008b1114544eb
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-11 22:49:08 +00:00
Jan
3134ec5a37
Merge pull request #400 from GoastcraftHD/main
Added MapEnts dumping for T6
2025-04-07 23:40:52 +02:00
Jan
0d35696940
chore: make map ents dumping add ents extension instead of replacing 2025-04-07 22:16:08 +01:00
GoastcraftHD
b215b22018 Fixed MapEnts dumping in wrong folder 2025-04-07 22:34:21 +02:00
GoastcraftHD
a447dd29fa
Fixed include order 2025-04-07 20:05:01 +02:00
GoastcraftHD
985996975b
Update SupportedAssetTypes.md 2025-04-07 12:05:56 +02:00
Simon Ickler
f235798cf6 Added MapEnts dumping for T6 2025-04-07 12:05:03 +02:00
Jan
0228e86980
Merge pull request #399 from Laupetin/fix/64-bit-compilation
fix: 64 bit compilation
2025-04-06 19:27:06 +02:00
Jan
01302cf061
fix: too large obj files for x64 on windows 2025-04-06 18:02:48 +01:00
Jan
6f31e8cc29
chore: fix compilation issues with x64 2025-04-06 18:02:47 +01:00
Jan
37d52ae8da
chore: add compilation scripts for x64 2025-04-06 17:44:26 +02:00
Jan
481d301545
chore: change c++ version to c++23 2025-04-06 17:43:50 +02:00
Jan
d3bb99e92c
Merge pull request #395 from Laupetin/fix/bad-xmodel-loading
fix: bad xmodel loading
2025-04-05 17:59:45 +02:00
Jan
cec70e783f
fix: not using lookup to common vertices when writing rigid bone data
no more pizza cheese problem
2025-04-05 17:36:29 +02:00
Jan
a2c8129a13
fix: messed up reordering of vertices for bone count 2025-04-05 16:30:58 +02:00
Jan
e13eb256bb
chore: update code style 2025-04-05 16:30:54 +02:00
Jan
aab510c917
Merge pull request #398 from Laupetin/fix/linux-folder-file-capitalization
fix: linux folder file capitalization
2025-04-05 13:07:14 +02:00
Jan
820fe47473
fix: always use lowercase extensions for xmodels 2025-04-05 12:42:55 +02:00
Jan
0366b24bd7
fix: game name in linker paths must be lowercase for linux 2025-04-05 12:42:52 +02:00
Jan
49f0794545
Merge pull request #397 from Laupetin/dependabot/submodules/thirdparty/json-11aa5f9
chore(deps): bump thirdparty/json from `11a835d` to `11aa5f9`
2025-04-05 08:51:42 +02:00
Jan
20911d552d
Merge pull request #396 from Laupetin/dependabot/submodules/thirdparty/eigen-b860042
chore(deps): bump thirdparty/eigen from `e0c99a8` to `b860042`
2025-04-05 08:51:27 +02:00
dependabot[bot]
1748f9e1a5
chore(deps): bump thirdparty/json from 11a835d to 11aa5f9
Bumps [thirdparty/json](https://github.com/nlohmann/json) from `11a835d` to `11aa5f9`.
- [Release notes](https://github.com/nlohmann/json/releases)
- [Commits](11a835df85...11aa5f944d)

---
updated-dependencies:
- dependency-name: thirdparty/json
  dependency-version: 11aa5f944d17ed5b96250ca133bf33c5ca8b0161
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-04 23:00:25 +00:00
dependabot[bot]
a37b5fee8c
chore(deps): bump thirdparty/eigen from e0c99a8 to b860042
Bumps [thirdparty/eigen](https://gitlab.com/libeigen/eigen) from `e0c99a8` to `b860042`.
- [Release notes](https://gitlab.com/libeigen/eigen/tags)
- [Commits](e0c99a8dd6...b860042263)

---
updated-dependencies:
- dependency-name: thirdparty/eigen
  dependency-version: b86004226361882ea6c9308c0a940007a049d1d5
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-04 23:00:23 +00:00
Jan
42e2eb80b3
Merge pull request #394 from Laupetin/dependabot/submodules/thirdparty/eigen-e0c99a8
chore(deps): bump thirdparty/eigen from `6579e36` to `e0c99a8`
2025-03-29 00:27:10 +01:00
dependabot[bot]
885c57bfa5
chore(deps): bump thirdparty/eigen from 6579e36 to e0c99a8
Bumps [thirdparty/eigen](https://gitlab.com/libeigen/eigen) from `6579e36` to `e0c99a8`.
- [Release notes](https://gitlab.com/libeigen/eigen/tags)
- [Commits](6579e36eb4...e0c99a8dd6)

---
updated-dependencies:
- dependency-name: thirdparty/eigen
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-28 22:45:27 +00:00
Jan
fa88b135f9
Merge pull request #393 from Laupetin/fix/rename-clipmap-asset-iw3-iw4-t5
fix: set clipmap asset name of non-pvs clipmap to clipmap_unused in IW3,IW4,T5
2025-03-27 17:43:53 +01:00
Jan
56c4eeb5cd
fix: set clipmap asset name of non-pvs clipmap to clipmap_unused in IW3,IW4,T5 2025-03-27 17:16:28 +01:00
Jan
0fcae6a55a
Merge pull request #391 from LJW-Dev/fix/T6-clipmap-asset
Update T6 asset loading code to use ASSET_TYPE_CLIPMAP_PVS.
2025-03-27 17:14:14 +01:00
LJW-Dev
f97f38dc31
Merge branch 'Laupetin:main' into fix/T6-clipmap-asset 2025-03-27 12:33:05 +08:00
LJW-Dev
95f5dca5e0 Updated zone loading code to only use ASSET_TYPE_CLIPMAP_PVS. 2025-03-27 12:32:43 +08:00
Jan
f2723255f5
Merge pull request #390 from Laupetin/dependabot/submodules/thirdparty/json-11a835d
chore(deps): bump thirdparty/json from `8215dba` to `11a835d`
2025-03-25 20:31:53 +01:00
dependabot[bot]
11cb93f736
chore(deps): bump thirdparty/json from 8215dba to 11a835d
Bumps [thirdparty/json](https://github.com/nlohmann/json) from `8215dba` to `11a835d`.
- [Release notes](https://github.com/nlohmann/json/releases)
- [Commits](8215dbafbd...11a835df85)

---
updated-dependencies:
- dependency-name: thirdparty/json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-25 18:54:35 +00:00
Jan
e40d688e11
Merge pull request #389 from Laupetin/dependabot/submodules/thirdparty/libtommath-e823b0c
chore(deps): bump thirdparty/libtommath from `5938524` to `e823b0c`
2025-03-25 19:53:42 +01:00
dependabot[bot]
2eeb20d1cd
chore(deps): bump thirdparty/libtommath from 5938524 to e823b0c
Bumps [thirdparty/libtommath](https://github.com/libtom/libtommath) from `5938524` to `e823b0c`.
- [Release notes](https://github.com/libtom/libtommath/releases)
- [Commits](5938524c60...e823b0c34c)

---
updated-dependencies:
- dependency-name: thirdparty/libtommath
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-25 18:25:18 +00:00
Jan
7b79504477
Merge pull request #388 from Laupetin/dependabot/submodules/thirdparty/eigen-ac2165c
chore(deps): bump thirdparty/eigen from `5fc6fc9` to `ac2165c`
2025-03-25 19:24:21 +01:00
dependabot[bot]
4cc7ab77d5
chore(deps): bump thirdparty/eigen from 5fc6fc9 to ac2165c
Bumps [thirdparty/eigen](https://gitlab.com/libeigen/eigen) from `5fc6fc9` to `ac2165c`.
- [Release notes](https://gitlab.com/libeigen/eigen/tags)
- [Commits](5fc6fc9881...ac2165c11f)

---
updated-dependencies:
- dependency-name: thirdparty/eigen
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-25 18:00:47 +00:00
Jan
08fb6b0496
Merge pull request #386 from Laupetin/dependabot/submodules/thirdparty/catch2-76f70b1
chore(deps): bump thirdparty/catch2 from `914aeec` to `76f70b1`
2025-03-25 18:59:43 +01:00
dependabot[bot]
a871889c13
chore(deps): bump thirdparty/catch2 from 914aeec to 76f70b1
Bumps [thirdparty/catch2](https://github.com/catchorg/Catch2) from `914aeec` to `76f70b1`.
- [Release notes](https://github.com/catchorg/Catch2/releases)
- [Commits](914aeecfe2...76f70b1403)

---
updated-dependencies:
- dependency-name: thirdparty/catch2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-25 17:36:11 +00:00
Jan
81bc21eacf
Merge pull request #384 from Laupetin/dependabot/submodules/thirdparty/libtomcrypt-a6b9aff
chore(deps): bump thirdparty/libtomcrypt from `d032686` to `a6b9aff`
2025-03-25 18:35:04 +01:00
dependabot[bot]
aec779dae5
chore(deps): bump thirdparty/libtomcrypt from d032686 to a6b9aff
Bumps [thirdparty/libtomcrypt](https://github.com/libtom/libtomcrypt) from `d032686` to `a6b9aff`.
- [Release notes](https://github.com/libtom/libtomcrypt/releases)
- [Commits](d032686639...a6b9aff7aa)

---
updated-dependencies:
- dependency-name: thirdparty/libtomcrypt
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-25 17:11:32 +00:00
Jan
97c4a23d5e
Merge pull request #392 from Laupetin/fix/compilation-on-windows
fix: compilation on msvc
2025-03-25 18:09:57 +01:00
Jan
0c587e5e5f
fix: compilation on msvc 2025-03-25 17:38:07 +01:00
Jan
4ac38bfc66
Merge pull request #376 from Laupetin/dependabot/submodules/thirdparty/json-8215dba
chore(deps): bump thirdparty/json from `606b634` to `8215dba`
2025-02-22 17:31:01 +01:00
Jan
34a0bd4f4f
Merge pull request #377 from Laupetin/dependabot/submodules/thirdparty/zlib-5a82f71
chore(deps): bump thirdparty/zlib from `7108497` to `5a82f71`
2025-02-22 17:30:53 +01:00
Jan
047e8aa125
Merge pull request #378 from Laupetin/dependabot/submodules/thirdparty/eigen-5fc6fc9
chore(deps): bump thirdparty/eigen from `9c21143` to `5fc6fc9`
2025-02-22 17:30:45 +01:00
Jan
b5303475d9
Merge pull request #379 from Laupetin/dependabot/submodules/thirdparty/libtomcrypt-d032686
chore(deps): bump thirdparty/libtomcrypt from `54f0456` to `d032686`
2025-02-22 17:30:38 +01:00
dependabot[bot]
4adc9115b2
chore(deps): bump thirdparty/libtomcrypt from 54f0456 to d032686
Bumps [thirdparty/libtomcrypt](https://github.com/libtom/libtomcrypt) from `54f0456` to `d032686`.
- [Release notes](https://github.com/libtom/libtomcrypt/releases)
- [Commits](54f0456559...d032686639)

---
updated-dependencies:
- dependency-name: thirdparty/libtomcrypt
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-21 22:39:15 +00:00
dependabot[bot]
a4347b0b0d
chore(deps): bump thirdparty/zlib from 7108497 to 5a82f71
Bumps [thirdparty/zlib](https://github.com/madler/zlib) from `7108497` to `5a82f71`.
- [Release notes](https://github.com/madler/zlib/releases)
- [Commits](7108497fda...5a82f71ed1)

---
updated-dependencies:
- dependency-name: thirdparty/zlib
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-21 22:39:13 +00:00
dependabot[bot]
4e5c72d79a
chore(deps): bump thirdparty/eigen from 9c21143 to 5fc6fc9
Bumps [thirdparty/eigen](https://gitlab.com/libeigen/eigen) from `9c21143` to `5fc6fc9`.
- [Release notes](https://gitlab.com/libeigen/eigen/tags)
- [Commits](9c211430b5...5fc6fc9881)

---
updated-dependencies:
- dependency-name: thirdparty/eigen
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-21 22:39:12 +00:00
dependabot[bot]
58f5f66dcf
chore(deps): bump thirdparty/json from 606b634 to 8215dba
Bumps [thirdparty/json](https://github.com/nlohmann/json) from `606b634` to `8215dba`.
- [Release notes](https://github.com/nlohmann/json/releases)
- [Commits](606b6347ed...8215dbafbd)

---
updated-dependencies:
- dependency-name: thirdparty/json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-21 22:39:10 +00:00
Jan
54d19dcc8a
Merge pull request #373 from Laupetin/dependabot/submodules/thirdparty/eigen-9c21143
chore(deps): bump thirdparty/eigen from `715deac` to `9c21143`
2025-02-14 23:23:02 +01:00
Jan
f05a21984a
Merge pull request #374 from Laupetin/dependabot/submodules/thirdparty/zlib-7108497
chore(deps): bump thirdparty/zlib from `8a844d4` to `7108497`
2025-02-14 23:22:40 +01:00
dependabot[bot]
b071beea3f
chore(deps): bump thirdparty/zlib from 8a844d4 to 7108497
Bumps [thirdparty/zlib](https://github.com/madler/zlib) from `8a844d4` to `7108497`.
- [Release notes](https://github.com/madler/zlib/releases)
- [Commits](8a844d434f...7108497fda)

---
updated-dependencies:
- dependency-name: thirdparty/zlib
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-14 22:01:47 +00:00
dependabot[bot]
548c0c23bf
chore(deps): bump thirdparty/eigen from 715deac to 9c21143
Bumps [thirdparty/eigen](https://gitlab.com/libeigen/eigen) from `715deac` to `9c21143`.
- [Release notes](https://gitlab.com/libeigen/eigen/tags)
- [Commits](715deac188...9c211430b5)

---
updated-dependencies:
- dependency-name: thirdparty/eigen
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-14 22:01:45 +00:00
Jan
6d186bc09c
Merge pull request #372 from Laupetin/dependabot/submodules/thirdparty/eigen-715deac
chore(deps): bump thirdparty/eigen from `9589cc4` to `715deac`
2025-02-08 17:57:32 +01:00
Jan
96dc2c9318
Merge pull request #371 from Laupetin/dependabot/submodules/thirdparty/zlib-8a844d4
chore(deps): bump thirdparty/zlib from `ef24c4c` to `8a844d4`
2025-02-08 17:57:20 +01:00
dependabot[bot]
e4c08e1372
chore(deps): bump thirdparty/eigen from 9589cc4 to 715deac
Bumps [thirdparty/eigen](https://gitlab.com/libeigen/eigen) from `9589cc4` to `715deac`.
- [Release notes](https://gitlab.com/libeigen/eigen/tags)
- [Commits](9589cc4e7f...715deac188)

---
updated-dependencies:
- dependency-name: thirdparty/eigen
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-07 22:44:15 +00:00
dependabot[bot]
1b6824f2bd
chore(deps): bump thirdparty/zlib from ef24c4c to 8a844d4
Bumps [thirdparty/zlib](https://github.com/madler/zlib) from `ef24c4c` to `8a844d4`.
- [Release notes](https://github.com/madler/zlib/releases)
- [Commits](ef24c4c750...8a844d434f)

---
updated-dependencies:
- dependency-name: thirdparty/zlib
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-07 22:44:14 +00:00
Jan
0eb0383051
Merge pull request #370 from Laupetin/dependabot/submodules/thirdparty/eigen-9589cc4
chore(deps): bump thirdparty/eigen from `4a6ac97` to `9589cc4`
2025-02-01 17:18:26 +01:00
Jan
222d96a923
Merge pull request #369 from Laupetin/dependabot/submodules/thirdparty/json-606b634
chore(deps): bump thirdparty/json from `d0789e3` to `606b634`
2025-02-01 17:18:07 +01:00
Jan
07dccbf2f8
Merge pull request #368 from Laupetin/dependabot/submodules/thirdparty/libtomcrypt-54f0456
chore(deps): bump thirdparty/libtomcrypt from `427e055` to `54f0456`
2025-02-01 17:17:45 +01:00
Jan
b24b6b1979
Merge pull request #367 from Laupetin/dependabot/submodules/thirdparty/libtommath-5938524
chore(deps): bump thirdparty/libtommath from `5809141` to `5938524`
2025-02-01 17:17:22 +01:00
dependabot[bot]
a220142e86
chore(deps): bump thirdparty/eigen from 4a6ac97 to 9589cc4
Bumps [thirdparty/eigen](https://gitlab.com/libeigen/eigen) from `4a6ac97` to `9589cc4`.
- [Release notes](https://gitlab.com/libeigen/eigen/tags)
- [Commits](4a6ac97d13...9589cc4e7f)

---
updated-dependencies:
- dependency-name: thirdparty/eigen
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-31 22:38:54 +00:00
dependabot[bot]
4c30bd129a
chore(deps): bump thirdparty/json from d0789e3 to 606b634
Bumps [thirdparty/json](https://github.com/nlohmann/json) from `d0789e3` to `606b634`.
- [Release notes](https://github.com/nlohmann/json/releases)
- [Commits](d0789e365d...606b6347ed)

---
updated-dependencies:
- dependency-name: thirdparty/json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-31 22:38:51 +00:00
dependabot[bot]
3d3a0ca565
chore(deps): bump thirdparty/libtomcrypt from 427e055 to 54f0456
Bumps [thirdparty/libtomcrypt](https://github.com/libtom/libtomcrypt) from `427e055` to `54f0456`.
- [Release notes](https://github.com/libtom/libtomcrypt/releases)
- [Commits](427e0551c0...54f0456559)

---
updated-dependencies:
- dependency-name: thirdparty/libtomcrypt
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-31 22:38:49 +00:00
dependabot[bot]
903bd5a960
chore(deps): bump thirdparty/libtommath from 5809141 to 5938524
Bumps [thirdparty/libtommath](https://github.com/libtom/libtommath) from `5809141` to `5938524`.
- [Release notes](https://github.com/libtom/libtommath/releases)
- [Commits](5809141a3a...5938524c60)

---
updated-dependencies:
- dependency-name: thirdparty/libtommath
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-31 22:38:47 +00:00
Jan
2402d4f9c7
Merge pull request #364 from Laupetin/dependabot/submodules/thirdparty/json-d0789e3
chore(deps): bump thirdparty/json from `e72046e` to `d0789e3`
2025-01-25 00:30:50 +01:00
Jan
a21b410fd7
Merge pull request #363 from Laupetin/dependabot/submodules/thirdparty/libtomcrypt-427e055
chore(deps): bump thirdparty/libtomcrypt from `2e9f2b5` to `427e055`
2025-01-25 00:30:38 +01:00
Jan
2b1ade2b5a
Merge pull request #362 from Laupetin/dependabot/submodules/thirdparty/eigen-4a6ac97
chore(deps): bump thirdparty/eigen from `abac563` to `4a6ac97`
2025-01-25 00:30:24 +01:00
dependabot[bot]
d869de5881
chore(deps): bump thirdparty/json from e72046e to d0789e3
Bumps [thirdparty/json](https://github.com/nlohmann/json) from `e72046e` to `d0789e3`.
- [Release notes](https://github.com/nlohmann/json/releases)
- [Commits](e72046ef9f...d0789e365d)

---
updated-dependencies:
- dependency-name: thirdparty/json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-24 22:12:59 +00:00
dependabot[bot]
2ce1a4e050
chore(deps): bump thirdparty/libtomcrypt from 2e9f2b5 to 427e055
Bumps [thirdparty/libtomcrypt](https://github.com/libtom/libtomcrypt) from `2e9f2b5` to `427e055`.
- [Release notes](https://github.com/libtom/libtomcrypt/releases)
- [Commits](2e9f2b5e44...427e0551c0)

---
updated-dependencies:
- dependency-name: thirdparty/libtomcrypt
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-24 22:12:57 +00:00
dependabot[bot]
89e22329f8
chore(deps): bump thirdparty/eigen from abac563 to 4a6ac97
Bumps [thirdparty/eigen](https://gitlab.com/libeigen/eigen) from `abac563` to `4a6ac97`.
- [Release notes](https://gitlab.com/libeigen/eigen/tags)
- [Commits](abac563f5d...4a6ac97d13)

---
updated-dependencies:
- dependency-name: thirdparty/eigen
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-24 22:12:55 +00:00
Jan
bea601d932
Merge pull request #360 from Laupetin/fix/gltf-multiple-mesh-loading
fix: loading of gltf with multiple meshes
2025-01-23 23:47:50 +01:00
Jan
826c1d2f2d
fix: loading of gltf with multiple meshes 2025-01-23 22:25:38 +00:00
Jan
0b91eeb932
Merge pull request #359 from Laupetin/fix/load-gltf-base64
fix: loading of base64 data from gltf files
2025-01-23 22:40:44 +01:00
Jan
94ca0ab79e
fix: loading of base64 data from gltf files 2025-01-23 21:17:51 +00:00
Jan
f6d36b2d6e
Merge pull request #358 from Laupetin/feature/gltf-separate-meshes
feat: separate objects into gltf meshes instead of primitives
2025-01-23 19:12:04 +01:00
Jan
140eb7b7a4
feat: dump objects into gltf meshes instead of primitives 2025-01-23 17:47:30 +00:00
Jan
708e759f8c
chore: update code style of gltf writer 2025-01-23 17:23:33 +00:00
Jan
80fa61b45c
chore: update xmodel dumper code style 2025-01-23 17:09:09 +00:00
Jan
f436cd6caa
Merge pull request #357 from Laupetin/fix/load-non-reference-assets
fix: load non reference assets
2025-01-21 23:42:31 +01:00
Jan
4d0b0651eb
fix: formatting 2025-01-21 23:20:55 +01:00
Jan
7a639a359c
fix: not being able to ignore assets of type attachment,attachmentunique 2025-01-21 22:17:06 +00:00
Jan
990bfe27df
chore: add force loading of assets 2025-01-21 22:16:55 +00:00
Jan
b4194eff28
chore: always use dynamic asset pools and remove static implementation 2025-01-21 22:14:24 +00:00
Jan
8ace49b715
Merge pull request #353 from Laupetin/dependabot/submodules/thirdparty/json-e72046e
chore(deps): bump thirdparty/json from `2d42229` to `e72046e`
2025-01-18 11:45:17 +01:00
Jan
b623ed49a0
Merge pull request #352 from Laupetin/dependabot/submodules/thirdparty/eigen-abac563
chore(deps): bump thirdparty/eigen from `9836e8d` to `abac563`
2025-01-18 11:45:07 +01:00
dependabot[bot]
0ffbdf5b73
chore(deps): bump thirdparty/json from 2d42229 to e72046e
Bumps [thirdparty/json](https://github.com/nlohmann/json) from `2d42229` to `e72046e`.
- [Release notes](https://github.com/nlohmann/json/releases)
- [Commits](2d42229f4d...e72046ef9f)

---
updated-dependencies:
- dependency-name: thirdparty/json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-17 22:48:29 +00:00
dependabot[bot]
f930c874b8
chore(deps): bump thirdparty/eigen from 9836e8d to abac563
Bumps [thirdparty/eigen](https://gitlab.com/libeigen/eigen) from `9836e8d` to `abac563`.
- [Release notes](https://gitlab.com/libeigen/eigen/tags)
- [Commits](9836e8d035...abac563f5d)

---
updated-dependencies:
- dependency-name: thirdparty/eigen
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-17 22:48:27 +00:00
Jan
74f84cbf83
Merge pull request #351 from Laupetin/fix/invalid-dds-mip-map-flags
fix: support dds files that lie about their mipmaps
2025-01-15 20:44:00 +01:00
Jan
8c453f1683
fix: support dds files that lie about their mipmaps 2025-01-15 19:18:04 +00:00
Jan
aa73dca59d
Merge pull request #350 from Laupetin/fix/not-loading-iwd
fix: not loading iwds from search-path in Unlinker
2025-01-15 19:10:13 +01:00
Jan
a41d15d43a
fix: not loading iwds from search-path in Unlinker 2025-01-15 17:47:33 +00:00
Jan
64bac44e63
Merge pull request #348 from Laupetin/fix/t6-long-fastfile-names
fix: long fastfile names
2025-01-15 01:09:57 +01:00
Jan
85d9f1c255
fix: salsa20 encryption only initializes encryption with zone name of at max 31 characters length 2025-01-15 00:47:01 +01:00
Jan
d9f23a0b76
fix: make file name verification consider max file name length in zone properly 2025-01-15 00:46:22 +01:00
Jan
a1d3e64813
Merge pull request #347 from Laupetin/refactor/outpath-search-path
refactor: use OutputPathFilesystem for writing fastfiles
2025-01-14 23:38:34 +01:00
Jan
cc67f6e730
refactor: use OutputPathFilesystem for writing fastfiles 2025-01-14 22:03:44 +01:00
Jan
a364e63258
Merge pull request #346 from Laupetin/refactor/remove-memorymanager-create
refactor: remove MemoryManager create method usages
2025-01-13 23:26:00 +01:00
Jan
4c09e94220
refactor: remove MemoryManager create method usages 2025-01-13 22:03:20 +00:00
Jan
62f1ac41c5
chore: remove debug log in generate script 2025-01-13 20:19:36 +00:00
Jan
fea4970b84
Merge pull request #345 from Laupetin/chore/premake-update
chore: remove premake5 executable from repo
2025-01-13 20:40:18 +01:00
Jan
0f1c67b54c
fix: properly interpret windows errorlevels 2025-01-13 19:15:21 +00:00
Jan
419481b4da
chore: add possibility to ignore premake5 from path 2025-01-13 01:27:32 +01:00
Jan
32c0ecb04d
chore: replace deprecated flags usage of FatalWarnings for premake 2025-01-12 23:45:11 +00:00
Jan
d1d4752114
chore: run generate script in ci 2025-01-12 23:41:23 +00:00
Jan
6e6bfca38c
chore: update premake version in ci 2025-01-12 23:49:17 +01:00
Jan
4240ddd4c7
chore: update and automatically install premake5 2025-01-12 23:47:59 +01:00
Jan
1d39062372
Merge pull request #341 from Laupetin/refactor/obj-dumping-output-path
refactor: obj dumping output path
2025-01-11 18:14:11 +01:00
Jan
2d58054ffc
refactor: make use of IOutputPath in ObjWriting 2025-01-11 17:52:04 +01:00
Jan
b584cd7423
fix: make sure creating directories in OutputPathFilesystem cannot lead to a crash 2025-01-11 13:05:45 +01:00
Jan
27c01e0a41
Merge pull request #339 from diamante0018/fix/recover-from-filesystem-ex
Recover from filesystem exception when dumping
2025-01-11 12:37:10 +01:00
Jan
a759f3d82b
Merge pull request #340 from Laupetin/fix/regressions-from-obj-compiling-refactor
fix: regressions from obj compiling refactor
2025-01-11 12:22:47 +01:00
Jan
c86f9f6391
fix: not accessing previous zone data when taking an asset from global asset pools 2025-01-11 11:57:09 +01:00
Jan
36f0764cd5
fix: not registering script strings for xmodel loading 2025-01-11 11:56:39 +01:00
Jan
0a98da9a79
fix: not calculating fields in t6 attachment unique loader 2025-01-11 11:56:04 +01:00
315eb76127
recover from filesystem exception when dumping 2025-01-11 11:20:12 +01:00
Jan
68665c79c9
Merge pull request #338 from Laupetin/dependabot/submodules/thirdparty/libtomcrypt-2e9f2b5
chore(deps): bump thirdparty/libtomcrypt from `c900951` to `2e9f2b5`
2025-01-11 00:32:51 +01:00
Jan
d04e76e635
Merge pull request #337 from Laupetin/dependabot/submodules/thirdparty/catch2-914aeec
chore(deps): bump thirdparty/catch2 from `0321d2f` to `914aeec`
2025-01-11 00:32:37 +01:00
Jan
50ece7dee2
Merge pull request #336 from Laupetin/dependabot/submodules/thirdparty/eigen-9836e8d
chore(deps): bump thirdparty/eigen from `7bb23b1` to `9836e8d`
2025-01-11 00:32:24 +01:00
Jan
9535342e60
Merge pull request #335 from Laupetin/dependabot/submodules/thirdparty/json-2d42229
chore(deps): bump thirdparty/json from `60c4875` to `2d42229`
2025-01-11 00:32:08 +01:00
dependabot[bot]
44440ab92e
chore(deps): bump thirdparty/libtomcrypt from c900951 to 2e9f2b5
Bumps [thirdparty/libtomcrypt](https://github.com/libtom/libtomcrypt) from `c900951` to `2e9f2b5`.
- [Release notes](https://github.com/libtom/libtomcrypt/releases)
- [Commits](c900951dab...2e9f2b5e44)

---
updated-dependencies:
- dependency-name: thirdparty/libtomcrypt
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-10 22:56:08 +00:00
dependabot[bot]
f449527e51
chore(deps): bump thirdparty/catch2 from 0321d2f to 914aeec
Bumps [thirdparty/catch2](https://github.com/catchorg/Catch2) from `0321d2f` to `914aeec`.
- [Release notes](https://github.com/catchorg/Catch2/releases)
- [Commits](0321d2fce3...914aeecfe2)

---
updated-dependencies:
- dependency-name: thirdparty/catch2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-10 22:56:06 +00:00
dependabot[bot]
77c6e2d53c
chore(deps): bump thirdparty/eigen from 7bb23b1 to 9836e8d
Bumps [thirdparty/eigen](https://gitlab.com/libeigen/eigen) from `7bb23b1` to `9836e8d`.
- [Release notes](https://gitlab.com/libeigen/eigen/tags)
- [Commits](7bb23b1e36...9836e8d035)

---
updated-dependencies:
- dependency-name: thirdparty/eigen
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-10 22:56:04 +00:00
dependabot[bot]
2c5f5215f3
chore(deps): bump thirdparty/json from 60c4875 to 2d42229
Bumps [thirdparty/json](https://github.com/nlohmann/json) from `60c4875` to `2d42229`.
- [Release notes](https://github.com/nlohmann/json/releases)
- [Commits](60c48755e3...2d42229f4d)

---
updated-dependencies:
- dependency-name: thirdparty/json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-10 22:56:03 +00:00
Jan
5d69473551
Merge pull request #333 from awsms/main
tiny mistakes in the filenames of the make scripts
2025-01-10 16:16:03 +01:00
awsms
e5e92b7b23 tiny mistakes in the filenames of the make scripts 2025-01-10 13:52:15 +01:00
Jan
98288f5d47
Merge pull request #330 from Laupetin/test/obj-compiling-tests
Add tests for ObjCompiling module
2025-01-08 22:55:18 +01:00
Jan
d1e6aa9da0
test: add unit test for IwdCreator 2025-01-08 21:25:48 +00:00
Jan
fa249b0bd3
test: add unit test for IPakCreator 2025-01-08 21:05:11 +00:00
Jan
54e240e98c
fix: compilation 2025-01-08 17:39:34 +00:00
Jan
3b5ca86b0d
test: add unit test for ImageIwdPostProcessor 2025-01-08 17:37:19 +00:00
Jan
8c8ceae0bd
test: add unit test for ImageIPakPostProcessor 2025-01-08 17:36:01 +00:00
Jan
e0f8b3d3ca
chore: add abstraction for opening output files to be able to mock it 2025-01-07 00:02:38 +01:00
Jan
cacccf64e1
fix: make sure kvps are in a deterministic order 2025-01-05 10:16:14 +00:00
Jan
67fb11506c
chore: initialize ipak and iwd post processors immediately in constructor 2025-01-05 09:35:52 +00:00
Jan
83833cb84e
fix: use canonical instead of absolute in test initialization 2025-01-05 09:05:47 +00:00
Jan
ce3786f086
chore: check exact paths of test executable and provide temp dir 2025-01-05 00:16:58 +00:00
Jan
fc9e6ce14d
test: add test for KeyValuePairsCompilerT6 2025-01-05 00:16:57 +00:00
Jan
16e82f68ca
Merge pull request #332 from Laupetin/dependabot/submodules/thirdparty/json-60c4875
chore(deps): bump thirdparty/json from `6be4e85` to `60c4875`
2025-01-04 12:50:17 +01:00
Jan
dbecafd2a2
Merge pull request #331 from Laupetin/dependabot/submodules/thirdparty/eigen-7bb23b1
chore(deps): bump thirdparty/eigen from `24e0c2a` to `7bb23b1`
2025-01-04 12:50:04 +01:00
dependabot[bot]
3ef65f741b
chore(deps): bump thirdparty/json from 6be4e85 to 60c4875
Bumps [thirdparty/json](https://github.com/nlohmann/json) from `6be4e85` to `60c4875`.
- [Release notes](https://github.com/nlohmann/json/releases)
- [Commits](6be4e85600...60c48755e3)

---
updated-dependencies:
- dependency-name: thirdparty/json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-03 22:39:34 +00:00
dependabot[bot]
768f4337f7
chore(deps): bump thirdparty/eigen from 24e0c2a to 7bb23b1
Bumps [thirdparty/eigen](https://gitlab.com/libeigen/eigen) from `24e0c2a` to `7bb23b1`.
- [Release notes](https://gitlab.com/libeigen/eigen/tags)
- [Commits](24e0c2a125...7bb23b1e36)

---
updated-dependencies:
- dependency-name: thirdparty/eigen
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-03 22:39:32 +00:00
Jan
a781aae1c9
Merge pull request #286 from Laupetin/feature/obj-container-improvements
feat: improve building IWD and IPak obj containers
2025-01-03 15:16:45 +01:00
Jan
b84c719d3f
chore: add missing headers 2025-01-03 14:55:19 +01:00
Jan
ac43b646cc
feat: automatically add ipak_read kvp when creating ipak 2025-01-03 14:55:19 +01:00
Jan
2313da1c12
chore: inject ZoneAssetCreationStateCollection to states 2025-01-03 14:55:19 +01:00
Jan
ef862ff246
chore: make keyvaluepairscompiler use a zonestate 2025-01-03 14:55:19 +01:00
Jan
3c3161448f
chore: get Iwd and Ipak creators in constructor for post processors 2025-01-03 11:18:33 +01:00
Jan
416823c6cd
chore: rename ZoneAssetLoaderState to ZoneAssetCreationState 2025-01-03 11:01:44 +01:00
Jan
9068e96dfa
chore: make IZoneLoadingState return reference 2025-01-03 10:42:37 +01:00
Jan
fa6f9451d2
chore: extract ZoneAssetLoaderContainer to separate class 2025-01-03 10:25:51 +01:00
Jan
41d97c0954
chore: initialize KeyValuePairsCompiler for T6 as obj compiler 2025-01-03 09:59:28 +01:00
Jan
e92797e0b8
chore: remove outdated ipak code 2025-01-02 23:16:03 +01:00
Jan
ca761dfdbc
chore: do not fail upon failure to find ipak file 2025-01-02 22:59:21 +01:00
Jan
9097db7d0f
fix: compilation on windows 2025-01-02 22:39:14 +01:00
Jan
dfd6e4117c
feat: write data to ipak files 2025-01-02 17:59:49 +01:00
Jan
351b6bb1ea
feat: write iwi data to specified iwds 2025-01-02 17:54:46 +01:00
Jan
fe5d0f79ff
chore: consider specified obj containers when post processing 2025-01-02 16:26:42 +01:00
Jan
a7254aa11c
feat: add post processors compiling iwds and ipaks 2025-01-02 12:57:10 +01:00
Jan
b5937ef975
fix: fix not finalizing obj containers when parsing zone definition 2025-01-01 21:19:28 +01:00
Jan
aa212e0958
chore: parse includes and assetlists while parsing zone definition 2025-01-01 18:14:43 +01:00
Jan
9852f52a15
chore: get rid of now unused AssetLoading classes 2025-01-01 18:14:43 +01:00
Jan
e11e8a361e
chore: adjust message when no asset creator could create asset 2025-01-01 18:14:43 +01:00
Jan
dd4f18b638
chore: do not consider not finding global asset a failure 2025-01-01 18:14:42 +01:00
Jan
ffac925410
fix: reallocate assets before adding to zone pool when loading from
fastfile
2025-01-01 18:14:42 +01:00
Jan
da7a60221c
fix: initialize default asset creator collection 2025-01-01 18:14:42 +01:00
Jan
27ef3152a0
chore: do not initialize zone pools in ZoneCreator 2025-01-01 18:14:42 +01:00
Jan
b7c8c70f2a
fix: compilation 2025-01-01 18:14:42 +01:00
Jan
80c4a9a2ae
fix: do not reallocate assets for dynamic asset pool 2025-01-01 18:14:42 +01:00
Jan
306ffb730e
chore: fix error in ZoneCreator 2025-01-01 18:14:42 +01:00
Jan
692c31b711
chore: fix test compilation 2025-01-01 18:14:42 +01:00
Jan
83d13aa166
chore: fix loading and writing code for T6 2025-01-01 18:14:41 +01:00
Jan
d8bc156ffd
chore: fix loading and writing code for T5 2025-01-01 18:14:41 +01:00
Jan
a36581b06e
chore: fix loading and writing code for IW5 2025-01-01 18:14:41 +01:00
Jan
9ae5aaa1db
chore: fix loading and writing code for IW4 2025-01-01 18:14:41 +01:00
Jan
a5873a301f
chore: adjust IW3 asset loaders to fit IW4 format 2025-01-01 18:14:41 +01:00
Jan
7ef944ebd4
chore: refactor IW4 asset loaders 2025-01-01 18:14:41 +01:00
Jan
f9456101e6
chore: enable all currently implemented loaders for iw3 2025-01-01 18:14:41 +01:00
Jan
4f585c6aa7
chore: add generic default asset constructors for all games 2025-01-01 18:14:40 +01:00
Jan
9ebea5034a
chore: generalize default asset creators 2025-01-01 18:14:40 +01:00
Jan
c524cb007a
chore: implement obj loading skeleton with localize asset 2025-01-01 18:14:40 +01:00
Jan
673db0592f
chore: add scripts for formatting via docker containers 2025-01-01 18:14:40 +01:00
Jan
2c8fcf1630
chore: formatting 2025-01-01 18:14:40 +01:00
Jan
4f0a405bdc
chore: adjust asset creation process to use separated AssetCreators 2025-01-01 18:14:40 +01:00
Jan
63046f5681
chore: do not add duplicate paths in LinkerPaths 2025-01-01 18:14:40 +01:00
Jan
a240824706
chore: normalize paths before making use of them in LinkerPaths 2025-01-01 18:14:39 +01:00
Jan
110f31e58a
chore: fix linux build 2025-01-01 18:14:39 +01:00
Jan
be6c30c503
refactor: rework search paths 2025-01-01 18:14:39 +01:00
Jan
fd421c4784
chore: use std format for linker and unlinker args 2025-01-01 18:14:39 +01:00
Jan
3803ae24f5
chore: add ObjCompiling component 2025-01-01 18:14:39 +01:00
Jan
f9e0bdaa7b
chore: always build fastfile when there are assets defined 2025-01-01 18:14:39 +01:00
Jan
2182196730
feat: add ipak and iwd zone definition metadata to replace type 2025-01-01 18:14:39 +01:00
Jan
973ff73554
Merge pull request #324 from Laupetin/dependabot/submodules/thirdparty/json-6be4e85
chore(deps): bump thirdparty/json from `af4ad79` to `6be4e85`
2024-12-31 12:40:55 +01:00
dependabot[bot]
7097e36d27
chore(deps): bump thirdparty/json from af4ad79 to 6be4e85
Bumps [thirdparty/json](https://github.com/nlohmann/json) from `af4ad79` to `6be4e85`.
- [Release notes](https://github.com/nlohmann/json/releases)
- [Commits](af4ad7915c...6be4e85600)

---
updated-dependencies:
- dependency-name: thirdparty/json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-27 22:06:52 +00:00
Jan
a98fa5b5e3
Merge pull request #323 from Laupetin/dependabot/submodules/thirdparty/eigen-24e0c2a
chore(deps): bump thirdparty/eigen from `af59ada` to `24e0c2a`
2024-12-23 18:28:08 +01:00
Jan
f3d8addde8
Merge pull request #322 from Laupetin/dependabot/submodules/thirdparty/json-af4ad79
chore(deps): bump thirdparty/json from `620034e` to `af4ad79`
2024-12-23 18:27:52 +01:00
Jan
00ab5e69e1
Merge pull request #321 from Laupetin/dependabot/submodules/thirdparty/libtomcrypt-c900951
chore(deps): bump thirdparty/libtomcrypt from `a81dab9` to `c900951`
2024-12-23 18:27:31 +01:00
dependabot[bot]
1a5ebb0d81
chore(deps): bump thirdparty/eigen from af59ada to 24e0c2a
Bumps [thirdparty/eigen](https://gitlab.com/libeigen/eigen) from `af59ada` to `24e0c2a`.
- [Release notes](https://gitlab.com/libeigen/eigen/tags)
- [Commits](af59ada0ac...24e0c2a125)

---
updated-dependencies:
- dependency-name: thirdparty/eigen
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-20 22:44:26 +00:00
dependabot[bot]
a17360c916
chore(deps): bump thirdparty/json from 620034e to af4ad79
Bumps [thirdparty/json](https://github.com/nlohmann/json) from `620034e` to `af4ad79`.
- [Release notes](https://github.com/nlohmann/json/releases)
- [Commits](620034ecec...af4ad7915c)

---
updated-dependencies:
- dependency-name: thirdparty/json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-20 22:44:24 +00:00
dependabot[bot]
f6921acbc2
chore(deps): bump thirdparty/libtomcrypt from a81dab9 to c900951
Bumps [thirdparty/libtomcrypt](https://github.com/libtom/libtomcrypt) from `a81dab9` to `c900951`.
- [Release notes](https://github.com/libtom/libtomcrypt/releases)
- [Commits](a81dab9970...c900951dab)

---
updated-dependencies:
- dependency-name: thirdparty/libtomcrypt
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-20 22:44:23 +00:00
Jan
3db816fb7f
Merge pull request #320 from Laupetin/dependabot/submodules/thirdparty/eigen-af59ada
chore(deps): bump thirdparty/eigen from `fd48fbb` to `af59ada`
2024-12-19 17:14:30 +01:00
Jan
50e396c587
Merge pull request #319 from Laupetin/dependabot/submodules/thirdparty/json-620034e
chore(deps): bump thirdparty/json from `9f60e85` to `620034e`
2024-12-19 17:14:11 +01:00
Jan
cc39a394e6
Merge pull request #318 from Laupetin/dependabot/submodules/thirdparty/libtomcrypt-a81dab9
chore(deps): bump thirdparty/libtomcrypt from `507c668` to `a81dab9`
2024-12-19 17:13:57 +01:00
dependabot[bot]
b16198c705
chore(deps): bump thirdparty/eigen from fd48fbb to af59ada
Bumps [thirdparty/eigen](https://gitlab.com/libeigen/eigen) from `fd48fbb` to `af59ada`.
- [Release notes](https://gitlab.com/libeigen/eigen/tags)
- [Commits](fd48fbb260...af59ada0ac)

---
updated-dependencies:
- dependency-name: thirdparty/eigen
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-13 22:33:52 +00:00
dependabot[bot]
f1f13d09eb
chore(deps): bump thirdparty/json from 9f60e85 to 620034e
Bumps [thirdparty/json](https://github.com/nlohmann/json) from `9f60e85` to `620034e`.
- [Release notes](https://github.com/nlohmann/json/releases)
- [Commits](9f60e85557...620034ecec)

---
updated-dependencies:
- dependency-name: thirdparty/json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-13 22:33:51 +00:00
dependabot[bot]
5e02352784
chore(deps): bump thirdparty/libtomcrypt from 507c668 to a81dab9
Bumps [thirdparty/libtomcrypt](https://github.com/libtom/libtomcrypt) from `507c668` to `a81dab9`.
- [Release notes](https://github.com/libtom/libtomcrypt/releases)
- [Commits](507c66827f...a81dab9970)

---
updated-dependencies:
- dependency-name: thirdparty/libtomcrypt
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-13 22:33:48 +00:00
Jan
ce3f2c6d97
Merge pull request #317 from Laupetin/dependabot/submodules/thirdparty/json-9f60e85
chore(deps): bump thirdparty/json from `1b9a9d1` to `9f60e85`
2024-12-07 14:03:38 +01:00
Jan
b571024385
Merge pull request #316 from Laupetin/dependabot/submodules/thirdparty/libtomcrypt-507c668
chore(deps): bump thirdparty/libtomcrypt from `1764254` to `507c668`
2024-12-07 14:03:26 +01:00
Jan
fa250531b2
Merge pull request #315 from Laupetin/dependabot/submodules/thirdparty/eigen-fd48fbb
chore(deps): bump thirdparty/eigen from `d34b100` to `fd48fbb`
2024-12-07 14:03:11 +01:00
dependabot[bot]
9d37005445
chore(deps): bump thirdparty/json from 1b9a9d1 to 9f60e85
Bumps [thirdparty/json](https://github.com/nlohmann/json) from `1b9a9d1` to `9f60e85`.
- [Release notes](https://github.com/nlohmann/json/releases)
- [Commits](1b9a9d1f21...9f60e85557)

---
updated-dependencies:
- dependency-name: thirdparty/json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-06 23:00:10 +00:00
dependabot[bot]
45ac414c11
chore(deps): bump thirdparty/libtomcrypt from 1764254 to 507c668
Bumps [thirdparty/libtomcrypt](https://github.com/libtom/libtomcrypt) from `1764254` to `507c668`.
- [Release notes](https://github.com/libtom/libtomcrypt/releases)
- [Commits](17642547e4...507c66827f)

---
updated-dependencies:
- dependency-name: thirdparty/libtomcrypt
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-06 23:00:08 +00:00
dependabot[bot]
6d7fed74a6
chore(deps): bump thirdparty/eigen from d34b100 to fd48fbb
Bumps [thirdparty/eigen](https://gitlab.com/libeigen/eigen) from `d34b100` to `fd48fbb`.
- [Release notes](https://gitlab.com/libeigen/eigen/tags)
- [Commits](d34b100c13...fd48fbb260)

---
updated-dependencies:
- dependency-name: thirdparty/eigen
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-06 23:00:06 +00:00
Jan
815f484aa6
Merge pull request #314 from Laupetin/dependabot/submodules/thirdparty/json-1b9a9d1
chore(deps): bump thirdparty/json from `a97041a` to `1b9a9d1`
2024-12-06 11:08:15 +01:00
Jan
fddfe57d99
Merge pull request #313 from Laupetin/dependabot/submodules/thirdparty/eigen-d34b100
chore(deps): bump thirdparty/eigen from `8ad4344` to `d34b100`
2024-12-06 11:08:05 +01:00
dependabot[bot]
9ab581c072
chore(deps): bump thirdparty/json from a97041a to 1b9a9d1
Bumps [thirdparty/json](https://github.com/nlohmann/json) from `a97041a` to `1b9a9d1`.
- [Release notes](https://github.com/nlohmann/json/releases)
- [Commits](a97041a98f...1b9a9d1f21)

---
updated-dependencies:
- dependency-name: thirdparty/json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-29 22:35:56 +00:00
dependabot[bot]
96b055a37b
chore(deps): bump thirdparty/eigen from 8ad4344 to d34b100
Bumps [thirdparty/eigen](https://gitlab.com/libeigen/eigen) from `8ad4344` to `d34b100`.
- [Release notes](https://gitlab.com/libeigen/eigen/tags)
- [Commits](8ad4344ca7...d34b100c13)

---
updated-dependencies:
- dependency-name: thirdparty/eigen
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-29 22:35:54 +00:00
Jan
b5e50c87fb
Merge pull request #310 from Laupetin/dependabot/submodules/thirdparty/catch2-0321d2f
chore(deps): bump thirdparty/catch2 from `506276c` to `0321d2f`
2024-11-27 11:59:15 +01:00
Jan
2c837a53b9
Merge pull request #311 from Laupetin/dependabot/submodules/thirdparty/json-a97041a
chore(deps): bump thirdparty/json from `fde9a86` to `a97041a`
2024-11-27 11:59:05 +01:00
Jan
d4a9211211
Merge pull request #312 from Laupetin/dependabot/submodules/thirdparty/eigen-8ad4344
chore(deps): bump thirdparty/eigen from `d6e3b52` to `8ad4344`
2024-11-27 11:58:56 +01:00
Jan
39a5564186
Merge pull request #309 from Laupetin/dependabot/submodules/thirdparty/libtomcrypt-1764254
chore(deps): bump thirdparty/libtomcrypt from `5d2b154` to `1764254`
2024-11-27 11:58:47 +01:00
dependabot[bot]
76aed9af14
chore(deps): bump thirdparty/eigen from d6e3b52 to 8ad4344
Bumps [thirdparty/eigen](https://gitlab.com/libeigen/eigen) from `d6e3b52` to `8ad4344`.
- [Release notes](https://gitlab.com/libeigen/eigen/tags)
- [Commits](d6e3b528b2...8ad4344ca7)

---
updated-dependencies:
- dependency-name: thirdparty/eigen
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-22 22:32:52 +00:00
dependabot[bot]
e6f8ec3419
chore(deps): bump thirdparty/json from fde9a86 to a97041a
Bumps [thirdparty/json](https://github.com/nlohmann/json) from `fde9a86` to `a97041a`.
- [Release notes](https://github.com/nlohmann/json/releases)
- [Commits](fde9a86c5a...a97041a98f)

---
updated-dependencies:
- dependency-name: thirdparty/json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-22 22:32:50 +00:00
dependabot[bot]
130933ac29
chore(deps): bump thirdparty/catch2 from 506276c to 0321d2f
Bumps [thirdparty/catch2](https://github.com/catchorg/Catch2) from `506276c` to `0321d2f`.
- [Release notes](https://github.com/catchorg/Catch2/releases)
- [Commits](506276c592...0321d2fce3)

---
updated-dependencies:
- dependency-name: thirdparty/catch2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-22 22:32:48 +00:00
dependabot[bot]
9da2f5e788
chore(deps): bump thirdparty/libtomcrypt from 5d2b154 to 1764254
Bumps [thirdparty/libtomcrypt](https://github.com/libtom/libtomcrypt) from `5d2b154` to `1764254`.
- [Release notes](https://github.com/libtom/libtomcrypt/releases)
- [Commits](5d2b15472f...17642547e4)

---
updated-dependencies:
- dependency-name: thirdparty/libtomcrypt
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-22 22:32:45 +00:00
Jan
a2063057ec
Merge pull request #308 from Laupetin/dependabot/submodules/thirdparty/zlib-ef24c4c
chore(deps): bump thirdparty/zlib from `d476828` to `ef24c4c`
2024-11-17 18:20:00 +01:00
Jan
59ff4c0b1d
Merge pull request #307 from Laupetin/dependabot/submodules/thirdparty/libtomcrypt-5d2b154
chore(deps): bump thirdparty/libtomcrypt from `2dd6690` to `5d2b154`
2024-11-17 18:19:51 +01:00
Jan
ecf2a026f7
Merge pull request #306 from Laupetin/dependabot/submodules/thirdparty/eigen-d6e3b52
chore(deps): bump thirdparty/eigen from `0d366f6` to `d6e3b52`
2024-11-17 18:19:41 +01:00
Jan
6117f4c206
Merge pull request #305 from Laupetin/dependabot/submodules/thirdparty/json-fde9a86
chore(deps): bump thirdparty/json from `18ff442` to `fde9a86`
2024-11-17 18:19:32 +01:00
Jan
a6340adb38
Merge pull request #304 from Laupetin/dependabot/submodules/thirdparty/catch2-506276c
chore(deps): bump thirdparty/catch2 from `119a7bb` to `506276c`
2024-11-17 18:19:21 +01:00
dependabot[bot]
66beda8723
chore(deps): bump thirdparty/zlib from d476828 to ef24c4c
Bumps [thirdparty/zlib](https://github.com/madler/zlib) from `d476828` to `ef24c4c`.
- [Release notes](https://github.com/madler/zlib/releases)
- [Commits](d476828316...ef24c4c750)

---
updated-dependencies:
- dependency-name: thirdparty/zlib
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-15 22:08:04 +00:00
dependabot[bot]
46da761892
chore(deps): bump thirdparty/libtomcrypt from 2dd6690 to 5d2b154
Bumps [thirdparty/libtomcrypt](https://github.com/libtom/libtomcrypt) from `2dd6690` to `5d2b154`.
- [Release notes](https://github.com/libtom/libtomcrypt/releases)
- [Commits](2dd6690edf...5d2b15472f)

---
updated-dependencies:
- dependency-name: thirdparty/libtomcrypt
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-15 22:08:03 +00:00
dependabot[bot]
6fb132dbfc
chore(deps): bump thirdparty/eigen from 0d366f6 to d6e3b52
Bumps [thirdparty/eigen](https://gitlab.com/libeigen/eigen) from `0d366f6` to `d6e3b52`.
- [Release notes](https://gitlab.com/libeigen/eigen/tags)
- [Commits](0d366f6532...d6e3b528b2)

---
updated-dependencies:
- dependency-name: thirdparty/eigen
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-15 22:08:01 +00:00
dependabot[bot]
4572687502
chore(deps): bump thirdparty/json from 18ff442 to fde9a86
Bumps [thirdparty/json](https://github.com/nlohmann/json) from `18ff442` to `fde9a86`.
- [Release notes](https://github.com/nlohmann/json/releases)
- [Commits](18ff442e63...fde9a86c5a)

---
updated-dependencies:
- dependency-name: thirdparty/json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-15 22:08:00 +00:00
dependabot[bot]
7fb5c98894
chore(deps): bump thirdparty/catch2 from 119a7bb to 506276c
Bumps [thirdparty/catch2](https://github.com/catchorg/Catch2) from `119a7bb` to `506276c`.
- [Release notes](https://github.com/catchorg/Catch2/releases)
- [Commits](119a7bbe53...506276c592)

---
updated-dependencies:
- dependency-name: thirdparty/catch2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-15 22:07:58 +00:00
983 changed files with 21670 additions and 20332 deletions

View File

@ -8,20 +8,15 @@ on:
branches:
- "main"
env:
PREMAKE_VERSION: "5.0.0-beta2"
jobs:
build-test-linux:
env:
PREMAKE_CONFIG: gmake2
runs-on: ubuntu-latest
container: ubuntu:24.04
steps:
- name: Install g++ and multilib
run: |
apt-get update
apt-get install -y git make gcc-13 g++-13 gcc-13-multilib g++-13-multilib
apt-get install -y wget tar git make gcc-13 g++-13 gcc-13-multilib g++-13-multilib
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
update-alternatives --set gcc /usr/bin/gcc-13
@ -32,14 +27,11 @@ jobs:
with:
submodules: recursive
- name: Setup premake
uses: abel0b/setup-premake@v2.4
with:
version: ${{ env.PREMAKE_VERSION }}
- name: Premake generate
working-directory: ${{ github.workspace }}
run: premake5 ${{ env.PREMAKE_CONFIG }}
env:
PREMAKE_NO_PROMPT: 1
run: ./generate.sh
- name: Build
working-directory: ${{ github.workspace }}
@ -49,14 +41,13 @@ jobs:
working-directory: ${{ github.workspace }}/build/lib/Release_x86/tests
run: |
./ObjCommonTests
./ObjCompilingTests
./ObjLoadingTests
./ParserTests
./ZoneCodeGeneratorLibTests
./ZoneCommonTests
build-test-windows:
env:
PREMAKE_CONFIG: vs2022
runs-on: windows-latest
steps:
- name: Checkout repository
@ -67,14 +58,11 @@ jobs:
- name: Add MSBuild to PATH
uses: microsoft/setup-msbuild@v2.0.0
- name: Setup premake
uses: abel0b/setup-premake@v2.4
with:
version: ${{ env.PREMAKE_VERSION }}
- name: Premake generate
working-directory: ${{ github.workspace }}
run: premake5 ${{ env.PREMAKE_CONFIG }}
env:
PREMAKE_NO_PROMPT: 1
run: ./generate.bat
- name: Build
working-directory: ${{ github.workspace }}
@ -86,6 +74,8 @@ jobs:
$combinedExitCode = 0
./ObjCommonTests
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
./ObjCompilingTests
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
./ObjLoadingTests
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
./ParserTests

View File

@ -5,20 +5,15 @@ on:
tags:
- "v*.*.*"
env:
PREMAKE_VERSION: "5.0.0-beta2"
jobs:
build-release-linux:
env:
PREMAKE_CONFIG: gmake2
runs-on: ubuntu-latest
container: ubuntu:24.04
steps:
- name: Install g++ and multilib
run: |
apt-get update
apt-get install -y git make gcc-13 g++-13 gcc-13-multilib g++-13-multilib
apt-get install -y wget tar git make gcc-13 g++-13 gcc-13-multilib g++-13-multilib
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
update-alternatives --set gcc /usr/bin/gcc-13
@ -29,14 +24,11 @@ jobs:
with:
submodules: recursive
- name: Setup premake
uses: abel0b/setup-premake@v2.4
with:
version: ${{ env.PREMAKE_VERSION }}
- name: Premake generate
working-directory: ${{ github.workspace }}
run: premake5 ${{ env.PREMAKE_CONFIG }}
env:
PREMAKE_NO_PROMPT: 1
run: ./generate.sh
- name: Build
working-directory: ${{ github.workspace }}
@ -50,8 +42,6 @@ jobs:
${{ github.workspace }}/build/bin/Release_x86
build-release-windows:
env:
PREMAKE_CONFIG: vs2022
runs-on: windows-latest
steps:
- name: Checkout repository
@ -62,28 +52,25 @@ jobs:
- name: Add MSBuild to PATH
uses: microsoft/setup-msbuild@v2.0.0
- name: Setup premake
uses: abel0b/setup-premake@v2.4
with:
version: ${{ env.PREMAKE_VERSION }}
- name: Premake generate
working-directory: ${{ github.workspace }}
run: premake5 ${{ env.PREMAKE_CONFIG }}
env:
PREMAKE_NO_PROMPT: 1
run: ./generate.bat
- name: Build
working-directory: ${{ github.workspace }}
run: msbuild /m /p:Configuration=Release /p:Platform=Win32 build
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: oat-windows
path: |
${{ github.workspace }}/build/bin/Release_x86
release:
needs:
needs:
- build-release-linux
- build-release-windows
runs-on: ubuntu-latest
@ -106,4 +93,4 @@ jobs:
allowUpdates: true
draft: true
omitBodyDuringUpdate: true
omitDraftDuringUpdate: true
omitDraftDuringUpdate: true

View File

@ -93,7 +93,7 @@ Since you are most likely on a 64-bit machine you will also need multilib for co
Use `generate.sh` to generate make files.
When this is done you will have a `build` folder with a `Makefile`.
You now run `make` manually or use `./scripts/make_release.sh` or `./scripts/make_debug.sh` to build.
You now run `make` manually or use `./scripts/make-release.sh` or `./scripts/make-debug.sh` to build.
The resulting binaries can be found in `build/bin/<Debug_x86|Release_x86>`.

View File

@ -177,7 +177,7 @@ The following section specify which assets are supported to be dumped to disk (u
| ComWorld | ❌ | ❌ | |
| GameWorldSp | ❌ | ❌ | |
| GameWorldMp | ❌ | ❌ | |
| MapEnts | | ❌ | |
| MapEnts | | ❌ | |
| GfxWorld | ❌ | ❌ | |
| GfxLightDef | ❌ | ❌ | |
| Font_s | ❌ | ❌ | |

View File

@ -1,6 +1,85 @@
@echo off
set PREMAKE_URL="https://github.com/premake/premake-core/releases/download/v5.0.0-beta4/premake-5.0.0-beta4-windows.zip"
set PREMAKE_HASH="12d741d3b70445b025c03e26148e2d129801041fa5ddde61b4ac888a76017395"
@REM The following variables can be set:
@REM PREMAKE_NO_GLOBAL - Ignore premake5 executable from path
@REM PREMAKE_NO_PROMPT - Download premake5 without prompting
goto start
:downloadpremake
if not exist "build" mkdir "build"
where /q "pwsh"
IF NOT ERRORLEVEL 1 (
set POWERSHELL_BIN="pwsh"
) else (
set POWERSHELL_BIN="powershell"
)
echo Downloading...
%POWERSHELL_BIN% -NoProfile -NonInteractive -Command "Invoke-WebRequest %PREMAKE_URL% -OutFile build/premake.zip"
IF ERRORLEVEL 1 (
echo Download failed >&2
exit 2
)
echo Extracting...
%POWERSHELL_BIN% -NoProfile -NonInteractive -Command "Expand-Archive -LiteralPath build/premake.zip -DestinationPath build"
IF ERRORLEVEL 1 (
echo Extraction failed >&2
exit 2
)
rm build/premake.zip
echo Verifying hash...
%POWERSHELL_BIN% -NoProfile -NonInteractive -Command "if ((Get-FileHash -LiteralPath build/premake5.exe -Algorithm SHA256).Hash -eq \"%PREMAKE_HASH%\") { exit 0 } else { exit 1 }"
IF ERRORLEVEL 1 (
echo Hash verification failed >&2
rm build/premake5.exe
exit 2
)
exit /B 0
cd %~dp0
:start
IF "%PREMAKE_NO_GLOBAL%" EQU "" (
where /Q "premake5.exe"
IF NOT ERRORLEVEL 1 (
set PREMAKE_BIN="premake5.exe"
goto runpremake
)
)
IF EXIST build/premake5.exe (
set PREMAKE_BIN="build/premake5.exe"
goto runpremake
)
if "%PREMAKE_NO_PROMPT%" NEQ "" (
call:downloadpremake
set PREMAKE_BIN="build/premake5.exe"
goto runpremake
)
echo Could not find premake5. You can either install it yourself or this script download it for you.
set /p choice="Do you wish to download it automatically? [y/N]> "
if /i "%choice%" == "y" (
call:downloadpremake
set PREMAKE_BIN="build/premake5.exe"
goto runpremake
)
echo Please install premake5 and try again
exit 1
:runpremake
git submodule update --init --recursive
tools\premake5.exe %* vs2022
%PREMAKE_BIN% %* vs2022

View File

@ -1,7 +1,75 @@
#!/bin/bash
PREMAKE_URL='https://github.com/premake/premake-core/releases/download/v5.0.0-beta4/premake-5.0.0-beta4-linux.tar.gz'
PREMAKE_HASH='4356ab7cdec6085183d68fb240089376eacdc2fb751ffbd8063d797ae43abeb3'
# The following variables can be set:
# PREMAKE_NO_GLOBAL - Ignore premake5 executable from path
# PREMAKE_NO_PROMPT - Download premake5 without prompting
function install_premake {
if [[ ! -x "$(command -v wget)" ]]; then
echo "Failed: Installation requires wget" >&2
exit 2
fi
if [[ ! -x "$(command -v tar)" ]]; then
echo "Failed: Installation requires tar" >&2
exit 2
fi
if [[ ! -x "$(command -v sha256sum)" ]]; then
echo "Failed: Installation requires sha256sum" >&2
exit 2
fi
mkdir -p build
wget -nd -O build/premake.tar.gz "$PREMAKE_URL"
if [[ $? -ne 0 ]]; then
echo "Download failed" >&2
exit 2
fi
tar -xf build/premake.tar.gz -C build
if [[ $? -ne 0 ]]; then
echo "Extraction failed" >&2
exit 2
fi
rm build/premake.tar.gz
echo "${PREMAKE_HASH} build/premake5" | sha256sum -c
if [[ $? -ne 0 ]]; then
echo "Hash verification failed" >&2
rm build/premake5
exit 2
fi
chmod +x build/premake5
}
# Go to repository root
cd "$(dirname "$0")" || exit 2
if [[ ! -d ".git" ]]; then
echo "You must clone the OpenAssetTools repository using 'git clone'. Please read README.md." >&2
exit 1
fi
PREMAKE_BIN=''
if [[ -z "$PREMAKE_NO_GLOBAL" ]] && [[ -x "$(command -v premake5)" ]]; then
PREMAKE_BIN='premake5'
elif [[ -x "$(command -v build/premake5)" ]]; then
PREMAKE_BIN='build/premake5'
else
echo "Could not find premake5. You can either install it yourself or this script download it for you."
if [[ ! -z "$PREMAKE_NO_PROMPT" ]] || [[ "$(read -e -p 'Do you wish to download it automatically? [y/N]> '; echo $REPLY)" == [Yy]* ]]; then
echo "Installing premake"
install_premake
PREMAKE_BIN='build/premake5'
else
echo "Please install premake5 and try again"
exit 1
fi
fi
git submodule update --init --recursive
tools/premake5 $@ gmake2
$PREMAKE_BIN $@ gmake2

View File

@ -1,3 +1,5 @@
require("premake", ">=5.0.0-beta4")
include "tools/scripts/folders.lua"
include "tools/scripts/including.lua"
include "tools/scripts/linking.lua"
@ -14,7 +16,7 @@ workspace "OpenAssetTools"
objdir "%{wks.location}/obj"
symbols "On"
systemversion "latest"
cppdialect "C++20"
cppdialect "C++23"
largeaddressaware "on"
flags {
@ -52,13 +54,15 @@ workspace "OpenAssetTools"
symbols "On"
filter {}
filter {"system:windows", "configurations:Debug" }
buildoptions { "/bigobj" }
filter {}
filter "configurations:Release"
defines "NDEBUG"
optimize "Full"
symbols "Off"
flags {
"FatalWarnings"
}
fatalwarnings { "All" }
filter {}
defines {
@ -126,6 +130,7 @@ include "src/ZoneLoading.lua"
include "src/ZoneWriting.lua"
include "src/ZoneCommon.lua"
include "src/ObjCommon.lua"
include "src/ObjCompiling.lua"
include "src/ObjImage.lua"
include "src/ObjLoading.lua"
include "src/ObjWriting.lua"
@ -143,6 +148,7 @@ group "Components"
ZoneLoading:project()
ZoneWriting:project()
ObjCommon:project()
ObjCompiling:project()
ObjImage:project()
ObjLoading:project()
ObjWriting:project()
@ -168,7 +174,10 @@ group ""
-- ========================
-- Tests
-- ========================
include "test/Catch2Common.lua"
include "test/ObjCommonTestUtils.lua"
include "test/ObjCommonTests.lua"
include "test/ObjCompilingTests.lua"
include "test/ObjLoadingTests.lua"
include "test/ParserTestUtils.lua"
include "test/ParserTests.lua"
@ -177,7 +186,10 @@ include "test/ZoneCommonTests.lua"
-- Tests group: Unit test and other tests projects
group "Tests"
Catch2Common:project()
ObjCommonTestUtils:project()
ObjCommonTests:project()
ObjCompilingTests:project()
ObjLoadingTests:project()
ParserTestUtils:project()
ParserTests:project()

23
scripts/build.sh Executable file
View File

@ -0,0 +1,23 @@
#!/bin/bash
# Go to repository root
cd "$(dirname "$0")/.." || exit 2
TARGET='all'
ARCHITECTURE='x86'
CONFIG='debug'
for var in "$@"
do
if [ "$var" == "debug" ] || [ "$var" == "release" ]; then
CONFIG="$var"
elif [ "$var" == "x86" ] || [ "$var" == "x64" ]; then
ARCHITECTURE="$var"
else
TARGET="$var"
fi
done
echo "Building config=${CONFIG} architecture=${ARCHITECTURE} target=${TARGET}"
make -C build -j$(nproc) config=${CONFIG}_${ARCHITECTURE} "${TARGET}"

6
scripts/check-format-docker.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/bash
# Go to repository root
cd "$(dirname "$0")/.." || exit 2
docker run --rm -v ".:/code" --user "$(id -u):$(id -g)" silkeh/clang:17 /code/scripts/check-format.sh

View File

@ -4,4 +4,6 @@
cd "$(dirname "$0")/.." || exit 2
make -C build -j$(nproc) config=debug_x86 clean
make -C build -j$(nproc) config=release_x86 clean
make -C build -j$(nproc) config=release_x86 clean
make -C build -j$(nproc) config=debug_x64 clean
make -C build -j$(nproc) config=release_x64 clean

View File

@ -3,4 +3,4 @@
# Go to repository root
cd "$(dirname "$0")/.." || exit 2
make -C build -j$(nproc) config=debug_x86 all
make -C build -j$(nproc) config=debug_x86 all

View File

@ -4,4 +4,4 @@
cd "$(dirname "$0")/.." || exit 2
echo "Start building with $(nproc) threads"
make -C build -j$(nproc) config=release_x86 all
make -C build -j$(nproc) config=release_x86 all

6
scripts/reformat-all-docker.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/bash
# Go to repository root
cd "$(dirname "$0")/.." || exit 2
docker run --rm -v ".:/code" --user "$(id -u):$(id -g)" silkeh/clang:17 /code/scripts/reformat-all.sh

View File

@ -2,6 +2,9 @@
#include "Zone/ZoneTypes.h"
#include <stdexcept>
#include <type_traits>
struct IAssetBase
{
};
@ -12,3 +15,42 @@ public:
static constexpr auto EnumEntry = AssetTypeEnum;
using Type = AssetType;
};
template<typename AssetType> struct AssetNameAccessor
{
public:
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
// static constexpr bool IS_SINGLETON = false;
// const char*& operator()(AssetType::Type& asset)
// {
// throw std::runtime_error("Not implemented");
// }
};
#define DEFINE_ASSET_NAME_ACCESSOR(assetType, nameProperty) \
template<> struct AssetNameAccessor<assetType> \
{ \
public: \
static_assert(std::is_base_of_v<IAssetBase, assetType>); \
static constexpr bool IS_SINGLETON = false; \
\
const char*& operator()(assetType::Type& asset) \
{ \
return asset.nameProperty; \
} \
}
#define DEFINE_ASSET_NAME_ACCESSOR_SINGLETON(assetType, singletonName) \
template<> struct AssetNameAccessor<assetType> \
{ \
public: \
static_assert(std::is_base_of_v<IAssetBase, assetType>); \
static constexpr bool IS_SINGLETON = true; \
\
const char* const& operator()(assetType::Type& asset) \
{ \
static const char* NAME = singletonName; \
return NAME; \
} \
}

View File

@ -113,3 +113,32 @@ namespace IW3
using AssetRawFile = Asset<ASSET_TYPE_RAWFILE, RawFile>;
using AssetStringTable = Asset<ASSET_TYPE_STRINGTABLE, StringTable>;
} // namespace IW3
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetXModelPieces, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetPhysPreset, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetXAnim, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetXModel, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetMaterial, info.name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetTechniqueSet, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetImage, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetSound, aliasName);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetSoundCurve, filename);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetLoadedSound, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetClipMap, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetClipMapPvs, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetComWorld, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetGameWorldSp, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetGameWorldMp, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetMapEnts, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetGfxWorld, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetLightDef, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetFont, fontName);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetMenuList, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetMenu, window.name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetLocalize, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetWeapon, szInternalName);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetSoundDriverGlobals, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetFx, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetImpactFx, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetRawFile, name);
DEFINE_ASSET_NAME_ACCESSOR(IW3::AssetStringTable, name);

View File

@ -168,3 +168,41 @@ namespace IW4
using AssetVehicle = Asset<ASSET_TYPE_VEHICLE, VehicleDef>;
using AssetAddonMapEnts = Asset<ASSET_TYPE_ADDON_MAP_ENTS, AddonMapEnts>;
} // namespace IW4
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetPhysPreset, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetPhysCollMap, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetXAnim, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetXModelSurfs, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetXModel, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetMaterial, info.name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetPixelShader, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetVertexShader, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetVertexDecl, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetTechniqueSet, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetImage, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetSound, aliasName);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetSoundCurve, filename);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetLoadedSound, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetClipMapSp, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetClipMapMp, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetComWorld, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetGameWorldSp, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetGameWorldMp, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetMapEnts, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetFxWorld, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetGfxWorld, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetLightDef, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetFont, fontName);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetMenuList, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetMenu, window.name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetLocalize, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetWeapon, szInternalName);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetFx, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetImpactFx, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetRawFile, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetStringTable, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetLeaderboard, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetStructuredDataDef, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetTracer, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetVehicle, name);
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetAddonMapEnts, name);

View File

@ -179,3 +179,44 @@ namespace IW5
using AssetVehicle = Asset<ASSET_TYPE_VEHICLE, VehicleDef>;
using AssetAddonMapEnts = Asset<ASSET_TYPE_ADDON_MAP_ENTS, AddonMapEnts>;
} // namespace IW5
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetPhysPreset, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetPhysCollMap, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetXAnim, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetXModelSurfs, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetXModel, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetMaterial, info.name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetPixelShader, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetVertexShader, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetVertexDecl, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetTechniqueSet, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetImage, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetSound, aliasName);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetSoundCurve, filename);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetLoadedSound, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetClipMap, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetComWorld, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetGlassWorld, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetPathData, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetVehicleTrack, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetMapEnts, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetFxWorld, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetGfxWorld, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetLightDef, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetFont, fontName);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetMenuList, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetMenu, window.name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetLocalize, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetAttachment, szInternalName);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetWeapon, szInternalName);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetFx, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetImpactFx, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetSurfaceFx, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetRawFile, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetScript, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetStringTable, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetLeaderboard, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetStructuredDataDef, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetTracer, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetVehicle, name);
DEFINE_ASSET_NAME_ACCESSOR(IW5::AssetAddonMapEnts, name);

View File

@ -148,5 +148,38 @@ namespace T5
using AssetDDL = Asset<ASSET_TYPE_DDL, ddlRoot_t>;
using AssetGlasses = Asset<ASSET_TYPE_GLASSES, Glasses>;
using AssetEmblemSet = Asset<ASSET_TYPE_EMBLEMSET, EmblemSet>;
} // namespace T5
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetPhysPreset, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetPhysConstraints, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetDestructibleDef, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetXAnim, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetXModel, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetMaterial, info.name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetTechniqueSet, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetImage, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetSoundBank, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetSoundPatch, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetClipMap, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetClipMapPvs, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetComWorld, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetGameWorldSp, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetGameWorldMp, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetMapEnts, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetGfxWorld, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetLightDef, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetFont, fontName);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetMenuList, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetMenu, window.name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetLocalize, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetWeapon, szInternalName);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetSoundDriverGlobals, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetFx, name);
DEFINE_ASSET_NAME_ACCESSOR_SINGLETON(T5::AssetImpactFx, "ImpactFx");
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetRawFile, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetStringTable, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetPackIndex, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetXGlobals, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetDDL, name);
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetGlasses, name);
DEFINE_ASSET_NAME_ACCESSOR_SINGLETON(T5::AssetEmblemSet, "EmblemSet");

View File

@ -1311,7 +1311,7 @@ namespace T5
struct SndPatch
{
char* name;
const char* name;
unsigned int elementCount;
unsigned int* elements;
unsigned int fileCount;

View File

@ -209,3 +209,53 @@ namespace T6
using AssetFootstepFxTable = Asset<ASSET_TYPE_FOOTSTEPFX_TABLE, FootstepFXTableDef>;
using AssetZBarrier = Asset<ASSET_TYPE_ZBARRIER, ZBarrierDef>;
} // namespace T6
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetPhysPreset, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetPhysConstraints, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetDestructibleDef, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetXAnim, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetXModel, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetMaterial, info.name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetTechniqueSet, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetImage, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetSoundBank, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetSoundPatch, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetClipMap, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetClipMapPvs, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetComWorld, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetGameWorldSp, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetGameWorldMp, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetMapEnts, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetGfxWorld, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetLightDef, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetFont, fontName);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetFontIcon, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetMenuList, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetMenu, window.name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetLocalize, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetWeapon, szInternalName);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetAttachment, szInternalName);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetAttachmentUnique, szInternalName);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetWeaponCamo, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetSoundDriverGlobals, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetFx, name);
DEFINE_ASSET_NAME_ACCESSOR_SINGLETON(T6::AssetImpactFx, "ImpactFx");
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetRawFile, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetStringTable, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetLeaderboard, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetXGlobals, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetDDL, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetGlasses, name);
DEFINE_ASSET_NAME_ACCESSOR_SINGLETON(T6::AssetEmblemSet, "EmblemSet");
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetScript, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetKeyValuePairs, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetVehicle, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetMemoryBlock, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetAddonMapEnts, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetTracer, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetSkinnedVerts, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetQdb, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetSlug, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetFootstepTable, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetFootstepFxTable, name);
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetZBarrier, name);

View File

@ -2114,7 +2114,7 @@ namespace T6
struct KeyValuePairs
{
const char* name;
int numVariables;
unsigned int numVariables;
KeyValuePair* keyValuePairs;
};
@ -3814,7 +3814,8 @@ namespace T6
uint16_t dynEntId;
};
union gcc_align(8) __m128
// Usually __m128, but that is not portable
union gcc_align(8) custom_m128
{
float m128_f32[4];
uint64_t m128_u64[2];
@ -3827,19 +3828,12 @@ namespace T6
unsigned int m128_u32[4];
};
struct vector3
{
__m128 x;
__m128 y;
__m128 z;
};
struct vector4
{
__m128 x;
__m128 y;
__m128 z;
__m128 w;
custom_m128 x;
custom_m128 y;
custom_m128 z;
custom_m128 w;
};
struct type_align(16) SSkinInstance
@ -5569,8 +5563,8 @@ namespace T6
struct KeyValuePair
{
int keyHash;
int namespaceHash;
unsigned int keyHash;
unsigned int namespaceHash;
const char* value;
};

View File

@ -1,5 +1,6 @@
#pragma once
#include <cstdint>
#include <limits>
struct ZoneHeader
{
@ -7,21 +8,11 @@ struct ZoneHeader
uint32_t m_version;
};
#ifdef ARCH_x64
typedef uint32_t scr_string_t;
typedef uint64_t xchunk_size_t;
typedef uint64_t xblock_size_t;
typedef uint64_t zone_pointer_t;
constexpr uint16_t SCR_STRING_MAX = UINT32_MAX;
#elif ARCH_x86
typedef uint16_t scr_string_t;
typedef uint32_t xchunk_size_t;
typedef uint32_t xblock_size_t;
typedef uint32_t zone_pointer_t;
constexpr uint16_t SCR_STRING_MAX = UINT16_MAX;
#endif
constexpr uint16_t SCR_STRING_MAX = std::numeric_limits<scr_string_t>::max();
typedef int block_t;
typedef int asset_type_t;

View File

@ -32,7 +32,8 @@ namespace base64
size_t DecodeBase64(const void* base64Data, const size_t inputLength, void* outputBuffer, const size_t outputBufferSize)
{
unsigned long outLength = GetBase64DecodeOutputLength(inputLength);
unsigned long outLength = GetBase64DecodeOutputLength(base64Data, inputLength);
assert(outLength <= outputBufferSize);
if (outLength > outputBufferSize)
return 0u;
@ -42,8 +43,28 @@ namespace base64
return static_cast<size_t>(outLength);
}
size_t GetBase64DecodeOutputLength(const void* base64Data, const size_t inputLength)
{
assert(base64Data);
assert(inputLength);
if (!base64Data || inputLength == 0u)
return 0u;
auto padding = 0u;
if (inputLength >= 1 && static_cast<const char*>(base64Data)[inputLength - 1] == '=')
{
if (inputLength >= 2 && static_cast<const char*>(base64Data)[inputLength - 2] == '=')
padding = 2u;
else
padding = 1u;
}
return ((inputLength / 4u) * 3u) - padding;
}
size_t GetBase64DecodeOutputLength(const size_t inputLength)
{
return inputLength / 4u;
return (inputLength / 4u) * 3u;
}
} // namespace base64

View File

@ -8,5 +8,6 @@ namespace base64
size_t GetBase64EncodeOutputLength(size_t inputLength);
size_t DecodeBase64(const void* base64Data, size_t inputLength, void* outputBuffer, size_t outputBufferSize);
size_t GetBase64DecodeOutputLength(const void* base64Data, const size_t inputLength);
size_t GetBase64DecodeOutputLength(size_t inputLength);
} // namespace base64

View File

@ -39,6 +39,7 @@ function Linker:project()
self:include(includes)
Utils:include(includes)
ZoneLoading:include(includes)
ObjCompiling:include(includes)
ObjLoading:include(includes)
ObjWriting:include(includes)
ZoneWriting:include(includes)
@ -46,6 +47,7 @@ function Linker:project()
Raw:use()
links:linkto(Utils)
links:linkto(ObjCompiling)
links:linkto(ZoneLoading)
links:linkto(ZoneWriting)
links:linkto(ObjLoading)

View File

@ -1,72 +0,0 @@
#include "ZoneCreatorIW3.h"
#include "AssetLoading/AssetLoadingContext.h"
#include "Game/IW3/GameAssetPoolIW3.h"
#include "Game/IW3/GameIW3.h"
#include "IObjLoader.h"
#include "ObjLoading.h"
#include "Utils/StringUtils.h"
using namespace IW3;
std::vector<Gdt*> ZoneCreator::CreateGdtList(const ZoneCreationContext& context)
{
std::vector<Gdt*> gdtList;
gdtList.reserve(context.m_gdt_files.size());
for (const auto& gdt : context.m_gdt_files)
gdtList.push_back(gdt.get());
return gdtList;
}
void ZoneCreator::ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext)
{
for (const auto& ignoreEntry : creationContext.m_ignored_assets.m_entries)
loadingContext.m_ignored_asset_map[ignoreEntry.m_name] = ignoreEntry.m_type;
}
void ZoneCreator::CreateZoneAssetPools(Zone* zone) const
{
zone->m_pools = std::make_unique<GameAssetPoolIW3>(zone, zone->m_priority);
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
zone->m_pools->InitPoolDynamic(assetType);
}
GameId ZoneCreator::GetGameId() const
{
return GameId::IW3;
}
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
{
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, IGame::GetGameById(GameId::IW3));
CreateZoneAssetPools(zone.get());
for (const auto& assetEntry : context.m_definition->m_assets)
{
if (!assetEntry.m_is_reference)
continue;
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference);
}
const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
ApplyIgnoredAssets(context, *assetLoadingContext);
const auto* objLoader = IObjLoader::GetObjLoaderForGame(GameId::IW3);
for (const auto& assetEntry : context.m_definition->m_assets)
{
if (!objLoader->LoadAssetForZone(*assetLoadingContext, assetEntry.m_asset_type, assetEntry.m_asset_name))
return nullptr;
}
objLoader->FinalizeAssetsForZone(*assetLoadingContext);
return zone;
}
asset_type_t ZoneCreator::GetImageAssetType() const
{
return ASSET_TYPE_IMAGE;
}

View File

@ -1,20 +0,0 @@
#pragma once
#include "AssetLoading/AssetLoadingContext.h"
#include "Zone/ZoneTypes.h"
#include "ZoneCreation/ZoneCreator.h"
namespace IW3
{
class ZoneCreator final : public IZoneCreator
{
static std::vector<Gdt*> CreateGdtList(const ZoneCreationContext& context);
static void ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext);
void CreateZoneAssetPools(Zone* zone) const;
public:
[[nodiscard]] GameId GetGameId() const override;
[[nodiscard]] std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
[[nodiscard]] asset_type_t GetImageAssetType() const override;
};
} // namespace IW3

View File

@ -1,71 +0,0 @@
#include "ZoneCreatorIW4.h"
#include "Game/IW4/GameAssetPoolIW4.h"
#include "Game/IW4/GameIW4.h"
#include "IObjLoader.h"
#include "ObjLoading.h"
#include "Utils/StringUtils.h"
using namespace IW4;
std::vector<Gdt*> ZoneCreator::CreateGdtList(const ZoneCreationContext& context)
{
std::vector<Gdt*> gdtList;
gdtList.reserve(context.m_gdt_files.size());
for (const auto& gdt : context.m_gdt_files)
gdtList.push_back(gdt.get());
return gdtList;
}
void ZoneCreator::ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext)
{
for (const auto& ignoreEntry : creationContext.m_ignored_assets.m_entries)
loadingContext.m_ignored_asset_map[ignoreEntry.m_name] = ignoreEntry.m_type;
}
void ZoneCreator::CreateZoneAssetPools(Zone* zone) const
{
zone->m_pools = std::make_unique<GameAssetPoolIW4>(zone, zone->m_priority);
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
zone->m_pools->InitPoolDynamic(assetType);
}
GameId ZoneCreator::GetGameId() const
{
return GameId::IW4;
}
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
{
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, IGame::GetGameById(GameId::IW4));
CreateZoneAssetPools(zone.get());
for (const auto& assetEntry : context.m_definition->m_assets)
{
if (!assetEntry.m_is_reference)
continue;
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference);
}
const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
ApplyIgnoredAssets(context, *assetLoadingContext);
const auto* objLoader = IObjLoader::GetObjLoaderForGame(GameId::IW4);
for (const auto& assetEntry : context.m_definition->m_assets)
{
if (!objLoader->LoadAssetForZone(*assetLoadingContext, assetEntry.m_asset_type, assetEntry.m_asset_name))
return nullptr;
}
objLoader->FinalizeAssetsForZone(*assetLoadingContext);
return zone;
}
asset_type_t ZoneCreator::GetImageAssetType() const
{
return ASSET_TYPE_IMAGE;
}

View File

@ -1,20 +0,0 @@
#pragma once
#include "AssetLoading/AssetLoadingContext.h"
#include "Zone/ZoneTypes.h"
#include "ZoneCreation/ZoneCreator.h"
namespace IW4
{
class ZoneCreator final : public IZoneCreator
{
static std::vector<Gdt*> CreateGdtList(const ZoneCreationContext& context);
static void ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext);
void CreateZoneAssetPools(Zone* zone) const;
public:
[[nodiscard]] GameId GetGameId() const override;
[[nodiscard]] std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
[[nodiscard]] asset_type_t GetImageAssetType() const override;
};
} // namespace IW4

View File

@ -1,71 +0,0 @@
#include "ZoneCreatorIW5.h"
#include "Game/IW5/GameAssetPoolIW5.h"
#include "Game/IW5/GameIW5.h"
#include "IObjLoader.h"
#include "ObjLoading.h"
#include "Utils/StringUtils.h"
using namespace IW5;
std::vector<Gdt*> ZoneCreator::CreateGdtList(const ZoneCreationContext& context)
{
std::vector<Gdt*> gdtList;
gdtList.reserve(context.m_gdt_files.size());
for (const auto& gdt : context.m_gdt_files)
gdtList.push_back(gdt.get());
return gdtList;
}
void ZoneCreator::ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext)
{
for (const auto& ignoreEntry : creationContext.m_ignored_assets.m_entries)
loadingContext.m_ignored_asset_map[ignoreEntry.m_name] = ignoreEntry.m_type;
}
void ZoneCreator::CreateZoneAssetPools(Zone* zone) const
{
zone->m_pools = std::make_unique<GameAssetPoolIW5>(zone, zone->m_priority);
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
zone->m_pools->InitPoolDynamic(assetType);
}
GameId ZoneCreator::GetGameId() const
{
return GameId::IW5;
}
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
{
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, IGame::GetGameById(GameId::IW5));
CreateZoneAssetPools(zone.get());
for (const auto& assetEntry : context.m_definition->m_assets)
{
if (!assetEntry.m_is_reference)
continue;
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference);
}
const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
ApplyIgnoredAssets(context, *assetLoadingContext);
const auto* objLoader = IObjLoader::GetObjLoaderForGame(GameId::IW5);
for (const auto& assetEntry : context.m_definition->m_assets)
{
if (!objLoader->LoadAssetForZone(*assetLoadingContext, assetEntry.m_asset_type, assetEntry.m_asset_name))
return nullptr;
}
objLoader->FinalizeAssetsForZone(*assetLoadingContext);
return zone;
}
asset_type_t ZoneCreator::GetImageAssetType() const
{
return ASSET_TYPE_IMAGE;
}

View File

@ -1,19 +0,0 @@
#pragma once
#include "AssetLoading/AssetLoadingContext.h"
#include "Zone/ZoneTypes.h"
#include "ZoneCreation/ZoneCreator.h"
namespace IW5
{
class ZoneCreator final : public IZoneCreator
{
static std::vector<Gdt*> CreateGdtList(const ZoneCreationContext& context);
static void ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext);
void CreateZoneAssetPools(Zone* zone) const;
public:
[[nodiscard]] GameId GetGameId() const override;
[[nodiscard]] std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
[[nodiscard]] asset_type_t GetImageAssetType() const override;
};
} // namespace IW5

View File

@ -1,72 +0,0 @@
#include "ZoneCreatorT5.h"
#include "AssetLoading/AssetLoadingContext.h"
#include "Game/T5/GameAssetPoolT5.h"
#include "Game/T5/GameT5.h"
#include "IObjLoader.h"
#include "ObjLoading.h"
#include "Utils/StringUtils.h"
using namespace T5;
std::vector<Gdt*> ZoneCreator::CreateGdtList(ZoneCreationContext& context)
{
std::vector<Gdt*> gdtList;
gdtList.reserve(context.m_gdt_files.size());
for (const auto& gdt : context.m_gdt_files)
gdtList.push_back(gdt.get());
return gdtList;
}
void ZoneCreator::ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext)
{
for (const auto& ignoreEntry : creationContext.m_ignored_assets.m_entries)
loadingContext.m_ignored_asset_map[ignoreEntry.m_name] = ignoreEntry.m_type;
}
void ZoneCreator::CreateZoneAssetPools(Zone* zone) const
{
zone->m_pools = std::make_unique<GameAssetPoolT5>(zone, zone->m_priority);
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
zone->m_pools->InitPoolDynamic(assetType);
}
GameId ZoneCreator::GetGameId() const
{
return GameId::T5;
}
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
{
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, IGame::GetGameById(GameId::T5));
CreateZoneAssetPools(zone.get());
for (const auto& assetEntry : context.m_definition->m_assets)
{
if (!assetEntry.m_is_reference)
continue;
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference);
}
const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
ApplyIgnoredAssets(context, *assetLoadingContext);
const auto* objLoader = IObjLoader::GetObjLoaderForGame(GameId::T5);
for (const auto& assetEntry : context.m_definition->m_assets)
{
if (!objLoader->LoadAssetForZone(*assetLoadingContext, assetEntry.m_asset_type, assetEntry.m_asset_name))
return nullptr;
}
objLoader->FinalizeAssetsForZone(*assetLoadingContext);
return zone;
}
asset_type_t ZoneCreator::GetImageAssetType() const
{
return ASSET_TYPE_IMAGE;
}

View File

@ -1,19 +0,0 @@
#pragma once
#include "AssetLoading/AssetLoadingContext.h"
#include "Zone/ZoneTypes.h"
#include "ZoneCreation/ZoneCreator.h"
namespace T5
{
class ZoneCreator final : public IZoneCreator
{
static std::vector<Gdt*> CreateGdtList(ZoneCreationContext& context);
static void ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext);
void CreateZoneAssetPools(Zone* zone) const;
public:
[[nodiscard]] GameId GetGameId() const override;
[[nodiscard]] std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
[[nodiscard]] asset_type_t GetImageAssetType() const override;
};
} // namespace T5

View File

@ -1,125 +0,0 @@
#include "ZoneCreatorT6.h"
#include "Game/T6/CommonT6.h"
#include "Game/T6/GameAssetPoolT6.h"
#include "Game/T6/GameT6.h"
#include "Game/T6/T6.h"
#include "IObjLoader.h"
#include "ObjLoading.h"
#include "Utils/StringUtils.h"
#include <iostream>
using namespace T6;
std::vector<Gdt*> ZoneCreator::CreateGdtList(const ZoneCreationContext& context)
{
std::vector<Gdt*> gdtList;
gdtList.reserve(context.m_gdt_files.size());
for (const auto& gdt : context.m_gdt_files)
gdtList.push_back(gdt.get());
return gdtList;
}
void ZoneCreator::ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext)
{
for (const auto& ignoreEntry : creationContext.m_ignored_assets.m_entries)
loadingContext.m_ignored_asset_map[ignoreEntry.m_name] = ignoreEntry.m_type;
}
void ZoneCreator::CreateZoneAssetPools(Zone* zone) const
{
zone->m_pools = std::make_unique<GameAssetPoolT6>(zone, zone->m_priority);
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
zone->m_pools->InitPoolDynamic(assetType);
}
void ZoneCreator::HandleMetadata(Zone* zone, const ZoneCreationContext& context) const
{
std::vector<KeyValuePair> kvpList;
for (const auto& metaData : context.m_definition->m_properties.m_properties)
{
if (metaData.first.rfind("level.", 0) == 0)
{
const std::string strValue = metaData.first.substr(std::char_traits<char>::length("level."));
if (strValue.empty())
continue;
int keyHash;
if (strValue[0] == '@')
{
char* endPtr;
keyHash = strtol(&strValue[1], &endPtr, 16);
if (endPtr != &strValue[strValue.size()])
{
std::cout << "Could not parse metadata key \"" << metaData.first << "\" as hash\n";
continue;
}
}
else
{
keyHash = Common::Com_HashKey(strValue.c_str(), 64);
}
KeyValuePair kvp{keyHash, Common::Com_HashKey(zone->m_name.c_str(), 64), zone->GetMemory()->Dup(metaData.second.c_str())};
kvpList.push_back(kvp);
}
}
if (!kvpList.empty())
{
auto* kvps = zone->GetMemory()->Create<KeyValuePairs>();
kvps->name = zone->GetMemory()->Dup(zone->m_name.c_str());
kvps->numVariables = kvpList.size();
kvps->keyValuePairs = zone->GetMemory()->Alloc<KeyValuePair>(kvpList.size());
for (auto i = 0u; i < kvpList.size(); i++)
kvps->keyValuePairs[i] = kvpList[i];
zone->m_pools->AddAsset(std::make_unique<XAssetInfo<KeyValuePairs>>(ASSET_TYPE_KEYVALUEPAIRS, zone->m_name, kvps));
}
}
GameId ZoneCreator::GetGameId() const
{
return GameId::T6;
}
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
{
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, IGame::GetGameById(GameId::T6));
CreateZoneAssetPools(zone.get());
for (const auto& assetEntry : context.m_definition->m_assets)
{
if (!assetEntry.m_is_reference)
continue;
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference);
}
const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
ApplyIgnoredAssets(context, *assetLoadingContext);
HandleMetadata(zone.get(), context);
const auto* objLoader = IObjLoader::GetObjLoaderForGame(GameId::T6);
for (const auto& assetEntry : context.m_definition->m_assets)
{
if (!objLoader->LoadAssetForZone(*assetLoadingContext, assetEntry.m_asset_type, assetEntry.m_asset_name))
return nullptr;
}
objLoader->FinalizeAssetsForZone(*assetLoadingContext);
return zone;
}
asset_type_t ZoneCreator::GetImageAssetType() const
{
return ASSET_TYPE_IMAGE;
}

View File

@ -1,20 +0,0 @@
#pragma once
#include "AssetLoading/AssetLoadingContext.h"
#include "Zone/ZoneTypes.h"
#include "ZoneCreation/ZoneCreator.h"
namespace T6
{
class ZoneCreator final : public IZoneCreator
{
static std::vector<Gdt*> CreateGdtList(const ZoneCreationContext& context);
static void ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext);
void CreateZoneAssetPools(Zone* zone) const;
void HandleMetadata(Zone* zone, const ZoneCreationContext& context) const;
public:
[[nodiscard]] GameId GetGameId() const override;
[[nodiscard]] std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
[[nodiscard]] asset_type_t GetImageAssetType() const override;
};
} // namespace T6

View File

@ -1,16 +1,14 @@
#include "Linker.h"
#include "LinkerArgs.h"
#include "LinkerSearchPaths.h"
#include "ObjContainer/IPak/IPakWriter.h"
#include "ObjContainer/IWD/IWD.h"
#include "LinkerPaths.h"
#include "ObjContainer/SoundBank/SoundBankWriter.h"
#include "ObjLoading.h"
#include "ObjWriting.h"
#include "SearchPath/OutputPathFilesystem.h"
#include "SearchPath/SearchPaths.h"
#include "Utils/ObjFileStream.h"
#include "Zone/AssetList/AssetList.h"
#include "Zone/AssetList/AssetListStream.h"
#include "Zone/AssetList/AssetListReader.h"
#include "Zone/Definition/ZoneDefinitionStream.h"
#include "ZoneCreation/ZoneCreationContext.h"
#include "ZoneCreation/ZoneCreator.h"
@ -21,133 +19,157 @@
#include <filesystem>
#include <format>
#include <fstream>
#include <set>
#include <unordered_set>
namespace fs = std::filesystem;
namespace
{
class LinkerSearchPathContext
{
public:
explicit LinkerSearchPathContext(const ILinkerSearchPathBuilder& searchPathBuilder)
: m_search_path_builder(searchPathBuilder)
{
m_independent_search_paths = m_search_path_builder.BuildIndependentSearchPaths();
if (m_independent_search_paths)
m_search_paths.IncludeSearchPath(m_independent_search_paths.get());
}
[[nodiscard]] ISearchPath& GetSearchPaths()
{
return m_search_paths;
}
void LoadProjectSpecific(const std::string& projectName)
{
m_project_specific_search_paths = m_search_path_builder.BuildSearchPathsSpecificToProject(projectName);
if (m_project_specific_search_paths)
m_search_paths.IncludeSearchPath(m_project_specific_search_paths.get());
}
void UnloadProjectSpecific()
{
if (!m_project_specific_search_paths)
return;
m_search_paths.RemoveSearchPath(m_project_specific_search_paths.get());
m_project_specific_search_paths.reset();
}
void LoadGameSpecific(const std::string& projectName, const GameId game)
{
m_game_specific_search_paths = m_search_path_builder.BuildSearchPathsSpecificToProjectAndGame(projectName, game);
if (m_game_specific_search_paths)
m_search_paths.IncludeSearchPath(m_game_specific_search_paths.get());
}
void UnloadGameSpecific()
{
if (!m_game_specific_search_paths)
return;
m_search_paths.RemoveSearchPath(m_game_specific_search_paths.get());
m_game_specific_search_paths.reset();
}
private:
const ILinkerSearchPathBuilder& m_search_path_builder;
std::unique_ptr<ISearchPath> m_independent_search_paths;
std::unique_ptr<ISearchPath> m_project_specific_search_paths;
std::unique_ptr<ISearchPath> m_game_specific_search_paths;
SearchPaths m_search_paths;
};
class LinkerPathManager
{
public:
explicit LinkerPathManager(const LinkerArgs& args)
: m_linker_paths(ILinkerPaths::FromArgs(args)),
m_asset_paths(m_linker_paths->AssetSearchPaths()),
m_gdt_paths(m_linker_paths->GdtSearchPaths()),
m_source_paths(m_linker_paths->SourceSearchPaths())
{
}
std::unique_ptr<ILinkerPaths> m_linker_paths;
LinkerSearchPathContext m_asset_paths;
LinkerSearchPathContext m_gdt_paths;
LinkerSearchPathContext m_source_paths;
};
class PathProjectContext
{
public:
PathProjectContext(LinkerPathManager& paths, const std::string& projectName)
: m_paths(paths)
{
m_paths.m_asset_paths.LoadProjectSpecific(projectName);
m_paths.m_gdt_paths.LoadProjectSpecific(projectName);
m_paths.m_source_paths.LoadProjectSpecific(projectName);
}
~PathProjectContext()
{
m_paths.m_asset_paths.UnloadProjectSpecific();
m_paths.m_gdt_paths.UnloadProjectSpecific();
m_paths.m_source_paths.UnloadProjectSpecific();
}
PathProjectContext(const PathProjectContext& other) = delete;
PathProjectContext(PathProjectContext&& other) noexcept = delete;
PathProjectContext& operator=(const PathProjectContext& other) = delete;
PathProjectContext& operator=(PathProjectContext&& other) noexcept = delete;
private:
LinkerPathManager& m_paths;
};
class PathGameContext
{
public:
PathGameContext(LinkerPathManager& paths, const std::string& projectName, const GameId game)
: m_paths(paths)
{
m_paths.m_asset_paths.LoadGameSpecific(projectName, game);
m_paths.m_gdt_paths.LoadGameSpecific(projectName, game);
m_paths.m_source_paths.LoadGameSpecific(projectName, game);
}
~PathGameContext()
{
m_paths.m_asset_paths.UnloadGameSpecific();
m_paths.m_gdt_paths.UnloadGameSpecific();
m_paths.m_source_paths.UnloadGameSpecific();
}
PathGameContext(const PathGameContext& other) = delete;
PathGameContext(PathGameContext&& other) noexcept = delete;
PathGameContext& operator=(const PathGameContext& other) = delete;
PathGameContext& operator=(PathGameContext&& other) noexcept = delete;
private:
LinkerPathManager& m_paths;
};
} // namespace
class LinkerImpl final : public Linker
{
LinkerArgs m_args;
LinkerSearchPaths m_search_paths;
std::vector<std::unique_ptr<Zone>> m_loaded_zones;
bool IncludeAdditionalZoneDefinitions(const std::string& initialFileName, ZoneDefinition& zoneDefinition, ISearchPath* sourceSearchPath) const
{
std::set<std::string> sourceNames;
sourceNames.emplace(initialFileName);
std::deque<std::string> toIncludeQueue;
for (const auto& include : zoneDefinition.m_includes)
toIncludeQueue.emplace_back(include);
while (!toIncludeQueue.empty())
{
const auto& source = toIncludeQueue.front();
if (sourceNames.find(source) == sourceNames.end())
{
sourceNames.emplace(source);
std::unique_ptr<ZoneDefinition> includeDefinition;
{
const auto definitionFileName = std::format("{}.zone", source);
const auto definitionStream = sourceSearchPath->Open(definitionFileName);
if (!definitionStream.IsOpen())
{
std::cerr << std::format("Could not find zone definition file for project \"{}\".\n", source);
return false;
}
ZoneDefinitionInputStream zoneDefinitionInputStream(*definitionStream.m_stream, source, definitionFileName, m_args.m_verbose);
zoneDefinitionInputStream.SetPreviouslySetGame(zoneDefinition.m_game);
includeDefinition = zoneDefinitionInputStream.ReadDefinition();
}
if (!includeDefinition)
{
std::cerr << std::format("Failed to read zone definition file for project \"{}\".\n", source);
return false;
}
for (const auto& include : includeDefinition->m_includes)
toIncludeQueue.emplace_back(include);
zoneDefinition.Include(*includeDefinition);
}
toIncludeQueue.pop_front();
}
return true;
}
bool ReadAssetList(const std::string& zoneName, const GameId game, AssetList& assetList, ISearchPath* sourceSearchPath) const
{
{
const auto assetListFileName = std::format("assetlist/{}.csv", zoneName);
const auto assetListStream = sourceSearchPath->Open(assetListFileName);
if (assetListStream.IsOpen())
{
const AssetListInputStream stream(*assetListStream.m_stream, game);
AssetListEntry entry;
bool failure;
while (stream.NextEntry(entry, &failure))
{
assetList.m_entries.emplace_back(std::move(entry));
}
return !failure;
}
}
{
const auto zoneDefinition = ReadZoneDefinition(zoneName, sourceSearchPath);
if (zoneDefinition)
{
for (const auto& entry : zoneDefinition->m_assets)
{
assetList.m_entries.emplace_back(entry.m_asset_type, entry.m_asset_name, entry.m_is_reference);
}
return true;
}
}
return false;
}
bool IncludeAssetLists(ZoneDefinition& zoneDefinition, ISearchPath* sourceSearchPath) const
{
for (const auto& assetListName : zoneDefinition.m_asset_lists)
{
AssetList assetList;
if (!ReadAssetList(assetListName, zoneDefinition.m_game, assetList, sourceSearchPath))
{
std::cerr << std::format("Failed to read asset list \"{}\"\n", assetListName);
return false;
}
zoneDefinition.Include(assetList);
}
return true;
}
std::unique_ptr<ZoneDefinition> ReadZoneDefinition(const std::string& targetName, ISearchPath* sourceSearchPath) const
std::unique_ptr<ZoneDefinition> ReadZoneDefinition(LinkerPathManager& paths, const std::string& targetName, bool logMissing = true) const
{
auto& sourceSearchPath = paths.m_source_paths.GetSearchPaths();
std::unique_ptr<ZoneDefinition> zoneDefinition;
{
const auto definitionFileName = std::format("{}.zone", targetName);
const auto definitionStream = sourceSearchPath->Open(definitionFileName);
const auto definitionStream = sourceSearchPath.Open(definitionFileName);
if (!definitionStream.IsOpen())
{
std::cerr << std::format("Could not find zone definition file for target \"{}\".\n", targetName);
if (logMissing)
std::cerr << std::format("Could not find zone definition file for target \"{}\".\n", targetName);
return nullptr;
}
ZoneDefinitionInputStream zoneDefinitionInputStream(*definitionStream.m_stream, targetName, definitionFileName, m_args.m_verbose);
ZoneDefinitionInputStream zoneDefinitionInputStream(*definitionStream.m_stream, targetName, definitionFileName, sourceSearchPath);
zoneDefinition = zoneDefinitionInputStream.ReadDefinition();
}
@ -157,20 +179,41 @@ class LinkerImpl final : public Linker
return nullptr;
}
// If no type was defined explicitly make it fastfile
if (zoneDefinition->m_type == ProjectType::NONE)
zoneDefinition->m_type = ProjectType::FASTFILE;
if (!IncludeAdditionalZoneDefinitions(targetName, *zoneDefinition, sourceSearchPath))
return nullptr;
if (!IncludeAssetLists(*zoneDefinition, sourceSearchPath))
return nullptr;
return zoneDefinition;
}
bool ProcessZoneDefinitionIgnores(const std::string& targetName, ZoneCreationContext& context, ISearchPath* sourceSearchPath) const
bool ReadIgnoreEntries(LinkerPathManager& paths, const std::string& zoneName, const GameId game, AssetList& assetList) const
{
{
AssetListReader assetListReader(paths.m_source_paths.GetSearchPaths(), game);
const auto maybeReadAssetList = assetListReader.ReadAssetList(zoneName, false);
if (maybeReadAssetList)
{
assetList.m_entries.reserve(assetList.m_entries.size() + maybeReadAssetList->m_entries.size());
for (auto& entry : maybeReadAssetList->m_entries)
assetList.m_entries.emplace_back(std::move(entry));
return true;
}
}
{
const auto zoneDefinition = ReadZoneDefinition(paths, zoneName, false);
if (zoneDefinition)
{
assetList.m_entries.reserve(assetList.m_entries.size() + zoneDefinition->m_assets.size());
for (const auto& entry : zoneDefinition->m_assets)
assetList.m_entries.emplace_back(entry.m_asset_type, entry.m_asset_name, entry.m_is_reference);
return true;
}
}
return false;
}
bool ProcessZoneDefinitionIgnores(LinkerPathManager& paths, const std::string& targetName, ZoneCreationContext& context) const
{
if (context.m_definition->m_ignores.empty())
return true;
@ -180,8 +223,7 @@ class LinkerImpl final : public Linker
if (ignore == targetName)
continue;
std::vector<AssetListEntry> assetList;
if (!ReadAssetList(ignore, context.m_definition->m_game, context.m_ignored_assets, sourceSearchPath))
if (!ReadIgnoreEntries(paths, ignore, context.m_definition->m_game, context.m_ignored_assets))
{
std::cerr << std::format("Failed to read asset listing for ignoring assets of project \"{}\".\n", ignore);
return false;
@ -215,158 +257,95 @@ class LinkerImpl final : public Linker
return true;
}
std::unique_ptr<Zone> CreateZoneForDefinition(const std::string& targetName,
ZoneDefinition& zoneDefinition,
ISearchPath* assetSearchPath,
ISearchPath* gdtSearchPath,
ISearchPath* sourceSearchPath) const
std::unique_ptr<Zone> CreateZoneForDefinition(
LinkerPathManager& paths, const fs::path& outDir, const fs::path& cacheDir, const std::string& targetName, ZoneDefinition& zoneDefinition) const
{
const auto context = std::make_unique<ZoneCreationContext>(&zoneDefinition, assetSearchPath);
if (!ProcessZoneDefinitionIgnores(targetName, *context, sourceSearchPath))
ZoneCreationContext context(&zoneDefinition, &paths.m_asset_paths.GetSearchPaths(), outDir, cacheDir);
if (!ProcessZoneDefinitionIgnores(paths, targetName, context))
return nullptr;
if (!LoadGdtFilesFromZoneDefinition(context->m_gdt_files, zoneDefinition, gdtSearchPath))
if (!LoadGdtFilesFromZoneDefinition(context.m_gdt_files, zoneDefinition, &paths.m_gdt_paths.GetSearchPaths()))
return nullptr;
const auto* creator = IZoneCreator::GetCreatorForGame(zoneDefinition.m_game);
return creator->CreateZoneForDefinition(*context);
return zone_creator::CreateZoneForDefinition(zoneDefinition.m_game, context);
}
bool WriteZoneToFile(const std::string& projectName, Zone* zone) const
static bool WriteZoneToFile(IOutputPath& outPath, const Zone& zone)
{
const fs::path zoneFolderPath(m_args.GetOutputFolderPathForProject(projectName));
auto zoneFilePath(zoneFolderPath);
zoneFilePath.append(zone->m_name + ".ff");
fs::create_directories(zoneFolderPath);
std::ofstream stream(zoneFilePath, std::fstream::out | std::fstream::binary);
if (!stream.is_open())
return false;
if (m_args.m_verbose)
const auto stream = outPath.Open(std::format("{}.ff", zone.m_name));
if (!stream)
{
std::cout << std::format("Building zone \"{}\"\n", zoneFilePath.string());
std::cerr << std::format("Failed to open file for zone: {}\n", zone.m_name);
return false;
}
if (!ZoneWriting::WriteZone(stream, zone))
std::cout << std::format("Building zone \"{}\"\n", zone.m_name);
if (!ZoneWriting::WriteZone(*stream, zone))
{
std::cerr << "Writing zone failed.\n";
stream.close();
return false;
}
std::cout << std::format("Created zone \"{}\"\n", zoneFilePath.string());
std::cout << std::format("Created zone \"{}\"\n", zone.m_name);
stream.close();
return true;
}
bool BuildFastFile(const std::string& projectName,
const std::string& targetName,
ZoneDefinition& zoneDefinition,
SearchPaths& assetSearchPaths,
SearchPaths& gdtSearchPaths,
SearchPaths& sourceSearchPaths) const
bool BuildFastFile(LinkerPathManager& paths, const std::string& projectName, const std::string& targetName, ZoneDefinition& zoneDefinition) const
{
SoundBankWriter::OutputPath = fs::path(m_args.GetOutputFolderPathForProject(projectName));
const fs::path outDir(paths.m_linker_paths->BuildOutputFolderPath(projectName, zoneDefinition.m_game));
const auto zone = CreateZoneForDefinition(targetName, zoneDefinition, &assetSearchPaths, &gdtSearchPaths, &sourceSearchPaths);
OutputPathFilesystem outputPath(outDir);
const fs::path cacheDir(paths.m_linker_paths->BuildCacheFolderPath(projectName, zoneDefinition.m_game));
SoundBankWriter::OutputPath = outDir;
const auto zone = CreateZoneForDefinition(paths, outDir, cacheDir, targetName, zoneDefinition);
auto result = zone != nullptr;
if (zone)
result = WriteZoneToFile(projectName, zone.get());
result = WriteZoneToFile(outputPath, *zone);
return result;
}
bool BuildIPak(const std::string& projectName, const ZoneDefinition& zoneDefinition, SearchPaths& assetSearchPaths) const
bool BuildProject(LinkerPathManager& paths, const std::string& projectName, const std::string& targetName) const
{
const fs::path ipakFolderPath(m_args.GetOutputFolderPathForProject(projectName));
auto ipakFilePath(ipakFolderPath);
ipakFilePath.append(std::format("{}.ipak", zoneDefinition.m_name));
std::deque<std::string> targetsToBuild;
std::unordered_set<std::string> alreadyBuiltTargets;
fs::create_directories(ipakFolderPath);
targetsToBuild.emplace_back(targetName);
std::ofstream stream(ipakFilePath, std::fstream::out | std::fstream::binary);
if (!stream.is_open())
return false;
const auto ipakWriter = IPakWriter::Create(stream, &assetSearchPaths);
const auto imageAssetType = IZoneCreator::GetCreatorForGame(zoneDefinition.m_game)->GetImageAssetType();
for (const auto& assetEntry : zoneDefinition.m_assets)
while (!targetsToBuild.empty())
{
if (assetEntry.m_is_reference)
continue;
const auto currentTarget = std::move(targetsToBuild.front());
targetsToBuild.pop_front();
alreadyBuiltTargets.emplace(currentTarget);
if (assetEntry.m_asset_type == imageAssetType)
ipakWriter->AddImage(assetEntry.m_asset_name);
}
PathProjectContext projectContext(paths, projectName);
if (!ipakWriter->Write())
{
std::cerr << "Writing ipak failed.\n";
stream.close();
return false;
}
const auto zoneDefinition = ReadZoneDefinition(paths, targetName);
if (!zoneDefinition)
return false;
std::cout << std::format("Created ipak \"{}\"\n", ipakFilePath.string());
PathGameContext gameContext(paths, projectName, zoneDefinition->m_game);
stream.close();
return true;
}
bool BuildReferencedTargets(const std::string& projectName, const std::string& targetName, const ZoneDefinition& zoneDefinition)
{
return std::ranges::all_of(zoneDefinition.m_targets_to_build,
[this, &projectName, &targetName](const std::string& buildTargetName)
{
if (buildTargetName == targetName)
{
std::cerr << std::format("Cannot build target with same name: \"{}\"\n", targetName);
return false;
}
std::cout << std::format("Building referenced target \"{}\"\n", buildTargetName);
return BuildProject(projectName, buildTargetName);
});
}
bool BuildProject(const std::string& projectName, const std::string& targetName)
{
auto sourceSearchPaths = m_search_paths.GetSourceSearchPathsForProject(projectName);
const auto zoneDefinition = ReadZoneDefinition(targetName, &sourceSearchPaths);
if (!zoneDefinition)
return false;
auto result = true;
if (zoneDefinition->m_type != ProjectType::NONE)
{
const auto& gameName = GameId_Names[static_cast<unsigned>(zoneDefinition->m_game)];
auto assetSearchPaths = m_search_paths.GetAssetSearchPathsForProject(gameName, projectName);
auto gdtSearchPaths = m_search_paths.GetGdtSearchPathsForProject(gameName, projectName);
switch (zoneDefinition->m_type)
if (!zoneDefinition->m_assets.empty())
{
case ProjectType::FASTFILE:
result = BuildFastFile(projectName, targetName, *zoneDefinition, assetSearchPaths, gdtSearchPaths, sourceSearchPaths);
break;
if (!BuildFastFile(paths, projectName, targetName, *zoneDefinition))
return false;
case ProjectType::IPAK:
result = BuildIPak(projectName, *zoneDefinition, assetSearchPaths);
break;
default:
assert(false);
result = false;
break;
for (const auto& referencedTarget : zoneDefinition->m_targets_to_build)
{
if (alreadyBuiltTargets.find(referencedTarget) == alreadyBuiltTargets.end())
{
targetsToBuild.emplace_back(referencedTarget);
std::cout << std::format("Building referenced target \"{}\"\n", referencedTarget);
}
}
}
}
m_search_paths.UnloadProjectSpecificSearchPaths();
result = result && BuildReferencedTargets(projectName, targetName, *zoneDefinition);
return result;
return true;
}
bool LoadZones()
@ -384,8 +363,8 @@ class LinkerImpl final : public Linker
zoneDirectory = fs::current_path();
auto absoluteZoneDirectory = absolute(zoneDirectory).string();
auto zone = std::unique_ptr<Zone>(ZoneLoading::LoadZone(zonePath));
if (zone == nullptr)
auto zone = ZoneLoading::LoadZone(zonePath);
if (!zone)
{
std::cerr << std::format("Failed to load zone \"{}\".\n", zonePath);
return false;
@ -452,11 +431,6 @@ class LinkerImpl final : public Linker
}
public:
LinkerImpl()
: m_search_paths(m_args)
{
}
bool Start(const int argc, const char** argv) override
{
auto shouldContinue = true;
@ -466,8 +440,7 @@ public:
if (!shouldContinue)
return true;
if (!m_search_paths.BuildProjectIndependentSearchPaths())
return false;
LinkerPathManager paths(m_args);
if (!LoadZones())
return false;
@ -483,7 +456,7 @@ public:
break;
}
if (!BuildProject(projectName, targetName))
if (!BuildProject(paths, projectName, targetName))
{
result = false;
break;
@ -494,6 +467,10 @@ public:
return result;
}
private:
LinkerArgs m_args;
std::vector<std::unique_ptr<Zone>> m_loaded_zones;
};
std::unique_ptr<Linker> Linker::Create()

View File

@ -9,7 +9,6 @@
#include <filesystem>
#include <format>
#include <iostream>
#include <regex>
#include <type_traits>
namespace fs = std::filesystem;
@ -46,7 +45,7 @@ const CommandLineOption* const OPTION_BASE_FOLDER =
const CommandLineOption* const OPTION_OUTPUT_FOLDER =
CommandLineOption::Builder::Create()
.WithLongName("output-folder")
.WithDescription("Specifies the output folder containing the build artifacts. Defaults to \"" + std::string(LinkerArgs::DEFAULT_OUTPUT_FOLDER) + "\".")
.WithDescription(std::format("Specifies the output folder containing the build artifacts. Defaults to \"{}\".", LinkerArgs::DEFAULT_OUTPUT_FOLDER))
.WithParameter("outputFolderPath")
.Build();
@ -61,14 +60,14 @@ const CommandLineOption* const OPTION_ADD_ASSET_SEARCH_PATH =
const CommandLineOption* const OPTION_ASSET_SEARCH_PATH =
CommandLineOption::Builder::Create()
.WithLongName("asset-search-path")
.WithDescription("Specifies the search paths used for assets. Defaults to \"" + std::string(LinkerArgs::DEFAULT_ASSET_SEARCH_PATH) + "\".")
.WithDescription(std::format("Specifies the search paths used for assets. Defaults to \"{}\".", LinkerArgs::DEFAULT_ASSET_SEARCH_PATH))
.WithParameter("assetSearchPathString")
.Build();
const CommandLineOption* const OPTION_GDT_SEARCH_PATH =
CommandLineOption::Builder::Create()
.WithLongName("gdt-search-path")
.WithDescription("Specifies the search paths used for gdt files. Defaults to \"" + std::string(LinkerArgs::DEFAULT_GDT_SEARCH_PATH) + "\".")
.WithDescription(std::format("Specifies the search paths used for gdt files. Defaults to \"{}\".", LinkerArgs::DEFAULT_GDT_SEARCH_PATH))
.WithParameter("gdtSearchPathString")
.Build();
@ -83,7 +82,7 @@ const CommandLineOption* const OPTION_ADD_SOURCE_SEARCH_PATH =
const CommandLineOption* const OPTION_SOURCE_SEARCH_PATH =
CommandLineOption::Builder::Create()
.WithLongName("source-search-path")
.WithDescription("Specifies the search paths used for source files. Defaults to \"" + std::string(LinkerArgs::DEFAULT_SOURCE_SEARCH_PATH) + "\".")
.WithDescription(std::format("Specifies the search paths used for source files. Defaults to \"{}\".", LinkerArgs::DEFAULT_SOURCE_SEARCH_PATH))
.WithParameter("sourceSearchPathString")
.Build();
@ -129,13 +128,7 @@ const CommandLineOption* const COMMAND_LINE_OPTIONS[]{
LinkerArgs::LinkerArgs()
: m_verbose(false),
m_base_folder_depends_on_project(false),
m_out_folder_depends_on_project(false),
m_argument_parser(COMMAND_LINE_OPTIONS, std::extent_v<decltype(COMMAND_LINE_OPTIONS)>),
m_bin_pattern(R"(\?bin\?)"),
m_base_pattern(R"(\?base\?)"),
m_game_pattern(R"(\?game\?)"),
m_project_pattern(R"(\?project\?)")
m_argument_parser(COMMAND_LINE_OPTIONS, std::extent_v<decltype(COMMAND_LINE_OPTIONS)>)
{
}
@ -172,76 +165,6 @@ void LinkerArgs::SetVerbose(const bool isVerbose)
ObjWriting::Configuration.Verbose = isVerbose;
}
std::string LinkerArgs::GetBasePathForProject(const std::string& projectName) const
{
return std::regex_replace(m_base_folder, m_project_pattern, projectName);
}
void LinkerArgs::SetDefaultBasePath()
{
const auto currentDir = fs::absolute(fs::current_path());
if (currentDir.filename() == "bin")
{
m_base_folder = currentDir.parent_path().string();
}
else
{
m_base_folder = currentDir.string();
}
}
std::set<std::string> LinkerArgs::GetProjectIndependentSearchPaths(const std::set<std::string>& set) const
{
std::set<std::string> out;
for (const auto& path : set)
{
if (path.find(PATTERN_GAME) != std::string::npos)
continue;
if (path.find(PATTERN_PROJECT) != std::string::npos)
continue;
if (path.find(PATTERN_BASE) != std::string::npos)
{
if (m_base_folder_depends_on_project)
continue;
out.emplace(std::regex_replace(path, m_base_pattern, m_base_folder));
}
else
{
out.emplace(path);
}
}
return out;
}
std::set<std::string> LinkerArgs::GetSearchPathsForProject(const std::set<std::string>& set, const std::string& gameName, const std::string& projectName) const
{
std::set<std::string> out;
const auto basePath = GetBasePathForProject(projectName);
for (const auto& path : set)
{
if (path.find(PATTERN_GAME) == std::string::npos && path.find(PATTERN_PROJECT) == std::string::npos
&& (!m_base_folder_depends_on_project || path.find(PATTERN_BASE) == std::string::npos))
{
continue;
}
fs::path p(std::regex_replace(std::regex_replace(std::regex_replace(std::regex_replace(path, m_project_pattern, projectName), m_game_pattern, gameName),
m_base_pattern,
basePath),
m_bin_pattern,
m_bin_folder));
out.emplace(p.make_preferred().string());
}
return out;
}
bool LinkerArgs::ParseArgs(const int argc, const char** argv, bool& shouldContinue)
{
shouldContinue = true;
@ -284,15 +207,13 @@ bool LinkerArgs::ParseArgs(const int argc, const char** argv, bool& shouldContin
if (m_argument_parser.IsOptionSpecified(OPTION_BASE_FOLDER))
m_base_folder = m_argument_parser.GetValueForOption(OPTION_BASE_FOLDER);
else
SetDefaultBasePath();
m_base_folder_depends_on_project = m_base_folder.find(PATTERN_GAME) != std::string::npos || m_base_folder.find(PATTERN_PROJECT) != std::string::npos;
m_base_folder = DEFAULT_BASE_FOLDER;
// --output-folder
if (m_argument_parser.IsOptionSpecified(OPTION_OUTPUT_FOLDER))
m_out_folder = m_argument_parser.GetValueForOption(OPTION_OUTPUT_FOLDER);
else
m_out_folder = DEFAULT_OUTPUT_FOLDER;
m_out_folder_depends_on_project = m_out_folder.find(PATTERN_PROJECT) != std::string::npos;
// --asset-search-path
if (m_argument_parser.IsOptionSpecified(OPTION_ASSET_SEARCH_PATH))
@ -358,38 +279,3 @@ bool LinkerArgs::ParseArgs(const int argc, const char** argv, bool& shouldContin
return true;
}
std::string LinkerArgs::GetOutputFolderPathForProject(const std::string& projectName) const
{
return std::regex_replace(std::regex_replace(m_out_folder, m_project_pattern, projectName), m_base_pattern, GetBasePathForProject(projectName));
}
std::set<std::string> LinkerArgs::GetProjectIndependentAssetSearchPaths() const
{
return GetProjectIndependentSearchPaths(m_asset_search_paths);
}
std::set<std::string> LinkerArgs::GetProjectIndependentGdtSearchPaths() const
{
return GetProjectIndependentSearchPaths(m_gdt_search_paths);
}
std::set<std::string> LinkerArgs::GetProjectIndependentSourceSearchPaths() const
{
return GetProjectIndependentSearchPaths(m_source_search_paths);
}
std::set<std::string> LinkerArgs::GetAssetSearchPathsForProject(const std::string& gameName, const std::string& projectName) const
{
return GetSearchPathsForProject(m_asset_search_paths, gameName, projectName);
}
std::set<std::string> LinkerArgs::GetGdtSearchPathsForProject(const std::string& gameName, const std::string& projectName) const
{
return GetSearchPathsForProject(m_gdt_search_paths, gameName, projectName);
}
std::set<std::string> LinkerArgs::GetSourceSearchPathsForProject(const std::string& projectName) const
{
return GetSearchPathsForProject(m_source_search_paths, "", projectName);
}

View File

@ -1,22 +1,14 @@
#pragma once
#include "Utils/Arguments/ArgumentParser.h"
#include "Utils/ClassUtils.h"
#include "Zone/Zone.h"
#include <regex>
#include <set>
#include <vector>
class LinkerArgs
{
public:
static constexpr auto PATTERN_BIN = "?bin?";
static constexpr auto PATTERN_BASE = "?base?";
static constexpr auto PATTERN_GAME = "?game?";
static constexpr auto PATTERN_PROJECT = "?project?";
static constexpr auto DEFAULT_BASE_FOLDER = ".";
static constexpr auto DEFAULT_BASE_FOLDER_MOD_TOOLS = "..";
static constexpr auto DEFAULT_CACHE_FOLDER = "?base?/.oat/cache/?project?";
static constexpr auto DEFAULT_OUTPUT_FOLDER = "?base?/zone_out/?project?";
static constexpr auto DEFAULT_ASSET_SEARCH_PATH = "?bin?/raw/?game?;?base?/raw;?base?/raw/?game?;?base?/zone_raw/?project?";
static constexpr auto DEFAULT_GDT_SEARCH_PATH = "?base?/source_data;?base?/zone_raw/?project?/source_data";
@ -25,21 +17,6 @@ public:
LinkerArgs();
bool ParseArgs(int argc, const char** argv, bool& shouldContinue);
/**
* \brief Converts the output path specified by command line arguments to a path applies for the specified project.
* \param projectName The name of the project to resolve the path input for.
* \return An output path for the project based on the user input.
*/
_NODISCARD std::string GetOutputFolderPathForProject(const std::string& projectName) const;
_NODISCARD std::set<std::string> GetProjectIndependentAssetSearchPaths() const;
_NODISCARD std::set<std::string> GetProjectIndependentGdtSearchPaths() const;
_NODISCARD std::set<std::string> GetProjectIndependentSourceSearchPaths() const;
_NODISCARD std::set<std::string> GetAssetSearchPathsForProject(const std::string& gameName, const std::string& projectName) const;
_NODISCARD std::set<std::string> GetGdtSearchPathsForProject(const std::string& gameName, const std::string& projectName) const;
_NODISCARD std::set<std::string> GetSourceSearchPathsForProject(const std::string& projectName) const;
bool m_verbose;
std::vector<std::string> m_zones_to_load;
@ -48,8 +25,6 @@ public:
std::string m_bin_folder;
std::string m_base_folder;
std::string m_out_folder;
bool m_base_folder_depends_on_project;
bool m_out_folder_depends_on_project;
std::set<std::string> m_asset_search_paths;
std::set<std::string> m_gdt_search_paths;
@ -63,18 +38,7 @@ private:
static void PrintVersion();
void SetBinFolder(const char* argv0);
void SetVerbose(bool isVerbose);
_NODISCARD std::string GetBasePathForProject(const std::string& projectName) const;
void SetDefaultBasePath();
_NODISCARD std::set<std::string> GetProjectIndependentSearchPaths(const std::set<std::string>& set) const;
_NODISCARD std::set<std::string>
GetSearchPathsForProject(const std::set<std::string>& set, const std::string& gameName, const std::string& projectName) const;
ArgumentParser m_argument_parser;
std::regex m_bin_pattern;
std::regex m_base_pattern;
std::regex m_game_pattern;
std::regex m_project_pattern;
};

342
src/Linker/LinkerPaths.cpp Normal file
View File

@ -0,0 +1,342 @@
#include "LinkerPaths.h"
#include "SearchPath/IWD.h"
#include "SearchPath/SearchPathFilesystem.h"
#include "SearchPath/SearchPaths.h"
#include "Utils/StringUtils.h"
#include <cassert>
#include <cstdint>
#include <cstring>
#include <filesystem>
#include <format>
#include <iostream>
#include <sstream>
#include <type_traits>
#include <unordered_set>
namespace fs = std::filesystem;
namespace
{
enum class PathTemplateParameterType : std::uint8_t
{
BIN = 1 << 0,
BASE = 1 << 1,
PROJECT = 1 << 2,
GAME = 1 << 3,
};
class LinkerPathTemplate
{
static constexpr auto PATTERN_BIN = "?bin?";
static constexpr auto PATTERN_BASE = "?base?";
static constexpr auto PATTERN_GAME = "?game?";
static constexpr auto PATTERN_PROJECT = "?project?";
struct Pattern
{
const char* m_str;
PathTemplateParameterType m_type;
};
static constexpr Pattern PATTERNS[]{
{PATTERN_BIN, PathTemplateParameterType::BIN },
{PATTERN_BASE, PathTemplateParameterType::BASE },
{PATTERN_GAME, PathTemplateParameterType::GAME },
{PATTERN_PROJECT, PathTemplateParameterType::PROJECT},
};
public:
LinkerPathTemplate()
: m_parameter_type_flags(0u)
{
}
void CreateFromString(const std::string& templateString)
{
const auto templateStringLength = templateString.size();
auto partStart = 0u;
for (auto i = 0u; i < templateStringLength; i++)
{
if (templateString[i] != '?')
continue;
for (const auto& pattern : PATTERNS)
{
const auto patternLength = std::strlen(pattern.m_str);
if (templateString.compare(i, patternLength, pattern.m_str) == 0)
{
m_parts.emplace_back(templateString.substr(partStart, i - partStart));
m_parameters.emplace_back(pattern.m_type);
m_parameter_type_flags |= static_cast<std::underlying_type_t<PathTemplateParameterType>>(pattern.m_type);
i += patternLength;
partStart = i;
break;
}
}
}
if (partStart < templateStringLength)
m_parts.emplace_back(templateString.substr(partStart, templateStringLength - partStart));
}
[[nodiscard]] std::string
Render(const std::string& binDir, const std::string& baseDir, const std::string& projectName, const std::string& gameName) const
{
if (m_parts.empty())
return "";
if (m_parameters.empty())
return m_parts[0];
std::ostringstream ss;
ss << m_parts[0];
const auto partsCount = m_parts.size();
const auto parameterCount = m_parameters.size();
for (auto parameterIndex = 0u; parameterIndex < parameterCount; parameterIndex++)
{
switch (m_parameters[parameterIndex])
{
case PathTemplateParameterType::BIN:
ss << binDir;
break;
case PathTemplateParameterType::BASE:
ss << baseDir;
break;
case PathTemplateParameterType::PROJECT:
ss << projectName;
break;
case PathTemplateParameterType::GAME:
ss << gameName;
break;
default:
assert(false);
break;
}
if (parameterIndex + 1 < partsCount)
ss << m_parts[parameterIndex + 1];
}
return fs::path(ss.str()).make_preferred().string();
}
[[nodiscard]] bool CanRender(const std::underlying_type_t<PathTemplateParameterType> availableParameters) const
{
return (m_parameter_type_flags & ~availableParameters) == 0;
}
private:
std::vector<std::string> m_parts;
std::vector<PathTemplateParameterType> m_parameters;
std::underlying_type_t<PathTemplateParameterType> m_parameter_type_flags;
};
class LinkerSearchPathBuilder final : public ILinkerSearchPathBuilder
{
static constexpr auto INDEPENDENT_MASK = static_cast<unsigned>(PathTemplateParameterType::BIN) | static_cast<unsigned>(PathTemplateParameterType::BASE);
static constexpr auto PROJECT_MASK = static_cast<unsigned>(PathTemplateParameterType::BIN) | static_cast<unsigned>(PathTemplateParameterType::BASE)
| static_cast<unsigned>(PathTemplateParameterType::PROJECT);
static constexpr auto GAME_MASK = static_cast<unsigned>(PathTemplateParameterType::BIN) | static_cast<unsigned>(PathTemplateParameterType::BASE)
| static_cast<unsigned>(PathTemplateParameterType::PROJECT) | static_cast<unsigned>(PathTemplateParameterType::GAME);
public:
LinkerSearchPathBuilder(const char* typeName, std::string binDir, std::string baseDir)
: m_type_name(typeName),
m_bin_dir(std::move(binDir)),
m_base_dir(std::move(baseDir))
{
}
void BuildFromArgs(const std::set<std::string>& templates)
{
m_templates.reserve(templates.size());
for (const auto& templateString : templates)
{
LinkerPathTemplate templateStruct;
templateStruct.CreateFromString(templateString);
m_templates.emplace_back(std::move(templateStruct));
}
}
[[nodiscard]] std::unique_ptr<ISearchPath> BuildIndependentSearchPaths() const override
{
SearchPaths searchPaths;
std::unordered_set<std::string> addedSearchPaths;
auto hasSearchPath = false;
for (const auto& curTemplate : m_templates)
{
if (curTemplate.CanRender(INDEPENDENT_MASK))
{
auto renderedTemplate = curTemplate.Render(m_bin_dir, m_base_dir, std::string(), std::string());
if (AddSearchPath(addedSearchPaths, searchPaths, renderedTemplate))
hasSearchPath = true;
}
}
if (hasSearchPath)
return std::make_unique<SearchPaths>(std::move(searchPaths));
return {};
}
[[nodiscard]] std::unique_ptr<ISearchPath> BuildSearchPathsSpecificToProject(const std::string& projectName) const override
{
SearchPaths searchPaths;
std::unordered_set<std::string> addedSearchPaths;
auto hasSearchPath = false;
for (const auto& curTemplate : m_templates)
{
if (!curTemplate.CanRender(INDEPENDENT_MASK) && curTemplate.CanRender(PROJECT_MASK))
{
auto renderedTemplate = curTemplate.Render(m_bin_dir, m_base_dir, projectName, std::string());
if (AddSearchPath(addedSearchPaths, searchPaths, renderedTemplate))
hasSearchPath = true;
}
}
if (hasSearchPath)
return std::make_unique<SearchPaths>(std::move(searchPaths));
return {};
}
[[nodiscard]] std::unique_ptr<ISearchPath> BuildSearchPathsSpecificToProjectAndGame(const std::string& projectName, GameId game) const override
{
SearchPaths searchPaths;
std::unordered_set<std::string> addedSearchPaths;
auto hasSearchPath = false;
for (const auto& curTemplate : m_templates)
{
if (!curTemplate.CanRender(PROJECT_MASK) && curTemplate.CanRender(GAME_MASK))
{
std::string gameName(GameId_Names[static_cast<unsigned>(game)]);
utils::MakeStringLowerCase(gameName);
auto renderedTemplate = curTemplate.Render(m_bin_dir, m_base_dir, projectName, gameName);
if (AddSearchPath(addedSearchPaths, searchPaths, renderedTemplate))
hasSearchPath = true;
}
}
if (hasSearchPath)
return std::make_unique<SearchPaths>(std::move(searchPaths));
return {};
}
private:
bool AddSearchPath(std::unordered_set<std::string>& existingSearchPaths, SearchPaths& searchPaths, const std::string& path) const
{
const auto existingSearchPath = existingSearchPaths.find(path);
if (existingSearchPath != existingSearchPaths.end())
return false;
existingSearchPaths.emplace(path);
if (!fs::is_directory(path))
{
std::cout << std::format("Adding {} search path (Not found): {}\n", m_type_name, path);
return false;
}
std::cout << std::format("Adding {} search path: {}\n", m_type_name, path);
searchPaths.CommitSearchPath(std::make_unique<SearchPathFilesystem>(path));
return true;
}
const char* m_type_name;
std::vector<LinkerPathTemplate> m_templates;
std::string m_bin_dir;
std::string m_base_dir;
};
class LinkerPaths final : public ILinkerPaths
{
public:
LinkerPaths(std::string binDir,
std::string baseDir,
LinkerSearchPathBuilder assetSearchPaths,
LinkerSearchPathBuilder gdtSearchPaths,
LinkerSearchPathBuilder sourceSearchPaths,
LinkerPathTemplate cacheTemplate,
LinkerPathTemplate outTemplate)
: m_bin_dir(std::move(binDir)),
m_base_dir(std::move(baseDir)),
m_asset_search_paths(std::move(assetSearchPaths)),
m_gdt_search_paths(std::move(gdtSearchPaths)),
m_source_search_paths(std::move(sourceSearchPaths)),
m_cache_template(std::move(cacheTemplate)),
m_out_template(std::move(outTemplate))
{
}
[[nodiscard]] const ILinkerSearchPathBuilder& AssetSearchPaths() const override
{
return m_asset_search_paths;
}
[[nodiscard]] const ILinkerSearchPathBuilder& GdtSearchPaths() const override
{
return m_gdt_search_paths;
}
[[nodiscard]] const ILinkerSearchPathBuilder& SourceSearchPaths() const override
{
return m_source_search_paths;
}
[[nodiscard]] std::string BuildCacheFolderPath(const std::string& projectName, GameId game) const override
{
return m_cache_template.Render(m_bin_dir, m_base_dir, projectName, GameId_Names[static_cast<unsigned>(game)]);
}
[[nodiscard]] std::string BuildOutputFolderPath(const std::string& projectName, GameId game) const override
{
return m_out_template.Render(m_bin_dir, m_base_dir, projectName, GameId_Names[static_cast<unsigned>(game)]);
}
private:
std::string m_bin_dir;
std::string m_base_dir;
LinkerSearchPathBuilder m_asset_search_paths;
LinkerSearchPathBuilder m_gdt_search_paths;
LinkerSearchPathBuilder m_source_search_paths;
LinkerPathTemplate m_cache_template;
LinkerPathTemplate m_out_template;
};
} // namespace
std::unique_ptr<ILinkerPaths> ILinkerPaths::FromArgs(const LinkerArgs& args)
{
std::string normalizedBinPath = fs::canonical(args.m_bin_folder).make_preferred().string();
std::string normalizedBasePath = fs::canonical(args.m_base_folder).make_preferred().string();
LinkerSearchPathBuilder assetSearchPaths("asset", normalizedBinPath, normalizedBasePath);
assetSearchPaths.BuildFromArgs(args.m_asset_search_paths);
LinkerSearchPathBuilder gdtSearchPaths("gdt", normalizedBinPath, normalizedBasePath);
gdtSearchPaths.BuildFromArgs(args.m_gdt_search_paths);
LinkerSearchPathBuilder sourceSearchPaths("source", normalizedBinPath, normalizedBasePath);
sourceSearchPaths.BuildFromArgs(args.m_source_search_paths);
LinkerPathTemplate cacheTemplate;
cacheTemplate.CreateFromString(LinkerArgs::DEFAULT_CACHE_FOLDER);
LinkerPathTemplate outTemplate;
outTemplate.CreateFromString(args.m_out_folder);
return std::make_unique<LinkerPaths>(std::move(normalizedBinPath),
std::move(normalizedBasePath),
std::move(assetSearchPaths),
std::move(gdtSearchPaths),
std::move(sourceSearchPaths),
std::move(cacheTemplate),
std::move(outTemplate));
}

74
src/Linker/LinkerPaths.h Normal file
View File

@ -0,0 +1,74 @@
#pragma once
#include "Game/IGame.h"
#include "LinkerArgs.h"
#include "SearchPath/ISearchPath.h"
#include <memory>
class ILinkerSearchPathBuilder
{
public:
ILinkerSearchPathBuilder() = default;
virtual ~ILinkerSearchPathBuilder() = default;
ILinkerSearchPathBuilder(const ILinkerSearchPathBuilder& other) = default;
ILinkerSearchPathBuilder(ILinkerSearchPathBuilder&& other) noexcept = default;
ILinkerSearchPathBuilder& operator=(const ILinkerSearchPathBuilder& other) = default;
ILinkerSearchPathBuilder& operator=(ILinkerSearchPathBuilder&& other) noexcept = default;
[[nodiscard]] virtual std::unique_ptr<ISearchPath> BuildIndependentSearchPaths() const = 0;
[[nodiscard]] virtual std::unique_ptr<ISearchPath> BuildSearchPathsSpecificToProject(const std::string& projectName) const = 0;
[[nodiscard]] virtual std::unique_ptr<ISearchPath> BuildSearchPathsSpecificToProjectAndGame(const std::string& projectName, GameId game) const = 0;
};
class ILinkerPaths
{
public:
ILinkerPaths() = default;
virtual ~ILinkerPaths() = default;
ILinkerPaths(const ILinkerPaths& other) = default;
ILinkerPaths(ILinkerPaths&& other) noexcept = default;
ILinkerPaths& operator=(const ILinkerPaths& other) = default;
ILinkerPaths& operator=(ILinkerPaths&& other) noexcept = default;
/**
* \brief Creates linker search paths based on templates from user specified args.
* \param args The user specified args.
* \return Linker search paths based on user specified templates.
*/
static std::unique_ptr<ILinkerPaths> FromArgs(const LinkerArgs& args);
/**
* \brief Grants access to the builder for asset search paths.
* \return A builder instance for building asset search paths.
*/
[[nodiscard]] virtual const ILinkerSearchPathBuilder& AssetSearchPaths() const = 0;
/**
* \brief Grants access to the builder for gdt search paths.
* \return A builder instance for building gdt search paths.
*/
[[nodiscard]] virtual const ILinkerSearchPathBuilder& GdtSearchPaths() const = 0;
/**
* \brief Grants access to the builder for source search paths.
* \return A builder instance for building source search paths.
*/
[[nodiscard]] virtual const ILinkerSearchPathBuilder& SourceSearchPaths() const = 0;
/**
* \brief Builds the cache path based on the specified information.
* \param projectName The name of the project to resolve the path input for.
* \param game The game to resolve the path input for.
* \return A cache path based on the input and preconfigured template.
*/
[[nodiscard]] virtual std::string BuildCacheFolderPath(const std::string& projectName, GameId game) const = 0;
/**
* \brief Builds the output path based on the specified information.
* \param projectName The name of the project to resolve the path input for.
* \param game The game to resolve the path input for.
* \return An output path based on the input and preconfigured template.
*/
[[nodiscard]] virtual std::string BuildOutputFolderPath(const std::string& projectName, GameId game) const = 0;
};

View File

@ -1,190 +0,0 @@
#include "LinkerSearchPaths.h"
#include "ObjContainer/IWD/IWD.h"
#include "ObjLoading.h"
#include "SearchPath/SearchPathFilesystem.h"
#include <filesystem>
#include <format>
#include <iostream>
namespace fs = std::filesystem;
LinkerSearchPaths::LinkerSearchPaths(const LinkerArgs& args)
: m_args(args)
{
}
void LinkerSearchPaths::LoadSearchPath(ISearchPath& searchPath) const
{
if (m_args.m_verbose)
{
std::cout << std::format("Loading search path: \"{}\"\n", searchPath.GetPath());
}
ObjLoading::LoadIWDsInSearchPath(searchPath);
}
void LinkerSearchPaths::UnloadSearchPath(ISearchPath& searchPath) const
{
if (m_args.m_verbose)
{
std::cout << std::format("Unloading search path: \"{}\"\n", searchPath.GetPath());
}
ObjLoading::UnloadIWDsInSearchPath(searchPath);
}
SearchPaths LinkerSearchPaths::GetAssetSearchPathsForProject(const std::string& gameName, const std::string& projectName)
{
SearchPaths searchPathsForProject;
for (const auto& searchPathStr : m_args.GetAssetSearchPathsForProject(gameName, projectName))
{
auto absolutePath = fs::absolute(searchPathStr);
if (!fs::is_directory(absolutePath))
{
if (m_args.m_verbose)
std::cout << std::format("Adding asset search path (Not found): {}\n", absolutePath.string());
continue;
}
if (m_args.m_verbose)
std::cout << std::format("Adding asset search path: {}\n", absolutePath.string());
auto searchPath = std::make_unique<SearchPathFilesystem>(searchPathStr);
LoadSearchPath(*searchPath);
searchPathsForProject.IncludeSearchPath(searchPath.get());
m_loaded_project_search_paths.emplace_back(std::move(searchPath));
}
searchPathsForProject.IncludeSearchPath(&m_asset_search_paths);
for (auto* iwd : IWD::Repository)
{
searchPathsForProject.IncludeSearchPath(iwd);
}
return searchPathsForProject;
}
SearchPaths LinkerSearchPaths::GetGdtSearchPathsForProject(const std::string& gameName, const std::string& projectName)
{
SearchPaths searchPathsForProject;
for (const auto& searchPathStr : m_args.GetGdtSearchPathsForProject(gameName, projectName))
{
auto absolutePath = fs::absolute(searchPathStr);
if (!fs::is_directory(absolutePath))
{
if (m_args.m_verbose)
std::cout << std::format("Adding gdt search path (Not found): {}\n", absolutePath.string());
continue;
}
if (m_args.m_verbose)
std::cout << std::format("Adding gdt search path: {}\n", absolutePath.string());
searchPathsForProject.CommitSearchPath(std::make_unique<SearchPathFilesystem>(searchPathStr));
}
searchPathsForProject.IncludeSearchPath(&m_gdt_search_paths);
return searchPathsForProject;
}
SearchPaths LinkerSearchPaths::GetSourceSearchPathsForProject(const std::string& projectName)
{
SearchPaths searchPathsForProject;
for (const auto& searchPathStr : m_args.GetSourceSearchPathsForProject(projectName))
{
auto absolutePath = fs::absolute(searchPathStr);
if (!fs::is_directory(absolutePath))
{
if (m_args.m_verbose)
std::cout << std::format("Adding source search path (Not found): {}\n", absolutePath.string());
continue;
}
if (m_args.m_verbose)
std::cout << std::format("Adding source search path: {}\n", absolutePath.string());
searchPathsForProject.CommitSearchPath(std::make_unique<SearchPathFilesystem>(searchPathStr));
}
searchPathsForProject.IncludeSearchPath(&m_source_search_paths);
return searchPathsForProject;
}
bool LinkerSearchPaths::BuildProjectIndependentSearchPaths()
{
for (const auto& path : m_args.GetProjectIndependentAssetSearchPaths())
{
auto absolutePath = fs::absolute(path);
if (!fs::is_directory(absolutePath))
{
if (m_args.m_verbose)
std::cout << std::format("Adding asset search path (Not found): {}\n", absolutePath.string());
continue;
}
if (m_args.m_verbose)
std::cout << std::format("Adding asset search path: {}\n", absolutePath.string());
auto searchPath = std::make_unique<SearchPathFilesystem>(absolutePath.string());
LoadSearchPath(*searchPath);
m_asset_search_paths.CommitSearchPath(std::move(searchPath));
}
for (const auto& path : m_args.GetProjectIndependentGdtSearchPaths())
{
auto absolutePath = fs::absolute(path);
if (!fs::is_directory(absolutePath))
{
if (m_args.m_verbose)
std::cout << std::format("Loading gdt search path (Not found): {}\n", absolutePath.string());
continue;
}
if (m_args.m_verbose)
std::cout << std::format("Adding gdt search path: {}\n", absolutePath.string());
m_gdt_search_paths.CommitSearchPath(std::make_unique<SearchPathFilesystem>(absolutePath.string()));
}
for (const auto& path : m_args.GetProjectIndependentSourceSearchPaths())
{
auto absolutePath = fs::absolute(path);
if (!fs::is_directory(absolutePath))
{
if (m_args.m_verbose)
std::cout << std::format("Loading source search path (Not found): {}\n", absolutePath.string());
continue;
}
if (m_args.m_verbose)
std::cout << std::format("Adding source search path: {}\n", absolutePath.string());
m_source_search_paths.CommitSearchPath(std::make_unique<SearchPathFilesystem>(absolutePath.string()));
}
return true;
}
void LinkerSearchPaths::UnloadProjectSpecificSearchPaths()
{
for (const auto& loadedSearchPath : m_loaded_project_search_paths)
{
UnloadSearchPath(*loadedSearchPath);
}
m_loaded_project_search_paths.clear();
}

View File

@ -1,45 +0,0 @@
#pragma once
#include "LinkerArgs.h"
#include "SearchPath/SearchPaths.h"
#include <memory>
#include <vector>
class LinkerSearchPaths
{
public:
explicit LinkerSearchPaths(const LinkerArgs& args);
/**
* \brief Loads a search path.
* \param searchPath The search path to load.
*/
void LoadSearchPath(ISearchPath& searchPath) const;
/**
* \brief Unloads a search path.
* \param searchPath The search path to unload.
*/
void UnloadSearchPath(ISearchPath& searchPath) const;
SearchPaths GetAssetSearchPathsForProject(const std::string& gameName, const std::string& projectName);
SearchPaths GetGdtSearchPathsForProject(const std::string& gameName, const std::string& projectName);
SearchPaths GetSourceSearchPathsForProject(const std::string& projectName);
/**
* \brief Initializes the Linker object's search paths based on the user's input.
* \return \c true if building the search paths was successful, otherwise \c false.
*/
bool BuildProjectIndependentSearchPaths();
void UnloadProjectSpecificSearchPaths();
private:
const LinkerArgs& m_args;
std::vector<std::unique_ptr<ISearchPath>> m_loaded_project_search_paths;
SearchPaths m_asset_search_paths;
SearchPaths m_gdt_search_paths;
SearchPaths m_source_search_paths;
};

View File

@ -1,13 +1,17 @@
#include "ZoneCreationContext.h"
namespace fs = std::filesystem;
ZoneCreationContext::ZoneCreationContext()
: m_definition(nullptr),
m_asset_search_path(nullptr)
{
}
ZoneCreationContext::ZoneCreationContext(ZoneDefinition* definition, ISearchPath* assetSearchPath)
ZoneCreationContext::ZoneCreationContext(ZoneDefinition* definition, ISearchPath* assetSearchPath, fs::path outDir, fs::path cacheDir)
: m_definition(definition),
m_asset_search_path(assetSearchPath)
m_asset_search_path(assetSearchPath),
m_out_dir(std::move(outDir)),
m_cache_dir(std::move(cacheDir))
{
}

View File

@ -4,6 +4,7 @@
#include "Zone/AssetList/AssetList.h"
#include "Zone/Definition/ZoneDefinition.h"
#include <filesystem>
#include <memory>
#include <vector>
@ -12,9 +13,11 @@ class ZoneCreationContext
public:
ZoneDefinition* m_definition;
ISearchPath* m_asset_search_path;
std::filesystem::path m_out_dir;
std::filesystem::path m_cache_dir;
std::vector<std::unique_ptr<Gdt>> m_gdt_files;
AssetList m_ignored_assets;
ZoneCreationContext();
ZoneCreationContext(ZoneDefinition* definition, ISearchPath* assetSearchPath);
ZoneCreationContext(ZoneDefinition* definition, ISearchPath* assetSearchPath, std::filesystem::path outDir, std::filesystem::path cacheDir);
};

View File

@ -1,27 +1,91 @@
#include "ZoneCreator.h"
#include "AssetLoading/AssetLoadingContext.h"
#include "Game/IW3/ZoneCreatorIW3.h"
#include "Game/IW4/ZoneCreatorIW4.h"
#include "Game/IW5/ZoneCreatorIW5.h"
#include "Game/T5/ZoneCreatorT5.h"
#include "Game/T6/ZoneCreatorT6.h"
#include "Gdt/GdtLookup.h"
#include "IObjCompiler.h"
#include "IObjLoader.h"
#include "SearchPath/OutputPathFilesystem.h"
#include <cassert>
const IZoneCreator* IZoneCreator::GetCreatorForGame(GameId game)
namespace
{
static const IZoneCreator* zoneCreators[static_cast<unsigned>(GameId::COUNT)]{
new IW3::ZoneCreator(),
new IW4::ZoneCreator(),
new IW5::ZoneCreator(),
new T5::ZoneCreator(),
new T6::ZoneCreator(),
};
std::unique_ptr<Zone> CreateZone(const ZoneCreationContext& context, const GameId gameId)
{
return std::make_unique<Zone>(context.m_definition->m_name, 0, IGame::GetGameById(gameId));
}
assert(static_cast<unsigned>(game) < static_cast<unsigned>(GameId::COUNT));
const auto* result = zoneCreators[static_cast<unsigned>(game)];
assert(result);
std::vector<Gdt*> CreateGdtList(const ZoneCreationContext& context)
{
std::vector<Gdt*> gdtList;
gdtList.reserve(context.m_gdt_files.size());
for (const auto& gdt : context.m_gdt_files)
gdtList.push_back(gdt.get());
return result;
}
return gdtList;
}
void IgnoreReferencesFromAssets(ZoneCreationContext& context)
{
for (const auto& assetEntry : context.m_definition->m_assets)
{
if (!assetEntry.m_is_reference)
continue;
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference);
}
}
} // namespace
namespace zone_creator
{
void InitLookup(const ZoneCreationContext& context, GdtLookup& lookup)
{
std::vector<const Gdt*> gdtFiles;
gdtFiles.reserve(context.m_gdt_files.size());
for (const auto& gdt : context.m_gdt_files)
{
gdtFiles.emplace_back(gdt.get());
}
lookup.Initialize(gdtFiles);
}
std::unique_ptr<Zone> CreateZoneForDefinition(GameId gameId, ZoneCreationContext& context)
{
auto zone = CreateZone(context, gameId);
IgnoreReferencesFromAssets(context);
IgnoredAssetLookup ignoredAssetLookup(context.m_ignored_assets);
GdtLookup lookup;
InitLookup(context, lookup);
const auto* objCompiler = IObjCompiler::GetObjCompilerForGame(gameId);
const auto* objLoader = IObjLoader::GetObjLoaderForGame(gameId);
AssetCreatorCollection creatorCollection(*zone);
ZoneDefinitionContext zoneDefinitionContext(*context.m_definition);
AssetCreationContext creationContext(*zone, &creatorCollection, &ignoredAssetLookup);
OutputPathFilesystem outDir(context.m_out_dir);
OutputPathFilesystem cacheDir(context.m_cache_dir);
objCompiler->ConfigureCreatorCollection(
creatorCollection, *zone, zoneDefinitionContext, *context.m_asset_search_path, lookup, creationContext, outDir, cacheDir);
objLoader->ConfigureCreatorCollection(creatorCollection, *zone, *context.m_asset_search_path, lookup);
for (const auto& assetEntry : context.m_definition->m_assets)
{
const auto* createdAsset = creationContext.LoadDependencyGeneric(assetEntry.m_asset_type, assetEntry.m_asset_name);
if (!createdAsset)
return nullptr;
++zoneDefinitionContext.m_asset_index_in_definition;
}
creatorCollection.FinalizeZone(creationContext);
return zone;
}
} // namespace zone_creator

View File

@ -3,19 +3,7 @@
#include "Zone/Zone.h"
#include "ZoneCreationContext.h"
class IZoneCreator
namespace zone_creator
{
public:
IZoneCreator() = default;
virtual ~IZoneCreator() = default;
IZoneCreator(const IZoneCreator& other) = default;
IZoneCreator(IZoneCreator&& other) noexcept = default;
IZoneCreator& operator=(const IZoneCreator& other) = default;
IZoneCreator& operator=(IZoneCreator&& other) noexcept = default;
[[nodiscard]] virtual GameId GetGameId() const = 0;
[[nodiscard]] virtual std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const = 0;
[[nodiscard]] virtual asset_type_t GetImageAssetType() const = 0;
static const IZoneCreator* GetCreatorForGame(GameId game);
};
[[nodiscard]] std::unique_ptr<Zone> CreateZoneForDefinition(GameId game, ZoneCreationContext& context);
}

View File

@ -5,6 +5,7 @@ function ObjCommon:include(includes)
Common:include(includes)
json:include(includes)
minizip:include(includes)
Parser:include(includes)
includedirs {
path.join(ProjectFolder(), "ObjCommon")
}
@ -16,6 +17,7 @@ function ObjCommon:link(links)
links:linkto(Utils)
links:linkto(Common)
links:linkto(minizip)
links:linkto(Parser)
end
function ObjCommon:use()

View File

@ -1,4 +1,5 @@
#pragma once
#include "Game/IW4/IW4.h"
namespace IW4

View File

@ -81,4 +81,17 @@ namespace T6
{"c4_yaw", offsetof(PhysConstraints, data[3].scale.y), CSPFT_FLOAT },
{"c4_pitch", offsetof(PhysConstraints, data[3].scale.x), CSPFT_FLOAT },
};
}
inline const char* s_constraintTypeNames[]{
"none",
"point",
"distance",
"hinge",
"joint",
"actuator",
"fake_shake",
"launch",
"rope",
"light",
};
} // namespace T6

View File

@ -36,4 +36,9 @@ namespace T6
{"colorB4", offsetof(TracerDef, colors[4].b), CSPFT_FLOAT },
{"colorA4", offsetof(TracerDef, colors[4].a), CSPFT_FLOAT },
};
}
inline const char* tracerTypeNames[]{
"Laser",
"Smoke",
};
} // namespace T6

View File

@ -561,4 +561,31 @@ namespace T6
{"customBool1", offsetof(VehicleDef, customBool1), CSPFT_BOOL },
{"customBool2", offsetof(VehicleDef, customBool2), CSPFT_BOOL },
};
}
inline const char* s_vehicleClassNames[]{
"4 wheel",
"motorcycle",
"tank",
"plane",
"boat",
"artillery",
"helicopter",
};
inline const char* s_vehicleCameraModes[]{
"first",
"chase",
"view",
"strafe",
"horse",
"oldtank",
"hover",
"vtol",
};
inline const char* s_tractionTypeNames[]{
"TRACTION_TYPE_FRONT",
"TRACTION_TYPE_BACK",
"TRACTION_TYPE_ALL_WD",
};
} // namespace T6

View File

@ -81,4 +81,4 @@ namespace T6
{"customBool1", offsetof(WeaponAttachment, customBool1), CSPFT_BOOL },
{"customBool2", offsetof(WeaponAttachment, customBool2), CSPFT_BOOL },
};
}
} // namespace T6

View File

@ -206,4 +206,4 @@ namespace T6
{"customBool1", offsetof(WeaponAttachmentUniqueFull, attachment.customBool1), CSPFT_BOOL },
{"customBool2", offsetof(WeaponAttachmentUniqueFull, attachment.customBool2), CSPFT_BOOL },
};
}
} // namespace T6

View File

@ -36,31 +36,11 @@ namespace T6
"crosshair",
};
inline const char* szWeapInventoryTypeNames[]{
"primary",
"offhand",
"item",
"altmode",
"melee",
"dwlefthand",
};
inline const char* szWeapClipTypeNames[]{
"bottom",
"top",
"left",
"dp28",
"ptrs",
"lmg",
};
inline const char* barrelTypeNames[]{
"Single",
"Dual Barrel",
"Dual Barrel Alternate",
"Quad Barrel",
"Quad Barrel Alternate",
"Quad Barrel Double Alternate",
inline const char* penetrateTypeNames[]{
"none",
"small",
"medium",
"large",
};
inline const char* impactTypeNames[]{
@ -165,6 +145,37 @@ namespace T6
"Turret Scope",
};
inline const char* szWeapInventoryTypeNames[]{
"primary",
"offhand",
"item",
"altmode",
"melee",
"dwlefthand",
};
inline const char* szWeapFireTypeNames[]{
"Full Auto",
"Single Shot",
"2-Round Burst",
"3-Round Burst",
"4-Round Burst",
"5-Round Burst",
"Stacked Fire",
"Minigun",
"Charge Shot",
"Jetgun",
};
inline const char* szWeapClipTypeNames[]{
"bottom",
"top",
"left",
"dp28",
"ptrs",
"lmg",
};
inline const char* ammoCounterClipNames[]{
"None",
"Magazine",
@ -181,75 +192,13 @@ namespace T6
"4:1",
};
inline const char* szAttachmentTypeNames[]{
"none", "acog", "dualclip", "dualoptic", "dw", "extbarrel", "extclip", "extramags", "fastads", "fastreload",
"fmj", "gl", "grip", "holo", "ir", "is", "longbreath", "mk", "mms", "rangefinder",
"reflex", "rf", "sf", "silencer", "stackfire", "stalker", "steadyaim", "swayreduc", "tacknife", "vzoom",
};
inline const char* szWeapFireTypeNames[]{
"Full Auto",
"Single Shot",
"2-Round Burst",
"3-Round Burst",
"4-Round Burst",
"5-Round Burst",
"Stacked Fire",
"Minigun",
"Charge Shot",
"Jetgun",
};
inline const char* penetrateTypeNames[]{
"none",
"small",
"medium",
"large",
};
inline const char* s_constraintTypeNames[]{
"none",
"point",
"distance",
"hinge",
"joint",
"actuator",
"fake_shake",
"launch",
"rope",
"light",
};
inline const char* s_vehicleClassNames[]{
"4 wheel",
"motorcycle",
"tank",
"plane",
"boat",
"artillery",
"helicopter",
};
inline const char* s_vehicleCameraModes[]{
"first",
"chase",
"view",
"strafe",
"horse",
"oldtank",
"hover",
"vtol",
};
inline const char* s_tractionTypeNames[]{
"TRACTION_TYPE_FRONT",
"TRACTION_TYPE_BACK",
"TRACTION_TYPE_ALL_WD",
};
inline const char* tracerTypeNames[]{
"Laser",
"Smoke",
inline const char* barrelTypeNames[]{
"Single",
"Dual Barrel",
"Dual Barrel Alternate",
"Quad Barrel",
"Quad Barrel Alternate",
"Quad Barrel Double Alternate",
};
inline const char* bounceSoundSuffixes[]{
@ -257,4 +206,10 @@ namespace T6
"_gravel", "_ice", "_metal", "_mud", "_paper", "_plaster", "_rock", "_sand", "_snow", "_water", "_wood",
"_asphalt", "_ceramic", "_plastic", "_rubber", "_cushion", "_fruit", "_paintedmetal", "_player", "_tallgrass", "_riotshield",
};
inline const char* szAttachmentTypeNames[]{
"none", "acog", "dualclip", "dualoptic", "dw", "extbarrel", "extclip", "extramags", "fastads", "fastreload",
"fmj", "gl", "grip", "holo", "ir", "is", "longbreath", "mk", "mms", "rangefinder",
"reflex", "rf", "sf", "silencer", "stackfire", "stalker", "steadyaim", "swayreduc", "tacknife", "vzoom",
};
} // namespace T6

View File

@ -16,7 +16,7 @@ namespace ipak_consts
static constexpr size_t IPAK_CHUNK_SIZE = 0x8000;
static constexpr size_t IPAK_CHUNK_COUNT_PER_READ = 0x8;
static constexpr uint32_t IPAK_COMMAND_DEFAULT_SIZE = 0x7F00;
static constexpr size_t IPAK_COMMAND_DEFAULT_SIZE = 0x7F00;
static constexpr uint32_t IPAK_COMMAND_UNCOMPRESSED = 0;
static constexpr uint32_t IPAK_COMMAND_COMPRESSED = 1;
static constexpr uint32_t IPAK_COMMAND_SKIP = 0xCF;

View File

@ -0,0 +1,18 @@
#pragma once
#include <memory>
#include <ostream>
#include <string>
class IOutputPath
{
public:
IOutputPath() = default;
virtual ~IOutputPath() = default;
IOutputPath(const IOutputPath& other) = default;
IOutputPath(IOutputPath&& other) noexcept = default;
IOutputPath& operator=(const IOutputPath& other) = default;
IOutputPath& operator=(IOutputPath&& other) noexcept = default;
virtual std::unique_ptr<std::ostream> Open(const std::string& fileName) = 0;
};

View File

@ -7,6 +7,7 @@
#include <functional>
#include <istream>
#include <memory>
#include <string>
class SearchPathOpenFile
{
@ -42,7 +43,7 @@ public:
* \brief Returns the path to the search path.
* \return The path to the search path.
*/
virtual std::string GetPath() = 0;
virtual const std::string& GetPath() = 0;
/**
* \brief Iterates through all files of the search path.

View File

@ -0,0 +1,39 @@
#include "OutputPathFilesystem.h"
#include <format>
#include <fstream>
#include <iostream>
namespace fs = std::filesystem;
OutputPathFilesystem::OutputPathFilesystem(const fs::path& path)
: m_path(fs::weakly_canonical(path))
{
}
std::unique_ptr<std::ostream> OutputPathFilesystem::Open(const std::string& fileName)
{
const auto fullNewPath = fs::weakly_canonical(m_path / fileName);
if (!fullNewPath.string().starts_with(m_path.string()))
return nullptr;
const auto containingDirectory = fullNewPath.parent_path();
std::error_code ec;
fs::create_directories(containingDirectory, ec);
if (ec)
{
std::cerr << std::format("Failed to create folder '{}' when try to open file '{}'\n", containingDirectory.string(), fileName);
return nullptr;
}
std::ofstream stream(fullNewPath, std::ios::binary | std::ios::out);
if (!stream.is_open())
{
std::cerr << std::format("Failed to open file '{}'\n", fileName);
return nullptr;
}
return std::make_unique<std::ofstream>(std::move(stream));
}

View File

@ -0,0 +1,16 @@
#pragma once
#include "IOutputPath.h"
#include <filesystem>
class OutputPathFilesystem final : public IOutputPath
{
public:
explicit OutputPathFilesystem(const std::filesystem::path& path);
std::unique_ptr<std::ostream> Open(const std::string& fileName) override;
private:
std::filesystem::path m_path;
};

View File

@ -3,16 +3,18 @@
#include "Utils/ObjFileStream.h"
#include <filesystem>
#include <format>
#include <fstream>
#include <iostream>
namespace fs = std::filesystem;
SearchPathFilesystem::SearchPathFilesystem(std::string path)
: m_path(std::move(path))
{
m_path = std::move(path);
}
std::string SearchPathFilesystem::GetPath()
const std::string& SearchPathFilesystem::GetPath()
{
return m_path;
}
@ -23,9 +25,7 @@ SearchPathOpenFile SearchPathFilesystem::Open(const std::string& fileName)
std::ifstream file(filePath.string(), std::fstream::in | std::fstream::binary);
if (file.is_open())
{
return SearchPathOpenFile(std::make_unique<std::ifstream>(std::move(file)), static_cast<int64_t>(file_size(filePath)));
}
return SearchPathOpenFile();
}
@ -59,6 +59,6 @@ void SearchPathFilesystem::Find(const SearchPathSearchOptions& options, const st
}
catch (std::filesystem::filesystem_error& e)
{
printf("Directory Iterator threw error when trying to find files: \"%s\"\n", e.what());
std::cerr << std::format("Directory Iterator threw error when trying to find files: \"{}\"\n", e.what());
}
}

View File

@ -12,6 +12,6 @@ public:
explicit SearchPathFilesystem(std::string path);
SearchPathOpenFile Open(const std::string& fileName) override;
std::string GetPath() override;
const std::string& GetPath() override;
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override;
};

View File

@ -0,0 +1,15 @@
#include "SearchPathMultiInputStream.h"
SearchPathMultiInputStream::SearchPathMultiInputStream(ISearchPath& searchPath)
: m_search_path(searchPath)
{
}
std::unique_ptr<std::istream> SearchPathMultiInputStream::OpenIncludedFile(const std::string& filename, const std::string& sourceFile)
{
auto foundFileToInclude = m_search_path.Open(filename);
if (!foundFileToInclude.IsOpen() || !foundFileToInclude.m_stream)
return nullptr;
return std::move(foundFileToInclude.m_stream);
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "Parsing/Impl/ParserMultiInputStream.h"
#include "SearchPath/ISearchPath.h"
class SearchPathMultiInputStream : public IInclusionCallback
{
public:
explicit SearchPathMultiInputStream(ISearchPath& searchPath);
std::unique_ptr<std::istream> OpenIncludedFile(const std::string& filename, const std::string& sourceFile) override;
protected:
ISearchPath& m_search_path;
};

View File

@ -18,9 +18,10 @@ SearchPathOpenFile SearchPaths::Open(const std::string& fileName)
return SearchPathOpenFile();
}
std::string SearchPaths::GetPath()
const std::string& SearchPaths::GetPath()
{
return "SearchPaths: " + std::to_string(m_search_paths.size()) + " entries";
static const std::string STATIC_NAME = "SearchPaths";
return STATIC_NAME;
}
void SearchPaths::Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback)

View File

@ -2,6 +2,7 @@
#include "ISearchPath.h"
#include <string>
#include <vector>
class SearchPaths final : public ISearchPath
@ -16,7 +17,7 @@ public:
~SearchPaths() override = default;
SearchPathOpenFile Open(const std::string& fileName) override;
std::string GetPath() override;
const std::string& GetPath() override;
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override;
SearchPaths(const SearchPaths& other) = delete;

View File

@ -68,7 +68,7 @@ namespace
T result;
} data{};
const auto byteCount = utils::Align(bitCount, 8u) / 8u;
const auto byteCount = utils::Align(bitCount, 8uz) / 8uz;
assert(byteCount <= sizeof(T));
const auto shiftCount = (8u - bitCount % 8) % 8;
@ -83,7 +83,7 @@ namespace
while (remainingBits > 0)
{
const auto curBits = static_cast<uint8_t>(std::min(remainingBits, 8u));
const auto curBits = static_cast<uint8_t>(std::min(remainingBits, 8uz));
if (m_remaining_bits_last_byte > 0)
{

View File

@ -59,7 +59,7 @@ size_t CommonStructuredDataType::GetSizeInBits(const CommonStructuredDataDef& de
return 0u;
}
const auto& indexedArray = def.m_indexed_arrays[m_info.type_index];
return utils::Align(indexedArray.m_element_size_in_bits * indexedArray.m_element_count, 8u);
return utils::Align(indexedArray.m_element_size_in_bits * indexedArray.m_element_count, 8uz);
}
case CommonStructuredDataTypeCategory::ENUM_ARRAY:
{
@ -69,7 +69,7 @@ size_t CommonStructuredDataType::GetSizeInBits(const CommonStructuredDataDef& de
return 0u;
}
const auto& enumedArray = def.m_enumed_arrays[m_info.type_index];
return utils::Align(enumedArray.m_element_size_in_bits * enumedArray.m_element_count, 8u);
return utils::Align(enumedArray.m_element_size_in_bits * enumedArray.m_element_count, 8uz);
}
case CommonStructuredDataTypeCategory::UNKNOWN:

58
src/ObjCompiling.lua Normal file
View File

@ -0,0 +1,58 @@
ObjCompiling = {}
function ObjCompiling:include(includes)
if includes:handle(self:name()) then
ObjCommon:include(includes)
ObjLoading:include(includes)
ObjImage:include(includes)
ZoneCommon:include(includes)
includedirs {
path.join(ProjectFolder(), "ObjCompiling")
}
end
end
function ObjCompiling:link(links)
links:add(self:name())
links:linkto(minilzo)
links:linkto(Utils)
links:linkto(ObjCommon)
links:linkto(ObjLoading)
links:linkto(ObjImage)
links:linkto(ZoneCommon)
end
function ObjCompiling:use()
end
function ObjCompiling:name()
return "ObjCompiling"
end
function ObjCompiling:project()
local folder = ProjectFolder()
local includes = Includes:create()
project(self:name())
targetdir(TargetDirectoryLib)
location "%{wks.location}/src/%{prj.name}"
kind "StaticLib"
language "C++"
files {
path.join(folder, "ObjCompiling/**.h"),
path.join(folder, "ObjCompiling/**.cpp")
}
vpaths {
["*"] = {
path.join(folder, "ObjCompiling")
}
}
self:include(includes)
minilzo:include(includes)
Utils:include(includes)
json:include(includes)
end

View File

@ -0,0 +1,43 @@
#include "ObjCompilerIW3.h"
#include "Game/IW3/IW3.h"
#include "Image/ImageIwdPostProcessor.h"
#include <memory>
using namespace IW3;
namespace
{
void ConfigureCompilers(AssetCreatorCollection& collection, Zone& zone, ISearchPath& searchPath)
{
auto& memory = *zone.GetMemory();
// No compilers yet
}
void ConfigurePostProcessors(AssetCreatorCollection& collection,
Zone& zone,
const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir)
{
auto& memory = *zone.GetMemory();
if (ImageIwdPostProcessor<AssetImage>::AppliesToZoneDefinition(zoneDefinition))
collection.AddAssetPostProcessor(std::make_unique<ImageIwdPostProcessor<AssetImage>>(zoneDefinition, searchPath, zoneStates, outDir));
}
} // namespace
void ObjCompiler::ConfigureCreatorCollection(AssetCreatorCollection& collection,
Zone& zone,
const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
IGdtQueryable& gdt,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir,
IOutputPath& cacheDir) const
{
ConfigurePostProcessors(collection, zone, zoneDefinition, searchPath, zoneStates, outDir);
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "IObjCompiler.h"
namespace IW3
{
class ObjCompiler final : public IObjCompiler
{
public:
void ConfigureCreatorCollection(AssetCreatorCollection& collection,
Zone& zone,
const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
IGdtQueryable& gdt,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir,
IOutputPath& cacheDir) const override;
};
} // namespace IW3

View File

@ -0,0 +1,43 @@
#include "ObjCompilerIW4.h"
#include "Game/IW4/IW4.h"
#include "Image/ImageIwdPostProcessor.h"
#include <memory>
using namespace IW4;
namespace
{
void ConfigureCompilers(AssetCreatorCollection& collection, Zone& zone, ISearchPath& searchPath)
{
auto& memory = *zone.GetMemory();
// No compilers yet
}
void ConfigurePostProcessors(AssetCreatorCollection& collection,
Zone& zone,
const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir)
{
auto& memory = *zone.GetMemory();
if (ImageIwdPostProcessor<AssetImage>::AppliesToZoneDefinition(zoneDefinition))
collection.AddAssetPostProcessor(std::make_unique<ImageIwdPostProcessor<AssetImage>>(zoneDefinition, searchPath, zoneStates, outDir));
}
} // namespace
void ObjCompiler::ConfigureCreatorCollection(AssetCreatorCollection& collection,
Zone& zone,
const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
IGdtQueryable& gdt,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir,
IOutputPath& cacheDir) const
{
ConfigurePostProcessors(collection, zone, zoneDefinition, searchPath, zoneStates, outDir);
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "IObjCompiler.h"
namespace IW4
{
class ObjCompiler final : public IObjCompiler
{
public:
void ConfigureCreatorCollection(AssetCreatorCollection& collection,
Zone& zone,
const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
IGdtQueryable& gdt,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir,
IOutputPath& cacheDir) const override;
};
} // namespace IW4

View File

@ -0,0 +1,43 @@
#include "ObjCompilerIW5.h"
#include "Game/IW5/IW5.h"
#include "Image/ImageIwdPostProcessor.h"
#include <memory>
using namespace IW5;
namespace
{
void ConfigureCompilers(AssetCreatorCollection& collection, Zone& zone, ISearchPath& searchPath)
{
auto& memory = *zone.GetMemory();
// No compilers yet
}
void ConfigurePostProcessors(AssetCreatorCollection& collection,
Zone& zone,
const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir)
{
auto& memory = *zone.GetMemory();
if (ImageIwdPostProcessor<AssetImage>::AppliesToZoneDefinition(zoneDefinition))
collection.AddAssetPostProcessor(std::make_unique<ImageIwdPostProcessor<AssetImage>>(zoneDefinition, searchPath, zoneStates, outDir));
}
} // namespace
void ObjCompiler::ConfigureCreatorCollection(AssetCreatorCollection& collection,
Zone& zone,
const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
IGdtQueryable& gdt,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir,
IOutputPath& cacheDir) const
{
ConfigurePostProcessors(collection, zone, zoneDefinition, searchPath, zoneStates, outDir);
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "IObjCompiler.h"
namespace IW5
{
class ObjCompiler final : public IObjCompiler
{
public:
void ConfigureCreatorCollection(AssetCreatorCollection& collection,
Zone& zone,
const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
IGdtQueryable& gdt,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir,
IOutputPath& cacheDir) const override;
};
} // namespace IW5

View File

@ -0,0 +1,43 @@
#include "ObjCompilerT5.h"
#include "Game/T5/T5.h"
#include "Image/ImageIwdPostProcessor.h"
#include <memory>
using namespace T5;
namespace
{
void ConfigureCompilers(AssetCreatorCollection& collection, Zone& zone, ISearchPath& searchPath)
{
auto& memory = *zone.GetMemory();
// No compilers yet
}
void ConfigurePostProcessors(AssetCreatorCollection& collection,
Zone& zone,
const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir)
{
auto& memory = *zone.GetMemory();
if (ImageIwdPostProcessor<AssetImage>::AppliesToZoneDefinition(zoneDefinition))
collection.AddAssetPostProcessor(std::make_unique<ImageIwdPostProcessor<AssetImage>>(zoneDefinition, searchPath, zoneStates, outDir));
}
} // namespace
void ObjCompiler::ConfigureCreatorCollection(AssetCreatorCollection& collection,
Zone& zone,
const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
IGdtQueryable& gdt,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir,
IOutputPath& cacheDir) const
{
ConfigurePostProcessors(collection, zone, zoneDefinition, searchPath, zoneStates, outDir);
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "IObjCompiler.h"
namespace T5
{
class ObjCompiler final : public IObjCompiler
{
public:
void ConfigureCreatorCollection(AssetCreatorCollection& collection,
Zone& zone,
const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
IGdtQueryable& gdt,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir,
IOutputPath& cacheDir) const override;
};
} // namespace T5

View File

@ -0,0 +1,82 @@
#include "KeyValuePairsCompilerT6.h"
#include "Game/T6/CommonT6.h"
#include "Game/T6/T6.h"
#include "KeyValuePairs/KeyValuePairsCreator.h"
#include <cassert>
#include <format>
#include <iostream>
using namespace T6;
namespace
{
class KeyValuePairsCompiler final : public IAssetCreator
{
public:
KeyValuePairsCompiler(MemoryManager& memory, const Zone& zone, const ZoneDefinition& zoneDefinition, ZoneAssetCreationStateContainer& zoneStates)
: m_memory(memory),
m_zone(zone),
m_zone_definition(zoneDefinition),
m_kvp_creator(zoneStates.GetZoneAssetCreationState<KeyValuePairsCreator>())
{
}
[[nodiscard]] std::optional<asset_type_t> GetHandlingAssetType() const override
{
return std::nullopt;
}
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
{
return AssetCreationResult::NoAction();
}
void FinalizeZone(AssetCreationContext& context) override
{
m_kvp_creator.Finalize(m_zone_definition);
const auto commonKvps = m_kvp_creator.GetFinalKeyValuePairs();
if (commonKvps.empty())
return;
auto* gameKvps = m_memory.Alloc<KeyValuePairs>();
gameKvps->name = m_memory.Dup(m_zone.m_name.c_str());
gameKvps->numVariables = commonKvps.size();
gameKvps->keyValuePairs = m_memory.Alloc<KeyValuePair>(commonKvps.size());
const auto namespaceHash = Common::Com_HashKey(m_zone.m_name.c_str(), 64);
for (auto kvpIndex = 0u; kvpIndex < gameKvps->numVariables; kvpIndex++)
{
const auto& commonKvp = commonKvps[kvpIndex];
auto& gameKvp = gameKvps->keyValuePairs[kvpIndex];
assert(commonKvp.m_key_str || commonKvp.m_key_hash);
if (commonKvp.m_key_str)
gameKvp.keyHash = Common::Com_HashKey(commonKvp.m_key_str->c_str(), 64);
else
gameKvp.keyHash = *commonKvp.m_key_hash;
gameKvp.namespaceHash = namespaceHash;
gameKvp.value = m_memory.Dup(commonKvp.m_value.c_str());
}
context.AddAsset(AssetRegistration<AssetKeyValuePairs>(m_zone.m_name, gameKvps));
}
private:
MemoryManager& m_memory;
const Zone& m_zone;
const ZoneDefinition& m_zone_definition;
KeyValuePairsCreator& m_kvp_creator;
};
} // namespace
namespace T6
{
std::unique_ptr<IAssetCreator>
CreateKeyValuePairsCompiler(MemoryManager& memory, const Zone& zone, const ZoneDefinition& zoneDefinition, ZoneAssetCreationStateContainer& zoneStates)
{
return std::make_unique<KeyValuePairsCompiler>(memory, zone, zoneDefinition, zoneStates);
}
} // namespace T6

View File

@ -0,0 +1,16 @@
#pragma once
#include "Asset/IAssetCreator.h"
#include "Asset/IZoneAssetCreationState.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include "Zone/Definition/ZoneDefinition.h"
#include "Zone/Zone.h"
#include <memory>
namespace T6
{
std::unique_ptr<IAssetCreator>
CreateKeyValuePairsCompiler(MemoryManager& memory, const Zone& zone, const ZoneDefinition& zoneDefinition, ZoneAssetCreationStateContainer& zoneStates);
} // namespace T6

View File

@ -0,0 +1,53 @@
#include "ObjCompilerT6.h"
#include "Game/T6/T6.h"
#include "Image/ImageIPakPostProcessor.h"
#include "Image/ImageIwdPostProcessor.h"
#include "KeyValuePairs/KeyValuePairsCompilerT6.h"
#include <memory>
using namespace T6;
namespace
{
void ConfigureCompilers(AssetCreatorCollection& collection,
Zone& zone,
const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
ZoneAssetCreationStateContainer& zoneStates)
{
auto& memory = *zone.GetMemory();
collection.AddAssetCreator(CreateKeyValuePairsCompiler(memory, zone, zoneDefinition.m_zone_definition, zoneStates));
}
void ConfigurePostProcessors(AssetCreatorCollection& collection,
Zone& zone,
const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir)
{
auto& memory = *zone.GetMemory();
if (ImageIPakPostProcessor<AssetImage>::AppliesToZoneDefinition(zoneDefinition))
collection.AddAssetPostProcessor(std::make_unique<ImageIPakPostProcessor<AssetImage>>(zoneDefinition, searchPath, zoneStates, outDir));
if (ImageIwdPostProcessor<AssetImage>::AppliesToZoneDefinition(zoneDefinition))
collection.AddAssetPostProcessor(std::make_unique<ImageIwdPostProcessor<AssetImage>>(zoneDefinition, searchPath, zoneStates, outDir));
}
} // namespace
void ObjCompiler::ConfigureCreatorCollection(AssetCreatorCollection& collection,
Zone& zone,
const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
IGdtQueryable& gdt,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir,
IOutputPath& cacheDir) const
{
ConfigureCompilers(collection, zone, zoneDefinition, searchPath, zoneStates);
ConfigurePostProcessors(collection, zone, zoneDefinition, searchPath, zoneStates, outDir);
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "IObjCompiler.h"
namespace T6
{
class ObjCompiler final : public IObjCompiler
{
public:
void ConfigureCreatorCollection(AssetCreatorCollection& collection,
Zone& zone,
const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
IGdtQueryable& gdt,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir,
IOutputPath& cacheDir) const override;
};
} // namespace T6

View File

@ -0,0 +1,27 @@
#include "IObjCompiler.h"
#include "Game/IW3/ObjCompilerIW3.h"
#include "Game/IW4/ObjCompilerIW4.h"
#include "Game/IW5/ObjCompilerIW5.h"
#include "Game/T5/ObjCompilerT5.h"
#include "Game/T6/ObjCompilerT6.h"
#include <cassert>
const IObjCompiler* IObjCompiler::GetObjCompilerForGame(GameId game)
{
static const IObjCompiler* objCompilers[static_cast<unsigned>(GameId::COUNT)]{
new IW3::ObjCompiler(),
new IW4::ObjCompiler(),
new IW5::ObjCompiler(),
new T5::ObjCompiler(),
new T6::ObjCompiler(),
};
static_assert(std::extent_v<decltype(objCompilers)> == static_cast<unsigned>(GameId::COUNT));
assert(static_cast<unsigned>(game) < static_cast<unsigned>(GameId::COUNT));
const auto* result = objCompilers[static_cast<unsigned>(game)];
assert(result);
return result;
}

View File

@ -0,0 +1,31 @@
#pragma once
#include "Asset/AssetCreatorCollection.h"
#include "Asset/IZoneAssetCreationState.h"
#include "Asset/ZoneDefinitionContext.h"
#include "Gdt/IGdtQueryable.h"
#include "SearchPath/IOutputPath.h"
#include "SearchPath/ISearchPath.h"
#include "Zone/Zone.h"
class IObjCompiler
{
public:
IObjCompiler() = default;
virtual ~IObjCompiler() = default;
IObjCompiler(const IObjCompiler& other) = default;
IObjCompiler(IObjCompiler&& other) noexcept = default;
IObjCompiler& operator=(const IObjCompiler& other) = default;
IObjCompiler& operator=(IObjCompiler&& other) noexcept = default;
virtual void ConfigureCreatorCollection(AssetCreatorCollection& collection,
Zone& zone,
const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
IGdtQueryable& gdt,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir,
IOutputPath& cacheDir) const = 0;
static const IObjCompiler* GetObjCompilerForGame(GameId game);
};

View File

@ -0,0 +1,436 @@
#include "IPakCreator.h"
#include "Game/T6/CommonT6.h"
#include "Game/T6/GameT6.h"
#include "GitVersion.h"
#include "ObjContainer/IPak/IPakTypes.h"
#include "Utils/Alignment.h"
#include <algorithm>
#include <cassert>
#include <format>
#include <fstream>
#include <iostream>
#include <minilzo.h>
#include <zlib.h>
namespace
{
constexpr auto USE_IPAK_COMPRESSION = true;
class IPakWriter
{
static constexpr char BRANDING[] = "Created with OpenAssetTools " GIT_VERSION;
static constexpr auto SECTION_COUNT = 3; // Index + Data + Branding
inline static const std::string PAD_DATA = std::string(256, '\xA7');
public:
IPakWriter(std::ostream& stream, ISearchPath& searchPath, const std::vector<std::string>& images)
: m_stream(stream),
m_search_path(searchPath),
m_images(images),
m_current_offset(0),
m_total_size(0),
m_data_section_offset(0),
m_data_section_size(0u),
m_index_section_offset(0),
m_branding_section_offset(0),
m_file_offset(0u),
m_chunk_buffer_window_start(0),
m_current_block{},
m_current_block_header_offset(0)
{
m_decompressed_buffer = std::make_unique<char[]>(ipak_consts::IPAK_CHUNK_SIZE);
m_lzo_work_buffer = std::make_unique<char[]>(LZO1X_1_MEM_COMPRESS);
}
bool Write()
{
// We will write the header and sections later since they need complementary data
GoTo(sizeof(IPakHeader) + sizeof(IPakSection) * SECTION_COUNT);
AlignToChunk();
WriteDataSection();
WriteIndexSection();
WriteBrandingSection();
WriteFileEnding();
WriteHeaderData();
return true;
}
private:
void GoTo(const int64_t offset)
{
m_stream.seekp(offset, std::ios::beg);
m_current_offset = offset;
}
void Write(const void* data, const size_t dataSize)
{
m_stream.write(static_cast<const char*>(data), dataSize);
m_current_offset += dataSize;
}
void Pad(const size_t paddingSize)
{
auto paddingSizeLeft = paddingSize;
while (paddingSizeLeft > 0)
{
const auto writeSize = std::min(paddingSizeLeft, PAD_DATA.size());
Write(PAD_DATA.data(), writeSize);
paddingSizeLeft -= writeSize;
}
}
void AlignToChunk()
{
Pad(static_cast<size_t>(utils::Align(m_current_offset, static_cast<int64_t>(ipak_consts::IPAK_CHUNK_SIZE)) - m_current_offset));
}
void AlignToBlockHeader()
{
Pad(static_cast<size_t>(utils::Align(m_current_offset, static_cast<int64_t>(sizeof(IPakDataBlockHeader))) - m_current_offset));
}
void WriteHeaderData()
{
GoTo(0);
const IPakHeader header{ipak_consts::IPAK_MAGIC, ipak_consts::IPAK_VERSION, static_cast<uint32_t>(m_total_size), SECTION_COUNT};
const IPakSection dataSection{
ipak_consts::IPAK_DATA_SECTION,
static_cast<uint32_t>(m_data_section_offset),
static_cast<uint32_t>(m_data_section_size),
static_cast<uint32_t>(m_index_entries.size()),
};
const IPakSection indexSection{
ipak_consts::IPAK_INDEX_SECTION,
static_cast<uint32_t>(m_index_section_offset),
static_cast<uint32_t>(sizeof(IPakIndexEntry) * m_index_entries.size()),
static_cast<uint32_t>(m_index_entries.size()),
};
const IPakSection brandingSection{
ipak_consts::IPAK_BRANDING_SECTION,
static_cast<uint32_t>(m_branding_section_offset),
std::extent_v<decltype(BRANDING)>,
1,
};
Write(&header, sizeof(header));
Write(&dataSection, sizeof(dataSection));
Write(&indexSection, sizeof(indexSection));
Write(&brandingSection, sizeof(brandingSection));
}
static std::string ImageFileName(const std::string& imageName)
{
return std::format("images/{}.iwi", imageName);
}
std::unique_ptr<char[]> ReadImageDataFromSearchPath(const std::string& imageName, size_t& imageSize) const
{
const auto fileName = ImageFileName(imageName);
const auto openFile = m_search_path.Open(fileName);
if (!openFile.IsOpen())
{
std::cerr << std::format("Failed to open file for ipak: {}\n", fileName);
return nullptr;
}
imageSize = static_cast<size_t>(openFile.m_length);
auto imageData = std::make_unique<char[]>(imageSize);
openFile.m_stream->read(imageData.get(), imageSize);
return imageData;
}
void FlushBlock()
{
if (m_current_block_header_offset > 0)
{
const auto previousOffset = m_current_offset;
GoTo(m_current_block_header_offset);
Write(&m_current_block, sizeof(m_current_block));
GoTo(previousOffset);
}
}
void FlushChunk()
{
FlushBlock();
AlignToBlockHeader();
const auto nextChunkOffset = utils::Align(m_current_offset, static_cast<int64_t>(ipak_consts::IPAK_CHUNK_SIZE));
const auto sizeToSkip = static_cast<size_t>(nextChunkOffset - m_current_offset);
if (sizeToSkip >= sizeof(IPakDataBlockHeader))
{
IPakDataBlockHeader skipBlockHeader{};
skipBlockHeader.countAndOffset.count = 1;
skipBlockHeader.commands[0].compressed = ipak_consts::IPAK_COMMAND_SKIP;
skipBlockHeader.commands[0].size = sizeToSkip - sizeof(IPakDataBlockHeader);
Write(&skipBlockHeader, sizeof(skipBlockHeader));
}
AlignToChunk();
m_chunk_buffer_window_start = m_current_offset;
}
void StartNewBlock()
{
AlignToBlockHeader();
// Skip to the next chunk when only the header could fit into the current chunk anyway
if (static_cast<size_t>(utils::Align(m_current_offset, static_cast<int64_t>(ipak_consts::IPAK_CHUNK_SIZE)) - m_current_offset)
<= sizeof(IPakDataBlockHeader))
FlushChunk();
m_current_block_header_offset = m_current_offset;
m_current_block = {};
m_current_block.countAndOffset.offset = static_cast<uint32_t>(m_file_offset);
// Reserve space to later write actual block header data
GoTo(m_current_offset + sizeof(IPakDataBlockHeader));
}
void WriteChunkData(const void* data, const size_t dataSize)
{
auto dataOffset = 0u;
while (dataOffset < dataSize)
{
if (m_current_block.countAndOffset.count >= std::extent_v<decltype(IPakDataBlockHeader::commands)>)
{
FlushBlock();
StartNewBlock();
}
const auto remainingSize = dataSize - dataOffset;
const auto remainingChunkBufferWindowSize = std::max((ipak_consts::IPAK_CHUNK_COUNT_PER_READ * ipak_consts::IPAK_CHUNK_SIZE)
- static_cast<size_t>(m_current_offset - m_chunk_buffer_window_start),
0uz);
if (remainingChunkBufferWindowSize == 0)
{
FlushChunk();
StartNewBlock();
continue;
}
const auto commandSize = std::min(std::min(remainingSize, ipak_consts::IPAK_COMMAND_DEFAULT_SIZE), remainingChunkBufferWindowSize);
auto writeUncompressed = true;
if (USE_IPAK_COMPRESSION)
{
auto outLen = static_cast<lzo_uint>(ipak_consts::IPAK_CHUNK_SIZE);
const auto result = lzo1x_1_compress(&static_cast<const unsigned char*>(data)[dataOffset],
commandSize,
reinterpret_cast<unsigned char*>(m_decompressed_buffer.get()),
&outLen,
m_lzo_work_buffer.get());
if (result == LZO_E_OK && outLen < commandSize)
{
writeUncompressed = false;
Write(m_decompressed_buffer.get(), outLen);
const auto currentCommand = m_current_block.countAndOffset.count;
m_current_block.commands[currentCommand].size = static_cast<uint32_t>(outLen);
m_current_block.commands[currentCommand].compressed = ipak_consts::IPAK_COMMAND_COMPRESSED;
m_current_block.countAndOffset.count = currentCommand + 1u;
}
}
if (writeUncompressed)
{
Write(&static_cast<const char*>(data)[dataOffset], commandSize);
const auto currentCommand = m_current_block.countAndOffset.count;
m_current_block.commands[currentCommand].size = commandSize;
m_current_block.commands[currentCommand].compressed = ipak_consts::IPAK_COMMAND_UNCOMPRESSED;
m_current_block.countAndOffset.count = currentCommand + 1u;
}
dataOffset += commandSize;
m_file_offset += commandSize;
}
}
void StartNewFile()
{
FlushBlock();
m_file_offset = 0u;
StartNewBlock();
m_chunk_buffer_window_start = utils::AlignToPrevious(m_current_offset, static_cast<int64_t>(ipak_consts::IPAK_CHUNK_SIZE));
}
void WriteImageData(const std::string& imageName)
{
size_t imageSize;
const auto imageData = ReadImageDataFromSearchPath(imageName, imageSize);
if (!imageData)
return;
const auto nameHash = T6::Common::R_HashString(imageName.c_str(), 0);
const auto dataHash = static_cast<unsigned>(crc32(0u, reinterpret_cast<const Bytef*>(imageData.get()), imageSize));
StartNewFile();
const auto startOffset = m_current_block_header_offset;
IPakIndexEntry indexEntry;
indexEntry.key.nameHash = nameHash;
indexEntry.key.dataHash = dataHash & 0x1FFFFFFF;
indexEntry.offset = static_cast<uint32_t>(startOffset - m_data_section_offset);
WriteChunkData(imageData.get(), imageSize);
const auto writtenImageSize = static_cast<size_t>(m_current_offset - startOffset);
indexEntry.size = writtenImageSize;
m_index_entries.emplace_back(indexEntry);
}
void WriteDataSection()
{
AlignToChunk();
m_data_section_offset = m_current_offset;
m_data_section_size = 0u;
m_index_entries.reserve(m_images.size());
for (const auto& imageName : m_images)
WriteImageData(imageName);
FlushBlock();
m_data_section_size = static_cast<size_t>(m_current_offset - m_data_section_offset);
}
static bool CompareIndices(const IPakIndexEntry& entry1, const IPakIndexEntry& entry2)
{
return entry1.key.combinedKey < entry2.key.combinedKey;
}
void SortIndexSectionEntries()
{
std::ranges::sort(m_index_entries, CompareIndices);
}
void WriteIndexSection()
{
AlignToChunk();
m_index_section_offset = m_current_offset;
SortIndexSectionEntries();
for (const auto& indexEntry : m_index_entries)
Write(&indexEntry, sizeof(indexEntry));
}
void WriteBrandingSection()
{
AlignToChunk();
m_branding_section_offset = m_current_offset;
Write(BRANDING, std::extent_v<decltype(BRANDING)>);
}
void WriteFileEnding()
{
AlignToChunk();
m_total_size = m_current_offset;
}
std::ostream& m_stream;
ISearchPath& m_search_path;
const std::vector<std::string>& m_images;
int64_t m_current_offset;
std::vector<IPakIndexEntry> m_index_entries;
int64_t m_total_size;
int64_t m_data_section_offset;
size_t m_data_section_size;
int64_t m_index_section_offset;
int64_t m_branding_section_offset;
std::unique_ptr<char[]> m_decompressed_buffer;
std::unique_ptr<char[]> m_lzo_work_buffer;
size_t m_file_offset;
int64_t m_chunk_buffer_window_start;
IPakDataBlockHeader m_current_block;
int64_t m_current_block_header_offset;
};
} // namespace
IPakToCreate::IPakToCreate(std::string name)
: m_name(std::move(name))
{
}
void IPakToCreate::AddImage(std::string imageName)
{
m_image_names.emplace_back(std::move(imageName));
}
void IPakToCreate::Build(ISearchPath& searchPath, IOutputPath& outPath)
{
const auto file = outPath.Open(std::format("{}.ipak", m_name));
if (!file)
{
std::cerr << std::format("Failed to open file for ipak {}\n", m_name);
return;
}
IPakWriter writer(*file, searchPath, m_image_names);
writer.Write();
std::cout << std::format("Created ipak {} with {} entries\n", m_name, m_image_names.size());
}
const std::vector<std::string>& IPakToCreate::GetImageNames() const
{
return m_image_names;
}
IPakCreator::IPakCreator()
: m_kvp_creator(nullptr)
{
}
void IPakCreator::Inject(ZoneAssetCreationInjection& inject)
{
m_kvp_creator = &inject.m_zone_states.GetZoneAssetCreationState<KeyValuePairsCreator>();
}
IPakToCreate* IPakCreator::GetOrAddIPak(const std::string& ipakName)
{
const auto existingIPak = m_ipak_lookup.find(ipakName);
if (existingIPak != m_ipak_lookup.end())
return existingIPak->second;
auto newIPak = std::make_unique<IPakToCreate>(ipakName);
auto* result = newIPak.get();
m_ipak_lookup.emplace(ipakName, result);
m_ipaks.emplace_back(std::move(newIPak));
assert(m_kvp_creator);
m_kvp_creator->AddKeyValuePair(CommonKeyValuePair("ipak_read", ipakName));
return result;
}
void IPakCreator::Finalize(ISearchPath& searchPath, IOutputPath& outPath)
{
for (const auto& ipakToCreate : m_ipaks)
ipakToCreate->Build(searchPath, outPath);
m_ipaks.clear();
m_ipak_lookup.clear();
}

View File

@ -0,0 +1,40 @@
#pragma once
#include "Asset/IZoneAssetCreationState.h"
#include "KeyValuePairs/KeyValuePairsCreator.h"
#include "SearchPath/IOutputPath.h"
#include "SearchPath/ISearchPath.h"
#include <memory>
#include <string>
#include <unordered_map>
class IPakToCreate
{
public:
explicit IPakToCreate(std::string name);
void AddImage(std::string imageName);
void Build(ISearchPath& searchPath, IOutputPath& outPath);
[[nodiscard]] const std::vector<std::string>& GetImageNames() const;
private:
std::string m_name;
std::vector<std::string> m_image_names;
};
class IPakCreator final : public IZoneAssetCreationState
{
public:
IPakCreator();
void Inject(ZoneAssetCreationInjection& inject) override;
IPakToCreate* GetOrAddIPak(const std::string& ipakName);
void Finalize(ISearchPath& searchPath, IOutputPath& outPath);
private:
KeyValuePairsCreator* m_kvp_creator;
std::unordered_map<std::string, IPakToCreate*> m_ipak_lookup;
std::vector<std::unique_ptr<IPakToCreate>> m_ipaks;
};

View File

@ -0,0 +1,66 @@
#include "ImageIPakPostProcessor.h"
#include "IPak/IPakCreator.h"
#include <algorithm>
AbstractImageIPakPostProcessor::AbstractImageIPakPostProcessor(const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir)
: m_zone_definition(zoneDefinition),
m_search_path(searchPath),
m_ipak_creator(zoneStates.GetZoneAssetCreationState<IPakCreator>()),
m_out_dir(outDir),
m_obj_container_index(0u),
m_current_ipak(nullptr),
m_current_ipak_start_index(0u),
m_current_ipak_end_index(0u)
{
FindNextObjContainer();
}
bool AbstractImageIPakPostProcessor::AppliesToZoneDefinition(const ZoneDefinitionContext& zoneDefinition)
{
return std::ranges::any_of(zoneDefinition.m_zone_definition.m_obj_containers,
[](const ZoneDefinitionObjContainer& objContainer)
{
return objContainer.m_type == ZoneDefinitionObjContainerType::IPAK;
});
}
void AbstractImageIPakPostProcessor::FindNextObjContainer()
{
const auto objContainerCount = m_zone_definition.m_zone_definition.m_obj_containers.size();
while (m_obj_container_index < objContainerCount)
{
const auto& objContainer = m_zone_definition.m_zone_definition.m_obj_containers[m_obj_container_index++];
if (objContainer.m_type != ZoneDefinitionObjContainerType::IPAK)
continue;
m_current_ipak = m_ipak_creator.GetOrAddIPak(objContainer.m_name);
m_current_ipak_start_index = objContainer.m_asset_start;
m_current_ipak_end_index = objContainer.m_asset_end;
return;
}
m_current_ipak = nullptr;
}
void AbstractImageIPakPostProcessor::PostProcessAsset(XAssetInfoGeneric& assetInfo, AssetCreationContext& context)
{
if (assetInfo.m_name.empty() || assetInfo.m_name[0] == ',')
return;
while (m_current_ipak && m_zone_definition.m_asset_index_in_definition >= m_current_ipak_end_index)
FindNextObjContainer();
if (m_current_ipak && m_zone_definition.m_asset_index_in_definition >= m_current_ipak_start_index)
m_current_ipak->AddImage(assetInfo.m_name);
}
void AbstractImageIPakPostProcessor::FinalizeZone(AssetCreationContext& context)
{
m_ipak_creator.Finalize(m_search_path, m_out_dir);
}

View File

@ -0,0 +1,52 @@
#pragma once
#include "Asset/IAssetPostProcessor.h"
#include "Asset/ZoneDefinitionContext.h"
#include "Image/IPak/IPakCreator.h"
#include "SearchPath/IOutputPath.h"
class AbstractImageIPakPostProcessor : public IAssetPostProcessor
{
public:
AbstractImageIPakPostProcessor(const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir);
static bool AppliesToZoneDefinition(const ZoneDefinitionContext& zoneDefinition);
void PostProcessAsset(XAssetInfoGeneric& assetInfo, AssetCreationContext& context) override;
void FinalizeZone(AssetCreationContext& context) override;
private:
void FindNextObjContainer();
const ZoneDefinitionContext& m_zone_definition;
ISearchPath& m_search_path;
IPakCreator& m_ipak_creator;
IOutputPath& m_out_dir;
unsigned m_obj_container_index;
IPakToCreate* m_current_ipak;
unsigned m_current_ipak_start_index;
unsigned m_current_ipak_end_index;
};
template<typename AssetType> class ImageIPakPostProcessor final : public AbstractImageIPakPostProcessor
{
public:
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
ImageIPakPostProcessor(const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir)
: AbstractImageIPakPostProcessor(zoneDefinition, searchPath, zoneStates, outDir)
{
}
[[nodiscard]] asset_type_t GetHandlingAssetType() const override
{
return AssetType::EnumEntry;
}
};

View File

@ -0,0 +1,67 @@
#include "ImageIwdPostProcessor.h"
#include "Iwd/IwdCreator.h"
#include <algorithm>
#include <format>
AbstractImageIwdPostProcessor::AbstractImageIwdPostProcessor(const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir)
: m_zone_definition(zoneDefinition),
m_search_path(searchPath),
m_iwd_creator(zoneStates.GetZoneAssetCreationState<IwdCreator>()),
m_out_dir(outDir),
m_obj_container_index(0u),
m_current_iwd(nullptr),
m_current_iwd_start_index(0u),
m_current_iwd_end_index(0u)
{
FindNextObjContainer();
}
bool AbstractImageIwdPostProcessor::AppliesToZoneDefinition(const ZoneDefinitionContext& zoneDefinition)
{
return std::ranges::any_of(zoneDefinition.m_zone_definition.m_obj_containers,
[](const ZoneDefinitionObjContainer& objContainer)
{
return objContainer.m_type == ZoneDefinitionObjContainerType::IWD;
});
}
void AbstractImageIwdPostProcessor::FindNextObjContainer()
{
const auto objContainerCount = m_zone_definition.m_zone_definition.m_obj_containers.size();
while (m_obj_container_index < objContainerCount)
{
const auto& objContainer = m_zone_definition.m_zone_definition.m_obj_containers[m_obj_container_index++];
if (objContainer.m_type != ZoneDefinitionObjContainerType::IWD)
continue;
m_current_iwd = m_iwd_creator.GetOrAddIwd(objContainer.m_name);
m_current_iwd_start_index = objContainer.m_asset_start;
m_current_iwd_end_index = objContainer.m_asset_end;
return;
}
m_current_iwd = nullptr;
}
void AbstractImageIwdPostProcessor::PostProcessAsset(XAssetInfoGeneric& assetInfo, AssetCreationContext& context)
{
if (assetInfo.m_name.empty() || assetInfo.m_name[0] == ',')
return;
while (m_current_iwd && m_zone_definition.m_asset_index_in_definition >= m_current_iwd_end_index)
FindNextObjContainer();
if (m_current_iwd && m_zone_definition.m_asset_index_in_definition >= m_current_iwd_start_index)
m_current_iwd->AddFile(std::format("images/{}.iwi", assetInfo.m_name));
}
void AbstractImageIwdPostProcessor::FinalizeZone(AssetCreationContext& context)
{
m_iwd_creator.Finalize(m_search_path, m_out_dir);
}

View File

@ -0,0 +1,52 @@
#pragma once
#include "Asset/IAssetPostProcessor.h"
#include "Asset/ZoneDefinitionContext.h"
#include "Iwd/IwdCreator.h"
#include "SearchPath/IOutputPath.h"
class AbstractImageIwdPostProcessor : public IAssetPostProcessor
{
public:
AbstractImageIwdPostProcessor(const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir);
static bool AppliesToZoneDefinition(const ZoneDefinitionContext& zoneDefinition);
void PostProcessAsset(XAssetInfoGeneric& assetInfo, AssetCreationContext& context) override;
void FinalizeZone(AssetCreationContext& context) override;
private:
void FindNextObjContainer();
const ZoneDefinitionContext& m_zone_definition;
ISearchPath& m_search_path;
IwdCreator& m_iwd_creator;
IOutputPath& m_out_dir;
unsigned m_obj_container_index;
IwdToCreate* m_current_iwd;
unsigned m_current_iwd_start_index;
unsigned m_current_iwd_end_index;
};
template<typename AssetType> class ImageIwdPostProcessor final : public AbstractImageIwdPostProcessor
{
public:
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
ImageIwdPostProcessor(const ZoneDefinitionContext& zoneDefinition,
ISearchPath& searchPath,
ZoneAssetCreationStateContainer& zoneStates,
IOutputPath& outDir)
: AbstractImageIwdPostProcessor(zoneDefinition, searchPath, zoneStates, outDir)
{
}
[[nodiscard]] asset_type_t GetHandlingAssetType() const override
{
return AssetType::EnumEntry;
}
};

Some files were not shown because too many files have changed in this diff Show More