mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-22 17:15:46 +00:00
Compare commits
354 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
1cccfe352b | ||
|
dbcf7d86af | ||
|
f888d7a5d4 | ||
|
74b9f7b010 | ||
|
ba4cb85639 | ||
|
da90bbd356 | ||
|
13b07c0fe4 | ||
|
37fe6b6a5c | ||
|
ea5d27a7f9 | ||
|
38d948ebdd | ||
|
9f8a933277 | ||
|
9f738da517 | ||
|
785cf8c025 | ||
|
0f3ee1fa79 | ||
|
c8cd6826c1 | ||
|
5afc24fd89 | ||
|
598abe095b | ||
|
d6eee273ff | ||
|
7edbe7378b | ||
|
b83bafb0f8 | ||
|
e750e3ffd9 | ||
|
d5b6c6e9c2 | ||
|
d6c1ef775e | ||
|
c05d4ea34e | ||
|
b2d9bf416d | ||
|
3134ec5a37 | ||
|
0d35696940 | ||
|
b215b22018 | ||
|
a447dd29fa | ||
|
985996975b | ||
|
f235798cf6 | ||
|
0228e86980 | ||
|
01302cf061 | ||
|
6f31e8cc29 | ||
|
37d52ae8da | ||
|
481d301545 | ||
|
d3bb99e92c | ||
|
cec70e783f | ||
|
a2c8129a13 | ||
|
e13eb256bb | ||
|
aab510c917 | ||
|
820fe47473 | ||
|
0366b24bd7 | ||
|
49f0794545 | ||
|
20911d552d | ||
|
1748f9e1a5 | ||
|
a37b5fee8c | ||
|
42e2eb80b3 | ||
|
885c57bfa5 | ||
|
fa88b135f9 | ||
|
56c4eeb5cd | ||
|
0fcae6a55a | ||
|
f97f38dc31 | ||
|
95f5dca5e0 | ||
|
f2723255f5 | ||
|
11cb93f736 | ||
|
e40d688e11 | ||
|
2eeb20d1cd | ||
|
7b79504477 | ||
|
4cc7ab77d5 | ||
|
08fb6b0496 | ||
|
a871889c13 | ||
|
81bc21eacf | ||
|
aec779dae5 | ||
|
97c4a23d5e | ||
|
0c587e5e5f | ||
|
4ac38bfc66 | ||
|
34a0bd4f4f | ||
|
047e8aa125 | ||
|
b5303475d9 | ||
|
4adc9115b2 | ||
|
a4347b0b0d | ||
|
4e5c72d79a | ||
|
58f5f66dcf | ||
|
54d19dcc8a | ||
|
f05a21984a | ||
|
b071beea3f | ||
|
548c0c23bf | ||
|
6d186bc09c | ||
|
96dc2c9318 | ||
|
e4c08e1372 | ||
|
1b6824f2bd | ||
|
0eb0383051 | ||
|
222d96a923 | ||
|
07dccbf2f8 | ||
|
b24b6b1979 | ||
|
a220142e86 | ||
|
4c30bd129a | ||
|
3d3a0ca565 | ||
|
903bd5a960 | ||
|
2402d4f9c7 | ||
|
a21b410fd7 | ||
|
2b1ade2b5a | ||
|
d869de5881 | ||
|
2ce1a4e050 | ||
|
89e22329f8 | ||
|
bea601d932 | ||
|
826c1d2f2d | ||
|
0b91eeb932 | ||
|
94ca0ab79e | ||
|
f6d36b2d6e | ||
|
140eb7b7a4 | ||
|
708e759f8c | ||
|
80fa61b45c | ||
|
f436cd6caa | ||
|
4d0b0651eb | ||
|
7a639a359c | ||
|
990bfe27df | ||
|
b4194eff28 | ||
|
8ace49b715 | ||
|
b623ed49a0 | ||
|
0ffbdf5b73 | ||
|
f930c874b8 | ||
|
74f84cbf83 | ||
|
8c453f1683 | ||
|
aa73dca59d | ||
|
a41d15d43a | ||
|
64bac44e63 | ||
|
85d9f1c255 | ||
|
d9f23a0b76 | ||
|
a1d3e64813 | ||
|
cc67f6e730 | ||
|
a364e63258 | ||
|
4c09e94220 | ||
|
62f1ac41c5 | ||
|
fea4970b84 | ||
|
0f1c67b54c | ||
|
419481b4da | ||
|
32c0ecb04d | ||
|
d1d4752114 | ||
|
6e6bfca38c | ||
|
4240ddd4c7 | ||
|
1d39062372 | ||
|
2d58054ffc | ||
|
b584cd7423 | ||
|
27c01e0a41 | ||
|
a759f3d82b | ||
|
c86f9f6391 | ||
|
36f0764cd5 | ||
|
0a98da9a79 | ||
315eb76127 | |||
|
68665c79c9 | ||
|
d04e76e635 | ||
|
50ece7dee2 | ||
|
9535342e60 | ||
|
44440ab92e | ||
|
f449527e51 | ||
|
77c6e2d53c | ||
|
2c5f5215f3 | ||
|
5d69473551 | ||
|
e5e92b7b23 | ||
|
98288f5d47 | ||
|
d1e6aa9da0 | ||
|
fa249b0bd3 | ||
|
54e240e98c | ||
|
3b5ca86b0d | ||
|
8c8ceae0bd | ||
|
e0f8b3d3ca | ||
|
cacccf64e1 | ||
|
67fb11506c | ||
|
83833cb84e | ||
|
ce3786f086 | ||
|
fc9e6ce14d | ||
|
16e82f68ca | ||
|
dbecafd2a2 | ||
|
3ef65f741b | ||
|
768f4337f7 | ||
|
a781aae1c9 | ||
|
b84c719d3f | ||
|
ac43b646cc | ||
|
2313da1c12 | ||
|
ef862ff246 | ||
|
3c3161448f | ||
|
416823c6cd | ||
|
9068e96dfa | ||
|
fa6f9451d2 | ||
|
41d97c0954 | ||
|
e92797e0b8 | ||
|
ca761dfdbc | ||
|
9097db7d0f | ||
|
dfd6e4117c | ||
|
351b6bb1ea | ||
|
fe5d0f79ff | ||
|
a7254aa11c | ||
|
b5937ef975 | ||
|
aa212e0958 | ||
|
9852f52a15 | ||
|
e11e8a361e | ||
|
dd4f18b638 | ||
|
ffac925410 | ||
|
da7a60221c | ||
|
27ef3152a0 | ||
|
b7c8c70f2a | ||
|
80c4a9a2ae | ||
|
306ffb730e | ||
|
692c31b711 | ||
|
83d13aa166 | ||
|
d8bc156ffd | ||
|
a36581b06e | ||
|
9ae5aaa1db | ||
|
a5873a301f | ||
|
7ef944ebd4 | ||
|
f9456101e6 | ||
|
4f585c6aa7 | ||
|
9ebea5034a | ||
|
c524cb007a | ||
|
673db0592f | ||
|
2c8fcf1630 | ||
|
4f0a405bdc | ||
|
63046f5681 | ||
|
a240824706 | ||
|
110f31e58a | ||
|
be6c30c503 | ||
|
fd421c4784 | ||
|
3803ae24f5 | ||
|
f9e0bdaa7b | ||
|
2182196730 | ||
|
973ff73554 | ||
|
7097e36d27 | ||
|
a98fa5b5e3 | ||
|
f3d8addde8 | ||
|
00ab5e69e1 | ||
|
1a5ebb0d81 | ||
|
a17360c916 | ||
|
f6921acbc2 | ||
|
3db816fb7f | ||
|
50e396c587 | ||
|
cc39a394e6 | ||
|
b16198c705 | ||
|
f1f13d09eb | ||
|
5e02352784 | ||
|
ce3f2c6d97 | ||
|
b571024385 | ||
|
fa250531b2 | ||
|
9d37005445 | ||
|
45ac414c11 | ||
|
6d7fed74a6 | ||
|
815f484aa6 | ||
|
fddfe57d99 | ||
|
9ab581c072 | ||
|
96b055a37b | ||
|
b5e50c87fb | ||
|
2c837a53b9 | ||
|
d4a9211211 | ||
|
39a5564186 | ||
|
76aed9af14 | ||
|
e6f8ec3419 | ||
|
130933ac29 | ||
|
9da2f5e788 | ||
|
a2063057ec | ||
|
59ff4c0b1d | ||
|
ecf2a026f7 | ||
|
6117f4c206 | ||
|
a6340adb38 | ||
|
66beda8723 | ||
|
46da761892 | ||
|
6fb132dbfc | ||
|
4572687502 | ||
|
7fb5c98894 | ||
|
3079c5ee0d | ||
|
218612b8c8 | ||
|
19f19f7adb | ||
|
47b6d7720c | ||
|
2034db3330 | ||
|
303f1da0bc | ||
|
a559fbafd2 | ||
|
6ed907c114 | ||
|
aa8300052a | ||
|
0591befd22 | ||
|
5ad37e0e44 | ||
|
106affc794 | ||
|
b0911919a5 | ||
|
c202264ad0 | ||
|
18c903a9e2 | ||
|
ecb7b06e11 | ||
|
242bf64576 | ||
|
b00c65c8c0 | ||
|
ce16d8e6c8 | ||
|
a1851b0ea0 | ||
|
778361728c | ||
|
897a571a41 | ||
|
3aaa821b74 | ||
|
e80b9d7460 | ||
|
bb845f68e9 | ||
|
4c9a84777f | ||
|
c034ac790a | ||
|
eec643fab5 | ||
|
5fb476719f | ||
|
130da9343f | ||
|
0e085971f3 | ||
|
d135da5134 | ||
|
b7af67e71d | ||
|
1c01a2d8c9 | ||
|
0e3d9efb0f | ||
|
bc0f42a18f | ||
|
0a423937f0 | ||
|
dadce3dcca | ||
|
dfcaf75b00 | ||
|
c13d0668e4 | ||
|
6a11f22a66 | ||
|
8127b667de | ||
|
36fda384b3 | ||
|
bf23d797aa | ||
|
ac7b1800f0 | ||
|
cfb7c7ca78 | ||
|
038ed9a37a | ||
|
e98fad73b9 | ||
|
6beff28518 | ||
|
e9720a2b1a | ||
|
9f9e20988a | ||
|
c245daf56e | ||
|
351a4441c2 | ||
|
bd57f84ecd | ||
|
321c5067ed | ||
|
ed06700f99 | ||
|
93a35f5dcf | ||
|
5f8eb30ce0 | ||
|
4529ff2c5e | ||
|
a926b752cf | ||
|
494ea8f89c | ||
|
2aac08a62d | ||
|
ff02491e08 | ||
|
1774001598 | ||
|
1fc31b8c44 | ||
|
d2b95b4ebe | ||
|
d814fe7b95 | ||
|
a3b9d2693c | ||
|
8620ce864c | ||
|
bc51ecb49d | ||
|
ff98b53625 | ||
|
c1d3138b04 | ||
|
90f45c0cea | ||
|
1a7d2cf1a2 | ||
|
1861bd689c | ||
|
b156c7348a | ||
|
d2b4b2dc38 | ||
|
963ec4f71c | ||
|
70bfd06fdc | ||
|
0ea55810ab | ||
|
cdc65e0425 | ||
|
c1896934ed | ||
|
a8fefbc978 | ||
|
d2fa1f40f4 | ||
|
2dccd423af | ||
|
a2d70c17ba | ||
|
8bd70662e0 | ||
|
5cc52c42cd | ||
|
5fee875495 | ||
|
32480a75eb | ||
|
2b1c048a4a | ||
|
da18291c89 | ||
|
c37e9984ba | ||
|
fabefc8cd5 | ||
|
d558a4e075 |
30
.github/workflows/ci.yaml
vendored
30
.github/workflows/ci.yaml
vendored
@ -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
|
||||
|
35
.github/workflows/release.yaml
vendored
35
.github/workflows/release.yaml
vendored
@ -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
|
||||
|
@ -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>`.
|
||||
|
||||
|
@ -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 | ❌ | ❌ | |
|
||||
|
84
generate.bat
84
generate.bat
@ -1,6 +1,88 @@
|
||||
@echo off
|
||||
|
||||
set PREMAKE_URL="https://github.com/premake/premake-core/releases/download/v5.0.0-beta6/premake-5.0.0-beta6-windows.zip"
|
||||
set PREMAKE_HASH="c34a6e0b15f119f6284886298fdd8df543af87ad16f3ce5f4d0a847be2a88343"
|
||||
|
||||
@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 -Force"
|
||||
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 (
|
||||
build\premake5.exe --version >NUL
|
||||
IF NOT ERRORLEVEL 1 (
|
||||
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
|
||||
|
75
generate.sh
75
generate.sh
@ -1,7 +1,80 @@
|
||||
#!/bin/bash
|
||||
|
||||
PREMAKE_URL='https://github.com/premake/premake-core/releases/download/v5.0.0-beta6/premake-5.0.0-beta6-linux.tar.gz'
|
||||
PREMAKE_HASH='fade2839ace1a2953556693e6f3d8f9b8b2897894b5a1f2ad477cdf8e9af042a'
|
||||
|
||||
# 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
|
||||
}
|
||||
|
||||
function expect_inside_git_repository {
|
||||
inside_git_repo="$(git rev-parse --is-inside-work-tree 2>/dev/null)"
|
||||
if [ ! -d ".git" ] && [ ! "$inside_git_repo" ]; then
|
||||
echo "You must clone the OpenAssetTools repository using 'git clone'. Please read README.md." >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Go to repository root
|
||||
cd "$(dirname "$0")" || exit 2
|
||||
|
||||
expect_inside_git_repository
|
||||
|
||||
PREMAKE_BIN=''
|
||||
if [[ -z "$PREMAKE_NO_GLOBAL" ]] && [[ -x "$(command -v premake5)" ]]; then
|
||||
PREMAKE_BIN='premake5'
|
||||
elif [[ -x "$(command -v build/premake5)" ]] && [[ ! -z "$(build/premake5 --version)" ]]; 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 $@ gmake
|
||||
|
24
premake5.lua
24
premake5.lua
@ -1,3 +1,5 @@
|
||||
require("premake", ">=5.0.0-beta5")
|
||||
|
||||
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 {
|
||||
@ -112,6 +116,7 @@ group ""
|
||||
-- ========================
|
||||
include "src/Common.lua"
|
||||
include "src/Crypto.lua"
|
||||
include "src/ImageConverter.lua"
|
||||
include "src/Linker.lua"
|
||||
include "src/Parser.lua"
|
||||
include "src/RawTemplater.lua"
|
||||
@ -125,6 +130,8 @@ 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"
|
||||
include "tools/scripts/raw.lua"
|
||||
@ -141,6 +148,8 @@ group "Components"
|
||||
ZoneLoading:project()
|
||||
ZoneWriting:project()
|
||||
ObjCommon:project()
|
||||
ObjCompiling:project()
|
||||
ObjImage:project()
|
||||
ObjLoading:project()
|
||||
ObjWriting:project()
|
||||
group ""
|
||||
@ -155,6 +164,7 @@ group ""
|
||||
group "Tools"
|
||||
Linker:project()
|
||||
Unlinker:project()
|
||||
ImageConverter:project()
|
||||
group ""
|
||||
|
||||
group "Raw"
|
||||
@ -164,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"
|
||||
@ -173,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
23
scripts/build.sh
Executable 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
6
scripts/check-format-docker.sh
Executable 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
6
scripts/reformat-all-docker.sh
Executable 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
|
@ -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; \
|
||||
} \
|
||||
}
|
||||
|
26
src/Common/Game/IGame.cpp
Normal file
26
src/Common/Game/IGame.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include "IGame.h"
|
||||
|
||||
#include "IW3/GameIW3.h"
|
||||
#include "IW4/GameIW4.h"
|
||||
#include "IW5/GameIW5.h"
|
||||
#include "T5/GameT5.h"
|
||||
#include "T6/GameT6.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
IGame* IGame::GetGameById(GameId gameId)
|
||||
{
|
||||
static IGame* games[static_cast<unsigned>(GameId::COUNT)]{
|
||||
new IW3::Game(),
|
||||
new IW4::Game(),
|
||||
new IW5::Game(),
|
||||
new T5::Game(),
|
||||
new T6::Game(),
|
||||
};
|
||||
|
||||
assert(static_cast<unsigned>(gameId) < static_cast<unsigned>(GameId::COUNT));
|
||||
auto* result = games[static_cast<unsigned>(gameId)];
|
||||
assert(result);
|
||||
|
||||
return result;
|
||||
}
|
@ -1,10 +1,31 @@
|
||||
#pragma once
|
||||
#include "GameLanguage.h"
|
||||
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
class Zone;
|
||||
|
||||
enum class GameId
|
||||
{
|
||||
IW3,
|
||||
IW4,
|
||||
IW5,
|
||||
T5,
|
||||
T6,
|
||||
|
||||
COUNT
|
||||
};
|
||||
|
||||
static constexpr const char* GameId_Names[]{
|
||||
"IW3",
|
||||
"IW4",
|
||||
"IW5",
|
||||
"T5",
|
||||
"T6",
|
||||
};
|
||||
static_assert(std::extent_v<decltype(GameId_Names)> == static_cast<unsigned>(GameId::COUNT));
|
||||
|
||||
class IGame
|
||||
{
|
||||
public:
|
||||
@ -15,10 +36,13 @@ public:
|
||||
IGame& operator=(const IGame& other) = default;
|
||||
IGame& operator=(IGame&& other) noexcept = default;
|
||||
|
||||
virtual std::string GetFullName() = 0;
|
||||
virtual std::string GetShortName() = 0;
|
||||
[[nodiscard]] virtual GameId GetId() const = 0;
|
||||
[[nodiscard]] virtual const std::string& GetFullName() const = 0;
|
||||
[[nodiscard]] virtual const std::string& GetShortName() const = 0;
|
||||
virtual void AddZone(Zone* zone) = 0;
|
||||
virtual void RemoveZone(Zone* zone) = 0;
|
||||
virtual std::vector<Zone*> GetZones() = 0;
|
||||
virtual std::vector<GameLanguagePrefix> GetLanguagePrefixes() = 0;
|
||||
[[nodiscard]] virtual const std::vector<Zone*>& GetZones() const = 0;
|
||||
[[nodiscard]] virtual const std::vector<GameLanguagePrefix>& GetLanguagePrefixes() const = 0;
|
||||
|
||||
static IGame* GetGameById(GameId gameId);
|
||||
};
|
||||
|
@ -1,29 +1,32 @@
|
||||
#include "GameIW3.h"
|
||||
|
||||
#include "IW3.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace IW3;
|
||||
|
||||
GameIW3 g_GameIW3;
|
||||
|
||||
std::string GameIW3::GetFullName()
|
||||
GameId Game::GetId() const
|
||||
{
|
||||
return "Call Of Duty 4: Modern Warfare";
|
||||
return GameId::IW3;
|
||||
}
|
||||
|
||||
std::string GameIW3::GetShortName()
|
||||
const std::string& Game::GetFullName() const
|
||||
{
|
||||
return "IW3";
|
||||
static std::string fullName = "Call Of Duty 4: Modern Warfare";
|
||||
return fullName;
|
||||
}
|
||||
|
||||
void GameIW3::AddZone(Zone* zone)
|
||||
const std::string& Game::GetShortName() const
|
||||
{
|
||||
static std::string shortName = "IW3";
|
||||
return shortName;
|
||||
}
|
||||
|
||||
void Game::AddZone(Zone* zone)
|
||||
{
|
||||
m_zones.push_back(zone);
|
||||
}
|
||||
|
||||
void GameIW3::RemoveZone(Zone* zone)
|
||||
void Game::RemoveZone(Zone* zone)
|
||||
{
|
||||
const auto foundEntry = std::ranges::find(m_zones, zone);
|
||||
|
||||
@ -31,13 +34,13 @@ void GameIW3::RemoveZone(Zone* zone)
|
||||
m_zones.erase(foundEntry);
|
||||
}
|
||||
|
||||
std::vector<Zone*> GameIW3::GetZones()
|
||||
const std::vector<Zone*>& Game::GetZones() const
|
||||
{
|
||||
return m_zones;
|
||||
}
|
||||
|
||||
std::vector<GameLanguagePrefix> GameIW3::GetLanguagePrefixes()
|
||||
const std::vector<GameLanguagePrefix>& Game::GetLanguagePrefixes() const
|
||||
{
|
||||
std::vector<GameLanguagePrefix> prefixes;
|
||||
static std::vector<GameLanguagePrefix> prefixes;
|
||||
return prefixes;
|
||||
}
|
||||
|
@ -1,17 +1,20 @@
|
||||
#pragma once
|
||||
#include "Game/IGame.h"
|
||||
|
||||
class GameIW3 : public IGame
|
||||
namespace IW3
|
||||
{
|
||||
std::vector<Zone*> m_zones;
|
||||
class Game final : public IGame
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] GameId GetId() const override;
|
||||
[[nodiscard]] const std::string& GetFullName() const override;
|
||||
[[nodiscard]] const std::string& GetShortName() const override;
|
||||
void AddZone(Zone* zone) override;
|
||||
void RemoveZone(Zone* zone) override;
|
||||
[[nodiscard]] const std::vector<Zone*>& GetZones() const override;
|
||||
[[nodiscard]] const std::vector<GameLanguagePrefix>& GetLanguagePrefixes() const override;
|
||||
|
||||
public:
|
||||
std::string GetFullName() override;
|
||||
std::string GetShortName() override;
|
||||
void AddZone(Zone* zone) override;
|
||||
void RemoveZone(Zone* zone) override;
|
||||
std::vector<Zone*> GetZones() override;
|
||||
std::vector<GameLanguagePrefix> GetLanguagePrefixes() override;
|
||||
};
|
||||
|
||||
extern GameIW3 g_GameIW3;
|
||||
private:
|
||||
std::vector<Zone*> m_zones;
|
||||
};
|
||||
} // namespace IW3
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
// #include <d3d9.h>
|
||||
#include "Game/IAsset.h"
|
||||
#include "Image/Texture.h"
|
||||
|
||||
#include "IW3_Assets.h"
|
||||
|
||||
@ -114,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);
|
||||
|
@ -1326,7 +1326,6 @@ namespace IW3
|
||||
// void/*IDirect3DTexture9*/* map;
|
||||
// void/*IDirect3DVolumeTexture9*/* volmap;
|
||||
// void/*IDirect3DCubeTexture9*/* cubemap;
|
||||
Texture* texture;
|
||||
GfxImageLoadDef* loadDef;
|
||||
};
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include "Utils/Pack.h"
|
||||
|
||||
#include <cctype>
|
||||
|
||||
using namespace IW4;
|
||||
|
||||
int Common::StringTable_HashString(const char* str)
|
||||
|
@ -1,29 +1,32 @@
|
||||
#include "GameIW4.h"
|
||||
|
||||
#include "IW4.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace IW4;
|
||||
|
||||
GameIW4 g_GameIW4;
|
||||
|
||||
std::string GameIW4::GetFullName()
|
||||
GameId Game::GetId() const
|
||||
{
|
||||
return "Call Of Duty: Modern Warfare 2";
|
||||
return GameId::IW4;
|
||||
}
|
||||
|
||||
std::string GameIW4::GetShortName()
|
||||
const std::string& Game::GetFullName() const
|
||||
{
|
||||
return "IW4";
|
||||
static std::string fullName = "Call Of Duty: Modern Warfare 2";
|
||||
return fullName;
|
||||
}
|
||||
|
||||
void GameIW4::AddZone(Zone* zone)
|
||||
const std::string& Game::GetShortName() const
|
||||
{
|
||||
static std::string shortName = "IW4";
|
||||
return shortName;
|
||||
}
|
||||
|
||||
void Game::AddZone(Zone* zone)
|
||||
{
|
||||
m_zones.push_back(zone);
|
||||
}
|
||||
|
||||
void GameIW4::RemoveZone(Zone* zone)
|
||||
void Game::RemoveZone(Zone* zone)
|
||||
{
|
||||
const auto foundEntry = std::ranges::find(m_zones, zone);
|
||||
|
||||
@ -31,13 +34,13 @@ void GameIW4::RemoveZone(Zone* zone)
|
||||
m_zones.erase(foundEntry);
|
||||
}
|
||||
|
||||
std::vector<Zone*> GameIW4::GetZones()
|
||||
const std::vector<Zone*>& Game::GetZones() const
|
||||
{
|
||||
return m_zones;
|
||||
}
|
||||
|
||||
std::vector<GameLanguagePrefix> GameIW4::GetLanguagePrefixes()
|
||||
const std::vector<GameLanguagePrefix>& Game::GetLanguagePrefixes() const
|
||||
{
|
||||
std::vector<GameLanguagePrefix> prefixes;
|
||||
static std::vector<GameLanguagePrefix> prefixes;
|
||||
return prefixes;
|
||||
}
|
||||
|
@ -1,17 +1,20 @@
|
||||
#pragma once
|
||||
#include "Game/IGame.h"
|
||||
|
||||
class GameIW4 : public IGame
|
||||
namespace IW4
|
||||
{
|
||||
std::vector<Zone*> m_zones;
|
||||
class Game final : public IGame
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] GameId GetId() const override;
|
||||
[[nodiscard]] const std::string& GetFullName() const override;
|
||||
[[nodiscard]] const std::string& GetShortName() const override;
|
||||
void AddZone(Zone* zone) override;
|
||||
void RemoveZone(Zone* zone) override;
|
||||
[[nodiscard]] const std::vector<Zone*>& GetZones() const override;
|
||||
[[nodiscard]] const std::vector<GameLanguagePrefix>& GetLanguagePrefixes() const override;
|
||||
|
||||
public:
|
||||
std::string GetFullName() override;
|
||||
std::string GetShortName() override;
|
||||
void AddZone(Zone* zone) override;
|
||||
void RemoveZone(Zone* zone) override;
|
||||
std::vector<Zone*> GetZones() override;
|
||||
std::vector<GameLanguagePrefix> GetLanguagePrefixes() override;
|
||||
};
|
||||
|
||||
extern GameIW4 g_GameIW4;
|
||||
private:
|
||||
std::vector<Zone*> m_zones;
|
||||
};
|
||||
} // namespace IW4
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
// #include <d3d9.h>
|
||||
#include "Game/IAsset.h"
|
||||
#include "Image/Texture.h"
|
||||
|
||||
#include "IW4_Assets.h"
|
||||
|
||||
@ -169,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);
|
||||
|
@ -1009,7 +1009,6 @@ namespace IW4
|
||||
// IDirect3DTexture9* map;
|
||||
// IDirect3DVolumeTexture9* volmap;
|
||||
// IDirect3DCubeTexture9* cubemap;
|
||||
Texture* texture;
|
||||
GfxImageLoadDef* loadDef;
|
||||
};
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include "Utils/Pack.h"
|
||||
|
||||
#include <cctype>
|
||||
|
||||
using namespace IW5;
|
||||
|
||||
int Common::StringTable_HashString(const char* str)
|
||||
|
@ -1,29 +1,32 @@
|
||||
#include "GameIW5.h"
|
||||
|
||||
#include "IW5.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace IW5;
|
||||
|
||||
GameIW5 g_GameIW5;
|
||||
|
||||
std::string GameIW5::GetFullName()
|
||||
GameId Game::GetId() const
|
||||
{
|
||||
return "Call Of Duty: Modern Warfare 3";
|
||||
return GameId::IW5;
|
||||
}
|
||||
|
||||
std::string GameIW5::GetShortName()
|
||||
const std::string& Game::GetFullName() const
|
||||
{
|
||||
return "IW5";
|
||||
static std::string fullName = "Call Of Duty: Modern Warfare 3";
|
||||
return fullName;
|
||||
}
|
||||
|
||||
void GameIW5::AddZone(Zone* zone)
|
||||
const std::string& Game::GetShortName() const
|
||||
{
|
||||
static std::string shortName = "IW5";
|
||||
return shortName;
|
||||
}
|
||||
|
||||
void Game::AddZone(Zone* zone)
|
||||
{
|
||||
m_zones.push_back(zone);
|
||||
}
|
||||
|
||||
void GameIW5::RemoveZone(Zone* zone)
|
||||
void Game::RemoveZone(Zone* zone)
|
||||
{
|
||||
const auto foundEntry = std::ranges::find(m_zones, zone);
|
||||
|
||||
@ -31,13 +34,13 @@ void GameIW5::RemoveZone(Zone* zone)
|
||||
m_zones.erase(foundEntry);
|
||||
}
|
||||
|
||||
std::vector<Zone*> GameIW5::GetZones()
|
||||
const std::vector<Zone*>& Game::GetZones() const
|
||||
{
|
||||
return m_zones;
|
||||
}
|
||||
|
||||
std::vector<GameLanguagePrefix> GameIW5::GetLanguagePrefixes()
|
||||
const std::vector<GameLanguagePrefix>& Game::GetLanguagePrefixes() const
|
||||
{
|
||||
std::vector<GameLanguagePrefix> prefixes;
|
||||
static std::vector<GameLanguagePrefix> prefixes;
|
||||
return prefixes;
|
||||
}
|
||||
|
@ -1,17 +1,20 @@
|
||||
#pragma once
|
||||
#include "Game/IGame.h"
|
||||
|
||||
class GameIW5 : public IGame
|
||||
namespace IW5
|
||||
{
|
||||
std::vector<Zone*> m_zones;
|
||||
class Game final : public IGame
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] GameId GetId() const override;
|
||||
[[nodiscard]] const std::string& GetFullName() const override;
|
||||
[[nodiscard]] const std::string& GetShortName() const override;
|
||||
void AddZone(Zone* zone) override;
|
||||
void RemoveZone(Zone* zone) override;
|
||||
[[nodiscard]] const std::vector<Zone*>& GetZones() const override;
|
||||
[[nodiscard]] const std::vector<GameLanguagePrefix>& GetLanguagePrefixes() const override;
|
||||
|
||||
public:
|
||||
std::string GetFullName() override;
|
||||
std::string GetShortName() override;
|
||||
void AddZone(Zone* zone) override;
|
||||
void RemoveZone(Zone* zone) override;
|
||||
std::vector<Zone*> GetZones() override;
|
||||
std::vector<GameLanguagePrefix> GetLanguagePrefixes() override;
|
||||
};
|
||||
|
||||
extern GameIW5 g_GameIW5;
|
||||
private:
|
||||
std::vector<Zone*> m_zones;
|
||||
};
|
||||
} // namespace IW5
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
// #include <d3d9.h>
|
||||
#include "Game/IAsset.h"
|
||||
#include "Image/Texture.h"
|
||||
|
||||
#include "IW5_Assets.h"
|
||||
|
||||
@ -180,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);
|
||||
|
@ -1143,9 +1143,6 @@ namespace IW5
|
||||
// IDirect3DTexture9* map;
|
||||
// IDirect3DVolumeTexture9* volmap;
|
||||
// IDirect3DCubeTexture9* cubemap;
|
||||
#ifndef __ida
|
||||
Texture* texture;
|
||||
#endif
|
||||
GfxImageLoadDef* loadDef;
|
||||
};
|
||||
|
||||
|
@ -1,29 +1,32 @@
|
||||
#include "GameT5.h"
|
||||
|
||||
#include "T5.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace T5;
|
||||
|
||||
GameT5 g_GameT5;
|
||||
|
||||
std::string GameT5::GetFullName()
|
||||
GameId Game::GetId() const
|
||||
{
|
||||
return "Call Of Duty: Black Ops";
|
||||
return GameId::T5;
|
||||
}
|
||||
|
||||
std::string GameT5::GetShortName()
|
||||
const std::string& Game::GetFullName() const
|
||||
{
|
||||
return "T5";
|
||||
static std::string fullName = "Call Of Duty: Black Ops";
|
||||
return fullName;
|
||||
}
|
||||
|
||||
void GameT5::AddZone(Zone* zone)
|
||||
const std::string& Game::GetShortName() const
|
||||
{
|
||||
static std::string shortName = "T5";
|
||||
return shortName;
|
||||
}
|
||||
|
||||
void Game::AddZone(Zone* zone)
|
||||
{
|
||||
m_zones.push_back(zone);
|
||||
}
|
||||
|
||||
void GameT5::RemoveZone(Zone* zone)
|
||||
void Game::RemoveZone(Zone* zone)
|
||||
{
|
||||
const auto foundEntry = std::ranges::find(m_zones, zone);
|
||||
|
||||
@ -31,28 +34,28 @@ void GameT5::RemoveZone(Zone* zone)
|
||||
m_zones.erase(foundEntry);
|
||||
}
|
||||
|
||||
std::vector<Zone*> GameT5::GetZones()
|
||||
const std::vector<Zone*>& Game::GetZones() const
|
||||
{
|
||||
return m_zones;
|
||||
}
|
||||
|
||||
std::vector<GameLanguagePrefix> GameT5::GetLanguagePrefixes()
|
||||
const std::vector<GameLanguagePrefix>& Game::GetLanguagePrefixes() const
|
||||
{
|
||||
std::vector<GameLanguagePrefix> prefixes;
|
||||
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_ENGLISH, "en_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_FRENCH, "fr_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_FRENCH_CAN, "fc_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_GERMAN, "ge_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_AUSTRIAN, "ge_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_ITALIAN, "it_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_SPANISH, "sp_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_BRITISH, "br_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_RUSSIAN, "ru_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_POLISH, "po_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_KOREAN, "ko_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_JAPANESE, "ja_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_CZECH, "cz_");
|
||||
static std::vector<GameLanguagePrefix> prefixes{
|
||||
{GameLanguage::LANGUAGE_ENGLISH, "en_"},
|
||||
{GameLanguage::LANGUAGE_FRENCH, "fr_"},
|
||||
{GameLanguage::LANGUAGE_FRENCH_CAN, "fc_"},
|
||||
{GameLanguage::LANGUAGE_GERMAN, "ge_"},
|
||||
{GameLanguage::LANGUAGE_AUSTRIAN, "ge_"},
|
||||
{GameLanguage::LANGUAGE_ITALIAN, "it_"},
|
||||
{GameLanguage::LANGUAGE_SPANISH, "sp_"},
|
||||
{GameLanguage::LANGUAGE_BRITISH, "br_"},
|
||||
{GameLanguage::LANGUAGE_RUSSIAN, "ru_"},
|
||||
{GameLanguage::LANGUAGE_POLISH, "po_"},
|
||||
{GameLanguage::LANGUAGE_KOREAN, "ko_"},
|
||||
{GameLanguage::LANGUAGE_JAPANESE, "ja_"},
|
||||
{GameLanguage::LANGUAGE_CZECH, "cz_"},
|
||||
};
|
||||
|
||||
return prefixes;
|
||||
}
|
||||
|
@ -1,17 +1,20 @@
|
||||
#pragma once
|
||||
#include "Game/IGame.h"
|
||||
|
||||
class GameT5 : public IGame
|
||||
namespace T5
|
||||
{
|
||||
std::vector<Zone*> m_zones;
|
||||
class Game final : public IGame
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] GameId GetId() const override;
|
||||
[[nodiscard]] const std::string& GetFullName() const override;
|
||||
[[nodiscard]] const std::string& GetShortName() const override;
|
||||
void AddZone(Zone* zone) override;
|
||||
void RemoveZone(Zone* zone) override;
|
||||
[[nodiscard]] const std::vector<Zone*>& GetZones() const override;
|
||||
[[nodiscard]] const std::vector<GameLanguagePrefix>& GetLanguagePrefixes() const override;
|
||||
|
||||
public:
|
||||
std::string GetFullName() override;
|
||||
std::string GetShortName() override;
|
||||
void AddZone(Zone* zone) override;
|
||||
void RemoveZone(Zone* zone) override;
|
||||
std::vector<Zone*> GetZones() override;
|
||||
std::vector<GameLanguagePrefix> GetLanguagePrefixes() override;
|
||||
};
|
||||
|
||||
extern GameT5 g_GameT5;
|
||||
private:
|
||||
std::vector<Zone*> m_zones;
|
||||
};
|
||||
} // namespace T5
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
// #include <d3d9.h>
|
||||
#include "Game/IAsset.h"
|
||||
#include "Image/Texture.h"
|
||||
|
||||
#include "T5_Assets.h"
|
||||
|
||||
@ -149,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");
|
||||
|
@ -1024,7 +1024,6 @@ namespace T5
|
||||
// IDirect3DTexture9* map;
|
||||
// IDirect3DVolumeTexture9* volmap;
|
||||
// IDirect3DCubeTexture9* cubemap;
|
||||
Texture* texture;
|
||||
GfxImageLoadDef* loadDef;
|
||||
};
|
||||
|
||||
@ -1312,7 +1311,7 @@ namespace T5
|
||||
|
||||
struct SndPatch
|
||||
{
|
||||
char* name;
|
||||
const char* name;
|
||||
unsigned int elementCount;
|
||||
unsigned int* elements;
|
||||
unsigned int fileCount;
|
||||
|
@ -2,62 +2,11 @@
|
||||
|
||||
#include "Utils/Pack.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
using namespace T6;
|
||||
|
||||
int Common::Com_HashKey(const char* str, const int maxLen)
|
||||
{
|
||||
if (str == nullptr)
|
||||
return 0;
|
||||
|
||||
int hash = 0;
|
||||
for (int i = 0; i < maxLen; i++)
|
||||
{
|
||||
if (str[i] == '\0')
|
||||
break;
|
||||
|
||||
hash += str[i] * (0x77 + i);
|
||||
}
|
||||
|
||||
return hash ^ ((hash ^ (hash >> 10)) >> 10);
|
||||
}
|
||||
|
||||
int Common::Com_HashString(const char* str)
|
||||
{
|
||||
if (!str)
|
||||
return 0;
|
||||
|
||||
auto result = 0x1505;
|
||||
auto offset = 0;
|
||||
while (str[offset])
|
||||
{
|
||||
const auto c = tolower(str[offset++]);
|
||||
result = c + 33 * result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int Common::Com_HashString(const char* str, const int len)
|
||||
{
|
||||
if (!str)
|
||||
return 0;
|
||||
|
||||
int result = 0x1505;
|
||||
int offset = 0;
|
||||
while (str[offset])
|
||||
{
|
||||
if (len > 0 && offset >= len)
|
||||
break;
|
||||
|
||||
const int c = tolower(str[offset++]);
|
||||
result = c + 33 * result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
PackedTexCoords Common::Vec2PackTexCoords(const float (&in)[2])
|
||||
{
|
||||
return PackedTexCoords{pack32::Vec2PackTexCoordsUV(in)};
|
||||
@ -87,3 +36,27 @@ void Common::Vec4UnpackGfxColor(const GfxColor& in, float (&out)[4])
|
||||
{
|
||||
pack32::Vec4UnpackGfxColor(in.packed, out);
|
||||
}
|
||||
|
||||
float Common::LinearToDbspl(const float linear)
|
||||
{
|
||||
const auto db = 20.0f * std::log10(std::max(linear, 0.0000152879f));
|
||||
if (db > -95.0f)
|
||||
return db + 100.0f;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
float Common::DbsplToLinear(const float dbsplValue)
|
||||
{
|
||||
return std::pow(10.0f, (dbsplValue - 100.0f) / 20.0f);
|
||||
}
|
||||
|
||||
float Common::HertzToCents(const float hertz)
|
||||
{
|
||||
return 1200.0f * std::log2(hertz);
|
||||
}
|
||||
|
||||
float Common::CentsToHertz(const float cents)
|
||||
{
|
||||
return std::pow(2.0f, cents / 1200.0f);
|
||||
}
|
||||
|
@ -2,14 +2,64 @@
|
||||
|
||||
#include "T6.h"
|
||||
|
||||
#include <cctype>
|
||||
|
||||
namespace T6
|
||||
{
|
||||
class Common
|
||||
{
|
||||
public:
|
||||
static int Com_HashKey(const char* str, int maxLen);
|
||||
static int Com_HashString(const char* str);
|
||||
static int Com_HashString(const char* str, int len);
|
||||
static constexpr int Com_HashKey(const char* str, const int maxLen)
|
||||
{
|
||||
if (str == nullptr)
|
||||
return 0;
|
||||
|
||||
int hash = 0;
|
||||
for (int i = 0; i < maxLen; i++)
|
||||
{
|
||||
if (str[i] == '\0')
|
||||
break;
|
||||
|
||||
hash += str[i] * (0x77 + i);
|
||||
}
|
||||
|
||||
return hash ^ ((hash ^ (hash >> 10)) >> 10);
|
||||
}
|
||||
|
||||
static constexpr int Com_HashString(const char* str)
|
||||
{
|
||||
if (!str)
|
||||
return 0;
|
||||
|
||||
auto result = 0x1505;
|
||||
auto offset = 0;
|
||||
while (str[offset])
|
||||
{
|
||||
const auto c = tolower(str[offset++]);
|
||||
result = c + 33 * result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static constexpr int Com_HashString(const char* str, const int len)
|
||||
{
|
||||
if (!str)
|
||||
return 0;
|
||||
|
||||
int result = 0x1505;
|
||||
int offset = 0;
|
||||
while (str[offset])
|
||||
{
|
||||
if (len > 0 && offset >= len)
|
||||
break;
|
||||
|
||||
const int c = tolower(str[offset++]);
|
||||
result = c + 33 * result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static constexpr uint32_t R_HashString(const char* str, uint32_t hash)
|
||||
{
|
||||
@ -52,5 +102,9 @@ namespace T6
|
||||
static void Vec2UnpackTexCoords(const PackedTexCoords& in, float (&out)[2]);
|
||||
static void Vec3UnpackUnitVec(const PackedUnitVec& in, float (&out)[3]);
|
||||
static void Vec4UnpackGfxColor(const GfxColor& in, float (&out)[4]);
|
||||
static float LinearToDbspl(const float linear);
|
||||
static float DbsplToLinear(const float dbsplValue);
|
||||
static float HertzToCents(const float hertz);
|
||||
static float CentsToHertz(const float cents);
|
||||
};
|
||||
} // namespace T6
|
||||
|
@ -1,29 +1,32 @@
|
||||
#include "GameT6.h"
|
||||
|
||||
#include "T6.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace T6;
|
||||
|
||||
GameT6 g_GameT6;
|
||||
|
||||
std::string GameT6::GetFullName()
|
||||
GameId Game::GetId() const
|
||||
{
|
||||
return "Call Of Duty: Black Ops II";
|
||||
return GameId::T6;
|
||||
}
|
||||
|
||||
std::string GameT6::GetShortName()
|
||||
const std::string& Game::GetFullName() const
|
||||
{
|
||||
return "T6";
|
||||
static std::string fullName = "Call Of Duty: Black Ops II";
|
||||
return fullName;
|
||||
}
|
||||
|
||||
void GameT6::AddZone(Zone* zone)
|
||||
const std::string& Game::GetShortName() const
|
||||
{
|
||||
static std::string shortName = "T6";
|
||||
return shortName;
|
||||
}
|
||||
|
||||
void Game::AddZone(Zone* zone)
|
||||
{
|
||||
m_zones.push_back(zone);
|
||||
}
|
||||
|
||||
void GameT6::RemoveZone(Zone* zone)
|
||||
void Game::RemoveZone(Zone* zone)
|
||||
{
|
||||
const auto foundEntry = std::ranges::find(m_zones, zone);
|
||||
|
||||
@ -31,31 +34,31 @@ void GameT6::RemoveZone(Zone* zone)
|
||||
m_zones.erase(foundEntry);
|
||||
}
|
||||
|
||||
std::vector<Zone*> GameT6::GetZones()
|
||||
const std::vector<Zone*>& Game::GetZones() const
|
||||
{
|
||||
return m_zones;
|
||||
}
|
||||
|
||||
std::vector<GameLanguagePrefix> GameT6::GetLanguagePrefixes()
|
||||
const std::vector<GameLanguagePrefix>& Game::GetLanguagePrefixes() const
|
||||
{
|
||||
std::vector<GameLanguagePrefix> prefixes;
|
||||
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_ENGLISH, "en_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_FRENCH, "fr_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_FRENCH_CAN, "fc_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_GERMAN, "ge_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_AUSTRIAN, "as_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_ITALIAN, "it_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_SPANISH, "sp_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_BRITISH, "br_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_RUSSIAN, "ru_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_POLISH, "po_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_KOREAN, "ko_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_JAPANESE, "ja_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_CZECH, "cz_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_FULL_JAPANESE, "fj_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_PORTUGUESE, "bp_");
|
||||
prefixes.emplace_back(GameLanguage::LANGUAGE_MEXICAN_SPANISH, "ms_");
|
||||
static std::vector<GameLanguagePrefix> prefixes{
|
||||
{GameLanguage::LANGUAGE_ENGLISH, "en_"},
|
||||
{GameLanguage::LANGUAGE_FRENCH, "fr_"},
|
||||
{GameLanguage::LANGUAGE_FRENCH_CAN, "fc_"},
|
||||
{GameLanguage::LANGUAGE_GERMAN, "ge_"},
|
||||
{GameLanguage::LANGUAGE_AUSTRIAN, "as_"},
|
||||
{GameLanguage::LANGUAGE_ITALIAN, "it_"},
|
||||
{GameLanguage::LANGUAGE_SPANISH, "sp_"},
|
||||
{GameLanguage::LANGUAGE_BRITISH, "br_"},
|
||||
{GameLanguage::LANGUAGE_RUSSIAN, "ru_"},
|
||||
{GameLanguage::LANGUAGE_POLISH, "po_"},
|
||||
{GameLanguage::LANGUAGE_KOREAN, "ko_"},
|
||||
{GameLanguage::LANGUAGE_JAPANESE, "ja_"},
|
||||
{GameLanguage::LANGUAGE_CZECH, "cz_"},
|
||||
{GameLanguage::LANGUAGE_FULL_JAPANESE, "fj_"},
|
||||
{GameLanguage::LANGUAGE_PORTUGUESE, "bp_"},
|
||||
{GameLanguage::LANGUAGE_MEXICAN_SPANISH, "ms_"},
|
||||
};
|
||||
|
||||
return prefixes;
|
||||
}
|
||||
|
@ -1,17 +1,20 @@
|
||||
#pragma once
|
||||
#include "Game/IGame.h"
|
||||
|
||||
class GameT6 : public IGame
|
||||
namespace T6
|
||||
{
|
||||
std::vector<Zone*> m_zones;
|
||||
class Game final : public IGame
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] GameId GetId() const override;
|
||||
[[nodiscard]] const std::string& GetFullName() const override;
|
||||
[[nodiscard]] const std::string& GetShortName() const override;
|
||||
void AddZone(Zone* zone) override;
|
||||
void RemoveZone(Zone* zone) override;
|
||||
[[nodiscard]] const std::vector<Zone*>& GetZones() const override;
|
||||
[[nodiscard]] const std::vector<GameLanguagePrefix>& GetLanguagePrefixes() const override;
|
||||
|
||||
public:
|
||||
std::string GetFullName() override;
|
||||
std::string GetShortName() override;
|
||||
void AddZone(Zone* zone) override;
|
||||
void RemoveZone(Zone* zone) override;
|
||||
std::vector<Zone*> GetZones() override;
|
||||
std::vector<GameLanguagePrefix> GetLanguagePrefixes() override;
|
||||
};
|
||||
|
||||
extern GameT6 g_GameT6;
|
||||
private:
|
||||
std::vector<Zone*> m_zones;
|
||||
};
|
||||
} // namespace T6
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
// #include <d3d11.h>
|
||||
#include "Game/IAsset.h"
|
||||
#include "Image/Texture.h"
|
||||
|
||||
#include "T6_Assets.h"
|
||||
|
||||
@ -210,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);
|
||||
|
@ -848,7 +848,6 @@ namespace T6
|
||||
union GfxTexture
|
||||
{
|
||||
void /*ID3D11ShaderResourceView*/* basemap;
|
||||
Texture* texture;
|
||||
GfxImageLoadDef* loadDef;
|
||||
};
|
||||
|
||||
@ -2115,7 +2114,7 @@ namespace T6
|
||||
struct KeyValuePairs
|
||||
{
|
||||
const char* name;
|
||||
int numVariables;
|
||||
unsigned int numVariables;
|
||||
KeyValuePair* keyValuePairs;
|
||||
};
|
||||
|
||||
@ -3815,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];
|
||||
@ -3828,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
|
||||
@ -5570,8 +5563,8 @@ namespace T6
|
||||
|
||||
struct KeyValuePair
|
||||
{
|
||||
int keyHash;
|
||||
int namespaceHash;
|
||||
unsigned int keyHash;
|
||||
unsigned int namespaceHash;
|
||||
const char* value;
|
||||
};
|
||||
|
||||
@ -6231,7 +6224,7 @@ namespace T6
|
||||
unsigned int isBig : 1; // 4
|
||||
unsigned int pauseable : 1; // 5
|
||||
unsigned int isMusic : 1; // 6
|
||||
unsigned int stopOnDeath : 1; // 7
|
||||
unsigned int stopOnEntDeath : 1; // 7
|
||||
unsigned int timescale : 1; // 8
|
||||
unsigned int voiceLimit : 1; // 9
|
||||
unsigned int ignoreMaxDist : 1; // 10
|
||||
@ -6250,7 +6243,9 @@ namespace T6
|
||||
unsigned int reverbFalloffCurve : 6; // 8-13
|
||||
unsigned int volumeMinFalloffCurve : 6; // 14-19
|
||||
unsigned int reverbMinFalloffCurve : 6; // 20-25
|
||||
unsigned int unknown1_1 : 6; // 26-31
|
||||
unsigned int unknown1_1 : 1; // 26
|
||||
unsigned int isCinematic : 1; // 27
|
||||
unsigned int unknown1_2 : 4; // 28-31
|
||||
};
|
||||
|
||||
struct SndAlias
|
||||
@ -6258,7 +6253,7 @@ namespace T6
|
||||
const char* name;
|
||||
unsigned int id;
|
||||
const char* subtitle;
|
||||
const char* secondaryname;
|
||||
const char* secondaryName;
|
||||
unsigned int assetId;
|
||||
const char* assetFileName;
|
||||
SndAliasFlags flags;
|
||||
|
@ -1,127 +0,0 @@
|
||||
#pragma once
|
||||
#include "ImageFormat.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class TextureType
|
||||
{
|
||||
T_2D,
|
||||
T_CUBE,
|
||||
T_3D
|
||||
};
|
||||
|
||||
class Texture
|
||||
{
|
||||
protected:
|
||||
const ImageFormat* m_format;
|
||||
bool m_has_mip_maps;
|
||||
uint8_t* m_data;
|
||||
|
||||
Texture(const ImageFormat* format, bool mipMaps);
|
||||
Texture(Texture&& other) noexcept;
|
||||
|
||||
Texture& operator=(Texture&& other) noexcept;
|
||||
|
||||
public:
|
||||
Texture(const Texture& other) = delete;
|
||||
virtual ~Texture();
|
||||
|
||||
Texture& operator=(const Texture& other) = delete;
|
||||
|
||||
virtual TextureType GetTextureType() const = 0;
|
||||
const ImageFormat* GetFormat() const;
|
||||
|
||||
virtual unsigned GetWidth() const = 0;
|
||||
virtual unsigned GetHeight() const = 0;
|
||||
virtual unsigned GetDepth() const = 0;
|
||||
virtual int GetFaceCount() const = 0;
|
||||
|
||||
void Allocate();
|
||||
bool Empty() const;
|
||||
|
||||
virtual size_t GetSizeOfMipLevel(int mipLevel) const = 0;
|
||||
virtual uint8_t* GetBufferForMipLevel(int mipLevel, int face) = 0;
|
||||
uint8_t* GetBufferForMipLevel(int mipLevel);
|
||||
|
||||
bool HasMipMaps() const;
|
||||
virtual int GetMipMapCount() const = 0;
|
||||
};
|
||||
|
||||
class Texture2D : public Texture
|
||||
{
|
||||
protected:
|
||||
unsigned m_width;
|
||||
unsigned m_height;
|
||||
|
||||
public:
|
||||
Texture2D(const ImageFormat* format, unsigned width, unsigned height);
|
||||
Texture2D(const ImageFormat* format, unsigned width, unsigned height, bool mipMaps);
|
||||
Texture2D(const Texture2D& other) = delete;
|
||||
Texture2D(Texture2D&& other) noexcept;
|
||||
~Texture2D() override;
|
||||
|
||||
Texture2D& operator=(const Texture2D& other) = delete;
|
||||
Texture2D& operator=(Texture2D&& other) noexcept;
|
||||
|
||||
TextureType GetTextureType() const override;
|
||||
|
||||
unsigned GetWidth() const override;
|
||||
unsigned GetHeight() const override;
|
||||
unsigned GetDepth() const override;
|
||||
int GetFaceCount() const override;
|
||||
|
||||
size_t GetSizeOfMipLevel(int mipLevel) const override;
|
||||
uint8_t* GetBufferForMipLevel(int mipLevel, int face) override;
|
||||
|
||||
int GetMipMapCount() const override;
|
||||
};
|
||||
|
||||
class TextureCube final : public Texture2D
|
||||
{
|
||||
static const int FACE_COUNT;
|
||||
|
||||
public:
|
||||
TextureCube(const ImageFormat* format, unsigned width, unsigned height);
|
||||
TextureCube(const ImageFormat* format, unsigned width, unsigned height, bool mipMaps);
|
||||
TextureCube(const TextureCube& other) = delete;
|
||||
TextureCube(TextureCube&& other) noexcept;
|
||||
~TextureCube() override;
|
||||
|
||||
TextureCube& operator=(const TextureCube& other) = delete;
|
||||
TextureCube& operator=(TextureCube&& other) noexcept;
|
||||
|
||||
TextureType GetTextureType() const override;
|
||||
|
||||
int GetFaceCount() const override;
|
||||
|
||||
uint8_t* GetBufferForMipLevel(int mipLevel, int face) override;
|
||||
};
|
||||
|
||||
class Texture3D final : public Texture
|
||||
{
|
||||
unsigned m_width;
|
||||
unsigned m_height;
|
||||
unsigned m_depth;
|
||||
|
||||
public:
|
||||
Texture3D(const ImageFormat* format, unsigned width, unsigned height, unsigned depth);
|
||||
Texture3D(const ImageFormat* format, unsigned width, unsigned height, unsigned depth, bool mipMaps);
|
||||
Texture3D(const Texture3D& other) = delete;
|
||||
Texture3D(Texture3D&& other) noexcept;
|
||||
~Texture3D() override;
|
||||
|
||||
Texture3D& operator=(const Texture3D& other) = delete;
|
||||
Texture3D& operator=(Texture3D&& other) noexcept;
|
||||
|
||||
TextureType GetTextureType() const override;
|
||||
|
||||
unsigned GetWidth() const override;
|
||||
unsigned GetHeight() const override;
|
||||
unsigned GetDepth() const override;
|
||||
int GetFaceCount() const override;
|
||||
|
||||
size_t GetSizeOfMipLevel(int mipLevel) const override;
|
||||
uint8_t* GetBufferForMipLevel(int mipLevel, int face) override;
|
||||
|
||||
int GetMipMapCount() const override;
|
||||
};
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
48
src/ImageConverter.lua
Normal file
48
src/ImageConverter.lua
Normal file
@ -0,0 +1,48 @@
|
||||
ImageConverter = {}
|
||||
|
||||
function ImageConverter:include(includes)
|
||||
if includes:handle(self:name()) then
|
||||
includedirs {
|
||||
path.join(ProjectFolder(), "ImageConverter")
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function ImageConverter:link(links)
|
||||
|
||||
end
|
||||
|
||||
function ImageConverter:use()
|
||||
dependson(self:name())
|
||||
end
|
||||
|
||||
function ImageConverter:name()
|
||||
return "ImageConverter"
|
||||
end
|
||||
|
||||
function ImageConverter:project()
|
||||
local folder = ProjectFolder()
|
||||
local includes = Includes:create()
|
||||
local links = Links:create()
|
||||
|
||||
project(self:name())
|
||||
targetdir(TargetDirectoryBin)
|
||||
location "%{wks.location}/src/%{prj.name}"
|
||||
kind "ConsoleApp"
|
||||
language "C++"
|
||||
|
||||
files {
|
||||
path.join(folder, "ImageConverter/**.h"),
|
||||
path.join(folder, "ImageConverter/**.cpp")
|
||||
}
|
||||
|
||||
self:include(includes)
|
||||
Utils:include(includes)
|
||||
ObjImage:include(includes)
|
||||
|
||||
Raw:use()
|
||||
|
||||
links:linkto(Utils)
|
||||
links:linkto(ObjImage)
|
||||
links:linkall()
|
||||
end
|
202
src/ImageConverter/ImageConverter.cpp
Normal file
202
src/ImageConverter/ImageConverter.cpp
Normal file
@ -0,0 +1,202 @@
|
||||
#include "ImageConverter.h"
|
||||
|
||||
#include "Image/DdsLoader.h"
|
||||
#include "Image/DdsWriter.h"
|
||||
#include "Image/IwiLoader.h"
|
||||
#include "Image/IwiWriter13.h"
|
||||
#include "Image/IwiWriter27.h"
|
||||
#include "Image/IwiWriter6.h"
|
||||
#include "Image/IwiWriter8.h"
|
||||
#include "Image/Texture.h"
|
||||
#include "ImageConverterArgs.h"
|
||||
#include "Utils/StringUtils.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <filesystem>
|
||||
#include <format>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace image_converter
|
||||
{
|
||||
constexpr auto EXTENSION_IWI = ".iwi";
|
||||
constexpr auto EXTENSION_DDS = ".dds";
|
||||
|
||||
class ImageConverterImpl final : public ImageConverter
|
||||
{
|
||||
public:
|
||||
ImageConverterImpl()
|
||||
: m_game_to_convert_to(image_converter::Game::UNKNOWN)
|
||||
{
|
||||
}
|
||||
|
||||
bool Start(const int argc, const char** argv) override
|
||||
{
|
||||
auto shouldContinue = true;
|
||||
if (!m_args.ParseArgs(argc, argv, shouldContinue))
|
||||
return false;
|
||||
|
||||
if (!shouldContinue)
|
||||
return true;
|
||||
|
||||
m_game_to_convert_to = m_args.m_game_to_convert_to;
|
||||
|
||||
for (const auto& file : m_args.m_files_to_convert)
|
||||
Convert(file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void Convert(const std::string& file)
|
||||
{
|
||||
const fs::path filePath(file);
|
||||
auto extension = filePath.extension().string();
|
||||
utils::MakeStringLowerCase(extension);
|
||||
|
||||
if (extension == EXTENSION_IWI)
|
||||
ConvertIwi(filePath);
|
||||
else if (extension == EXTENSION_DDS)
|
||||
ConvertDds(filePath);
|
||||
else
|
||||
std::cerr << std::format("Unsupported extension {}\n", extension);
|
||||
}
|
||||
|
||||
bool ConvertIwi(const fs::path& iwiPath)
|
||||
{
|
||||
std::ifstream file(iwiPath, std::ios::in | std::ios::binary);
|
||||
if (!file.is_open())
|
||||
{
|
||||
std::cerr << std::format("Failed to open input file {}\n", iwiPath.string());
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto texture = iwi::LoadIwi(file);
|
||||
if (!texture)
|
||||
return false;
|
||||
|
||||
auto outPath = iwiPath;
|
||||
outPath.replace_extension(".dds");
|
||||
|
||||
std::ofstream outFile(outPath, std::ios::out | std::ios::binary);
|
||||
if (!outFile.is_open())
|
||||
{
|
||||
std::cerr << std::format("Failed to open output file {}\n", outPath.string());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_dds_writer.DumpImage(outFile, texture.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConvertDds(const fs::path& ddsPath)
|
||||
{
|
||||
std::ifstream file(ddsPath, std::ios::in | std::ios::binary);
|
||||
if (!file.is_open())
|
||||
{
|
||||
std::cerr << std::format("Failed to open input file {}\n", ddsPath.string());
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto texture = dds::LoadDds(file);
|
||||
if (!texture)
|
||||
return false;
|
||||
|
||||
if (!EnsureIwiWriterIsPresent())
|
||||
return false;
|
||||
|
||||
auto outPath = ddsPath;
|
||||
outPath.replace_extension(".iwi");
|
||||
|
||||
std::ofstream outFile(outPath, std::ios::out | std::ios::binary);
|
||||
if (!outFile.is_open())
|
||||
{
|
||||
std::cerr << std::format("Failed to open output file {}\n", outPath.string());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_iwi_writer->DumpImage(outFile, texture.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EnsureIwiWriterIsPresent()
|
||||
{
|
||||
if (m_iwi_writer)
|
||||
return true;
|
||||
|
||||
if (m_game_to_convert_to == Game::UNKNOWN && !ShowGameTui())
|
||||
return false;
|
||||
|
||||
switch (m_game_to_convert_to)
|
||||
{
|
||||
case Game::IW3:
|
||||
m_iwi_writer = std::make_unique<iwi6::IwiWriter>();
|
||||
break;
|
||||
case Game::IW4:
|
||||
case Game::IW5:
|
||||
m_iwi_writer = std::make_unique<iwi8::IwiWriter>();
|
||||
break;
|
||||
case Game::T5:
|
||||
m_iwi_writer = std::make_unique<iwi13::IwiWriter>();
|
||||
break;
|
||||
case Game::T6:
|
||||
m_iwi_writer = std::make_unique<iwi27::IwiWriter>();
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShowGameTui()
|
||||
{
|
||||
std::cout << "Select the game to convert to:\n";
|
||||
std::cout << " 1 - Call Of Duty 4: Modern Warfare (IW3)\n";
|
||||
std::cout << " 2 - Call Of Duty: Modern Warfare 2 (IW4)\n";
|
||||
std::cout << " 3 - Call Of Duty: Modern Warfare 3 (IW5)\n";
|
||||
std::cout << " 4 - Call Of Duty: Black Ops (T5)\n";
|
||||
std::cout << " 5 - Call Of Duty: Black Ops 2 (T6)\n";
|
||||
|
||||
unsigned num;
|
||||
std::cin >> num;
|
||||
|
||||
switch (num)
|
||||
{
|
||||
case 1:
|
||||
m_game_to_convert_to = Game::IW3;
|
||||
break;
|
||||
case 2:
|
||||
m_game_to_convert_to = Game::IW4;
|
||||
break;
|
||||
case 3:
|
||||
m_game_to_convert_to = Game::IW5;
|
||||
break;
|
||||
case 4:
|
||||
m_game_to_convert_to = Game::T5;
|
||||
break;
|
||||
case 5:
|
||||
m_game_to_convert_to = Game::T6;
|
||||
break;
|
||||
default:
|
||||
std::cerr << "Invalid input\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ImageConverterArgs m_args;
|
||||
image_converter::Game m_game_to_convert_to;
|
||||
DdsWriter m_dds_writer;
|
||||
std::unique_ptr<IImageWriter> m_iwi_writer;
|
||||
};
|
||||
} // namespace image_converter
|
||||
|
||||
std::unique_ptr<ImageConverter> ImageConverter::Create()
|
||||
{
|
||||
return std::make_unique<image_converter::ImageConverterImpl>();
|
||||
}
|
24
src/ImageConverter/ImageConverter.h
Normal file
24
src/ImageConverter/ImageConverter.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
|
||||
class ImageConverter
|
||||
{
|
||||
public:
|
||||
ImageConverter() = default;
|
||||
virtual ~ImageConverter() = default;
|
||||
|
||||
ImageConverter(const ImageConverter& other) = delete;
|
||||
ImageConverter(ImageConverter&& other) noexcept = delete;
|
||||
ImageConverter& operator=(const ImageConverter& other) = delete;
|
||||
ImageConverter& operator=(ImageConverter&& other) noexcept = delete;
|
||||
|
||||
/**
|
||||
* \brief Starts the ImageConverter application logic.
|
||||
* \param argc The amount of command line arguments specified.
|
||||
* \param argv The command line arguments.
|
||||
* \return \c true if the application was successful or \c false if an error occurred.
|
||||
*/
|
||||
virtual bool Start(int argc, const char** argv) = 0;
|
||||
|
||||
static std::unique_ptr<ImageConverter> Create();
|
||||
};
|
149
src/ImageConverter/ImageConverterArgs.cpp
Normal file
149
src/ImageConverter/ImageConverterArgs.cpp
Normal file
@ -0,0 +1,149 @@
|
||||
#include "ImageConverterArgs.h"
|
||||
|
||||
#include "GitVersion.h"
|
||||
#include "Utils/Arguments/UsageInformation.h"
|
||||
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <type_traits>
|
||||
|
||||
// clang-format off
|
||||
const CommandLineOption* const OPTION_HELP =
|
||||
CommandLineOption::Builder::Create()
|
||||
.WithShortName("?")
|
||||
.WithLongName("help")
|
||||
.WithDescription("Displays usage information.")
|
||||
.Build();
|
||||
|
||||
const CommandLineOption* const OPTION_VERSION =
|
||||
CommandLineOption::Builder::Create()
|
||||
.WithLongName("version")
|
||||
.WithDescription("Prints the application version.")
|
||||
.Build();
|
||||
|
||||
const CommandLineOption* const OPTION_VERBOSE =
|
||||
CommandLineOption::Builder::Create()
|
||||
.WithShortName("v")
|
||||
.WithLongName("verbose")
|
||||
.WithDescription("Outputs a lot more and more detailed messages.")
|
||||
.Build();
|
||||
|
||||
constexpr auto CATEGORY_GAME = "Game";
|
||||
|
||||
const CommandLineOption* const OPTION_GAME_IW3 =
|
||||
CommandLineOption::Builder::Create()
|
||||
.WithLongName("iw3")
|
||||
.WithCategory(CATEGORY_GAME)
|
||||
.WithDescription("Converts images for IW3.")
|
||||
.Build();
|
||||
|
||||
const CommandLineOption* const OPTION_GAME_IW4 =
|
||||
CommandLineOption::Builder::Create()
|
||||
.WithLongName("iw4")
|
||||
.WithCategory(CATEGORY_GAME)
|
||||
.WithDescription("Converts images for IW4.")
|
||||
.Build();
|
||||
|
||||
const CommandLineOption* const OPTION_GAME_IW5 =
|
||||
CommandLineOption::Builder::Create()
|
||||
.WithLongName("iw5")
|
||||
.WithCategory(CATEGORY_GAME)
|
||||
.WithDescription("Converts images for IW5.")
|
||||
.Build();
|
||||
|
||||
const CommandLineOption* const OPTION_GAME_T5 =
|
||||
CommandLineOption::Builder::Create()
|
||||
.WithLongName("t5")
|
||||
.WithCategory(CATEGORY_GAME)
|
||||
.WithDescription("Converts images for T5.")
|
||||
.Build();
|
||||
|
||||
const CommandLineOption* const OPTION_GAME_T6 =
|
||||
CommandLineOption::Builder::Create()
|
||||
.WithLongName("t6")
|
||||
.WithCategory(CATEGORY_GAME)
|
||||
.WithDescription("Converts images for T6.")
|
||||
.Build();
|
||||
// clang-format on
|
||||
|
||||
const CommandLineOption* const COMMAND_LINE_OPTIONS[]{
|
||||
OPTION_HELP,
|
||||
OPTION_VERSION,
|
||||
OPTION_VERBOSE,
|
||||
OPTION_GAME_IW3,
|
||||
OPTION_GAME_IW4,
|
||||
OPTION_GAME_IW5,
|
||||
OPTION_GAME_T5,
|
||||
OPTION_GAME_T6,
|
||||
};
|
||||
|
||||
ImageConverterArgs::ImageConverterArgs()
|
||||
: m_verbose(false),
|
||||
m_game_to_convert_to(image_converter::Game::UNKNOWN),
|
||||
m_argument_parser(COMMAND_LINE_OPTIONS, std::extent_v<decltype(COMMAND_LINE_OPTIONS)>)
|
||||
{
|
||||
}
|
||||
|
||||
void ImageConverterArgs::PrintUsage()
|
||||
{
|
||||
UsageInformation usage("ImageConverter.exe");
|
||||
|
||||
for (const auto* commandLineOption : COMMAND_LINE_OPTIONS)
|
||||
{
|
||||
usage.AddCommandLineOption(commandLineOption);
|
||||
}
|
||||
|
||||
usage.AddArgument("fileToConvert");
|
||||
usage.SetVariableArguments(true);
|
||||
|
||||
usage.Print();
|
||||
}
|
||||
|
||||
void ImageConverterArgs::PrintVersion()
|
||||
{
|
||||
std::cout << std::format("OpenAssetTools ImageConverter {}\n", GIT_VERSION);
|
||||
}
|
||||
|
||||
void ImageConverterArgs::SetVerbose(const bool isVerbose)
|
||||
{
|
||||
m_verbose = isVerbose;
|
||||
}
|
||||
|
||||
bool ImageConverterArgs::ParseArgs(const int argc, const char** argv, bool& shouldContinue)
|
||||
{
|
||||
shouldContinue = true;
|
||||
if (!m_argument_parser.ParseArguments(argc, argv))
|
||||
{
|
||||
PrintUsage();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the user requested help
|
||||
if (m_argument_parser.IsOptionSpecified(OPTION_HELP))
|
||||
{
|
||||
PrintUsage();
|
||||
shouldContinue = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if the user wants to see the version
|
||||
if (m_argument_parser.IsOptionSpecified(OPTION_VERSION))
|
||||
{
|
||||
PrintVersion();
|
||||
shouldContinue = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
m_files_to_convert = m_argument_parser.GetArguments();
|
||||
if (m_files_to_convert.empty())
|
||||
{
|
||||
// No files to convert specified...
|
||||
PrintUsage();
|
||||
return false;
|
||||
}
|
||||
|
||||
// -v; --verbose
|
||||
SetVerbose(m_argument_parser.IsOptionSpecified(OPTION_VERBOSE));
|
||||
|
||||
return true;
|
||||
}
|
42
src/ImageConverter/ImageConverterArgs.h
Normal file
42
src/ImageConverter/ImageConverterArgs.h
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utils/Arguments/ArgumentParser.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace image_converter
|
||||
{
|
||||
enum class Game : std::uint8_t
|
||||
{
|
||||
UNKNOWN,
|
||||
IW3,
|
||||
IW4,
|
||||
IW5,
|
||||
T5,
|
||||
T6
|
||||
};
|
||||
} // namespace image_converter
|
||||
|
||||
class ImageConverterArgs
|
||||
{
|
||||
public:
|
||||
ImageConverterArgs();
|
||||
bool ParseArgs(int argc, const char** argv, bool& shouldContinue);
|
||||
|
||||
bool m_verbose;
|
||||
std::vector<std::string> m_files_to_convert;
|
||||
image_converter::Game m_game_to_convert_to;
|
||||
|
||||
private:
|
||||
/**
|
||||
* \brief Prints a command line usage help text for the ImageConverter tool to stdout.
|
||||
*/
|
||||
static void PrintUsage();
|
||||
static void PrintVersion();
|
||||
|
||||
void SetVerbose(bool isVerbose);
|
||||
|
||||
ArgumentParser m_argument_parser;
|
||||
};
|
8
src/ImageConverter/main.cpp
Normal file
8
src/ImageConverter/main.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
#include "ImageConverter.h"
|
||||
|
||||
int main(const int argc, const char** argv)
|
||||
{
|
||||
const auto imageConverter = ImageConverter::Create();
|
||||
|
||||
return imageConverter->Start(argc, argv) ? 0 : 1;
|
||||
}
|
@ -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)
|
||||
|
@ -1,102 +0,0 @@
|
||||
#include "ZoneCreatorIW3.h"
|
||||
|
||||
#include "AssetLoading/AssetLoadingContext.h"
|
||||
#include "Game/IW3/GameAssetPoolIW3.h"
|
||||
#include "Game/IW3/GameIW3.h"
|
||||
#include "ObjLoading.h"
|
||||
#include "Utils/StringUtils.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace IW3;
|
||||
|
||||
ZoneCreator::ZoneCreator()
|
||||
{
|
||||
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
|
||||
{
|
||||
AddAssetTypeName(assetType, GameAssetPoolIW3::AssetTypeNameByType(assetType));
|
||||
}
|
||||
}
|
||||
|
||||
void ZoneCreator::AddAssetTypeName(asset_type_t assetType, std::string name)
|
||||
{
|
||||
m_asset_types_by_name.emplace(std::make_pair(std::move(name), assetType));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool ZoneCreator::CreateIgnoredAssetMap(const ZoneCreationContext& context, std::unordered_map<std::string, asset_type_t>& ignoredAssetMap) const
|
||||
{
|
||||
for (const auto& ignoreEntry : context.m_ignored_assets.m_entries)
|
||||
{
|
||||
const auto foundAssetTypeEntry = m_asset_types_by_name.find(ignoreEntry.m_type);
|
||||
if (foundAssetTypeEntry == m_asset_types_by_name.end())
|
||||
{
|
||||
std::cout << "Unknown asset type \"" << ignoreEntry.m_type << "\" for ignore \"" << ignoreEntry.m_name << "\"\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
ignoredAssetMap[ignoreEntry.m_name] = foundAssetTypeEntry->second;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool ZoneCreator::SupportsGame(const std::string& gameName) const
|
||||
{
|
||||
auto shortName = g_GameIW3.GetShortName();
|
||||
utils::MakeStringLowerCase(shortName);
|
||||
|
||||
return gameName == shortName;
|
||||
}
|
||||
|
||||
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
|
||||
{
|
||||
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, &g_GameIW3);
|
||||
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.get(), context.m_asset_search_path, CreateGdtList(context));
|
||||
if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map))
|
||||
return nullptr;
|
||||
|
||||
for (const auto& assetEntry : context.m_definition->m_assets)
|
||||
{
|
||||
const auto foundAssetTypeEntry = m_asset_types_by_name.find(assetEntry.m_asset_type);
|
||||
if (foundAssetTypeEntry == m_asset_types_by_name.end())
|
||||
{
|
||||
std::cout << "Unknown asset type \"" << assetEntry.m_asset_type << "\"\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!ObjLoading::LoadAssetForZone(assetLoadingContext.get(), foundAssetTypeEntry->second, assetEntry.m_asset_name))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ObjLoading::FinalizeAssetsForZone(assetLoadingContext.get());
|
||||
|
||||
return zone;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
#include "Zone/ZoneTypes.h"
|
||||
#include "ZoneCreation/IZoneCreator.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace IW3
|
||||
{
|
||||
class ZoneCreator final : public IZoneCreator
|
||||
{
|
||||
std::unordered_map<std::string, asset_type_t> m_asset_types_by_name;
|
||||
|
||||
void AddAssetTypeName(asset_type_t assetType, std::string name);
|
||||
static std::vector<Gdt*> CreateGdtList(const ZoneCreationContext& context);
|
||||
bool CreateIgnoredAssetMap(const ZoneCreationContext& context, std::unordered_map<std::string, asset_type_t>& ignoredAssetMap) const;
|
||||
void CreateZoneAssetPools(Zone* zone) const;
|
||||
|
||||
public:
|
||||
ZoneCreator();
|
||||
|
||||
_NODISCARD bool SupportsGame(const std::string& gameName) const override;
|
||||
_NODISCARD std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
|
||||
};
|
||||
} // namespace IW3
|
@ -1,101 +0,0 @@
|
||||
#include "ZoneCreatorIW4.h"
|
||||
|
||||
#include "Game/IW4/GameAssetPoolIW4.h"
|
||||
#include "Game/IW4/GameIW4.h"
|
||||
#include "ObjLoading.h"
|
||||
#include "Utils/StringUtils.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace IW4;
|
||||
|
||||
ZoneCreator::ZoneCreator()
|
||||
{
|
||||
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
|
||||
{
|
||||
AddAssetTypeName(assetType, GameAssetPoolIW4::AssetTypeNameByType(assetType));
|
||||
}
|
||||
}
|
||||
|
||||
void ZoneCreator::AddAssetTypeName(asset_type_t assetType, std::string name)
|
||||
{
|
||||
m_asset_types_by_name.emplace(std::make_pair(std::move(name), assetType));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool ZoneCreator::CreateIgnoredAssetMap(const ZoneCreationContext& context, std::unordered_map<std::string, asset_type_t>& ignoredAssetMap) const
|
||||
{
|
||||
for (const auto& ignoreEntry : context.m_ignored_assets.m_entries)
|
||||
{
|
||||
const auto foundAssetTypeEntry = m_asset_types_by_name.find(ignoreEntry.m_type);
|
||||
if (foundAssetTypeEntry == m_asset_types_by_name.end())
|
||||
{
|
||||
std::cout << "Unknown asset type \"" << ignoreEntry.m_type << "\" for ignore \"" << ignoreEntry.m_name << "\"\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
ignoredAssetMap[ignoreEntry.m_name] = foundAssetTypeEntry->second;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool ZoneCreator::SupportsGame(const std::string& gameName) const
|
||||
{
|
||||
auto shortName = g_GameIW4.GetShortName();
|
||||
utils::MakeStringLowerCase(shortName);
|
||||
|
||||
return gameName == shortName;
|
||||
}
|
||||
|
||||
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
|
||||
{
|
||||
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, &g_GameIW4);
|
||||
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.get(), context.m_asset_search_path, CreateGdtList(context));
|
||||
if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map))
|
||||
return nullptr;
|
||||
|
||||
for (const auto& assetEntry : context.m_definition->m_assets)
|
||||
{
|
||||
const auto foundAssetTypeEntry = m_asset_types_by_name.find(assetEntry.m_asset_type);
|
||||
if (foundAssetTypeEntry == m_asset_types_by_name.end())
|
||||
{
|
||||
std::cout << "Unknown asset type \"" << assetEntry.m_asset_type << "\"\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!ObjLoading::LoadAssetForZone(assetLoadingContext.get(), foundAssetTypeEntry->second, assetEntry.m_asset_name))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ObjLoading::FinalizeAssetsForZone(assetLoadingContext.get());
|
||||
|
||||
return zone;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
#include "Zone/ZoneTypes.h"
|
||||
#include "ZoneCreation/IZoneCreator.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace IW4
|
||||
{
|
||||
class ZoneCreator final : public IZoneCreator
|
||||
{
|
||||
std::unordered_map<std::string, asset_type_t> m_asset_types_by_name;
|
||||
|
||||
void AddAssetTypeName(asset_type_t assetType, std::string name);
|
||||
static std::vector<Gdt*> CreateGdtList(const ZoneCreationContext& context);
|
||||
bool CreateIgnoredAssetMap(const ZoneCreationContext& context, std::unordered_map<std::string, asset_type_t>& ignoredAssetMap) const;
|
||||
void CreateZoneAssetPools(Zone* zone) const;
|
||||
|
||||
public:
|
||||
ZoneCreator();
|
||||
|
||||
_NODISCARD bool SupportsGame(const std::string& gameName) const override;
|
||||
_NODISCARD std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
|
||||
};
|
||||
} // namespace IW4
|
@ -1,101 +0,0 @@
|
||||
#include "ZoneCreatorIW5.h"
|
||||
|
||||
#include "Game/IW5/GameAssetPoolIW5.h"
|
||||
#include "Game/IW5/GameIW5.h"
|
||||
#include "ObjLoading.h"
|
||||
#include "Utils/StringUtils.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace IW5;
|
||||
|
||||
ZoneCreator::ZoneCreator()
|
||||
{
|
||||
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
|
||||
{
|
||||
AddAssetTypeName(assetType, GameAssetPoolIW5::AssetTypeNameByType(assetType));
|
||||
}
|
||||
}
|
||||
|
||||
void ZoneCreator::AddAssetTypeName(asset_type_t assetType, std::string name)
|
||||
{
|
||||
m_asset_types_by_name.emplace(std::make_pair(std::move(name), assetType));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool ZoneCreator::CreateIgnoredAssetMap(const ZoneCreationContext& context, std::unordered_map<std::string, asset_type_t>& ignoredAssetMap) const
|
||||
{
|
||||
for (const auto& ignoreEntry : context.m_ignored_assets.m_entries)
|
||||
{
|
||||
const auto foundAssetTypeEntry = m_asset_types_by_name.find(ignoreEntry.m_type);
|
||||
if (foundAssetTypeEntry == m_asset_types_by_name.end())
|
||||
{
|
||||
std::cout << "Unknown asset type \"" << ignoreEntry.m_type << "\" for ignore \"" << ignoreEntry.m_name << "\"\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
ignoredAssetMap[ignoreEntry.m_name] = foundAssetTypeEntry->second;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool ZoneCreator::SupportsGame(const std::string& gameName) const
|
||||
{
|
||||
auto shortName = g_GameIW5.GetShortName();
|
||||
utils::MakeStringLowerCase(shortName);
|
||||
|
||||
return gameName == shortName;
|
||||
}
|
||||
|
||||
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
|
||||
{
|
||||
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, &g_GameIW5);
|
||||
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.get(), context.m_asset_search_path, CreateGdtList(context));
|
||||
if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map))
|
||||
return nullptr;
|
||||
|
||||
for (const auto& assetEntry : context.m_definition->m_assets)
|
||||
{
|
||||
const auto foundAssetTypeEntry = m_asset_types_by_name.find(assetEntry.m_asset_type);
|
||||
if (foundAssetTypeEntry == m_asset_types_by_name.end())
|
||||
{
|
||||
std::cout << "Unknown asset type \"" << assetEntry.m_asset_type << "\"\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!ObjLoading::LoadAssetForZone(assetLoadingContext.get(), foundAssetTypeEntry->second, assetEntry.m_asset_name))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ObjLoading::FinalizeAssetsForZone(assetLoadingContext.get());
|
||||
|
||||
return zone;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
#include "Zone/ZoneTypes.h"
|
||||
#include "ZoneCreation/IZoneCreator.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace IW5
|
||||
{
|
||||
class ZoneCreator final : public IZoneCreator
|
||||
{
|
||||
std::unordered_map<std::string, asset_type_t> m_asset_types_by_name;
|
||||
|
||||
void AddAssetTypeName(asset_type_t assetType, std::string name);
|
||||
static std::vector<Gdt*> CreateGdtList(const ZoneCreationContext& context);
|
||||
bool CreateIgnoredAssetMap(const ZoneCreationContext& context, std::unordered_map<std::string, asset_type_t>& ignoredAssetMap) const;
|
||||
void CreateZoneAssetPools(Zone* zone) const;
|
||||
|
||||
public:
|
||||
ZoneCreator();
|
||||
|
||||
_NODISCARD bool SupportsGame(const std::string& gameName) const override;
|
||||
_NODISCARD std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
|
||||
};
|
||||
} // namespace IW5
|
@ -1,102 +0,0 @@
|
||||
#include "ZoneCreatorT5.h"
|
||||
|
||||
#include "AssetLoading/AssetLoadingContext.h"
|
||||
#include "Game/T5/GameAssetPoolT5.h"
|
||||
#include "Game/T5/GameT5.h"
|
||||
#include "ObjLoading.h"
|
||||
#include "Utils/StringUtils.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace T5;
|
||||
|
||||
ZoneCreator::ZoneCreator()
|
||||
{
|
||||
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
|
||||
{
|
||||
AddAssetTypeName(assetType, GameAssetPoolT5::AssetTypeNameByType(assetType));
|
||||
}
|
||||
}
|
||||
|
||||
void ZoneCreator::AddAssetTypeName(asset_type_t assetType, std::string name)
|
||||
{
|
||||
m_asset_types_by_name.emplace(std::make_pair(std::move(name), assetType));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool ZoneCreator::CreateIgnoredAssetMap(const ZoneCreationContext& context, std::unordered_map<std::string, asset_type_t>& ignoredAssetMap) const
|
||||
{
|
||||
for (const auto& ignoreEntry : context.m_ignored_assets.m_entries)
|
||||
{
|
||||
const auto foundAssetTypeEntry = m_asset_types_by_name.find(ignoreEntry.m_type);
|
||||
if (foundAssetTypeEntry == m_asset_types_by_name.end())
|
||||
{
|
||||
std::cout << "Unknown asset type \"" << ignoreEntry.m_type << "\" for ignore \"" << ignoreEntry.m_name << "\"\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
ignoredAssetMap[ignoreEntry.m_name] = foundAssetTypeEntry->second;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool ZoneCreator::SupportsGame(const std::string& gameName) const
|
||||
{
|
||||
auto shortName = g_GameT5.GetShortName();
|
||||
utils::MakeStringLowerCase(shortName);
|
||||
|
||||
return gameName == shortName;
|
||||
}
|
||||
|
||||
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
|
||||
{
|
||||
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, &g_GameT5);
|
||||
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.get(), context.m_asset_search_path, CreateGdtList(context));
|
||||
if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map))
|
||||
return nullptr;
|
||||
|
||||
for (const auto& assetEntry : context.m_definition->m_assets)
|
||||
{
|
||||
const auto foundAssetTypeEntry = m_asset_types_by_name.find(assetEntry.m_asset_type);
|
||||
if (foundAssetTypeEntry == m_asset_types_by_name.end())
|
||||
{
|
||||
std::cout << "Unknown asset type \"" << assetEntry.m_asset_type << "\"\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!ObjLoading::LoadAssetForZone(assetLoadingContext.get(), foundAssetTypeEntry->second, assetEntry.m_asset_name))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ObjLoading::FinalizeAssetsForZone(assetLoadingContext.get());
|
||||
|
||||
return zone;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
#include "Zone/ZoneTypes.h"
|
||||
#include "ZoneCreation/IZoneCreator.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace T5
|
||||
{
|
||||
class ZoneCreator final : public IZoneCreator
|
||||
{
|
||||
std::unordered_map<std::string, asset_type_t> m_asset_types_by_name;
|
||||
|
||||
void AddAssetTypeName(asset_type_t assetType, std::string name);
|
||||
static std::vector<Gdt*> CreateGdtList(ZoneCreationContext& context);
|
||||
bool CreateIgnoredAssetMap(const ZoneCreationContext& context, std::unordered_map<std::string, asset_type_t>& ignoredAssetMap) const;
|
||||
void CreateZoneAssetPools(Zone* zone) const;
|
||||
|
||||
public:
|
||||
ZoneCreator();
|
||||
|
||||
_NODISCARD bool SupportsGame(const std::string& gameName) const override;
|
||||
_NODISCARD std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
|
||||
};
|
||||
} // namespace T5
|
@ -1,153 +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 "ObjLoading.h"
|
||||
#include "Utils/StringUtils.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace T6;
|
||||
|
||||
ZoneCreator::ZoneCreator()
|
||||
{
|
||||
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
|
||||
{
|
||||
AddAssetTypeName(assetType, GameAssetPoolT6::AssetTypeNameByType(assetType));
|
||||
}
|
||||
}
|
||||
|
||||
void ZoneCreator::AddAssetTypeName(asset_type_t assetType, std::string name)
|
||||
{
|
||||
m_asset_types_by_name.emplace(std::make_pair(std::move(name), assetType));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool ZoneCreator::CreateIgnoredAssetMap(const ZoneCreationContext& context, std::unordered_map<std::string, asset_type_t>& ignoredAssetMap) const
|
||||
{
|
||||
for (const auto& ignoreEntry : context.m_ignored_assets.m_entries)
|
||||
{
|
||||
const auto foundAssetTypeEntry = m_asset_types_by_name.find(ignoreEntry.m_type);
|
||||
if (foundAssetTypeEntry == m_asset_types_by_name.end())
|
||||
{
|
||||
std::cout << "Unknown asset type \"" << ignoreEntry.m_type << "\" for ignore \"" << ignoreEntry.m_name << "\"\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
ignoredAssetMap[ignoreEntry.m_name] = foundAssetTypeEntry->second;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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_metadata)
|
||||
{
|
||||
if (metaData->m_key.rfind("level.", 0) == 0)
|
||||
{
|
||||
const std::string strValue = metaData->m_key.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->m_key << "\" 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->m_value.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));
|
||||
}
|
||||
}
|
||||
|
||||
bool ZoneCreator::SupportsGame(const std::string& gameName) const
|
||||
{
|
||||
auto shortName = g_GameT6.GetShortName();
|
||||
utils::MakeStringLowerCase(shortName);
|
||||
|
||||
return gameName == shortName;
|
||||
}
|
||||
|
||||
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
|
||||
{
|
||||
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, &g_GameT6);
|
||||
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.get(), context.m_asset_search_path, CreateGdtList(context));
|
||||
if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map))
|
||||
return nullptr;
|
||||
|
||||
HandleMetadata(zone.get(), context);
|
||||
|
||||
for (const auto& assetEntry : context.m_definition->m_assets)
|
||||
{
|
||||
const auto foundAssetTypeEntry = m_asset_types_by_name.find(assetEntry.m_asset_type);
|
||||
if (foundAssetTypeEntry == m_asset_types_by_name.end())
|
||||
{
|
||||
std::cout << "Unknown asset type \"" << assetEntry.m_asset_type << "\"\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!ObjLoading::LoadAssetForZone(assetLoadingContext.get(), foundAssetTypeEntry->second, assetEntry.m_asset_name))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ObjLoading::FinalizeAssetsForZone(assetLoadingContext.get());
|
||||
|
||||
return zone;
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
#pragma once
|
||||
#include "Zone/ZoneTypes.h"
|
||||
#include "ZoneCreation/IZoneCreator.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace T6
|
||||
{
|
||||
class ZoneCreator final : public IZoneCreator
|
||||
{
|
||||
std::unordered_map<std::string, asset_type_t> m_asset_types_by_name;
|
||||
|
||||
void AddAssetTypeName(asset_type_t assetType, std::string name);
|
||||
static std::vector<Gdt*> CreateGdtList(const ZoneCreationContext& context);
|
||||
bool CreateIgnoredAssetMap(const ZoneCreationContext& context, std::unordered_map<std::string, asset_type_t>& ignoredAssetMap) const;
|
||||
void CreateZoneAssetPools(Zone* zone) const;
|
||||
void HandleMetadata(Zone* zone, const ZoneCreationContext& context) const;
|
||||
|
||||
public:
|
||||
ZoneCreator();
|
||||
|
||||
_NODISCARD bool SupportsGame(const std::string& gameName) const override;
|
||||
_NODISCARD std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
|
||||
};
|
||||
} // namespace T6
|
@ -1,27 +1,17 @@
|
||||
#include "Linker.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 "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/Arguments/ArgumentParser.h"
|
||||
#include "Utils/ClassUtils.h"
|
||||
#include "Utils/ObjFileStream.h"
|
||||
#include "Utils/StringUtils.h"
|
||||
#include "Zone/AssetList/AssetList.h"
|
||||
#include "Zone/AssetList/AssetListStream.h"
|
||||
#include "Zone/AssetList/AssetListReader.h"
|
||||
#include "Zone/Definition/ZoneDefinitionStream.h"
|
||||
#include "ZoneCreation/IZoneCreator.h"
|
||||
#include "ZoneCreation/ZoneCreationContext.h"
|
||||
#include "ZoneCreation/ZoneCreator.h"
|
||||
#include "ZoneLoading.h"
|
||||
#include "ZoneWriting.h"
|
||||
|
||||
@ -29,186 +19,157 @@
|
||||
#include <filesystem>
|
||||
#include <format>
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
const IZoneCreator* const ZONE_CREATORS[]{
|
||||
new IW3::ZoneCreator(),
|
||||
new IW4::ZoneCreator(),
|
||||
new IW5::ZoneCreator(),
|
||||
new T5::ZoneCreator(),
|
||||
new T6::ZoneCreator(),
|
||||
};
|
||||
|
||||
enum class ProjectType
|
||||
namespace
|
||||
{
|
||||
NONE,
|
||||
FASTFILE,
|
||||
IPAK,
|
||||
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());
|
||||
}
|
||||
|
||||
MAX
|
||||
};
|
||||
[[nodiscard]] ISearchPath& GetSearchPaths()
|
||||
{
|
||||
return m_search_paths;
|
||||
}
|
||||
|
||||
constexpr const char* PROJECT_TYPE_NAMES[static_cast<unsigned>(ProjectType::MAX)]{
|
||||
"none",
|
||||
"fastfile",
|
||||
"ipak",
|
||||
};
|
||||
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
|
||||
{
|
||||
static constexpr auto METADATA_GAME = "game";
|
||||
static constexpr auto METADATA_GDT = "gdt";
|
||||
static constexpr auto METADATA_NAME = "name";
|
||||
static constexpr auto METADATA_TYPE = "type";
|
||||
|
||||
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, definitionFileName, m_args.m_verbose);
|
||||
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, 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);
|
||||
AssetListEntry entry;
|
||||
|
||||
while (stream.NextEntry(entry))
|
||||
{
|
||||
assetList.m_entries.emplace_back(std::move(entry));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
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, assetList, sourceSearchPath))
|
||||
{
|
||||
std::cerr << std::format("Failed to read asset list \"{}\"\n", assetListName);
|
||||
return false;
|
||||
}
|
||||
|
||||
zoneDefinition.Include(assetList);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool GetNameFromZoneDefinition(std::string& name, const std::string& targetName, const ZoneDefinition& zoneDefinition)
|
||||
{
|
||||
auto firstNameEntry = true;
|
||||
const auto [rangeBegin, rangeEnd] = zoneDefinition.m_metadata_lookup.equal_range(METADATA_NAME);
|
||||
for (auto i = rangeBegin; i != rangeEnd; ++i)
|
||||
{
|
||||
if (firstNameEntry)
|
||||
{
|
||||
name = i->second->m_value;
|
||||
firstNameEntry = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (name != i->second->m_value)
|
||||
{
|
||||
std::cerr << std::format("Conflicting names in target \"{}\": {} != {}\n", targetName, name, i->second->m_value);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (firstNameEntry)
|
||||
name = targetName;
|
||||
|
||||
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 = targetName + ".zone";
|
||||
const auto definitionStream = sourceSearchPath->Open(definitionFileName);
|
||||
const auto definitionFileName = std::format("{}.zone", targetName);
|
||||
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, definitionFileName, m_args.m_verbose);
|
||||
ZoneDefinitionInputStream zoneDefinitionInputStream(*definitionStream.m_stream, targetName, definitionFileName, sourceSearchPath);
|
||||
zoneDefinition = zoneDefinitionInputStream.ReadDefinition();
|
||||
}
|
||||
|
||||
@ -218,36 +179,51 @@ class LinkerImpl final : public Linker
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!GetNameFromZoneDefinition(zoneDefinition->m_name, targetName, *zoneDefinition))
|
||||
return nullptr;
|
||||
|
||||
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;
|
||||
|
||||
std::map<std::string, std::reference_wrapper<ZoneDefinitionEntry>> zoneDefinitionAssetsByName;
|
||||
for (auto& entry : context.m_definition->m_assets)
|
||||
{
|
||||
zoneDefinitionAssetsByName.try_emplace(entry.m_asset_name, entry);
|
||||
}
|
||||
|
||||
for (const auto& ignore : context.m_definition->m_ignores)
|
||||
{
|
||||
if (ignore == targetName)
|
||||
continue;
|
||||
|
||||
std::vector<AssetListEntry> assetList;
|
||||
if (!ReadAssetList(ignore, 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;
|
||||
@ -256,101 +232,14 @@ class LinkerImpl final : public Linker
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ProjectTypeByName(ProjectType& projectType, const std::string& projectTypeName)
|
||||
{
|
||||
for (auto i = 0u; i < static_cast<unsigned>(ProjectType::MAX); i++)
|
||||
{
|
||||
if (projectTypeName == PROJECT_TYPE_NAMES[i])
|
||||
{
|
||||
projectType = static_cast<ProjectType>(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool GetProjectTypeFromZoneDefinition(ProjectType& projectType, const std::string& targetName, const ZoneDefinition& zoneDefinition)
|
||||
{
|
||||
auto firstTypeEntry = true;
|
||||
const auto [rangeBegin, rangeEnd] = zoneDefinition.m_metadata_lookup.equal_range(METADATA_TYPE);
|
||||
for (auto i = rangeBegin; i != rangeEnd; ++i)
|
||||
{
|
||||
ProjectType parsedProjectType;
|
||||
if (!ProjectTypeByName(parsedProjectType, i->second->m_value))
|
||||
{
|
||||
std::cerr << std::format("Not a valid project type: \"{}\"\n", i->second->m_value);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (firstTypeEntry)
|
||||
{
|
||||
projectType = parsedProjectType;
|
||||
firstTypeEntry = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (projectType != parsedProjectType)
|
||||
{
|
||||
std::cerr << std::format("Conflicting types in target \"{}\": {} != {}\n",
|
||||
targetName,
|
||||
PROJECT_TYPE_NAMES[static_cast<unsigned>(projectType)],
|
||||
PROJECT_TYPE_NAMES[static_cast<unsigned>(parsedProjectType)]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (firstTypeEntry)
|
||||
{
|
||||
if (zoneDefinition.m_assets.empty())
|
||||
projectType = ProjectType::NONE;
|
||||
else
|
||||
projectType = ProjectType::FASTFILE;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool GetGameNameFromZoneDefinition(std::string& gameName, const std::string& targetName, const ZoneDefinition& zoneDefinition)
|
||||
{
|
||||
auto firstGameEntry = true;
|
||||
const auto [rangeBegin, rangeEnd] = zoneDefinition.m_metadata_lookup.equal_range(METADATA_GAME);
|
||||
for (auto i = rangeBegin; i != rangeEnd; ++i)
|
||||
{
|
||||
if (firstGameEntry)
|
||||
{
|
||||
gameName = i->second->m_value;
|
||||
firstGameEntry = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gameName != i->second->m_value)
|
||||
{
|
||||
std::cerr << std::format("Conflicting game names in target \"{}\": {} != {}\n", targetName, gameName, i->second->m_value);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (firstGameEntry)
|
||||
{
|
||||
std::cerr << std::format("No game name was specified for target \"{}\"\n", targetName);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool LoadGdtFilesFromZoneDefinition(std::vector<std::unique_ptr<Gdt>>& gdtList, const ZoneDefinition& zoneDefinition, ISearchPath* gdtSearchPath)
|
||||
{
|
||||
const auto [rangeBegin, rangeEnd] = zoneDefinition.m_metadata_lookup.equal_range(METADATA_GDT);
|
||||
for (auto i = rangeBegin; i != rangeEnd; ++i)
|
||||
for (const auto& gdtName : zoneDefinition.m_gdts)
|
||||
{
|
||||
const auto gdtFile = gdtSearchPath->Open(i->second->m_value + ".gdt");
|
||||
const auto gdtFile = gdtSearchPath->Open(std::format("{}.gdt", gdtName));
|
||||
if (!gdtFile.IsOpen())
|
||||
{
|
||||
std::cerr << std::format("Failed to open file for gdt \"{}\"\n", i->second->m_value);
|
||||
std::cerr << std::format("Failed to open file for gdt \"{}\"\n", gdtName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -358,7 +247,7 @@ class LinkerImpl final : public Linker
|
||||
auto gdt = std::make_unique<Gdt>();
|
||||
if (!gdtReader.Read(*gdt))
|
||||
{
|
||||
std::cerr << std::format("Failed to read gdt file \"{}\"\n", i->second->m_value);
|
||||
std::cerr << std::format("Failed to read gdt file \"{}\"\n", gdtName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -368,174 +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>(assetSearchPath, &zoneDefinition);
|
||||
if (!ProcessZoneDefinitionIgnores(targetName, *context, sourceSearchPath))
|
||||
ZoneCreationContext context(&zoneDefinition, &paths.m_asset_paths.GetSearchPaths(), outDir, cacheDir);
|
||||
if (!ProcessZoneDefinitionIgnores(paths, targetName, context))
|
||||
return nullptr;
|
||||
if (!GetGameNameFromZoneDefinition(context->m_game_name, targetName, zoneDefinition))
|
||||
return nullptr;
|
||||
utils::MakeStringLowerCase(context->m_game_name);
|
||||
if (!LoadGdtFilesFromZoneDefinition(context->m_gdt_files, zoneDefinition, gdtSearchPath))
|
||||
if (!LoadGdtFilesFromZoneDefinition(context.m_gdt_files, zoneDefinition, &paths.m_gdt_paths.GetSearchPaths()))
|
||||
return nullptr;
|
||||
|
||||
for (const auto* zoneCreator : ZONE_CREATORS)
|
||||
{
|
||||
if (zoneCreator->SupportsGame(context->m_game_name))
|
||||
return zoneCreator->CreateZoneForDefinition(*context);
|
||||
}
|
||||
|
||||
std::cerr << std::format("Unsupported game: {}\n", context->m_game_name);
|
||||
return nullptr;
|
||||
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(zoneDefinition.m_name + ".ipak");
|
||||
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);
|
||||
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 == "image")
|
||||
ipakWriter->AddImage(assetEntry.m_asset_name);
|
||||
}
|
||||
PathProjectContext projectContext(paths, projectName);
|
||||
|
||||
if (!ipakWriter->Write())
|
||||
{
|
||||
std::cerr << "Writing ipak failed.\n";
|
||||
stream.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << std::format("Created ipak \"{}\"\n", ipakFilePath.string());
|
||||
|
||||
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;
|
||||
|
||||
ProjectType projectType;
|
||||
if (!GetProjectTypeFromZoneDefinition(projectType, targetName, *zoneDefinition))
|
||||
return false;
|
||||
|
||||
auto result = true;
|
||||
if (projectType != ProjectType::NONE)
|
||||
{
|
||||
std::string gameName;
|
||||
if (!GetGameNameFromZoneDefinition(gameName, targetName, *zoneDefinition))
|
||||
const auto zoneDefinition = ReadZoneDefinition(paths, targetName);
|
||||
if (!zoneDefinition)
|
||||
return false;
|
||||
utils::MakeStringLowerCase(gameName);
|
||||
|
||||
auto assetSearchPaths = m_search_paths.GetAssetSearchPathsForProject(gameName, projectName);
|
||||
auto gdtSearchPaths = m_search_paths.GetGdtSearchPathsForProject(gameName, projectName);
|
||||
PathGameContext gameContext(paths, projectName, zoneDefinition->m_game);
|
||||
|
||||
switch (projectType)
|
||||
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()
|
||||
@ -553,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;
|
||||
@ -621,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;
|
||||
@ -635,8 +440,7 @@ public:
|
||||
if (!shouldContinue)
|
||||
return true;
|
||||
|
||||
if (!m_search_paths.BuildProjectIndependentSearchPaths())
|
||||
return false;
|
||||
LinkerPathManager paths(m_args);
|
||||
|
||||
if (!LoadZones())
|
||||
return false;
|
||||
@ -652,7 +456,7 @@ public:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!BuildProject(projectName, targetName))
|
||||
if (!BuildProject(paths, projectName, targetName))
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
@ -663,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()
|
||||
|
@ -7,8 +7,8 @@
|
||||
#include "Utils/FileUtils.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
#include <type_traits>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
@ -45,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();
|
||||
|
||||
@ -60,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();
|
||||
|
||||
@ -82,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();
|
||||
|
||||
@ -128,19 +128,13 @@ 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)>)
|
||||
{
|
||||
}
|
||||
|
||||
void LinkerArgs::PrintUsage()
|
||||
void LinkerArgs::PrintUsage() const
|
||||
{
|
||||
UsageInformation usage("Linker.exe");
|
||||
UsageInformation usage(m_argument_parser.GetExecutableName());
|
||||
|
||||
for (const auto* commandLineOption : COMMAND_LINE_OPTIONS)
|
||||
{
|
||||
@ -155,7 +149,7 @@ void LinkerArgs::PrintUsage()
|
||||
|
||||
void LinkerArgs::PrintVersion()
|
||||
{
|
||||
std::cout << "OpenAssetTools Linker " << std::string(GIT_VERSION) << "\n";
|
||||
std::cout << std::format("OpenAssetTools Linker {}\n", GIT_VERSION);
|
||||
}
|
||||
|
||||
void LinkerArgs::SetBinFolder(const char* argv0)
|
||||
@ -171,80 +165,10 @@ 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;
|
||||
if (!m_argument_parser.ParseArguments(argc - 1, &argv[1]))
|
||||
if (!m_argument_parser.ParseArguments(argc, argv))
|
||||
{
|
||||
PrintUsage();
|
||||
return false;
|
||||
@ -283,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))
|
||||
@ -357,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);
|
||||
}
|
||||
|
@ -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;
|
||||
@ -59,22 +34,11 @@ private:
|
||||
/**
|
||||
* \brief Prints a command line usage help text for the Linker tool to stdout.
|
||||
*/
|
||||
static void PrintUsage();
|
||||
void PrintUsage() const;
|
||||
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
342
src/Linker/LinkerPaths.cpp
Normal 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
74
src/Linker/LinkerPaths.h
Normal 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;
|
||||
};
|
@ -1,189 +0,0 @@
|
||||
#include "LinkerSearchPaths.h"
|
||||
|
||||
#include "ObjContainer/IWD/IWD.h"
|
||||
#include "ObjLoading.h"
|
||||
#include "SearchPath/SearchPathFilesystem.h"
|
||||
|
||||
#include <filesystem>
|
||||
#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)
|
||||
{
|
||||
printf("Loading search path: \"%s\"\n", searchPath->GetPath().c_str());
|
||||
}
|
||||
|
||||
ObjLoading::LoadIWDsInSearchPath(searchPath);
|
||||
}
|
||||
|
||||
void LinkerSearchPaths::UnloadSearchPath(ISearchPath* searchPath) const
|
||||
{
|
||||
if (m_args.m_verbose)
|
||||
{
|
||||
printf("Unloading search path: \"%s\"\n", searchPath->GetPath().c_str());
|
||||
}
|
||||
|
||||
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 << "Adding asset search path (Not found): " << absolutePath.string() << "\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_args.m_verbose)
|
||||
std::cout << "Adding asset search path: " << absolutePath.string() << "\n";
|
||||
|
||||
auto searchPath = std::make_unique<SearchPathFilesystem>(searchPathStr);
|
||||
LoadSearchPath(searchPath.get());
|
||||
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 << "Adding gdt search path (Not found): " << absolutePath.string() << "\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_args.m_verbose)
|
||||
std::cout << "Adding gdt search path: " << absolutePath.string() << "\n";
|
||||
|
||||
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 << "Adding source search path (Not found): " << absolutePath.string() << "\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_args.m_verbose)
|
||||
std::cout << "Adding source search path: " << absolutePath.string() << "\n";
|
||||
|
||||
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 << "Adding asset search path (Not found): " << absolutePath.string() << "\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_args.m_verbose)
|
||||
std::cout << "Adding asset search path: " << absolutePath.string() << "\n";
|
||||
|
||||
auto searchPath = std::make_unique<SearchPathFilesystem>(absolutePath.string());
|
||||
LoadSearchPath(searchPath.get());
|
||||
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 << "Loading gdt search path (Not found): " << absolutePath.string() << "\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_args.m_verbose)
|
||||
std::cout << "Adding gdt search path: " << absolutePath.string() << "\n";
|
||||
|
||||
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 << "Loading source search path (Not found): " << absolutePath.string() << "\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_args.m_verbose)
|
||||
std::cout << "Adding source search path: " << absolutePath.string() << "\n";
|
||||
|
||||
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.get());
|
||||
}
|
||||
|
||||
m_loaded_project_search_paths.clear();
|
||||
}
|
@ -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;
|
||||
};
|
@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
#include "Utils/ClassUtils.h"
|
||||
#include "Zone/Zone.h"
|
||||
#include "ZoneCreationContext.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class IZoneCreator
|
||||
{
|
||||
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 bool SupportsGame(const std::string& gameName) const = 0;
|
||||
_NODISCARD virtual std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const = 0;
|
||||
};
|
@ -1,13 +1,17 @@
|
||||
#include "ZoneCreationContext.h"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
ZoneCreationContext::ZoneCreationContext()
|
||||
: m_asset_search_path(nullptr),
|
||||
m_definition(nullptr)
|
||||
: m_definition(nullptr),
|
||||
m_asset_search_path(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ZoneCreationContext::ZoneCreationContext(ISearchPath* assetSearchPath, ZoneDefinition* definition)
|
||||
: m_asset_search_path(assetSearchPath),
|
||||
m_definition(definition)
|
||||
ZoneCreationContext::ZoneCreationContext(ZoneDefinition* definition, ISearchPath* assetSearchPath, fs::path outDir, fs::path cacheDir)
|
||||
: m_definition(definition),
|
||||
m_asset_search_path(assetSearchPath),
|
||||
m_out_dir(std::move(outDir)),
|
||||
m_cache_dir(std::move(cacheDir))
|
||||
{
|
||||
}
|
||||
|
@ -4,19 +4,20 @@
|
||||
#include "Zone/AssetList/AssetList.h"
|
||||
#include "Zone/Definition/ZoneDefinition.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class ZoneCreationContext
|
||||
{
|
||||
public:
|
||||
std::string m_game_name;
|
||||
ISearchPath* m_asset_search_path;
|
||||
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(ISearchPath* assetSearchPath, ZoneDefinition* definition);
|
||||
ZoneCreationContext(ZoneDefinition* definition, ISearchPath* assetSearchPath, std::filesystem::path outDir, std::filesystem::path cacheDir);
|
||||
};
|
||||
|
91
src/Linker/ZoneCreation/ZoneCreator.cpp
Normal file
91
src/Linker/ZoneCreation/ZoneCreator.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
#include "ZoneCreator.h"
|
||||
|
||||
#include "Gdt/GdtLookup.h"
|
||||
#include "IObjCompiler.h"
|
||||
#include "IObjLoader.h"
|
||||
#include "SearchPath/OutputPathFilesystem.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
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 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
|
9
src/Linker/ZoneCreation/ZoneCreator.h
Normal file
9
src/Linker/ZoneCreation/ZoneCreator.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "Zone/Zone.h"
|
||||
#include "ZoneCreationContext.h"
|
||||
|
||||
namespace zone_creator
|
||||
{
|
||||
[[nodiscard]] std::unique_ptr<Zone> CreateZoneForDefinition(GameId game, ZoneCreationContext& context);
|
||||
}
|
@ -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()
|
||||
|
34
src/ObjCommon/Csv/CsvHeaderRow.cpp
Normal file
34
src/ObjCommon/Csv/CsvHeaderRow.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include "Csv/CsvHeaderRow.h"
|
||||
|
||||
CsvHeaderRow::CsvHeaderRow() = default;
|
||||
|
||||
bool CsvHeaderRow::Read(const CsvInputStream& inputStream)
|
||||
{
|
||||
if (!m_header_row.empty())
|
||||
return false;
|
||||
|
||||
return inputStream.NextRow(m_header_row);
|
||||
}
|
||||
|
||||
const std::string& CsvHeaderRow::HeaderNameForColumn(const unsigned columnIndex) const
|
||||
{
|
||||
return m_header_row[columnIndex];
|
||||
}
|
||||
|
||||
bool CsvHeaderRow::RequireIndexForHeader(const std::string& headerName, unsigned& out) const
|
||||
{
|
||||
const auto existingHeader = std::ranges::find(m_header_row, headerName);
|
||||
if (existingHeader == m_header_row.end())
|
||||
return false;
|
||||
|
||||
out = std::distance(m_header_row.begin(), existingHeader);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<unsigned> CsvHeaderRow::GetIndexForHeader(const std::string& headerName) const
|
||||
{
|
||||
unsigned result;
|
||||
if (!RequireIndexForHeader(headerName, result))
|
||||
return std::nullopt;
|
||||
return result;
|
||||
}
|
22
src/ObjCommon/Csv/CsvHeaderRow.h
Normal file
22
src/ObjCommon/Csv/CsvHeaderRow.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "Csv/CsvStream.h"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class CsvHeaderRow
|
||||
{
|
||||
public:
|
||||
CsvHeaderRow();
|
||||
|
||||
bool Read(const CsvInputStream& inputStream);
|
||||
|
||||
const std::string& HeaderNameForColumn(unsigned columnIndex) const;
|
||||
bool RequireIndexForHeader(const std::string& headerName, unsigned& out) const;
|
||||
[[nodiscard]] std::optional<unsigned> GetIndexForHeader(const std::string& headerName) const;
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_header_row;
|
||||
};
|
@ -1,14 +1,88 @@
|
||||
#include "CsvStream.h"
|
||||
|
||||
#include "Utils/StringUtils.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
|
||||
constexpr char CSV_SEPARATOR = ',';
|
||||
|
||||
CsvCell::CsvCell(std::string value)
|
||||
: m_value(std::move(value))
|
||||
{
|
||||
}
|
||||
|
||||
bool CsvCell::AsFloat(float& out) const
|
||||
{
|
||||
const char* startPtr = m_value.c_str();
|
||||
char* endPtr;
|
||||
out = std::strtof(startPtr, &endPtr);
|
||||
|
||||
if (endPtr == startPtr)
|
||||
return false;
|
||||
|
||||
for (const auto* c = endPtr; *c; c++)
|
||||
{
|
||||
if (!isspace(*c))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CsvCell::AsInt32(int32_t& out) const
|
||||
{
|
||||
const char* startPtr = m_value.c_str();
|
||||
char* endPtr;
|
||||
out = std::strtol(startPtr, &endPtr, 0);
|
||||
|
||||
if (endPtr == startPtr)
|
||||
return false;
|
||||
|
||||
for (const auto* c = endPtr; *c; c++)
|
||||
{
|
||||
if (!isspace(*c))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CsvCell::AsUInt32(uint32_t& out) const
|
||||
{
|
||||
const char* startPtr = m_value.c_str();
|
||||
char* endPtr;
|
||||
out = std::strtoul(startPtr, &endPtr, 0);
|
||||
|
||||
if (endPtr == startPtr)
|
||||
return false;
|
||||
|
||||
for (const auto* c = endPtr; *c; c++)
|
||||
{
|
||||
if (!isspace(*c))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CsvInputStream::CsvInputStream(std::istream& stream)
|
||||
: m_stream(stream)
|
||||
{
|
||||
}
|
||||
|
||||
bool CsvInputStream::NextRow(std::vector<CsvCell>& out) const
|
||||
{
|
||||
if (!out.empty())
|
||||
out.clear();
|
||||
|
||||
return EmitNextRow(
|
||||
[&out](std::string value)
|
||||
{
|
||||
out.emplace_back(std::move(value));
|
||||
});
|
||||
}
|
||||
|
||||
bool CsvInputStream::NextRow(std::vector<std::string>& out) const
|
||||
{
|
||||
if (!out.empty())
|
||||
@ -38,13 +112,17 @@ bool CsvInputStream::EmitNextRow(const std::function<void(std::string)>& cb) con
|
||||
auto c = m_stream.get();
|
||||
const auto isEof = c == EOF;
|
||||
std::ostringstream col;
|
||||
auto content = false;
|
||||
while (c != EOF)
|
||||
{
|
||||
if (c == CSV_SEPARATOR)
|
||||
{
|
||||
cb(col.str());
|
||||
auto value = col.str();
|
||||
utils::StringTrimR(value);
|
||||
cb(std::move(value));
|
||||
col.clear();
|
||||
col.str(std::string());
|
||||
content = false;
|
||||
}
|
||||
else if (c == '\r')
|
||||
{
|
||||
@ -57,8 +135,14 @@ bool CsvInputStream::EmitNextRow(const std::function<void(std::string)>& cb) con
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (isspace(c))
|
||||
{
|
||||
if (content)
|
||||
col << static_cast<char>(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
content = true;
|
||||
col << static_cast<char>(c);
|
||||
}
|
||||
|
||||
@ -67,7 +151,9 @@ bool CsvInputStream::EmitNextRow(const std::function<void(std::string)>& cb) con
|
||||
|
||||
if (!isEof)
|
||||
{
|
||||
cb(col.str());
|
||||
auto value = col.str();
|
||||
utils::StringTrimR(value);
|
||||
cb(std::move(value));
|
||||
}
|
||||
|
||||
return !isEof;
|
||||
|
@ -1,16 +1,30 @@
|
||||
#pragma once
|
||||
#include "Utils/MemoryManager.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class CsvCell
|
||||
{
|
||||
public:
|
||||
explicit CsvCell(std::string value);
|
||||
|
||||
bool AsFloat(float& out) const;
|
||||
bool AsInt32(int32_t& out) const;
|
||||
bool AsUInt32(uint32_t& out) const;
|
||||
|
||||
std::string m_value;
|
||||
};
|
||||
|
||||
class CsvInputStream
|
||||
{
|
||||
public:
|
||||
explicit CsvInputStream(std::istream& stream);
|
||||
|
||||
bool NextRow(std::vector<CsvCell>& out) const;
|
||||
bool NextRow(std::vector<std::string>& out) const;
|
||||
bool NextRow(std::vector<const char*>& out, MemoryManager& memory) const;
|
||||
|
||||
|
@ -1,80 +0,0 @@
|
||||
#include "Csv/ParsedCsv.h"
|
||||
|
||||
ParsedCsvRow::ParsedCsvRow(std::unordered_map<std::string, size_t>& headers, std::vector<std::string> row)
|
||||
: headers(headers),
|
||||
values(std::move(row))
|
||||
{
|
||||
}
|
||||
|
||||
std::string ParsedCsvRow::GetValue(const std::string& header, const bool required) const
|
||||
{
|
||||
if (this->headers.find(header) == this->headers.end())
|
||||
{
|
||||
if (required)
|
||||
std::cerr << "ERROR: Required column \"" << header << "\" was not found\n";
|
||||
else
|
||||
std::cerr << "WARNING: Expected column \"" << header << "\" was not found\n";
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
auto& value = this->values.at(this->headers[header]);
|
||||
if (required && value.empty())
|
||||
{
|
||||
std::cerr << "ERROR: Required column \"" << header << "\" does not have a value\n";
|
||||
return {};
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
float ParsedCsvRow::GetValueFloat(const std::string& header, const bool required) const
|
||||
{
|
||||
const auto& value = this->GetValue(header, required);
|
||||
if (!value.empty())
|
||||
{
|
||||
std::istringstream ss(value);
|
||||
float out;
|
||||
ss >> out;
|
||||
return out;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
ParsedCsv::ParsedCsv(const CsvInputStream& inputStream, const bool hasHeaders)
|
||||
{
|
||||
std::vector<std::vector<std::string>> csvLines;
|
||||
std::vector<std::string> currentLine;
|
||||
|
||||
while (inputStream.NextRow(currentLine))
|
||||
{
|
||||
csvLines.emplace_back(std::move(currentLine));
|
||||
currentLine = std::vector<std::string>();
|
||||
}
|
||||
|
||||
if (hasHeaders)
|
||||
{
|
||||
const auto& headersRow = csvLines[0];
|
||||
for (auto i = 0u; i < headersRow.size(); i++)
|
||||
{
|
||||
this->headers[headersRow[i]] = i;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i = hasHeaders ? 1u : 0u; i < csvLines.size(); i++)
|
||||
{
|
||||
auto& rowValues = csvLines[i];
|
||||
this->rows.emplace_back(this->headers, std::move(rowValues));
|
||||
}
|
||||
}
|
||||
|
||||
size_t ParsedCsv::Size() const
|
||||
{
|
||||
return this->rows.size();
|
||||
}
|
||||
|
||||
ParsedCsvRow ParsedCsv::operator[](const size_t index) const
|
||||
{
|
||||
return this->rows.at(index);
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Csv/CsvStream.h"
|
||||
#include "Utils/ClassUtils.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
|
||||
class ParsedCsvRow
|
||||
{
|
||||
std::unordered_map<std::string, size_t>& headers;
|
||||
std::vector<std::string> values;
|
||||
|
||||
public:
|
||||
explicit ParsedCsvRow(std::unordered_map<std::string, size_t>& headers, std::vector<std::string> row);
|
||||
_NODISCARD std::string GetValue(const std::string& header, bool required = false) const;
|
||||
_NODISCARD float GetValueFloat(const std::string& header, bool required = false) const;
|
||||
|
||||
template<typename T> T GetValueInt(const std::string& header, const bool required = false) const
|
||||
{
|
||||
const auto& value = this->GetValue(header, required);
|
||||
if (!value.empty())
|
||||
{
|
||||
std::istringstream ss(value);
|
||||
long long out;
|
||||
ss >> out;
|
||||
return static_cast<T>(out);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
class ParsedCsv
|
||||
{
|
||||
std::unordered_map<std::string, size_t> headers;
|
||||
std::vector<ParsedCsvRow> rows;
|
||||
|
||||
public:
|
||||
explicit ParsedCsv(const CsvInputStream& inputStream, bool hasHeaders = true);
|
||||
|
||||
_NODISCARD size_t Size() const;
|
||||
|
||||
ParsedCsvRow operator[](size_t index) const;
|
||||
};
|
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "Game/IW4/IW4.h"
|
||||
|
||||
namespace IW4
|
@ -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
|
@ -95,6 +95,43 @@ namespace T6
|
||||
"snp_x3",
|
||||
};
|
||||
|
||||
// From SndDriverGlobals
|
||||
inline constexpr const char* SOUND_PANS[]{
|
||||
"default",
|
||||
"music",
|
||||
"wpn_all",
|
||||
"wpn_fnt",
|
||||
"wpn_rear",
|
||||
"wpn_left",
|
||||
"wpn_right",
|
||||
"music_all",
|
||||
"fly_foot_all",
|
||||
"front",
|
||||
"back",
|
||||
"front_mostly",
|
||||
"back_mostly",
|
||||
"all",
|
||||
"center",
|
||||
"front_and_center",
|
||||
"lfe",
|
||||
"quad",
|
||||
"front_mostly_some_center",
|
||||
"front_halfback",
|
||||
"halffront_back",
|
||||
"test",
|
||||
"brass_right",
|
||||
"brass_left",
|
||||
"veh_back",
|
||||
"tst_left",
|
||||
"tst_center",
|
||||
"tst_right",
|
||||
"tst_surround_left",
|
||||
"tst_surround_right",
|
||||
"tst_lfe",
|
||||
"pip",
|
||||
"movie_vo",
|
||||
};
|
||||
|
||||
inline constexpr const char* SOUND_LIMIT_TYPES[]{
|
||||
"none",
|
||||
"oldest",
|
||||
@ -138,9 +175,23 @@ namespace T6
|
||||
|
||||
// From executable
|
||||
inline constexpr const char* SOUND_RANDOMIZE_TYPES[]{
|
||||
"",
|
||||
"volume",
|
||||
"pitch",
|
||||
"variant",
|
||||
};
|
||||
|
||||
inline constexpr const char* SOUND_NO_YES[]{
|
||||
"no",
|
||||
"yes",
|
||||
};
|
||||
|
||||
inline constexpr const char* SOUND_LOOP_TYPES[]{
|
||||
"nonlooping",
|
||||
"looping",
|
||||
};
|
||||
|
||||
inline constexpr const char* SOUND_PAN_TYPES[]{
|
||||
"2d",
|
||||
"3d",
|
||||
};
|
||||
} // namespace T6
|
||||
|
@ -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
|
@ -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
|
@ -81,4 +81,4 @@ namespace T6
|
||||
{"customBool1", offsetof(WeaponAttachment, customBool1), CSPFT_BOOL },
|
||||
{"customBool2", offsetof(WeaponAttachment, customBool2), CSPFT_BOOL },
|
||||
};
|
||||
}
|
||||
} // namespace T6
|
@ -206,4 +206,4 @@ namespace T6
|
||||
{"customBool1", offsetof(WeaponAttachmentUniqueFull, attachment.customBool1), CSPFT_BOOL },
|
||||
{"customBool2", offsetof(WeaponAttachmentUniqueFull, attachment.customBool2), CSPFT_BOOL },
|
||||
};
|
||||
}
|
||||
} // namespace T6
|
@ -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
|
@ -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;
|
||||
|
18
src/ObjCommon/SearchPath/IOutputPath.h
Normal file
18
src/ObjCommon/SearchPath/IOutputPath.h
Normal 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;
|
||||
};
|
@ -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.
|
39
src/ObjCommon/SearchPath/OutputPathFilesystem.cpp
Normal file
39
src/ObjCommon/SearchPath/OutputPathFilesystem.cpp
Normal 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));
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user