mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-21 00:25:44 +00:00
Compare commits
No commits in common. "main" and "v0.19.2" have entirely different histories.
30
.github/workflows/ci.yaml
vendored
30
.github/workflows/ci.yaml
vendored
@ -8,15 +8,20 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- "main"
|
- "main"
|
||||||
|
|
||||||
|
env:
|
||||||
|
PREMAKE_VERSION: "5.0.0-beta2"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-test-linux:
|
build-test-linux:
|
||||||
|
env:
|
||||||
|
PREMAKE_CONFIG: gmake2
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: ubuntu:24.04
|
container: ubuntu:24.04
|
||||||
steps:
|
steps:
|
||||||
- name: Install g++ and multilib
|
- name: Install g++ and multilib
|
||||||
run: |
|
run: |
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y wget tar git make gcc-13 g++-13 gcc-13-multilib g++-13-multilib
|
apt-get install -y 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/gcc gcc /usr/bin/gcc-13 13
|
||||||
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
|
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
|
||||||
update-alternatives --set gcc /usr/bin/gcc-13
|
update-alternatives --set gcc /usr/bin/gcc-13
|
||||||
@ -27,11 +32,14 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Setup premake
|
||||||
|
uses: abel0b/setup-premake@v2.4
|
||||||
|
with:
|
||||||
|
version: ${{ env.PREMAKE_VERSION }}
|
||||||
|
|
||||||
- name: Premake generate
|
- name: Premake generate
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
env:
|
run: premake5 ${{ env.PREMAKE_CONFIG }}
|
||||||
PREMAKE_NO_PROMPT: 1
|
|
||||||
run: ./generate.sh
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
@ -41,13 +49,14 @@ jobs:
|
|||||||
working-directory: ${{ github.workspace }}/build/lib/Release_x86/tests
|
working-directory: ${{ github.workspace }}/build/lib/Release_x86/tests
|
||||||
run: |
|
run: |
|
||||||
./ObjCommonTests
|
./ObjCommonTests
|
||||||
./ObjCompilingTests
|
|
||||||
./ObjLoadingTests
|
./ObjLoadingTests
|
||||||
./ParserTests
|
./ParserTests
|
||||||
./ZoneCodeGeneratorLibTests
|
./ZoneCodeGeneratorLibTests
|
||||||
./ZoneCommonTests
|
./ZoneCommonTests
|
||||||
|
|
||||||
build-test-windows:
|
build-test-windows:
|
||||||
|
env:
|
||||||
|
PREMAKE_CONFIG: vs2022
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
@ -58,11 +67,14 @@ jobs:
|
|||||||
- name: Add MSBuild to PATH
|
- name: Add MSBuild to PATH
|
||||||
uses: microsoft/setup-msbuild@v2.0.0
|
uses: microsoft/setup-msbuild@v2.0.0
|
||||||
|
|
||||||
|
- name: Setup premake
|
||||||
|
uses: abel0b/setup-premake@v2.4
|
||||||
|
with:
|
||||||
|
version: ${{ env.PREMAKE_VERSION }}
|
||||||
|
|
||||||
- name: Premake generate
|
- name: Premake generate
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
env:
|
run: premake5 ${{ env.PREMAKE_CONFIG }}
|
||||||
PREMAKE_NO_PROMPT: 1
|
|
||||||
run: ./generate.bat
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
@ -74,8 +86,6 @@ jobs:
|
|||||||
$combinedExitCode = 0
|
$combinedExitCode = 0
|
||||||
./ObjCommonTests
|
./ObjCommonTests
|
||||||
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
||||||
./ObjCompilingTests
|
|
||||||
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
|
||||||
./ObjLoadingTests
|
./ObjLoadingTests
|
||||||
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
||||||
./ParserTests
|
./ParserTests
|
||||||
|
27
.github/workflows/release.yaml
vendored
27
.github/workflows/release.yaml
vendored
@ -5,15 +5,20 @@ on:
|
|||||||
tags:
|
tags:
|
||||||
- "v*.*.*"
|
- "v*.*.*"
|
||||||
|
|
||||||
|
env:
|
||||||
|
PREMAKE_VERSION: "5.0.0-beta2"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-release-linux:
|
build-release-linux:
|
||||||
|
env:
|
||||||
|
PREMAKE_CONFIG: gmake2
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: ubuntu:24.04
|
container: ubuntu:24.04
|
||||||
steps:
|
steps:
|
||||||
- name: Install g++ and multilib
|
- name: Install g++ and multilib
|
||||||
run: |
|
run: |
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y wget tar git make gcc-13 g++-13 gcc-13-multilib g++-13-multilib
|
apt-get install -y 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/gcc gcc /usr/bin/gcc-13 13
|
||||||
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
|
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
|
||||||
update-alternatives --set gcc /usr/bin/gcc-13
|
update-alternatives --set gcc /usr/bin/gcc-13
|
||||||
@ -24,11 +29,14 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Setup premake
|
||||||
|
uses: abel0b/setup-premake@v2.4
|
||||||
|
with:
|
||||||
|
version: ${{ env.PREMAKE_VERSION }}
|
||||||
|
|
||||||
- name: Premake generate
|
- name: Premake generate
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
env:
|
run: premake5 ${{ env.PREMAKE_CONFIG }}
|
||||||
PREMAKE_NO_PROMPT: 1
|
|
||||||
run: ./generate.sh
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
@ -42,6 +50,8 @@ jobs:
|
|||||||
${{ github.workspace }}/build/bin/Release_x86
|
${{ github.workspace }}/build/bin/Release_x86
|
||||||
|
|
||||||
build-release-windows:
|
build-release-windows:
|
||||||
|
env:
|
||||||
|
PREMAKE_CONFIG: vs2022
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
@ -52,11 +62,14 @@ jobs:
|
|||||||
- name: Add MSBuild to PATH
|
- name: Add MSBuild to PATH
|
||||||
uses: microsoft/setup-msbuild@v2.0.0
|
uses: microsoft/setup-msbuild@v2.0.0
|
||||||
|
|
||||||
|
- name: Setup premake
|
||||||
|
uses: abel0b/setup-premake@v2.4
|
||||||
|
with:
|
||||||
|
version: ${{ env.PREMAKE_VERSION }}
|
||||||
|
|
||||||
- name: Premake generate
|
- name: Premake generate
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
env:
|
run: premake5 ${{ env.PREMAKE_CONFIG }}
|
||||||
PREMAKE_NO_PROMPT: 1
|
|
||||||
run: ./generate.bat
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
|
@ -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.
|
Use `generate.sh` to generate make files.
|
||||||
When this is done you will have a `build` folder with a `Makefile`.
|
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>`.
|
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 | ❌ | ❌ | |
|
| ComWorld | ❌ | ❌ | |
|
||||||
| GameWorldSp | ❌ | ❌ | |
|
| GameWorldSp | ❌ | ❌ | |
|
||||||
| GameWorldMp | ❌ | ❌ | |
|
| GameWorldMp | ❌ | ❌ | |
|
||||||
| MapEnts | ✅ | ❌ | |
|
| MapEnts | ❌ | ❌ | |
|
||||||
| GfxWorld | ❌ | ❌ | |
|
| GfxWorld | ❌ | ❌ | |
|
||||||
| GfxLightDef | ❌ | ❌ | |
|
| GfxLightDef | ❌ | ❌ | |
|
||||||
| Font_s | ❌ | ❌ | |
|
| Font_s | ❌ | ❌ | |
|
||||||
|
81
generate.bat
81
generate.bat
@ -1,85 +1,6 @@
|
|||||||
@echo off
|
@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"
|
|
||||||
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
|
cd %~dp0
|
||||||
|
|
||||||
:start
|
|
||||||
|
|
||||||
IF "%PREMAKE_NO_GLOBAL%" EQU "" (
|
|
||||||
where /Q "premake5.exe"
|
|
||||||
IF NOT ERRORLEVEL 1 (
|
|
||||||
set PREMAKE_BIN="premake5.exe"
|
|
||||||
goto runpremake
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
IF EXIST build/premake5.exe (
|
|
||||||
set PREMAKE_BIN="build/premake5.exe"
|
|
||||||
goto runpremake
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%PREMAKE_NO_PROMPT%" NEQ "" (
|
|
||||||
call:downloadpremake
|
|
||||||
set PREMAKE_BIN="build/premake5.exe"
|
|
||||||
goto runpremake
|
|
||||||
)
|
|
||||||
|
|
||||||
echo Could not find premake5. You can either install it yourself or this script download it for you.
|
|
||||||
set /p choice="Do you wish to download it automatically? [y/N]> "
|
|
||||||
if /i "%choice%" == "y" (
|
|
||||||
call:downloadpremake
|
|
||||||
set PREMAKE_BIN="build/premake5.exe"
|
|
||||||
goto runpremake
|
|
||||||
)
|
|
||||||
|
|
||||||
echo Please install premake5 and try again
|
|
||||||
exit 1
|
|
||||||
|
|
||||||
:runpremake
|
|
||||||
git submodule update --init --recursive
|
git submodule update --init --recursive
|
||||||
%PREMAKE_BIN% %* vs2022
|
tools\premake5.exe %* vs2022
|
75
generate.sh
75
generate.sh
@ -1,80 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/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
|
# Go to repository root
|
||||||
cd "$(dirname "$0")" || exit 2
|
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)" ]]; 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
|
git submodule update --init --recursive
|
||||||
$PREMAKE_BIN $@ gmake
|
tools/premake5 $@ gmake2
|
20
premake5.lua
20
premake5.lua
@ -1,5 +1,3 @@
|
|||||||
require("premake", ">=5.0.0-beta5")
|
|
||||||
|
|
||||||
include "tools/scripts/folders.lua"
|
include "tools/scripts/folders.lua"
|
||||||
include "tools/scripts/including.lua"
|
include "tools/scripts/including.lua"
|
||||||
include "tools/scripts/linking.lua"
|
include "tools/scripts/linking.lua"
|
||||||
@ -16,7 +14,7 @@ workspace "OpenAssetTools"
|
|||||||
objdir "%{wks.location}/obj"
|
objdir "%{wks.location}/obj"
|
||||||
symbols "On"
|
symbols "On"
|
||||||
systemversion "latest"
|
systemversion "latest"
|
||||||
cppdialect "C++23"
|
cppdialect "C++20"
|
||||||
largeaddressaware "on"
|
largeaddressaware "on"
|
||||||
|
|
||||||
flags {
|
flags {
|
||||||
@ -54,15 +52,13 @@ workspace "OpenAssetTools"
|
|||||||
symbols "On"
|
symbols "On"
|
||||||
filter {}
|
filter {}
|
||||||
|
|
||||||
filter {"system:windows", "configurations:Debug" }
|
|
||||||
buildoptions { "/bigobj" }
|
|
||||||
filter {}
|
|
||||||
|
|
||||||
filter "configurations:Release"
|
filter "configurations:Release"
|
||||||
defines "NDEBUG"
|
defines "NDEBUG"
|
||||||
optimize "Full"
|
optimize "Full"
|
||||||
symbols "Off"
|
symbols "Off"
|
||||||
fatalwarnings { "All" }
|
flags {
|
||||||
|
"FatalWarnings"
|
||||||
|
}
|
||||||
filter {}
|
filter {}
|
||||||
|
|
||||||
defines {
|
defines {
|
||||||
@ -130,7 +126,6 @@ include "src/ZoneLoading.lua"
|
|||||||
include "src/ZoneWriting.lua"
|
include "src/ZoneWriting.lua"
|
||||||
include "src/ZoneCommon.lua"
|
include "src/ZoneCommon.lua"
|
||||||
include "src/ObjCommon.lua"
|
include "src/ObjCommon.lua"
|
||||||
include "src/ObjCompiling.lua"
|
|
||||||
include "src/ObjImage.lua"
|
include "src/ObjImage.lua"
|
||||||
include "src/ObjLoading.lua"
|
include "src/ObjLoading.lua"
|
||||||
include "src/ObjWriting.lua"
|
include "src/ObjWriting.lua"
|
||||||
@ -148,7 +143,6 @@ group "Components"
|
|||||||
ZoneLoading:project()
|
ZoneLoading:project()
|
||||||
ZoneWriting:project()
|
ZoneWriting:project()
|
||||||
ObjCommon:project()
|
ObjCommon:project()
|
||||||
ObjCompiling:project()
|
|
||||||
ObjImage:project()
|
ObjImage:project()
|
||||||
ObjLoading:project()
|
ObjLoading:project()
|
||||||
ObjWriting:project()
|
ObjWriting:project()
|
||||||
@ -174,10 +168,7 @@ group ""
|
|||||||
-- ========================
|
-- ========================
|
||||||
-- Tests
|
-- Tests
|
||||||
-- ========================
|
-- ========================
|
||||||
include "test/Catch2Common.lua"
|
|
||||||
include "test/ObjCommonTestUtils.lua"
|
|
||||||
include "test/ObjCommonTests.lua"
|
include "test/ObjCommonTests.lua"
|
||||||
include "test/ObjCompilingTests.lua"
|
|
||||||
include "test/ObjLoadingTests.lua"
|
include "test/ObjLoadingTests.lua"
|
||||||
include "test/ParserTestUtils.lua"
|
include "test/ParserTestUtils.lua"
|
||||||
include "test/ParserTests.lua"
|
include "test/ParserTests.lua"
|
||||||
@ -186,10 +177,7 @@ include "test/ZoneCommonTests.lua"
|
|||||||
|
|
||||||
-- Tests group: Unit test and other tests projects
|
-- Tests group: Unit test and other tests projects
|
||||||
group "Tests"
|
group "Tests"
|
||||||
Catch2Common:project()
|
|
||||||
ObjCommonTestUtils:project()
|
|
||||||
ObjCommonTests:project()
|
ObjCommonTests:project()
|
||||||
ObjCompilingTests:project()
|
|
||||||
ObjLoadingTests:project()
|
ObjLoadingTests:project()
|
||||||
ParserTestUtils:project()
|
ParserTestUtils:project()
|
||||||
ParserTests:project()
|
ParserTests:project()
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
#!/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}"
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
|||||||
#!/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
|
|
@ -5,5 +5,3 @@ cd "$(dirname "$0")/.." || exit 2
|
|||||||
|
|
||||||
make -C build -j$(nproc) config=debug_x86 clean
|
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
|
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
#!/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,9 +2,6 @@
|
|||||||
|
|
||||||
#include "Zone/ZoneTypes.h"
|
#include "Zone/ZoneTypes.h"
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
struct IAssetBase
|
struct IAssetBase
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
@ -15,42 +12,3 @@ public:
|
|||||||
static constexpr auto EnumEntry = AssetTypeEnum;
|
static constexpr auto EnumEntry = AssetTypeEnum;
|
||||||
using Type = AssetType;
|
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; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
@ -113,32 +113,3 @@ namespace IW3
|
|||||||
using AssetRawFile = Asset<ASSET_TYPE_RAWFILE, RawFile>;
|
using AssetRawFile = Asset<ASSET_TYPE_RAWFILE, RawFile>;
|
||||||
using AssetStringTable = Asset<ASSET_TYPE_STRINGTABLE, StringTable>;
|
using AssetStringTable = Asset<ASSET_TYPE_STRINGTABLE, StringTable>;
|
||||||
} // namespace IW3
|
} // 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);
|
|
||||||
|
@ -168,41 +168,3 @@ namespace IW4
|
|||||||
using AssetVehicle = Asset<ASSET_TYPE_VEHICLE, VehicleDef>;
|
using AssetVehicle = Asset<ASSET_TYPE_VEHICLE, VehicleDef>;
|
||||||
using AssetAddonMapEnts = Asset<ASSET_TYPE_ADDON_MAP_ENTS, AddonMapEnts>;
|
using AssetAddonMapEnts = Asset<ASSET_TYPE_ADDON_MAP_ENTS, AddonMapEnts>;
|
||||||
} // namespace IW4
|
} // 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);
|
|
||||||
|
@ -179,44 +179,3 @@ namespace IW5
|
|||||||
using AssetVehicle = Asset<ASSET_TYPE_VEHICLE, VehicleDef>;
|
using AssetVehicle = Asset<ASSET_TYPE_VEHICLE, VehicleDef>;
|
||||||
using AssetAddonMapEnts = Asset<ASSET_TYPE_ADDON_MAP_ENTS, AddonMapEnts>;
|
using AssetAddonMapEnts = Asset<ASSET_TYPE_ADDON_MAP_ENTS, AddonMapEnts>;
|
||||||
} // namespace IW5
|
} // 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);
|
|
||||||
|
@ -148,38 +148,5 @@ namespace T5
|
|||||||
using AssetDDL = Asset<ASSET_TYPE_DDL, ddlRoot_t>;
|
using AssetDDL = Asset<ASSET_TYPE_DDL, ddlRoot_t>;
|
||||||
using AssetGlasses = Asset<ASSET_TYPE_GLASSES, Glasses>;
|
using AssetGlasses = Asset<ASSET_TYPE_GLASSES, Glasses>;
|
||||||
using AssetEmblemSet = Asset<ASSET_TYPE_EMBLEMSET, EmblemSet>;
|
using AssetEmblemSet = Asset<ASSET_TYPE_EMBLEMSET, EmblemSet>;
|
||||||
} // namespace T5
|
|
||||||
|
|
||||||
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetPhysPreset, name);
|
} // namespace T5
|
||||||
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");
|
|
||||||
|
@ -1311,7 +1311,7 @@ namespace T5
|
|||||||
|
|
||||||
struct SndPatch
|
struct SndPatch
|
||||||
{
|
{
|
||||||
const char* name;
|
char* name;
|
||||||
unsigned int elementCount;
|
unsigned int elementCount;
|
||||||
unsigned int* elements;
|
unsigned int* elements;
|
||||||
unsigned int fileCount;
|
unsigned int fileCount;
|
||||||
|
@ -209,53 +209,3 @@ namespace T6
|
|||||||
using AssetFootstepFxTable = Asset<ASSET_TYPE_FOOTSTEPFX_TABLE, FootstepFXTableDef>;
|
using AssetFootstepFxTable = Asset<ASSET_TYPE_FOOTSTEPFX_TABLE, FootstepFXTableDef>;
|
||||||
using AssetZBarrier = Asset<ASSET_TYPE_ZBARRIER, ZBarrierDef>;
|
using AssetZBarrier = Asset<ASSET_TYPE_ZBARRIER, ZBarrierDef>;
|
||||||
} // namespace T6
|
} // 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);
|
|
||||||
|
@ -2114,7 +2114,7 @@ namespace T6
|
|||||||
struct KeyValuePairs
|
struct KeyValuePairs
|
||||||
{
|
{
|
||||||
const char* name;
|
const char* name;
|
||||||
unsigned int numVariables;
|
int numVariables;
|
||||||
KeyValuePair* keyValuePairs;
|
KeyValuePair* keyValuePairs;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -3814,8 +3814,7 @@ namespace T6
|
|||||||
uint16_t dynEntId;
|
uint16_t dynEntId;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Usually __m128, but that is not portable
|
union gcc_align(8) __m128
|
||||||
union gcc_align(8) custom_m128
|
|
||||||
{
|
{
|
||||||
float m128_f32[4];
|
float m128_f32[4];
|
||||||
uint64_t m128_u64[2];
|
uint64_t m128_u64[2];
|
||||||
@ -3828,12 +3827,19 @@ namespace T6
|
|||||||
unsigned int m128_u32[4];
|
unsigned int m128_u32[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct vector3
|
||||||
|
{
|
||||||
|
__m128 x;
|
||||||
|
__m128 y;
|
||||||
|
__m128 z;
|
||||||
|
};
|
||||||
|
|
||||||
struct vector4
|
struct vector4
|
||||||
{
|
{
|
||||||
custom_m128 x;
|
__m128 x;
|
||||||
custom_m128 y;
|
__m128 y;
|
||||||
custom_m128 z;
|
__m128 z;
|
||||||
custom_m128 w;
|
__m128 w;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct type_align(16) SSkinInstance
|
struct type_align(16) SSkinInstance
|
||||||
@ -5563,8 +5569,8 @@ namespace T6
|
|||||||
|
|
||||||
struct KeyValuePair
|
struct KeyValuePair
|
||||||
{
|
{
|
||||||
unsigned int keyHash;
|
int keyHash;
|
||||||
unsigned int namespaceHash;
|
int namespaceHash;
|
||||||
const char* value;
|
const char* value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
struct ZoneHeader
|
struct ZoneHeader
|
||||||
{
|
{
|
||||||
@ -8,11 +7,21 @@ struct ZoneHeader
|
|||||||
uint32_t m_version;
|
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 uint16_t scr_string_t;
|
||||||
typedef uint32_t xchunk_size_t;
|
typedef uint32_t xchunk_size_t;
|
||||||
typedef uint32_t xblock_size_t;
|
typedef uint32_t xblock_size_t;
|
||||||
|
typedef uint32_t zone_pointer_t;
|
||||||
|
|
||||||
constexpr uint16_t SCR_STRING_MAX = std::numeric_limits<scr_string_t>::max();
|
constexpr uint16_t SCR_STRING_MAX = UINT16_MAX;
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef int block_t;
|
typedef int block_t;
|
||||||
typedef int asset_type_t;
|
typedef int asset_type_t;
|
||||||
|
@ -32,8 +32,7 @@ namespace base64
|
|||||||
|
|
||||||
size_t DecodeBase64(const void* base64Data, const size_t inputLength, void* outputBuffer, const size_t outputBufferSize)
|
size_t DecodeBase64(const void* base64Data, const size_t inputLength, void* outputBuffer, const size_t outputBufferSize)
|
||||||
{
|
{
|
||||||
unsigned long outLength = GetBase64DecodeOutputLength(base64Data, inputLength);
|
unsigned long outLength = GetBase64DecodeOutputLength(inputLength);
|
||||||
assert(outLength <= outputBufferSize);
|
|
||||||
if (outLength > outputBufferSize)
|
if (outLength > outputBufferSize)
|
||||||
return 0u;
|
return 0u;
|
||||||
|
|
||||||
@ -43,28 +42,8 @@ namespace base64
|
|||||||
return static_cast<size_t>(outLength);
|
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)
|
size_t GetBase64DecodeOutputLength(const size_t inputLength)
|
||||||
{
|
{
|
||||||
return (inputLength / 4u) * 3u;
|
return inputLength / 4u;
|
||||||
}
|
}
|
||||||
} // namespace base64
|
} // namespace base64
|
||||||
|
@ -8,6 +8,5 @@ namespace base64
|
|||||||
size_t GetBase64EncodeOutputLength(size_t inputLength);
|
size_t GetBase64EncodeOutputLength(size_t inputLength);
|
||||||
|
|
||||||
size_t DecodeBase64(const void* base64Data, size_t inputLength, void* outputBuffer, size_t outputBufferSize);
|
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);
|
size_t GetBase64DecodeOutputLength(size_t inputLength);
|
||||||
} // namespace base64
|
} // namespace base64
|
||||||
|
@ -39,7 +39,6 @@ function Linker:project()
|
|||||||
self:include(includes)
|
self:include(includes)
|
||||||
Utils:include(includes)
|
Utils:include(includes)
|
||||||
ZoneLoading:include(includes)
|
ZoneLoading:include(includes)
|
||||||
ObjCompiling:include(includes)
|
|
||||||
ObjLoading:include(includes)
|
ObjLoading:include(includes)
|
||||||
ObjWriting:include(includes)
|
ObjWriting:include(includes)
|
||||||
ZoneWriting:include(includes)
|
ZoneWriting:include(includes)
|
||||||
@ -47,7 +46,6 @@ function Linker:project()
|
|||||||
Raw:use()
|
Raw:use()
|
||||||
|
|
||||||
links:linkto(Utils)
|
links:linkto(Utils)
|
||||||
links:linkto(ObjCompiling)
|
|
||||||
links:linkto(ZoneLoading)
|
links:linkto(ZoneLoading)
|
||||||
links:linkto(ZoneWriting)
|
links:linkto(ZoneWriting)
|
||||||
links:linkto(ObjLoading)
|
links:linkto(ObjLoading)
|
||||||
|
72
src/Linker/Game/IW3/ZoneCreatorIW3.cpp
Normal file
72
src/Linker/Game/IW3/ZoneCreatorIW3.cpp
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#include "ZoneCreatorIW3.h"
|
||||||
|
|
||||||
|
#include "AssetLoading/AssetLoadingContext.h"
|
||||||
|
#include "Game/IW3/GameAssetPoolIW3.h"
|
||||||
|
#include "Game/IW3/GameIW3.h"
|
||||||
|
#include "IObjLoader.h"
|
||||||
|
#include "ObjLoading.h"
|
||||||
|
#include "Utils/StringUtils.h"
|
||||||
|
|
||||||
|
using namespace IW3;
|
||||||
|
|
||||||
|
std::vector<Gdt*> ZoneCreator::CreateGdtList(const ZoneCreationContext& context)
|
||||||
|
{
|
||||||
|
std::vector<Gdt*> gdtList;
|
||||||
|
gdtList.reserve(context.m_gdt_files.size());
|
||||||
|
for (const auto& gdt : context.m_gdt_files)
|
||||||
|
gdtList.push_back(gdt.get());
|
||||||
|
|
||||||
|
return gdtList;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneCreator::ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext)
|
||||||
|
{
|
||||||
|
for (const auto& ignoreEntry : creationContext.m_ignored_assets.m_entries)
|
||||||
|
loadingContext.m_ignored_asset_map[ignoreEntry.m_name] = ignoreEntry.m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneCreator::CreateZoneAssetPools(Zone* zone) const
|
||||||
|
{
|
||||||
|
zone->m_pools = std::make_unique<GameAssetPoolIW3>(zone, zone->m_priority);
|
||||||
|
|
||||||
|
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
|
||||||
|
zone->m_pools->InitPoolDynamic(assetType);
|
||||||
|
}
|
||||||
|
|
||||||
|
GameId ZoneCreator::GetGameId() const
|
||||||
|
{
|
||||||
|
return GameId::IW3;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
|
||||||
|
{
|
||||||
|
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, IGame::GetGameById(GameId::IW3));
|
||||||
|
CreateZoneAssetPools(zone.get());
|
||||||
|
|
||||||
|
for (const auto& assetEntry : context.m_definition->m_assets)
|
||||||
|
{
|
||||||
|
if (!assetEntry.m_is_reference)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
|
||||||
|
ApplyIgnoredAssets(context, *assetLoadingContext);
|
||||||
|
|
||||||
|
const auto* objLoader = IObjLoader::GetObjLoaderForGame(GameId::IW3);
|
||||||
|
for (const auto& assetEntry : context.m_definition->m_assets)
|
||||||
|
{
|
||||||
|
if (!objLoader->LoadAssetForZone(*assetLoadingContext, assetEntry.m_asset_type, assetEntry.m_asset_name))
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
objLoader->FinalizeAssetsForZone(*assetLoadingContext);
|
||||||
|
|
||||||
|
return zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
asset_type_t ZoneCreator::GetImageAssetType() const
|
||||||
|
{
|
||||||
|
return ASSET_TYPE_IMAGE;
|
||||||
|
}
|
20
src/Linker/Game/IW3/ZoneCreatorIW3.h
Normal file
20
src/Linker/Game/IW3/ZoneCreatorIW3.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AssetLoading/AssetLoadingContext.h"
|
||||||
|
#include "Zone/ZoneTypes.h"
|
||||||
|
#include "ZoneCreation/ZoneCreator.h"
|
||||||
|
|
||||||
|
namespace IW3
|
||||||
|
{
|
||||||
|
class ZoneCreator final : public IZoneCreator
|
||||||
|
{
|
||||||
|
static std::vector<Gdt*> CreateGdtList(const ZoneCreationContext& context);
|
||||||
|
static void ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext);
|
||||||
|
void CreateZoneAssetPools(Zone* zone) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
[[nodiscard]] GameId GetGameId() const override;
|
||||||
|
[[nodiscard]] std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
|
||||||
|
[[nodiscard]] asset_type_t GetImageAssetType() const override;
|
||||||
|
};
|
||||||
|
} // namespace IW3
|
71
src/Linker/Game/IW4/ZoneCreatorIW4.cpp
Normal file
71
src/Linker/Game/IW4/ZoneCreatorIW4.cpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#include "ZoneCreatorIW4.h"
|
||||||
|
|
||||||
|
#include "Game/IW4/GameAssetPoolIW4.h"
|
||||||
|
#include "Game/IW4/GameIW4.h"
|
||||||
|
#include "IObjLoader.h"
|
||||||
|
#include "ObjLoading.h"
|
||||||
|
#include "Utils/StringUtils.h"
|
||||||
|
|
||||||
|
using namespace IW4;
|
||||||
|
|
||||||
|
std::vector<Gdt*> ZoneCreator::CreateGdtList(const ZoneCreationContext& context)
|
||||||
|
{
|
||||||
|
std::vector<Gdt*> gdtList;
|
||||||
|
gdtList.reserve(context.m_gdt_files.size());
|
||||||
|
for (const auto& gdt : context.m_gdt_files)
|
||||||
|
gdtList.push_back(gdt.get());
|
||||||
|
|
||||||
|
return gdtList;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneCreator::ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext)
|
||||||
|
{
|
||||||
|
for (const auto& ignoreEntry : creationContext.m_ignored_assets.m_entries)
|
||||||
|
loadingContext.m_ignored_asset_map[ignoreEntry.m_name] = ignoreEntry.m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneCreator::CreateZoneAssetPools(Zone* zone) const
|
||||||
|
{
|
||||||
|
zone->m_pools = std::make_unique<GameAssetPoolIW4>(zone, zone->m_priority);
|
||||||
|
|
||||||
|
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
|
||||||
|
zone->m_pools->InitPoolDynamic(assetType);
|
||||||
|
}
|
||||||
|
|
||||||
|
GameId ZoneCreator::GetGameId() const
|
||||||
|
{
|
||||||
|
return GameId::IW4;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
|
||||||
|
{
|
||||||
|
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, IGame::GetGameById(GameId::IW4));
|
||||||
|
CreateZoneAssetPools(zone.get());
|
||||||
|
|
||||||
|
for (const auto& assetEntry : context.m_definition->m_assets)
|
||||||
|
{
|
||||||
|
if (!assetEntry.m_is_reference)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
|
||||||
|
ApplyIgnoredAssets(context, *assetLoadingContext);
|
||||||
|
|
||||||
|
const auto* objLoader = IObjLoader::GetObjLoaderForGame(GameId::IW4);
|
||||||
|
for (const auto& assetEntry : context.m_definition->m_assets)
|
||||||
|
{
|
||||||
|
if (!objLoader->LoadAssetForZone(*assetLoadingContext, assetEntry.m_asset_type, assetEntry.m_asset_name))
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
objLoader->FinalizeAssetsForZone(*assetLoadingContext);
|
||||||
|
|
||||||
|
return zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
asset_type_t ZoneCreator::GetImageAssetType() const
|
||||||
|
{
|
||||||
|
return ASSET_TYPE_IMAGE;
|
||||||
|
}
|
20
src/Linker/Game/IW4/ZoneCreatorIW4.h
Normal file
20
src/Linker/Game/IW4/ZoneCreatorIW4.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AssetLoading/AssetLoadingContext.h"
|
||||||
|
#include "Zone/ZoneTypes.h"
|
||||||
|
#include "ZoneCreation/ZoneCreator.h"
|
||||||
|
|
||||||
|
namespace IW4
|
||||||
|
{
|
||||||
|
class ZoneCreator final : public IZoneCreator
|
||||||
|
{
|
||||||
|
static std::vector<Gdt*> CreateGdtList(const ZoneCreationContext& context);
|
||||||
|
static void ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext);
|
||||||
|
void CreateZoneAssetPools(Zone* zone) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
[[nodiscard]] GameId GetGameId() const override;
|
||||||
|
[[nodiscard]] std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
|
||||||
|
[[nodiscard]] asset_type_t GetImageAssetType() const override;
|
||||||
|
};
|
||||||
|
} // namespace IW4
|
71
src/Linker/Game/IW5/ZoneCreatorIW5.cpp
Normal file
71
src/Linker/Game/IW5/ZoneCreatorIW5.cpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#include "ZoneCreatorIW5.h"
|
||||||
|
|
||||||
|
#include "Game/IW5/GameAssetPoolIW5.h"
|
||||||
|
#include "Game/IW5/GameIW5.h"
|
||||||
|
#include "IObjLoader.h"
|
||||||
|
#include "ObjLoading.h"
|
||||||
|
#include "Utils/StringUtils.h"
|
||||||
|
|
||||||
|
using namespace IW5;
|
||||||
|
|
||||||
|
std::vector<Gdt*> ZoneCreator::CreateGdtList(const ZoneCreationContext& context)
|
||||||
|
{
|
||||||
|
std::vector<Gdt*> gdtList;
|
||||||
|
gdtList.reserve(context.m_gdt_files.size());
|
||||||
|
for (const auto& gdt : context.m_gdt_files)
|
||||||
|
gdtList.push_back(gdt.get());
|
||||||
|
|
||||||
|
return gdtList;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneCreator::ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext)
|
||||||
|
{
|
||||||
|
for (const auto& ignoreEntry : creationContext.m_ignored_assets.m_entries)
|
||||||
|
loadingContext.m_ignored_asset_map[ignoreEntry.m_name] = ignoreEntry.m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneCreator::CreateZoneAssetPools(Zone* zone) const
|
||||||
|
{
|
||||||
|
zone->m_pools = std::make_unique<GameAssetPoolIW5>(zone, zone->m_priority);
|
||||||
|
|
||||||
|
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
|
||||||
|
zone->m_pools->InitPoolDynamic(assetType);
|
||||||
|
}
|
||||||
|
|
||||||
|
GameId ZoneCreator::GetGameId() const
|
||||||
|
{
|
||||||
|
return GameId::IW5;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
|
||||||
|
{
|
||||||
|
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, IGame::GetGameById(GameId::IW5));
|
||||||
|
CreateZoneAssetPools(zone.get());
|
||||||
|
|
||||||
|
for (const auto& assetEntry : context.m_definition->m_assets)
|
||||||
|
{
|
||||||
|
if (!assetEntry.m_is_reference)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
|
||||||
|
ApplyIgnoredAssets(context, *assetLoadingContext);
|
||||||
|
|
||||||
|
const auto* objLoader = IObjLoader::GetObjLoaderForGame(GameId::IW5);
|
||||||
|
for (const auto& assetEntry : context.m_definition->m_assets)
|
||||||
|
{
|
||||||
|
if (!objLoader->LoadAssetForZone(*assetLoadingContext, assetEntry.m_asset_type, assetEntry.m_asset_name))
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
objLoader->FinalizeAssetsForZone(*assetLoadingContext);
|
||||||
|
|
||||||
|
return zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
asset_type_t ZoneCreator::GetImageAssetType() const
|
||||||
|
{
|
||||||
|
return ASSET_TYPE_IMAGE;
|
||||||
|
}
|
19
src/Linker/Game/IW5/ZoneCreatorIW5.h
Normal file
19
src/Linker/Game/IW5/ZoneCreatorIW5.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "AssetLoading/AssetLoadingContext.h"
|
||||||
|
#include "Zone/ZoneTypes.h"
|
||||||
|
#include "ZoneCreation/ZoneCreator.h"
|
||||||
|
|
||||||
|
namespace IW5
|
||||||
|
{
|
||||||
|
class ZoneCreator final : public IZoneCreator
|
||||||
|
{
|
||||||
|
static std::vector<Gdt*> CreateGdtList(const ZoneCreationContext& context);
|
||||||
|
static void ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext);
|
||||||
|
void CreateZoneAssetPools(Zone* zone) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
[[nodiscard]] GameId GetGameId() const override;
|
||||||
|
[[nodiscard]] std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
|
||||||
|
[[nodiscard]] asset_type_t GetImageAssetType() const override;
|
||||||
|
};
|
||||||
|
} // namespace IW5
|
72
src/Linker/Game/T5/ZoneCreatorT5.cpp
Normal file
72
src/Linker/Game/T5/ZoneCreatorT5.cpp
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#include "ZoneCreatorT5.h"
|
||||||
|
|
||||||
|
#include "AssetLoading/AssetLoadingContext.h"
|
||||||
|
#include "Game/T5/GameAssetPoolT5.h"
|
||||||
|
#include "Game/T5/GameT5.h"
|
||||||
|
#include "IObjLoader.h"
|
||||||
|
#include "ObjLoading.h"
|
||||||
|
#include "Utils/StringUtils.h"
|
||||||
|
|
||||||
|
using namespace T5;
|
||||||
|
|
||||||
|
std::vector<Gdt*> ZoneCreator::CreateGdtList(ZoneCreationContext& context)
|
||||||
|
{
|
||||||
|
std::vector<Gdt*> gdtList;
|
||||||
|
gdtList.reserve(context.m_gdt_files.size());
|
||||||
|
for (const auto& gdt : context.m_gdt_files)
|
||||||
|
gdtList.push_back(gdt.get());
|
||||||
|
|
||||||
|
return gdtList;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneCreator::ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext)
|
||||||
|
{
|
||||||
|
for (const auto& ignoreEntry : creationContext.m_ignored_assets.m_entries)
|
||||||
|
loadingContext.m_ignored_asset_map[ignoreEntry.m_name] = ignoreEntry.m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneCreator::CreateZoneAssetPools(Zone* zone) const
|
||||||
|
{
|
||||||
|
zone->m_pools = std::make_unique<GameAssetPoolT5>(zone, zone->m_priority);
|
||||||
|
|
||||||
|
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
|
||||||
|
zone->m_pools->InitPoolDynamic(assetType);
|
||||||
|
}
|
||||||
|
|
||||||
|
GameId ZoneCreator::GetGameId() const
|
||||||
|
{
|
||||||
|
return GameId::T5;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
|
||||||
|
{
|
||||||
|
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, IGame::GetGameById(GameId::T5));
|
||||||
|
CreateZoneAssetPools(zone.get());
|
||||||
|
|
||||||
|
for (const auto& assetEntry : context.m_definition->m_assets)
|
||||||
|
{
|
||||||
|
if (!assetEntry.m_is_reference)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
|
||||||
|
ApplyIgnoredAssets(context, *assetLoadingContext);
|
||||||
|
|
||||||
|
const auto* objLoader = IObjLoader::GetObjLoaderForGame(GameId::T5);
|
||||||
|
for (const auto& assetEntry : context.m_definition->m_assets)
|
||||||
|
{
|
||||||
|
if (!objLoader->LoadAssetForZone(*assetLoadingContext, assetEntry.m_asset_type, assetEntry.m_asset_name))
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
objLoader->FinalizeAssetsForZone(*assetLoadingContext);
|
||||||
|
|
||||||
|
return zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
asset_type_t ZoneCreator::GetImageAssetType() const
|
||||||
|
{
|
||||||
|
return ASSET_TYPE_IMAGE;
|
||||||
|
}
|
19
src/Linker/Game/T5/ZoneCreatorT5.h
Normal file
19
src/Linker/Game/T5/ZoneCreatorT5.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "AssetLoading/AssetLoadingContext.h"
|
||||||
|
#include "Zone/ZoneTypes.h"
|
||||||
|
#include "ZoneCreation/ZoneCreator.h"
|
||||||
|
|
||||||
|
namespace T5
|
||||||
|
{
|
||||||
|
class ZoneCreator final : public IZoneCreator
|
||||||
|
{
|
||||||
|
static std::vector<Gdt*> CreateGdtList(ZoneCreationContext& context);
|
||||||
|
static void ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext);
|
||||||
|
void CreateZoneAssetPools(Zone* zone) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
[[nodiscard]] GameId GetGameId() const override;
|
||||||
|
[[nodiscard]] std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
|
||||||
|
[[nodiscard]] asset_type_t GetImageAssetType() const override;
|
||||||
|
};
|
||||||
|
} // namespace T5
|
125
src/Linker/Game/T6/ZoneCreatorT6.cpp
Normal file
125
src/Linker/Game/T6/ZoneCreatorT6.cpp
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
#include "ZoneCreatorT6.h"
|
||||||
|
|
||||||
|
#include "Game/T6/CommonT6.h"
|
||||||
|
#include "Game/T6/GameAssetPoolT6.h"
|
||||||
|
#include "Game/T6/GameT6.h"
|
||||||
|
#include "Game/T6/T6.h"
|
||||||
|
#include "IObjLoader.h"
|
||||||
|
#include "ObjLoading.h"
|
||||||
|
#include "Utils/StringUtils.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace T6;
|
||||||
|
|
||||||
|
std::vector<Gdt*> ZoneCreator::CreateGdtList(const ZoneCreationContext& context)
|
||||||
|
{
|
||||||
|
std::vector<Gdt*> gdtList;
|
||||||
|
gdtList.reserve(context.m_gdt_files.size());
|
||||||
|
for (const auto& gdt : context.m_gdt_files)
|
||||||
|
gdtList.push_back(gdt.get());
|
||||||
|
|
||||||
|
return gdtList;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneCreator::ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext)
|
||||||
|
{
|
||||||
|
for (const auto& ignoreEntry : creationContext.m_ignored_assets.m_entries)
|
||||||
|
loadingContext.m_ignored_asset_map[ignoreEntry.m_name] = ignoreEntry.m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneCreator::CreateZoneAssetPools(Zone* zone) const
|
||||||
|
{
|
||||||
|
zone->m_pools = std::make_unique<GameAssetPoolT6>(zone, zone->m_priority);
|
||||||
|
|
||||||
|
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
|
||||||
|
zone->m_pools->InitPoolDynamic(assetType);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneCreator::HandleMetadata(Zone* zone, const ZoneCreationContext& context) const
|
||||||
|
{
|
||||||
|
std::vector<KeyValuePair> kvpList;
|
||||||
|
|
||||||
|
for (const auto& metaData : context.m_definition->m_properties.m_properties)
|
||||||
|
{
|
||||||
|
if (metaData.first.rfind("level.", 0) == 0)
|
||||||
|
{
|
||||||
|
const std::string strValue = metaData.first.substr(std::char_traits<char>::length("level."));
|
||||||
|
if (strValue.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int keyHash;
|
||||||
|
if (strValue[0] == '@')
|
||||||
|
{
|
||||||
|
char* endPtr;
|
||||||
|
keyHash = strtol(&strValue[1], &endPtr, 16);
|
||||||
|
|
||||||
|
if (endPtr != &strValue[strValue.size()])
|
||||||
|
{
|
||||||
|
std::cout << "Could not parse metadata key \"" << metaData.first << "\" as hash\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
keyHash = Common::Com_HashKey(strValue.c_str(), 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyValuePair kvp{keyHash, Common::Com_HashKey(zone->m_name.c_str(), 64), zone->GetMemory()->Dup(metaData.second.c_str())};
|
||||||
|
kvpList.push_back(kvp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!kvpList.empty())
|
||||||
|
{
|
||||||
|
auto* kvps = zone->GetMemory()->Create<KeyValuePairs>();
|
||||||
|
kvps->name = zone->GetMemory()->Dup(zone->m_name.c_str());
|
||||||
|
kvps->numVariables = kvpList.size();
|
||||||
|
kvps->keyValuePairs = zone->GetMemory()->Alloc<KeyValuePair>(kvpList.size());
|
||||||
|
|
||||||
|
for (auto i = 0u; i < kvpList.size(); i++)
|
||||||
|
kvps->keyValuePairs[i] = kvpList[i];
|
||||||
|
|
||||||
|
zone->m_pools->AddAsset(std::make_unique<XAssetInfo<KeyValuePairs>>(ASSET_TYPE_KEYVALUEPAIRS, zone->m_name, kvps));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GameId ZoneCreator::GetGameId() const
|
||||||
|
{
|
||||||
|
return GameId::T6;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
|
||||||
|
{
|
||||||
|
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, IGame::GetGameById(GameId::T6));
|
||||||
|
CreateZoneAssetPools(zone.get());
|
||||||
|
|
||||||
|
for (const auto& assetEntry : context.m_definition->m_assets)
|
||||||
|
{
|
||||||
|
if (!assetEntry.m_is_reference)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
|
||||||
|
ApplyIgnoredAssets(context, *assetLoadingContext);
|
||||||
|
|
||||||
|
HandleMetadata(zone.get(), context);
|
||||||
|
|
||||||
|
const auto* objLoader = IObjLoader::GetObjLoaderForGame(GameId::T6);
|
||||||
|
for (const auto& assetEntry : context.m_definition->m_assets)
|
||||||
|
{
|
||||||
|
if (!objLoader->LoadAssetForZone(*assetLoadingContext, assetEntry.m_asset_type, assetEntry.m_asset_name))
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
objLoader->FinalizeAssetsForZone(*assetLoadingContext);
|
||||||
|
|
||||||
|
return zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
asset_type_t ZoneCreator::GetImageAssetType() const
|
||||||
|
{
|
||||||
|
return ASSET_TYPE_IMAGE;
|
||||||
|
}
|
20
src/Linker/Game/T6/ZoneCreatorT6.h
Normal file
20
src/Linker/Game/T6/ZoneCreatorT6.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "AssetLoading/AssetLoadingContext.h"
|
||||||
|
#include "Zone/ZoneTypes.h"
|
||||||
|
#include "ZoneCreation/ZoneCreator.h"
|
||||||
|
|
||||||
|
namespace T6
|
||||||
|
{
|
||||||
|
class ZoneCreator final : public IZoneCreator
|
||||||
|
{
|
||||||
|
static std::vector<Gdt*> CreateGdtList(const ZoneCreationContext& context);
|
||||||
|
static void ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext);
|
||||||
|
void CreateZoneAssetPools(Zone* zone) const;
|
||||||
|
void HandleMetadata(Zone* zone, const ZoneCreationContext& context) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
[[nodiscard]] GameId GetGameId() const override;
|
||||||
|
[[nodiscard]] std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
|
||||||
|
[[nodiscard]] asset_type_t GetImageAssetType() const override;
|
||||||
|
};
|
||||||
|
} // namespace T6
|
@ -1,14 +1,16 @@
|
|||||||
#include "Linker.h"
|
#include "Linker.h"
|
||||||
|
|
||||||
#include "LinkerArgs.h"
|
#include "LinkerArgs.h"
|
||||||
#include "LinkerPaths.h"
|
#include "LinkerSearchPaths.h"
|
||||||
|
#include "ObjContainer/IPak/IPakWriter.h"
|
||||||
|
#include "ObjContainer/IWD/IWD.h"
|
||||||
#include "ObjContainer/SoundBank/SoundBankWriter.h"
|
#include "ObjContainer/SoundBank/SoundBankWriter.h"
|
||||||
|
#include "ObjLoading.h"
|
||||||
#include "ObjWriting.h"
|
#include "ObjWriting.h"
|
||||||
#include "SearchPath/OutputPathFilesystem.h"
|
|
||||||
#include "SearchPath/SearchPaths.h"
|
#include "SearchPath/SearchPaths.h"
|
||||||
#include "Utils/ObjFileStream.h"
|
#include "Utils/ObjFileStream.h"
|
||||||
#include "Zone/AssetList/AssetList.h"
|
#include "Zone/AssetList/AssetList.h"
|
||||||
#include "Zone/AssetList/AssetListReader.h"
|
#include "Zone/AssetList/AssetListStream.h"
|
||||||
#include "Zone/Definition/ZoneDefinitionStream.h"
|
#include "Zone/Definition/ZoneDefinitionStream.h"
|
||||||
#include "ZoneCreation/ZoneCreationContext.h"
|
#include "ZoneCreation/ZoneCreationContext.h"
|
||||||
#include "ZoneCreation/ZoneCreator.h"
|
#include "ZoneCreation/ZoneCreator.h"
|
||||||
@ -19,157 +21,133 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <unordered_set>
|
#include <set>
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
class LinkerSearchPathContext
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit LinkerSearchPathContext(const ILinkerSearchPathBuilder& searchPathBuilder)
|
|
||||||
: m_search_path_builder(searchPathBuilder)
|
|
||||||
{
|
|
||||||
m_independent_search_paths = m_search_path_builder.BuildIndependentSearchPaths();
|
|
||||||
if (m_independent_search_paths)
|
|
||||||
m_search_paths.IncludeSearchPath(m_independent_search_paths.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] ISearchPath& GetSearchPaths()
|
|
||||||
{
|
|
||||||
return m_search_paths;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoadProjectSpecific(const std::string& projectName)
|
|
||||||
{
|
|
||||||
m_project_specific_search_paths = m_search_path_builder.BuildSearchPathsSpecificToProject(projectName);
|
|
||||||
if (m_project_specific_search_paths)
|
|
||||||
m_search_paths.IncludeSearchPath(m_project_specific_search_paths.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnloadProjectSpecific()
|
|
||||||
{
|
|
||||||
if (!m_project_specific_search_paths)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_search_paths.RemoveSearchPath(m_project_specific_search_paths.get());
|
|
||||||
m_project_specific_search_paths.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoadGameSpecific(const std::string& projectName, const GameId game)
|
|
||||||
{
|
|
||||||
m_game_specific_search_paths = m_search_path_builder.BuildSearchPathsSpecificToProjectAndGame(projectName, game);
|
|
||||||
if (m_game_specific_search_paths)
|
|
||||||
m_search_paths.IncludeSearchPath(m_game_specific_search_paths.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnloadGameSpecific()
|
|
||||||
{
|
|
||||||
if (!m_game_specific_search_paths)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_search_paths.RemoveSearchPath(m_game_specific_search_paths.get());
|
|
||||||
m_game_specific_search_paths.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const ILinkerSearchPathBuilder& m_search_path_builder;
|
|
||||||
std::unique_ptr<ISearchPath> m_independent_search_paths;
|
|
||||||
std::unique_ptr<ISearchPath> m_project_specific_search_paths;
|
|
||||||
std::unique_ptr<ISearchPath> m_game_specific_search_paths;
|
|
||||||
SearchPaths m_search_paths;
|
|
||||||
};
|
|
||||||
|
|
||||||
class LinkerPathManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit LinkerPathManager(const LinkerArgs& args)
|
|
||||||
: m_linker_paths(ILinkerPaths::FromArgs(args)),
|
|
||||||
m_asset_paths(m_linker_paths->AssetSearchPaths()),
|
|
||||||
m_gdt_paths(m_linker_paths->GdtSearchPaths()),
|
|
||||||
m_source_paths(m_linker_paths->SourceSearchPaths())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<ILinkerPaths> m_linker_paths;
|
|
||||||
LinkerSearchPathContext m_asset_paths;
|
|
||||||
LinkerSearchPathContext m_gdt_paths;
|
|
||||||
LinkerSearchPathContext m_source_paths;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PathProjectContext
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PathProjectContext(LinkerPathManager& paths, const std::string& projectName)
|
|
||||||
: m_paths(paths)
|
|
||||||
{
|
|
||||||
m_paths.m_asset_paths.LoadProjectSpecific(projectName);
|
|
||||||
m_paths.m_gdt_paths.LoadProjectSpecific(projectName);
|
|
||||||
m_paths.m_source_paths.LoadProjectSpecific(projectName);
|
|
||||||
}
|
|
||||||
|
|
||||||
~PathProjectContext()
|
|
||||||
{
|
|
||||||
m_paths.m_asset_paths.UnloadProjectSpecific();
|
|
||||||
m_paths.m_gdt_paths.UnloadProjectSpecific();
|
|
||||||
m_paths.m_source_paths.UnloadProjectSpecific();
|
|
||||||
}
|
|
||||||
|
|
||||||
PathProjectContext(const PathProjectContext& other) = delete;
|
|
||||||
PathProjectContext(PathProjectContext&& other) noexcept = delete;
|
|
||||||
PathProjectContext& operator=(const PathProjectContext& other) = delete;
|
|
||||||
PathProjectContext& operator=(PathProjectContext&& other) noexcept = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
LinkerPathManager& m_paths;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PathGameContext
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PathGameContext(LinkerPathManager& paths, const std::string& projectName, const GameId game)
|
|
||||||
: m_paths(paths)
|
|
||||||
{
|
|
||||||
m_paths.m_asset_paths.LoadGameSpecific(projectName, game);
|
|
||||||
m_paths.m_gdt_paths.LoadGameSpecific(projectName, game);
|
|
||||||
m_paths.m_source_paths.LoadGameSpecific(projectName, game);
|
|
||||||
}
|
|
||||||
|
|
||||||
~PathGameContext()
|
|
||||||
{
|
|
||||||
m_paths.m_asset_paths.UnloadGameSpecific();
|
|
||||||
m_paths.m_gdt_paths.UnloadGameSpecific();
|
|
||||||
m_paths.m_source_paths.UnloadGameSpecific();
|
|
||||||
}
|
|
||||||
|
|
||||||
PathGameContext(const PathGameContext& other) = delete;
|
|
||||||
PathGameContext(PathGameContext&& other) noexcept = delete;
|
|
||||||
PathGameContext& operator=(const PathGameContext& other) = delete;
|
|
||||||
PathGameContext& operator=(PathGameContext&& other) noexcept = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
LinkerPathManager& m_paths;
|
|
||||||
};
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
class LinkerImpl final : public Linker
|
class LinkerImpl final : public Linker
|
||||||
{
|
{
|
||||||
std::unique_ptr<ZoneDefinition> ReadZoneDefinition(LinkerPathManager& paths, const std::string& targetName, bool logMissing = true) const
|
LinkerArgs m_args;
|
||||||
|
LinkerSearchPaths m_search_paths;
|
||||||
|
std::vector<std::unique_ptr<Zone>> m_loaded_zones;
|
||||||
|
|
||||||
|
bool IncludeAdditionalZoneDefinitions(const std::string& initialFileName, ZoneDefinition& zoneDefinition, ISearchPath* sourceSearchPath) const
|
||||||
|
{
|
||||||
|
std::set<std::string> sourceNames;
|
||||||
|
sourceNames.emplace(initialFileName);
|
||||||
|
|
||||||
|
std::deque<std::string> toIncludeQueue;
|
||||||
|
for (const auto& include : zoneDefinition.m_includes)
|
||||||
|
toIncludeQueue.emplace_back(include);
|
||||||
|
|
||||||
|
while (!toIncludeQueue.empty())
|
||||||
|
{
|
||||||
|
const auto& source = toIncludeQueue.front();
|
||||||
|
|
||||||
|
if (sourceNames.find(source) == sourceNames.end())
|
||||||
|
{
|
||||||
|
sourceNames.emplace(source);
|
||||||
|
|
||||||
|
std::unique_ptr<ZoneDefinition> includeDefinition;
|
||||||
|
{
|
||||||
|
const auto definitionFileName = std::format("{}.zone", source);
|
||||||
|
const auto definitionStream = sourceSearchPath->Open(definitionFileName);
|
||||||
|
if (!definitionStream.IsOpen())
|
||||||
|
{
|
||||||
|
std::cerr << std::format("Could not find zone definition file for project \"{}\".\n", source);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZoneDefinitionInputStream zoneDefinitionInputStream(*definitionStream.m_stream, source, definitionFileName, m_args.m_verbose);
|
||||||
|
zoneDefinitionInputStream.SetPreviouslySetGame(zoneDefinition.m_game);
|
||||||
|
includeDefinition = zoneDefinitionInputStream.ReadDefinition();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!includeDefinition)
|
||||||
|
{
|
||||||
|
std::cerr << std::format("Failed to read zone definition file for project \"{}\".\n", source);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& include : includeDefinition->m_includes)
|
||||||
|
toIncludeQueue.emplace_back(include);
|
||||||
|
|
||||||
|
zoneDefinition.Include(*includeDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
toIncludeQueue.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadAssetList(const std::string& zoneName, const GameId game, AssetList& assetList, ISearchPath* sourceSearchPath) const
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const auto assetListFileName = std::format("assetlist/{}.csv", zoneName);
|
||||||
|
const auto assetListStream = sourceSearchPath->Open(assetListFileName);
|
||||||
|
|
||||||
|
if (assetListStream.IsOpen())
|
||||||
|
{
|
||||||
|
const AssetListInputStream stream(*assetListStream.m_stream, game);
|
||||||
|
AssetListEntry entry;
|
||||||
|
|
||||||
|
bool failure;
|
||||||
|
while (stream.NextEntry(entry, &failure))
|
||||||
|
{
|
||||||
|
assetList.m_entries.emplace_back(std::move(entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
return !failure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto zoneDefinition = ReadZoneDefinition(zoneName, sourceSearchPath);
|
||||||
|
|
||||||
|
if (zoneDefinition)
|
||||||
|
{
|
||||||
|
for (const auto& entry : zoneDefinition->m_assets)
|
||||||
|
{
|
||||||
|
assetList.m_entries.emplace_back(entry.m_asset_type, entry.m_asset_name, entry.m_is_reference);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IncludeAssetLists(ZoneDefinition& zoneDefinition, ISearchPath* sourceSearchPath) const
|
||||||
|
{
|
||||||
|
for (const auto& assetListName : zoneDefinition.m_asset_lists)
|
||||||
|
{
|
||||||
|
AssetList assetList;
|
||||||
|
if (!ReadAssetList(assetListName, zoneDefinition.m_game, assetList, sourceSearchPath))
|
||||||
|
{
|
||||||
|
std::cerr << std::format("Failed to read asset list \"{}\"\n", assetListName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
zoneDefinition.Include(assetList);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ZoneDefinition> ReadZoneDefinition(const std::string& targetName, ISearchPath* sourceSearchPath) const
|
||||||
{
|
{
|
||||||
auto& sourceSearchPath = paths.m_source_paths.GetSearchPaths();
|
|
||||||
std::unique_ptr<ZoneDefinition> zoneDefinition;
|
std::unique_ptr<ZoneDefinition> zoneDefinition;
|
||||||
{
|
{
|
||||||
const auto definitionFileName = std::format("{}.zone", targetName);
|
const auto definitionFileName = std::format("{}.zone", targetName);
|
||||||
const auto definitionStream = sourceSearchPath.Open(definitionFileName);
|
const auto definitionStream = sourceSearchPath->Open(definitionFileName);
|
||||||
if (!definitionStream.IsOpen())
|
if (!definitionStream.IsOpen())
|
||||||
{
|
{
|
||||||
if (logMissing)
|
|
||||||
std::cerr << std::format("Could not find zone definition file for target \"{}\".\n", targetName);
|
std::cerr << std::format("Could not find zone definition file for target \"{}\".\n", targetName);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZoneDefinitionInputStream zoneDefinitionInputStream(*definitionStream.m_stream, targetName, definitionFileName, sourceSearchPath);
|
ZoneDefinitionInputStream zoneDefinitionInputStream(*definitionStream.m_stream, targetName, definitionFileName, m_args.m_verbose);
|
||||||
zoneDefinition = zoneDefinitionInputStream.ReadDefinition();
|
zoneDefinition = zoneDefinitionInputStream.ReadDefinition();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,41 +157,20 @@ class LinkerImpl final : public Linker
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If no type was defined explicitly make it fastfile
|
||||||
|
if (zoneDefinition->m_type == ProjectType::NONE)
|
||||||
|
zoneDefinition->m_type = ProjectType::FASTFILE;
|
||||||
|
|
||||||
|
if (!IncludeAdditionalZoneDefinitions(targetName, *zoneDefinition, sourceSearchPath))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (!IncludeAssetLists(*zoneDefinition, sourceSearchPath))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
return zoneDefinition;
|
return zoneDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadIgnoreEntries(LinkerPathManager& paths, const std::string& zoneName, const GameId game, AssetList& assetList) const
|
bool ProcessZoneDefinitionIgnores(const std::string& targetName, ZoneCreationContext& context, ISearchPath* sourceSearchPath) 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())
|
if (context.m_definition->m_ignores.empty())
|
||||||
return true;
|
return true;
|
||||||
@ -223,7 +180,8 @@ class LinkerImpl final : public Linker
|
|||||||
if (ignore == targetName)
|
if (ignore == targetName)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!ReadIgnoreEntries(paths, ignore, context.m_definition->m_game, context.m_ignored_assets))
|
std::vector<AssetListEntry> assetList;
|
||||||
|
if (!ReadAssetList(ignore, context.m_definition->m_game, context.m_ignored_assets, sourceSearchPath))
|
||||||
{
|
{
|
||||||
std::cerr << std::format("Failed to read asset listing for ignoring assets of project \"{}\".\n", ignore);
|
std::cerr << std::format("Failed to read asset listing for ignoring assets of project \"{}\".\n", ignore);
|
||||||
return false;
|
return false;
|
||||||
@ -257,95 +215,158 @@ class LinkerImpl final : public Linker
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Zone> CreateZoneForDefinition(
|
std::unique_ptr<Zone> CreateZoneForDefinition(const std::string& targetName,
|
||||||
LinkerPathManager& paths, const fs::path& outDir, const fs::path& cacheDir, const std::string& targetName, ZoneDefinition& zoneDefinition) const
|
ZoneDefinition& zoneDefinition,
|
||||||
|
ISearchPath* assetSearchPath,
|
||||||
|
ISearchPath* gdtSearchPath,
|
||||||
|
ISearchPath* sourceSearchPath) const
|
||||||
{
|
{
|
||||||
ZoneCreationContext context(&zoneDefinition, &paths.m_asset_paths.GetSearchPaths(), outDir, cacheDir);
|
const auto context = std::make_unique<ZoneCreationContext>(&zoneDefinition, assetSearchPath);
|
||||||
if (!ProcessZoneDefinitionIgnores(paths, targetName, context))
|
if (!ProcessZoneDefinitionIgnores(targetName, *context, sourceSearchPath))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (!LoadGdtFilesFromZoneDefinition(context.m_gdt_files, zoneDefinition, &paths.m_gdt_paths.GetSearchPaths()))
|
if (!LoadGdtFilesFromZoneDefinition(context->m_gdt_files, zoneDefinition, gdtSearchPath))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return zone_creator::CreateZoneForDefinition(zoneDefinition.m_game, context);
|
const auto* creator = IZoneCreator::GetCreatorForGame(zoneDefinition.m_game);
|
||||||
|
return creator->CreateZoneForDefinition(*context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool WriteZoneToFile(IOutputPath& outPath, const Zone& zone)
|
bool WriteZoneToFile(const std::string& projectName, Zone* zone) const
|
||||||
{
|
{
|
||||||
const auto stream = outPath.Open(std::format("{}.ff", zone.m_name));
|
const fs::path zoneFolderPath(m_args.GetOutputFolderPathForProject(projectName));
|
||||||
if (!stream)
|
auto zoneFilePath(zoneFolderPath);
|
||||||
{
|
zoneFilePath.append(zone->m_name + ".ff");
|
||||||
std::cerr << std::format("Failed to open file for zone: {}\n", zone.m_name);
|
|
||||||
|
fs::create_directories(zoneFolderPath);
|
||||||
|
|
||||||
|
std::ofstream stream(zoneFilePath, std::fstream::out | std::fstream::binary);
|
||||||
|
if (!stream.is_open())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (m_args.m_verbose)
|
||||||
|
{
|
||||||
|
std::cout << std::format("Building zone \"{}\"\n", zoneFilePath.string());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << std::format("Building zone \"{}\"\n", zone.m_name);
|
if (!ZoneWriting::WriteZone(stream, zone))
|
||||||
|
|
||||||
if (!ZoneWriting::WriteZone(*stream, zone))
|
|
||||||
{
|
{
|
||||||
std::cerr << "Writing zone failed.\n";
|
std::cerr << "Writing zone failed.\n";
|
||||||
|
stream.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << std::format("Created zone \"{}\"\n", zone.m_name);
|
std::cout << std::format("Created zone \"{}\"\n", zoneFilePath.string());
|
||||||
|
|
||||||
|
stream.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BuildFastFile(LinkerPathManager& paths, const std::string& projectName, const std::string& targetName, ZoneDefinition& zoneDefinition) const
|
bool BuildFastFile(const std::string& projectName,
|
||||||
|
const std::string& targetName,
|
||||||
|
ZoneDefinition& zoneDefinition,
|
||||||
|
SearchPaths& assetSearchPaths,
|
||||||
|
SearchPaths& gdtSearchPaths,
|
||||||
|
SearchPaths& sourceSearchPaths) const
|
||||||
{
|
{
|
||||||
const fs::path outDir(paths.m_linker_paths->BuildOutputFolderPath(projectName, zoneDefinition.m_game));
|
SoundBankWriter::OutputPath = fs::path(m_args.GetOutputFolderPathForProject(projectName));
|
||||||
|
|
||||||
OutputPathFilesystem outputPath(outDir);
|
const auto zone = CreateZoneForDefinition(targetName, zoneDefinition, &assetSearchPaths, &gdtSearchPaths, &sourceSearchPaths);
|
||||||
|
|
||||||
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;
|
auto result = zone != nullptr;
|
||||||
if (zone)
|
if (zone)
|
||||||
result = WriteZoneToFile(outputPath, *zone);
|
result = WriteZoneToFile(projectName, zone.get());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BuildProject(LinkerPathManager& paths, const std::string& projectName, const std::string& targetName) const
|
bool BuildIPak(const std::string& projectName, const ZoneDefinition& zoneDefinition, SearchPaths& assetSearchPaths) const
|
||||||
{
|
{
|
||||||
std::deque<std::string> targetsToBuild;
|
const fs::path ipakFolderPath(m_args.GetOutputFolderPathForProject(projectName));
|
||||||
std::unordered_set<std::string> alreadyBuiltTargets;
|
auto ipakFilePath(ipakFolderPath);
|
||||||
|
ipakFilePath.append(std::format("{}.ipak", zoneDefinition.m_name));
|
||||||
|
|
||||||
targetsToBuild.emplace_back(targetName);
|
fs::create_directories(ipakFolderPath);
|
||||||
|
|
||||||
while (!targetsToBuild.empty())
|
std::ofstream stream(ipakFilePath, std::fstream::out | std::fstream::binary);
|
||||||
|
if (!stream.is_open())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto ipakWriter = IPakWriter::Create(stream, &assetSearchPaths);
|
||||||
|
const auto imageAssetType = IZoneCreator::GetCreatorForGame(zoneDefinition.m_game)->GetImageAssetType();
|
||||||
|
for (const auto& assetEntry : zoneDefinition.m_assets)
|
||||||
{
|
{
|
||||||
const auto currentTarget = std::move(targetsToBuild.front());
|
if (assetEntry.m_is_reference)
|
||||||
targetsToBuild.pop_front();
|
continue;
|
||||||
alreadyBuiltTargets.emplace(currentTarget);
|
|
||||||
|
|
||||||
PathProjectContext projectContext(paths, projectName);
|
if (assetEntry.m_asset_type == imageAssetType)
|
||||||
|
ipakWriter->AddImage(assetEntry.m_asset_name);
|
||||||
|
}
|
||||||
|
|
||||||
const auto zoneDefinition = ReadZoneDefinition(paths, targetName);
|
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)
|
if (!zoneDefinition)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
PathGameContext gameContext(paths, projectName, zoneDefinition->m_game);
|
auto result = true;
|
||||||
|
if (zoneDefinition->m_type != ProjectType::NONE)
|
||||||
|
{
|
||||||
|
const auto& gameName = GameId_Names[static_cast<unsigned>(zoneDefinition->m_game)];
|
||||||
|
auto assetSearchPaths = m_search_paths.GetAssetSearchPathsForProject(gameName, projectName);
|
||||||
|
auto gdtSearchPaths = m_search_paths.GetGdtSearchPathsForProject(gameName, projectName);
|
||||||
|
|
||||||
if (!zoneDefinition->m_assets.empty())
|
switch (zoneDefinition->m_type)
|
||||||
{
|
{
|
||||||
if (!BuildFastFile(paths, projectName, targetName, *zoneDefinition))
|
case ProjectType::FASTFILE:
|
||||||
return false;
|
result = BuildFastFile(projectName, targetName, *zoneDefinition, assetSearchPaths, gdtSearchPaths, sourceSearchPaths);
|
||||||
|
break;
|
||||||
|
|
||||||
for (const auto& referencedTarget : zoneDefinition->m_targets_to_build)
|
case ProjectType::IPAK:
|
||||||
{
|
result = BuildIPak(projectName, *zoneDefinition, assetSearchPaths);
|
||||||
if (alreadyBuiltTargets.find(referencedTarget) == alreadyBuiltTargets.end())
|
break;
|
||||||
{
|
|
||||||
targetsToBuild.emplace_back(referencedTarget);
|
default:
|
||||||
std::cout << std::format("Building referenced target \"{}\"\n", referencedTarget);
|
assert(false);
|
||||||
}
|
result = false;
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
m_search_paths.UnloadProjectSpecificSearchPaths();
|
||||||
|
|
||||||
|
result = result && BuildReferencedTargets(projectName, targetName, *zoneDefinition);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadZones()
|
bool LoadZones()
|
||||||
@ -363,8 +384,8 @@ class LinkerImpl final : public Linker
|
|||||||
zoneDirectory = fs::current_path();
|
zoneDirectory = fs::current_path();
|
||||||
auto absoluteZoneDirectory = absolute(zoneDirectory).string();
|
auto absoluteZoneDirectory = absolute(zoneDirectory).string();
|
||||||
|
|
||||||
auto zone = ZoneLoading::LoadZone(zonePath);
|
auto zone = std::unique_ptr<Zone>(ZoneLoading::LoadZone(zonePath));
|
||||||
if (!zone)
|
if (zone == nullptr)
|
||||||
{
|
{
|
||||||
std::cerr << std::format("Failed to load zone \"{}\".\n", zonePath);
|
std::cerr << std::format("Failed to load zone \"{}\".\n", zonePath);
|
||||||
return false;
|
return false;
|
||||||
@ -431,6 +452,11 @@ class LinkerImpl final : public Linker
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
LinkerImpl()
|
||||||
|
: m_search_paths(m_args)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool Start(const int argc, const char** argv) override
|
bool Start(const int argc, const char** argv) override
|
||||||
{
|
{
|
||||||
auto shouldContinue = true;
|
auto shouldContinue = true;
|
||||||
@ -440,7 +466,8 @@ public:
|
|||||||
if (!shouldContinue)
|
if (!shouldContinue)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
LinkerPathManager paths(m_args);
|
if (!m_search_paths.BuildProjectIndependentSearchPaths())
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!LoadZones())
|
if (!LoadZones())
|
||||||
return false;
|
return false;
|
||||||
@ -456,7 +483,7 @@ public:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!BuildProject(paths, projectName, targetName))
|
if (!BuildProject(projectName, targetName))
|
||||||
{
|
{
|
||||||
result = false;
|
result = false;
|
||||||
break;
|
break;
|
||||||
@ -467,10 +494,6 @@ public:
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
LinkerArgs m_args;
|
|
||||||
std::vector<std::unique_ptr<Zone>> m_loaded_zones;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<Linker> Linker::Create()
|
std::unique_ptr<Linker> Linker::Create()
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <regex>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
@ -45,7 +46,7 @@ const CommandLineOption* const OPTION_BASE_FOLDER =
|
|||||||
const CommandLineOption* const OPTION_OUTPUT_FOLDER =
|
const CommandLineOption* const OPTION_OUTPUT_FOLDER =
|
||||||
CommandLineOption::Builder::Create()
|
CommandLineOption::Builder::Create()
|
||||||
.WithLongName("output-folder")
|
.WithLongName("output-folder")
|
||||||
.WithDescription(std::format("Specifies the output folder containing the build artifacts. Defaults to \"{}\".", LinkerArgs::DEFAULT_OUTPUT_FOLDER))
|
.WithDescription("Specifies the output folder containing the build artifacts. Defaults to \"" + std::string(LinkerArgs::DEFAULT_OUTPUT_FOLDER) + "\".")
|
||||||
.WithParameter("outputFolderPath")
|
.WithParameter("outputFolderPath")
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
@ -60,14 +61,14 @@ const CommandLineOption* const OPTION_ADD_ASSET_SEARCH_PATH =
|
|||||||
const CommandLineOption* const OPTION_ASSET_SEARCH_PATH =
|
const CommandLineOption* const OPTION_ASSET_SEARCH_PATH =
|
||||||
CommandLineOption::Builder::Create()
|
CommandLineOption::Builder::Create()
|
||||||
.WithLongName("asset-search-path")
|
.WithLongName("asset-search-path")
|
||||||
.WithDescription(std::format("Specifies the search paths used for assets. Defaults to \"{}\".", LinkerArgs::DEFAULT_ASSET_SEARCH_PATH))
|
.WithDescription("Specifies the search paths used for assets. Defaults to \"" + std::string(LinkerArgs::DEFAULT_ASSET_SEARCH_PATH) + "\".")
|
||||||
.WithParameter("assetSearchPathString")
|
.WithParameter("assetSearchPathString")
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
const CommandLineOption* const OPTION_GDT_SEARCH_PATH =
|
const CommandLineOption* const OPTION_GDT_SEARCH_PATH =
|
||||||
CommandLineOption::Builder::Create()
|
CommandLineOption::Builder::Create()
|
||||||
.WithLongName("gdt-search-path")
|
.WithLongName("gdt-search-path")
|
||||||
.WithDescription(std::format("Specifies the search paths used for gdt files. Defaults to \"{}\".", LinkerArgs::DEFAULT_GDT_SEARCH_PATH))
|
.WithDescription("Specifies the search paths used for gdt files. Defaults to \"" + std::string(LinkerArgs::DEFAULT_GDT_SEARCH_PATH) + "\".")
|
||||||
.WithParameter("gdtSearchPathString")
|
.WithParameter("gdtSearchPathString")
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
@ -82,7 +83,7 @@ const CommandLineOption* const OPTION_ADD_SOURCE_SEARCH_PATH =
|
|||||||
const CommandLineOption* const OPTION_SOURCE_SEARCH_PATH =
|
const CommandLineOption* const OPTION_SOURCE_SEARCH_PATH =
|
||||||
CommandLineOption::Builder::Create()
|
CommandLineOption::Builder::Create()
|
||||||
.WithLongName("source-search-path")
|
.WithLongName("source-search-path")
|
||||||
.WithDescription(std::format("Specifies the search paths used for source files. Defaults to \"{}\".", LinkerArgs::DEFAULT_SOURCE_SEARCH_PATH))
|
.WithDescription("Specifies the search paths used for source files. Defaults to \"" + std::string(LinkerArgs::DEFAULT_SOURCE_SEARCH_PATH) + "\".")
|
||||||
.WithParameter("sourceSearchPathString")
|
.WithParameter("sourceSearchPathString")
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
@ -128,7 +129,13 @@ const CommandLineOption* const COMMAND_LINE_OPTIONS[]{
|
|||||||
|
|
||||||
LinkerArgs::LinkerArgs()
|
LinkerArgs::LinkerArgs()
|
||||||
: m_verbose(false),
|
: m_verbose(false),
|
||||||
m_argument_parser(COMMAND_LINE_OPTIONS, std::extent_v<decltype(COMMAND_LINE_OPTIONS)>)
|
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\?)")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,6 +172,76 @@ void LinkerArgs::SetVerbose(const bool isVerbose)
|
|||||||
ObjWriting::Configuration.Verbose = 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)
|
bool LinkerArgs::ParseArgs(const int argc, const char** argv, bool& shouldContinue)
|
||||||
{
|
{
|
||||||
shouldContinue = true;
|
shouldContinue = true;
|
||||||
@ -207,13 +284,15 @@ bool LinkerArgs::ParseArgs(const int argc, const char** argv, bool& shouldContin
|
|||||||
if (m_argument_parser.IsOptionSpecified(OPTION_BASE_FOLDER))
|
if (m_argument_parser.IsOptionSpecified(OPTION_BASE_FOLDER))
|
||||||
m_base_folder = m_argument_parser.GetValueForOption(OPTION_BASE_FOLDER);
|
m_base_folder = m_argument_parser.GetValueForOption(OPTION_BASE_FOLDER);
|
||||||
else
|
else
|
||||||
m_base_folder = DEFAULT_BASE_FOLDER;
|
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;
|
||||||
|
|
||||||
// --output-folder
|
// --output-folder
|
||||||
if (m_argument_parser.IsOptionSpecified(OPTION_OUTPUT_FOLDER))
|
if (m_argument_parser.IsOptionSpecified(OPTION_OUTPUT_FOLDER))
|
||||||
m_out_folder = m_argument_parser.GetValueForOption(OPTION_OUTPUT_FOLDER);
|
m_out_folder = m_argument_parser.GetValueForOption(OPTION_OUTPUT_FOLDER);
|
||||||
else
|
else
|
||||||
m_out_folder = DEFAULT_OUTPUT_FOLDER;
|
m_out_folder = DEFAULT_OUTPUT_FOLDER;
|
||||||
|
m_out_folder_depends_on_project = m_out_folder.find(PATTERN_PROJECT) != std::string::npos;
|
||||||
|
|
||||||
// --asset-search-path
|
// --asset-search-path
|
||||||
if (m_argument_parser.IsOptionSpecified(OPTION_ASSET_SEARCH_PATH))
|
if (m_argument_parser.IsOptionSpecified(OPTION_ASSET_SEARCH_PATH))
|
||||||
@ -279,3 +358,38 @@ bool LinkerArgs::ParseArgs(const int argc, const char** argv, bool& shouldContin
|
|||||||
|
|
||||||
return true;
|
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,14 +1,22 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Utils/Arguments/ArgumentParser.h"
|
#include "Utils/Arguments/ArgumentParser.h"
|
||||||
|
#include "Utils/ClassUtils.h"
|
||||||
|
#include "Zone/Zone.h"
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class LinkerArgs
|
class LinkerArgs
|
||||||
{
|
{
|
||||||
public:
|
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 = ".";
|
||||||
static constexpr auto DEFAULT_CACHE_FOLDER = "?base?/.oat/cache/?project?";
|
static constexpr auto DEFAULT_BASE_FOLDER_MOD_TOOLS = "..";
|
||||||
static constexpr auto DEFAULT_OUTPUT_FOLDER = "?base?/zone_out/?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_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";
|
static constexpr auto DEFAULT_GDT_SEARCH_PATH = "?base?/source_data;?base?/zone_raw/?project?/source_data";
|
||||||
@ -17,6 +25,21 @@ public:
|
|||||||
LinkerArgs();
|
LinkerArgs();
|
||||||
bool ParseArgs(int argc, const char** argv, bool& shouldContinue);
|
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;
|
bool m_verbose;
|
||||||
|
|
||||||
std::vector<std::string> m_zones_to_load;
|
std::vector<std::string> m_zones_to_load;
|
||||||
@ -25,6 +48,8 @@ public:
|
|||||||
std::string m_bin_folder;
|
std::string m_bin_folder;
|
||||||
std::string m_base_folder;
|
std::string m_base_folder;
|
||||||
std::string m_out_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_asset_search_paths;
|
||||||
std::set<std::string> m_gdt_search_paths;
|
std::set<std::string> m_gdt_search_paths;
|
||||||
@ -38,7 +63,18 @@ private:
|
|||||||
static void PrintVersion();
|
static void PrintVersion();
|
||||||
|
|
||||||
void SetBinFolder(const char* argv0);
|
void SetBinFolder(const char* argv0);
|
||||||
|
|
||||||
void SetVerbose(bool isVerbose);
|
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;
|
ArgumentParser m_argument_parser;
|
||||||
|
std::regex m_bin_pattern;
|
||||||
|
std::regex m_base_pattern;
|
||||||
|
std::regex m_game_pattern;
|
||||||
|
std::regex m_project_pattern;
|
||||||
};
|
};
|
||||||
|
@ -1,342 +0,0 @@
|
|||||||
#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));
|
|
||||||
}
|
|
@ -1,74 +0,0 @@
|
|||||||
#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;
|
|
||||||
};
|
|
190
src/Linker/LinkerSearchPaths.cpp
Normal file
190
src/Linker/LinkerSearchPaths.cpp
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
#include "LinkerSearchPaths.h"
|
||||||
|
|
||||||
|
#include "ObjContainer/IWD/IWD.h"
|
||||||
|
#include "ObjLoading.h"
|
||||||
|
#include "SearchPath/SearchPathFilesystem.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <format>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
LinkerSearchPaths::LinkerSearchPaths(const LinkerArgs& args)
|
||||||
|
: m_args(args)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinkerSearchPaths::LoadSearchPath(ISearchPath& searchPath) const
|
||||||
|
{
|
||||||
|
if (m_args.m_verbose)
|
||||||
|
{
|
||||||
|
std::cout << std::format("Loading search path: \"{}\"\n", searchPath.GetPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjLoading::LoadIWDsInSearchPath(searchPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinkerSearchPaths::UnloadSearchPath(ISearchPath& searchPath) const
|
||||||
|
{
|
||||||
|
if (m_args.m_verbose)
|
||||||
|
{
|
||||||
|
std::cout << std::format("Unloading search path: \"{}\"\n", searchPath.GetPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjLoading::UnloadIWDsInSearchPath(searchPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchPaths LinkerSearchPaths::GetAssetSearchPathsForProject(const std::string& gameName, const std::string& projectName)
|
||||||
|
{
|
||||||
|
SearchPaths searchPathsForProject;
|
||||||
|
|
||||||
|
for (const auto& searchPathStr : m_args.GetAssetSearchPathsForProject(gameName, projectName))
|
||||||
|
{
|
||||||
|
auto absolutePath = fs::absolute(searchPathStr);
|
||||||
|
|
||||||
|
if (!fs::is_directory(absolutePath))
|
||||||
|
{
|
||||||
|
if (m_args.m_verbose)
|
||||||
|
std::cout << std::format("Adding asset search path (Not found): {}\n", absolutePath.string());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_args.m_verbose)
|
||||||
|
std::cout << std::format("Adding asset search path: {}\n", absolutePath.string());
|
||||||
|
|
||||||
|
auto searchPath = std::make_unique<SearchPathFilesystem>(searchPathStr);
|
||||||
|
LoadSearchPath(*searchPath);
|
||||||
|
searchPathsForProject.IncludeSearchPath(searchPath.get());
|
||||||
|
m_loaded_project_search_paths.emplace_back(std::move(searchPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
searchPathsForProject.IncludeSearchPath(&m_asset_search_paths);
|
||||||
|
|
||||||
|
for (auto* iwd : IWD::Repository)
|
||||||
|
{
|
||||||
|
searchPathsForProject.IncludeSearchPath(iwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return searchPathsForProject;
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchPaths LinkerSearchPaths::GetGdtSearchPathsForProject(const std::string& gameName, const std::string& projectName)
|
||||||
|
{
|
||||||
|
SearchPaths searchPathsForProject;
|
||||||
|
|
||||||
|
for (const auto& searchPathStr : m_args.GetGdtSearchPathsForProject(gameName, projectName))
|
||||||
|
{
|
||||||
|
auto absolutePath = fs::absolute(searchPathStr);
|
||||||
|
|
||||||
|
if (!fs::is_directory(absolutePath))
|
||||||
|
{
|
||||||
|
if (m_args.m_verbose)
|
||||||
|
std::cout << std::format("Adding gdt search path (Not found): {}\n", absolutePath.string());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_args.m_verbose)
|
||||||
|
std::cout << std::format("Adding gdt search path: {}\n", absolutePath.string());
|
||||||
|
|
||||||
|
searchPathsForProject.CommitSearchPath(std::make_unique<SearchPathFilesystem>(searchPathStr));
|
||||||
|
}
|
||||||
|
|
||||||
|
searchPathsForProject.IncludeSearchPath(&m_gdt_search_paths);
|
||||||
|
|
||||||
|
return searchPathsForProject;
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchPaths LinkerSearchPaths::GetSourceSearchPathsForProject(const std::string& projectName)
|
||||||
|
{
|
||||||
|
SearchPaths searchPathsForProject;
|
||||||
|
|
||||||
|
for (const auto& searchPathStr : m_args.GetSourceSearchPathsForProject(projectName))
|
||||||
|
{
|
||||||
|
auto absolutePath = fs::absolute(searchPathStr);
|
||||||
|
|
||||||
|
if (!fs::is_directory(absolutePath))
|
||||||
|
{
|
||||||
|
if (m_args.m_verbose)
|
||||||
|
std::cout << std::format("Adding source search path (Not found): {}\n", absolutePath.string());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_args.m_verbose)
|
||||||
|
std::cout << std::format("Adding source search path: {}\n", absolutePath.string());
|
||||||
|
|
||||||
|
searchPathsForProject.CommitSearchPath(std::make_unique<SearchPathFilesystem>(searchPathStr));
|
||||||
|
}
|
||||||
|
|
||||||
|
searchPathsForProject.IncludeSearchPath(&m_source_search_paths);
|
||||||
|
|
||||||
|
return searchPathsForProject;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LinkerSearchPaths::BuildProjectIndependentSearchPaths()
|
||||||
|
{
|
||||||
|
for (const auto& path : m_args.GetProjectIndependentAssetSearchPaths())
|
||||||
|
{
|
||||||
|
auto absolutePath = fs::absolute(path);
|
||||||
|
|
||||||
|
if (!fs::is_directory(absolutePath))
|
||||||
|
{
|
||||||
|
if (m_args.m_verbose)
|
||||||
|
std::cout << std::format("Adding asset search path (Not found): {}\n", absolutePath.string());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_args.m_verbose)
|
||||||
|
std::cout << std::format("Adding asset search path: {}\n", absolutePath.string());
|
||||||
|
|
||||||
|
auto searchPath = std::make_unique<SearchPathFilesystem>(absolutePath.string());
|
||||||
|
LoadSearchPath(*searchPath);
|
||||||
|
m_asset_search_paths.CommitSearchPath(std::move(searchPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& path : m_args.GetProjectIndependentGdtSearchPaths())
|
||||||
|
{
|
||||||
|
auto absolutePath = fs::absolute(path);
|
||||||
|
|
||||||
|
if (!fs::is_directory(absolutePath))
|
||||||
|
{
|
||||||
|
if (m_args.m_verbose)
|
||||||
|
std::cout << std::format("Loading gdt search path (Not found): {}\n", absolutePath.string());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_args.m_verbose)
|
||||||
|
std::cout << std::format("Adding gdt search path: {}\n", absolutePath.string());
|
||||||
|
|
||||||
|
m_gdt_search_paths.CommitSearchPath(std::make_unique<SearchPathFilesystem>(absolutePath.string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& path : m_args.GetProjectIndependentSourceSearchPaths())
|
||||||
|
{
|
||||||
|
auto absolutePath = fs::absolute(path);
|
||||||
|
|
||||||
|
if (!fs::is_directory(absolutePath))
|
||||||
|
{
|
||||||
|
if (m_args.m_verbose)
|
||||||
|
std::cout << std::format("Loading source search path (Not found): {}\n", absolutePath.string());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_args.m_verbose)
|
||||||
|
std::cout << std::format("Adding source search path: {}\n", absolutePath.string());
|
||||||
|
|
||||||
|
m_source_search_paths.CommitSearchPath(std::make_unique<SearchPathFilesystem>(absolutePath.string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinkerSearchPaths::UnloadProjectSpecificSearchPaths()
|
||||||
|
{
|
||||||
|
for (const auto& loadedSearchPath : m_loaded_project_search_paths)
|
||||||
|
{
|
||||||
|
UnloadSearchPath(*loadedSearchPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_loaded_project_search_paths.clear();
|
||||||
|
}
|
45
src/Linker/LinkerSearchPaths.h
Normal file
45
src/Linker/LinkerSearchPaths.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#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,17 +1,13 @@
|
|||||||
#include "ZoneCreationContext.h"
|
#include "ZoneCreationContext.h"
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
|
||||||
|
|
||||||
ZoneCreationContext::ZoneCreationContext()
|
ZoneCreationContext::ZoneCreationContext()
|
||||||
: m_definition(nullptr),
|
: m_definition(nullptr),
|
||||||
m_asset_search_path(nullptr)
|
m_asset_search_path(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ZoneCreationContext::ZoneCreationContext(ZoneDefinition* definition, ISearchPath* assetSearchPath, fs::path outDir, fs::path cacheDir)
|
ZoneCreationContext::ZoneCreationContext(ZoneDefinition* definition, ISearchPath* assetSearchPath)
|
||||||
: m_definition(definition),
|
: m_definition(definition),
|
||||||
m_asset_search_path(assetSearchPath),
|
m_asset_search_path(assetSearchPath)
|
||||||
m_out_dir(std::move(outDir)),
|
|
||||||
m_cache_dir(std::move(cacheDir))
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include "Zone/AssetList/AssetList.h"
|
#include "Zone/AssetList/AssetList.h"
|
||||||
#include "Zone/Definition/ZoneDefinition.h"
|
#include "Zone/Definition/ZoneDefinition.h"
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -13,11 +12,9 @@ class ZoneCreationContext
|
|||||||
public:
|
public:
|
||||||
ZoneDefinition* m_definition;
|
ZoneDefinition* m_definition;
|
||||||
ISearchPath* m_asset_search_path;
|
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;
|
std::vector<std::unique_ptr<Gdt>> m_gdt_files;
|
||||||
AssetList m_ignored_assets;
|
AssetList m_ignored_assets;
|
||||||
|
|
||||||
ZoneCreationContext();
|
ZoneCreationContext();
|
||||||
ZoneCreationContext(ZoneDefinition* definition, ISearchPath* assetSearchPath, std::filesystem::path outDir, std::filesystem::path cacheDir);
|
ZoneCreationContext(ZoneDefinition* definition, ISearchPath* assetSearchPath);
|
||||||
};
|
};
|
||||||
|
@ -1,91 +1,27 @@
|
|||||||
#include "ZoneCreator.h"
|
#include "ZoneCreator.h"
|
||||||
|
|
||||||
#include "Gdt/GdtLookup.h"
|
#include "AssetLoading/AssetLoadingContext.h"
|
||||||
#include "IObjCompiler.h"
|
#include "Game/IW3/ZoneCreatorIW3.h"
|
||||||
#include "IObjLoader.h"
|
#include "Game/IW4/ZoneCreatorIW4.h"
|
||||||
#include "SearchPath/OutputPathFilesystem.h"
|
#include "Game/IW5/ZoneCreatorIW5.h"
|
||||||
|
#include "Game/T5/ZoneCreatorT5.h"
|
||||||
|
#include "Game/T6/ZoneCreatorT6.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
namespace
|
const IZoneCreator* IZoneCreator::GetCreatorForGame(GameId game)
|
||||||
{
|
{
|
||||||
std::unique_ptr<Zone> CreateZone(const ZoneCreationContext& context, const GameId gameId)
|
static const IZoneCreator* zoneCreators[static_cast<unsigned>(GameId::COUNT)]{
|
||||||
{
|
new IW3::ZoneCreator(),
|
||||||
return std::make_unique<Zone>(context.m_definition->m_name, 0, IGame::GetGameById(gameId));
|
new IW4::ZoneCreator(),
|
||||||
|
new IW5::ZoneCreator(),
|
||||||
|
new T5::ZoneCreator(),
|
||||||
|
new T6::ZoneCreator(),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(static_cast<unsigned>(game) < static_cast<unsigned>(GameId::COUNT));
|
||||||
|
const auto* result = zoneCreators[static_cast<unsigned>(game)];
|
||||||
|
assert(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Gdt*> CreateGdtList(const ZoneCreationContext& context)
|
|
||||||
{
|
|
||||||
std::vector<Gdt*> gdtList;
|
|
||||||
gdtList.reserve(context.m_gdt_files.size());
|
|
||||||
for (const auto& gdt : context.m_gdt_files)
|
|
||||||
gdtList.push_back(gdt.get());
|
|
||||||
|
|
||||||
return 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
|
|
||||||
|
@ -3,7 +3,19 @@
|
|||||||
#include "Zone/Zone.h"
|
#include "Zone/Zone.h"
|
||||||
#include "ZoneCreationContext.h"
|
#include "ZoneCreationContext.h"
|
||||||
|
|
||||||
namespace zone_creator
|
class IZoneCreator
|
||||||
{
|
{
|
||||||
[[nodiscard]] std::unique_ptr<Zone> CreateZoneForDefinition(GameId game, ZoneCreationContext& context);
|
public:
|
||||||
}
|
IZoneCreator() = default;
|
||||||
|
virtual ~IZoneCreator() = default;
|
||||||
|
IZoneCreator(const IZoneCreator& other) = default;
|
||||||
|
IZoneCreator(IZoneCreator&& other) noexcept = default;
|
||||||
|
IZoneCreator& operator=(const IZoneCreator& other) = default;
|
||||||
|
IZoneCreator& operator=(IZoneCreator&& other) noexcept = default;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual GameId GetGameId() const = 0;
|
||||||
|
[[nodiscard]] virtual std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const = 0;
|
||||||
|
[[nodiscard]] virtual asset_type_t GetImageAssetType() const = 0;
|
||||||
|
|
||||||
|
static const IZoneCreator* GetCreatorForGame(GameId game);
|
||||||
|
};
|
||||||
|
@ -5,7 +5,6 @@ function ObjCommon:include(includes)
|
|||||||
Common:include(includes)
|
Common:include(includes)
|
||||||
json:include(includes)
|
json:include(includes)
|
||||||
minizip:include(includes)
|
minizip:include(includes)
|
||||||
Parser:include(includes)
|
|
||||||
includedirs {
|
includedirs {
|
||||||
path.join(ProjectFolder(), "ObjCommon")
|
path.join(ProjectFolder(), "ObjCommon")
|
||||||
}
|
}
|
||||||
@ -17,7 +16,6 @@ function ObjCommon:link(links)
|
|||||||
links:linkto(Utils)
|
links:linkto(Utils)
|
||||||
links:linkto(Common)
|
links:linkto(Common)
|
||||||
links:linkto(minizip)
|
links:linkto(minizip)
|
||||||
links:linkto(Parser)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function ObjCommon:use()
|
function ObjCommon:use()
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Game/IW4/IW4.h"
|
#include "Game/IW4/IW4.h"
|
||||||
|
|
||||||
namespace IW4
|
namespace IW4
|
@ -36,11 +36,31 @@ namespace T6
|
|||||||
"crosshair",
|
"crosshair",
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const char* penetrateTypeNames[]{
|
inline const char* szWeapInventoryTypeNames[]{
|
||||||
"none",
|
"primary",
|
||||||
"small",
|
"offhand",
|
||||||
"medium",
|
"item",
|
||||||
"large",
|
"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* impactTypeNames[]{
|
inline const char* impactTypeNames[]{
|
||||||
@ -145,37 +165,6 @@ namespace T6
|
|||||||
"Turret Scope",
|
"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[]{
|
inline const char* ammoCounterClipNames[]{
|
||||||
"None",
|
"None",
|
||||||
"Magazine",
|
"Magazine",
|
||||||
@ -192,13 +181,75 @@ namespace T6
|
|||||||
"4:1",
|
"4:1",
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const char* barrelTypeNames[]{
|
inline const char* szAttachmentTypeNames[]{
|
||||||
"Single",
|
"none", "acog", "dualclip", "dualoptic", "dw", "extbarrel", "extclip", "extramags", "fastads", "fastreload",
|
||||||
"Dual Barrel",
|
"fmj", "gl", "grip", "holo", "ir", "is", "longbreath", "mk", "mms", "rangefinder",
|
||||||
"Dual Barrel Alternate",
|
"reflex", "rf", "sf", "silencer", "stackfire", "stalker", "steadyaim", "swayreduc", "tacknife", "vzoom",
|
||||||
"Quad Barrel",
|
};
|
||||||
"Quad Barrel Alternate",
|
|
||||||
"Quad Barrel Double Alternate",
|
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* bounceSoundSuffixes[]{
|
inline const char* bounceSoundSuffixes[]{
|
||||||
@ -206,10 +257,4 @@ namespace T6
|
|||||||
"_gravel", "_ice", "_metal", "_mud", "_paper", "_plaster", "_rock", "_sand", "_snow", "_water", "_wood",
|
"_gravel", "_ice", "_metal", "_mud", "_paper", "_plaster", "_rock", "_sand", "_snow", "_water", "_wood",
|
||||||
"_asphalt", "_ceramic", "_plastic", "_rubber", "_cushion", "_fruit", "_paintedmetal", "_player", "_tallgrass", "_riotshield",
|
"_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
|
} // namespace T6
|
@ -81,17 +81,4 @@ namespace T6
|
|||||||
{"c4_yaw", offsetof(PhysConstraints, data[3].scale.y), CSPFT_FLOAT },
|
{"c4_yaw", offsetof(PhysConstraints, data[3].scale.y), CSPFT_FLOAT },
|
||||||
{"c4_pitch", offsetof(PhysConstraints, data[3].scale.x), 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
|
|
@ -36,9 +36,4 @@ namespace T6
|
|||||||
{"colorB4", offsetof(TracerDef, colors[4].b), CSPFT_FLOAT },
|
{"colorB4", offsetof(TracerDef, colors[4].b), CSPFT_FLOAT },
|
||||||
{"colorA4", offsetof(TracerDef, colors[4].a), CSPFT_FLOAT },
|
{"colorA4", offsetof(TracerDef, colors[4].a), CSPFT_FLOAT },
|
||||||
};
|
};
|
||||||
|
}
|
||||||
inline const char* tracerTypeNames[]{
|
|
||||||
"Laser",
|
|
||||||
"Smoke",
|
|
||||||
};
|
|
||||||
} // namespace T6
|
|
@ -561,31 +561,4 @@ namespace T6
|
|||||||
{"customBool1", offsetof(VehicleDef, customBool1), CSPFT_BOOL },
|
{"customBool1", offsetof(VehicleDef, customBool1), CSPFT_BOOL },
|
||||||
{"customBool2", offsetof(VehicleDef, customBool2), 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 },
|
{"customBool1", offsetof(WeaponAttachment, customBool1), CSPFT_BOOL },
|
||||||
{"customBool2", offsetof(WeaponAttachment, customBool2), CSPFT_BOOL },
|
{"customBool2", offsetof(WeaponAttachment, customBool2), CSPFT_BOOL },
|
||||||
};
|
};
|
||||||
} // namespace T6
|
}
|
@ -206,4 +206,4 @@ namespace T6
|
|||||||
{"customBool1", offsetof(WeaponAttachmentUniqueFull, attachment.customBool1), CSPFT_BOOL },
|
{"customBool1", offsetof(WeaponAttachmentUniqueFull, attachment.customBool1), CSPFT_BOOL },
|
||||||
{"customBool2", offsetof(WeaponAttachmentUniqueFull, attachment.customBool2), CSPFT_BOOL },
|
{"customBool2", offsetof(WeaponAttachmentUniqueFull, attachment.customBool2), CSPFT_BOOL },
|
||||||
};
|
};
|
||||||
} // namespace T6
|
}
|
@ -16,7 +16,7 @@ namespace ipak_consts
|
|||||||
static constexpr size_t IPAK_CHUNK_SIZE = 0x8000;
|
static constexpr size_t IPAK_CHUNK_SIZE = 0x8000;
|
||||||
static constexpr size_t IPAK_CHUNK_COUNT_PER_READ = 0x8;
|
static constexpr size_t IPAK_CHUNK_COUNT_PER_READ = 0x8;
|
||||||
|
|
||||||
static constexpr size_t IPAK_COMMAND_DEFAULT_SIZE = 0x7F00;
|
static constexpr uint32_t IPAK_COMMAND_DEFAULT_SIZE = 0x7F00;
|
||||||
static constexpr uint32_t IPAK_COMMAND_UNCOMPRESSED = 0;
|
static constexpr uint32_t IPAK_COMMAND_UNCOMPRESSED = 0;
|
||||||
static constexpr uint32_t IPAK_COMMAND_COMPRESSED = 1;
|
static constexpr uint32_t IPAK_COMMAND_COMPRESSED = 1;
|
||||||
static constexpr uint32_t IPAK_COMMAND_SKIP = 0xCF;
|
static constexpr uint32_t IPAK_COMMAND_SKIP = 0xCF;
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
#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;
|
|
||||||
};
|
|
@ -1,39 +0,0 @@
|
|||||||
#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));
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "IOutputPath.h"
|
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
class OutputPathFilesystem final : public IOutputPath
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit OutputPathFilesystem(const std::filesystem::path& path);
|
|
||||||
|
|
||||||
std::unique_ptr<std::ostream> Open(const std::string& fileName) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::filesystem::path m_path;
|
|
||||||
};
|
|
@ -1,15 +0,0 @@
|
|||||||
#include "SearchPathMultiInputStream.h"
|
|
||||||
|
|
||||||
SearchPathMultiInputStream::SearchPathMultiInputStream(ISearchPath& searchPath)
|
|
||||||
: m_search_path(searchPath)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<std::istream> SearchPathMultiInputStream::OpenIncludedFile(const std::string& filename, const std::string& sourceFile)
|
|
||||||
{
|
|
||||||
auto foundFileToInclude = m_search_path.Open(filename);
|
|
||||||
if (!foundFileToInclude.IsOpen() || !foundFileToInclude.m_stream)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return std::move(foundFileToInclude.m_stream);
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Parsing/Impl/ParserMultiInputStream.h"
|
|
||||||
#include "SearchPath/ISearchPath.h"
|
|
||||||
|
|
||||||
class SearchPathMultiInputStream : public IInclusionCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit SearchPathMultiInputStream(ISearchPath& searchPath);
|
|
||||||
|
|
||||||
std::unique_ptr<std::istream> OpenIncludedFile(const std::string& filename, const std::string& sourceFile) override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
ISearchPath& m_search_path;
|
|
||||||
};
|
|
@ -68,7 +68,7 @@ namespace
|
|||||||
T result;
|
T result;
|
||||||
} data{};
|
} data{};
|
||||||
|
|
||||||
const auto byteCount = utils::Align(bitCount, 8uz) / 8uz;
|
const auto byteCount = utils::Align(bitCount, 8u) / 8u;
|
||||||
assert(byteCount <= sizeof(T));
|
assert(byteCount <= sizeof(T));
|
||||||
|
|
||||||
const auto shiftCount = (8u - bitCount % 8) % 8;
|
const auto shiftCount = (8u - bitCount % 8) % 8;
|
||||||
@ -83,7 +83,7 @@ namespace
|
|||||||
|
|
||||||
while (remainingBits > 0)
|
while (remainingBits > 0)
|
||||||
{
|
{
|
||||||
const auto curBits = static_cast<uint8_t>(std::min(remainingBits, 8uz));
|
const auto curBits = static_cast<uint8_t>(std::min(remainingBits, 8u));
|
||||||
|
|
||||||
if (m_remaining_bits_last_byte > 0)
|
if (m_remaining_bits_last_byte > 0)
|
||||||
{
|
{
|
||||||
|
@ -59,7 +59,7 @@ size_t CommonStructuredDataType::GetSizeInBits(const CommonStructuredDataDef& de
|
|||||||
return 0u;
|
return 0u;
|
||||||
}
|
}
|
||||||
const auto& indexedArray = def.m_indexed_arrays[m_info.type_index];
|
const auto& indexedArray = def.m_indexed_arrays[m_info.type_index];
|
||||||
return utils::Align(indexedArray.m_element_size_in_bits * indexedArray.m_element_count, 8uz);
|
return utils::Align(indexedArray.m_element_size_in_bits * indexedArray.m_element_count, 8u);
|
||||||
}
|
}
|
||||||
case CommonStructuredDataTypeCategory::ENUM_ARRAY:
|
case CommonStructuredDataTypeCategory::ENUM_ARRAY:
|
||||||
{
|
{
|
||||||
@ -69,7 +69,7 @@ size_t CommonStructuredDataType::GetSizeInBits(const CommonStructuredDataDef& de
|
|||||||
return 0u;
|
return 0u;
|
||||||
}
|
}
|
||||||
const auto& enumedArray = def.m_enumed_arrays[m_info.type_index];
|
const auto& enumedArray = def.m_enumed_arrays[m_info.type_index];
|
||||||
return utils::Align(enumedArray.m_element_size_in_bits * enumedArray.m_element_count, 8uz);
|
return utils::Align(enumedArray.m_element_size_in_bits * enumedArray.m_element_count, 8u);
|
||||||
}
|
}
|
||||||
|
|
||||||
case CommonStructuredDataTypeCategory::UNKNOWN:
|
case CommonStructuredDataTypeCategory::UNKNOWN:
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
ObjCompiling = {}
|
|
||||||
|
|
||||||
function ObjCompiling:include(includes)
|
|
||||||
if includes:handle(self:name()) then
|
|
||||||
ObjCommon:include(includes)
|
|
||||||
ObjLoading:include(includes)
|
|
||||||
ObjImage:include(includes)
|
|
||||||
ZoneCommon:include(includes)
|
|
||||||
includedirs {
|
|
||||||
path.join(ProjectFolder(), "ObjCompiling")
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ObjCompiling:link(links)
|
|
||||||
links:add(self:name())
|
|
||||||
links:linkto(minilzo)
|
|
||||||
links:linkto(Utils)
|
|
||||||
links:linkto(ObjCommon)
|
|
||||||
links:linkto(ObjLoading)
|
|
||||||
links:linkto(ObjImage)
|
|
||||||
links:linkto(ZoneCommon)
|
|
||||||
end
|
|
||||||
|
|
||||||
function ObjCompiling:use()
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function ObjCompiling:name()
|
|
||||||
return "ObjCompiling"
|
|
||||||
end
|
|
||||||
|
|
||||||
function ObjCompiling:project()
|
|
||||||
local folder = ProjectFolder()
|
|
||||||
local includes = Includes:create()
|
|
||||||
|
|
||||||
project(self:name())
|
|
||||||
targetdir(TargetDirectoryLib)
|
|
||||||
location "%{wks.location}/src/%{prj.name}"
|
|
||||||
kind "StaticLib"
|
|
||||||
language "C++"
|
|
||||||
|
|
||||||
files {
|
|
||||||
path.join(folder, "ObjCompiling/**.h"),
|
|
||||||
path.join(folder, "ObjCompiling/**.cpp")
|
|
||||||
}
|
|
||||||
|
|
||||||
vpaths {
|
|
||||||
["*"] = {
|
|
||||||
path.join(folder, "ObjCompiling")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self:include(includes)
|
|
||||||
minilzo:include(includes)
|
|
||||||
Utils:include(includes)
|
|
||||||
json:include(includes)
|
|
||||||
end
|
|
@ -1,43 +0,0 @@
|
|||||||
#include "ObjCompilerIW3.h"
|
|
||||||
|
|
||||||
#include "Game/IW3/IW3.h"
|
|
||||||
#include "Image/ImageIwdPostProcessor.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
using namespace IW3;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
void ConfigureCompilers(AssetCreatorCollection& collection, Zone& zone, ISearchPath& searchPath)
|
|
||||||
{
|
|
||||||
auto& memory = *zone.GetMemory();
|
|
||||||
|
|
||||||
// No compilers yet
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigurePostProcessors(AssetCreatorCollection& collection,
|
|
||||||
Zone& zone,
|
|
||||||
const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir)
|
|
||||||
{
|
|
||||||
auto& memory = *zone.GetMemory();
|
|
||||||
|
|
||||||
if (ImageIwdPostProcessor<AssetImage>::AppliesToZoneDefinition(zoneDefinition))
|
|
||||||
collection.AddAssetPostProcessor(std::make_unique<ImageIwdPostProcessor<AssetImage>>(zoneDefinition, searchPath, zoneStates, outDir));
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void ObjCompiler::ConfigureCreatorCollection(AssetCreatorCollection& collection,
|
|
||||||
Zone& zone,
|
|
||||||
const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
IGdtQueryable& gdt,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir,
|
|
||||||
IOutputPath& cacheDir) const
|
|
||||||
{
|
|
||||||
ConfigurePostProcessors(collection, zone, zoneDefinition, searchPath, zoneStates, outDir);
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "IObjCompiler.h"
|
|
||||||
|
|
||||||
namespace IW3
|
|
||||||
{
|
|
||||||
class ObjCompiler final : public IObjCompiler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void ConfigureCreatorCollection(AssetCreatorCollection& collection,
|
|
||||||
Zone& zone,
|
|
||||||
const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
IGdtQueryable& gdt,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir,
|
|
||||||
IOutputPath& cacheDir) const override;
|
|
||||||
};
|
|
||||||
} // namespace IW3
|
|
@ -1,43 +0,0 @@
|
|||||||
#include "ObjCompilerIW4.h"
|
|
||||||
|
|
||||||
#include "Game/IW4/IW4.h"
|
|
||||||
#include "Image/ImageIwdPostProcessor.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
using namespace IW4;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
void ConfigureCompilers(AssetCreatorCollection& collection, Zone& zone, ISearchPath& searchPath)
|
|
||||||
{
|
|
||||||
auto& memory = *zone.GetMemory();
|
|
||||||
|
|
||||||
// No compilers yet
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigurePostProcessors(AssetCreatorCollection& collection,
|
|
||||||
Zone& zone,
|
|
||||||
const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir)
|
|
||||||
{
|
|
||||||
auto& memory = *zone.GetMemory();
|
|
||||||
|
|
||||||
if (ImageIwdPostProcessor<AssetImage>::AppliesToZoneDefinition(zoneDefinition))
|
|
||||||
collection.AddAssetPostProcessor(std::make_unique<ImageIwdPostProcessor<AssetImage>>(zoneDefinition, searchPath, zoneStates, outDir));
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void ObjCompiler::ConfigureCreatorCollection(AssetCreatorCollection& collection,
|
|
||||||
Zone& zone,
|
|
||||||
const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
IGdtQueryable& gdt,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir,
|
|
||||||
IOutputPath& cacheDir) const
|
|
||||||
{
|
|
||||||
ConfigurePostProcessors(collection, zone, zoneDefinition, searchPath, zoneStates, outDir);
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "IObjCompiler.h"
|
|
||||||
|
|
||||||
namespace IW4
|
|
||||||
{
|
|
||||||
class ObjCompiler final : public IObjCompiler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void ConfigureCreatorCollection(AssetCreatorCollection& collection,
|
|
||||||
Zone& zone,
|
|
||||||
const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
IGdtQueryable& gdt,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir,
|
|
||||||
IOutputPath& cacheDir) const override;
|
|
||||||
};
|
|
||||||
} // namespace IW4
|
|
@ -1,43 +0,0 @@
|
|||||||
#include "ObjCompilerIW5.h"
|
|
||||||
|
|
||||||
#include "Game/IW5/IW5.h"
|
|
||||||
#include "Image/ImageIwdPostProcessor.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
using namespace IW5;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
void ConfigureCompilers(AssetCreatorCollection& collection, Zone& zone, ISearchPath& searchPath)
|
|
||||||
{
|
|
||||||
auto& memory = *zone.GetMemory();
|
|
||||||
|
|
||||||
// No compilers yet
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigurePostProcessors(AssetCreatorCollection& collection,
|
|
||||||
Zone& zone,
|
|
||||||
const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir)
|
|
||||||
{
|
|
||||||
auto& memory = *zone.GetMemory();
|
|
||||||
|
|
||||||
if (ImageIwdPostProcessor<AssetImage>::AppliesToZoneDefinition(zoneDefinition))
|
|
||||||
collection.AddAssetPostProcessor(std::make_unique<ImageIwdPostProcessor<AssetImage>>(zoneDefinition, searchPath, zoneStates, outDir));
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void ObjCompiler::ConfigureCreatorCollection(AssetCreatorCollection& collection,
|
|
||||||
Zone& zone,
|
|
||||||
const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
IGdtQueryable& gdt,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir,
|
|
||||||
IOutputPath& cacheDir) const
|
|
||||||
{
|
|
||||||
ConfigurePostProcessors(collection, zone, zoneDefinition, searchPath, zoneStates, outDir);
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "IObjCompiler.h"
|
|
||||||
|
|
||||||
namespace IW5
|
|
||||||
{
|
|
||||||
class ObjCompiler final : public IObjCompiler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void ConfigureCreatorCollection(AssetCreatorCollection& collection,
|
|
||||||
Zone& zone,
|
|
||||||
const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
IGdtQueryable& gdt,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir,
|
|
||||||
IOutputPath& cacheDir) const override;
|
|
||||||
};
|
|
||||||
} // namespace IW5
|
|
@ -1,43 +0,0 @@
|
|||||||
#include "ObjCompilerT5.h"
|
|
||||||
|
|
||||||
#include "Game/T5/T5.h"
|
|
||||||
#include "Image/ImageIwdPostProcessor.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
using namespace T5;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
void ConfigureCompilers(AssetCreatorCollection& collection, Zone& zone, ISearchPath& searchPath)
|
|
||||||
{
|
|
||||||
auto& memory = *zone.GetMemory();
|
|
||||||
|
|
||||||
// No compilers yet
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigurePostProcessors(AssetCreatorCollection& collection,
|
|
||||||
Zone& zone,
|
|
||||||
const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir)
|
|
||||||
{
|
|
||||||
auto& memory = *zone.GetMemory();
|
|
||||||
|
|
||||||
if (ImageIwdPostProcessor<AssetImage>::AppliesToZoneDefinition(zoneDefinition))
|
|
||||||
collection.AddAssetPostProcessor(std::make_unique<ImageIwdPostProcessor<AssetImage>>(zoneDefinition, searchPath, zoneStates, outDir));
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void ObjCompiler::ConfigureCreatorCollection(AssetCreatorCollection& collection,
|
|
||||||
Zone& zone,
|
|
||||||
const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
IGdtQueryable& gdt,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir,
|
|
||||||
IOutputPath& cacheDir) const
|
|
||||||
{
|
|
||||||
ConfigurePostProcessors(collection, zone, zoneDefinition, searchPath, zoneStates, outDir);
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "IObjCompiler.h"
|
|
||||||
|
|
||||||
namespace T5
|
|
||||||
{
|
|
||||||
class ObjCompiler final : public IObjCompiler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void ConfigureCreatorCollection(AssetCreatorCollection& collection,
|
|
||||||
Zone& zone,
|
|
||||||
const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
IGdtQueryable& gdt,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir,
|
|
||||||
IOutputPath& cacheDir) const override;
|
|
||||||
};
|
|
||||||
} // namespace T5
|
|
@ -1,82 +0,0 @@
|
|||||||
#include "KeyValuePairsCompilerT6.h"
|
|
||||||
|
|
||||||
#include "Game/T6/CommonT6.h"
|
|
||||||
#include "Game/T6/T6.h"
|
|
||||||
#include "KeyValuePairs/KeyValuePairsCreator.h"
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <format>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using namespace T6;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
class KeyValuePairsCompiler final : public IAssetCreator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
KeyValuePairsCompiler(MemoryManager& memory, const Zone& zone, const ZoneDefinition& zoneDefinition, ZoneAssetCreationStateContainer& zoneStates)
|
|
||||||
: m_memory(memory),
|
|
||||||
m_zone(zone),
|
|
||||||
m_zone_definition(zoneDefinition),
|
|
||||||
m_kvp_creator(zoneStates.GetZoneAssetCreationState<KeyValuePairsCreator>())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] std::optional<asset_type_t> GetHandlingAssetType() const override
|
|
||||||
{
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
|
||||||
{
|
|
||||||
return AssetCreationResult::NoAction();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FinalizeZone(AssetCreationContext& context) override
|
|
||||||
{
|
|
||||||
m_kvp_creator.Finalize(m_zone_definition);
|
|
||||||
const auto commonKvps = m_kvp_creator.GetFinalKeyValuePairs();
|
|
||||||
if (commonKvps.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto* gameKvps = m_memory.Alloc<KeyValuePairs>();
|
|
||||||
gameKvps->name = m_memory.Dup(m_zone.m_name.c_str());
|
|
||||||
gameKvps->numVariables = commonKvps.size();
|
|
||||||
gameKvps->keyValuePairs = m_memory.Alloc<KeyValuePair>(commonKvps.size());
|
|
||||||
|
|
||||||
const auto namespaceHash = Common::Com_HashKey(m_zone.m_name.c_str(), 64);
|
|
||||||
for (auto kvpIndex = 0u; kvpIndex < gameKvps->numVariables; kvpIndex++)
|
|
||||||
{
|
|
||||||
const auto& commonKvp = commonKvps[kvpIndex];
|
|
||||||
auto& gameKvp = gameKvps->keyValuePairs[kvpIndex];
|
|
||||||
|
|
||||||
assert(commonKvp.m_key_str || commonKvp.m_key_hash);
|
|
||||||
if (commonKvp.m_key_str)
|
|
||||||
gameKvp.keyHash = Common::Com_HashKey(commonKvp.m_key_str->c_str(), 64);
|
|
||||||
else
|
|
||||||
gameKvp.keyHash = *commonKvp.m_key_hash;
|
|
||||||
|
|
||||||
gameKvp.namespaceHash = namespaceHash;
|
|
||||||
gameKvp.value = m_memory.Dup(commonKvp.m_value.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
context.AddAsset(AssetRegistration<AssetKeyValuePairs>(m_zone.m_name, gameKvps));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
MemoryManager& m_memory;
|
|
||||||
const Zone& m_zone;
|
|
||||||
const ZoneDefinition& m_zone_definition;
|
|
||||||
KeyValuePairsCreator& m_kvp_creator;
|
|
||||||
};
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace T6
|
|
||||||
{
|
|
||||||
std::unique_ptr<IAssetCreator>
|
|
||||||
CreateKeyValuePairsCompiler(MemoryManager& memory, const Zone& zone, const ZoneDefinition& zoneDefinition, ZoneAssetCreationStateContainer& zoneStates)
|
|
||||||
{
|
|
||||||
return std::make_unique<KeyValuePairsCompiler>(memory, zone, zoneDefinition, zoneStates);
|
|
||||||
}
|
|
||||||
} // namespace T6
|
|
@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Asset/IAssetCreator.h"
|
|
||||||
#include "Asset/IZoneAssetCreationState.h"
|
|
||||||
#include "SearchPath/ISearchPath.h"
|
|
||||||
#include "Utils/MemoryManager.h"
|
|
||||||
#include "Zone/Definition/ZoneDefinition.h"
|
|
||||||
#include "Zone/Zone.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace T6
|
|
||||||
{
|
|
||||||
std::unique_ptr<IAssetCreator>
|
|
||||||
CreateKeyValuePairsCompiler(MemoryManager& memory, const Zone& zone, const ZoneDefinition& zoneDefinition, ZoneAssetCreationStateContainer& zoneStates);
|
|
||||||
} // namespace T6
|
|
@ -1,53 +0,0 @@
|
|||||||
#include "ObjCompilerT6.h"
|
|
||||||
|
|
||||||
#include "Game/T6/T6.h"
|
|
||||||
#include "Image/ImageIPakPostProcessor.h"
|
|
||||||
#include "Image/ImageIwdPostProcessor.h"
|
|
||||||
#include "KeyValuePairs/KeyValuePairsCompilerT6.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
using namespace T6;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
void ConfigureCompilers(AssetCreatorCollection& collection,
|
|
||||||
Zone& zone,
|
|
||||||
const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates)
|
|
||||||
{
|
|
||||||
auto& memory = *zone.GetMemory();
|
|
||||||
|
|
||||||
collection.AddAssetCreator(CreateKeyValuePairsCompiler(memory, zone, zoneDefinition.m_zone_definition, zoneStates));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigurePostProcessors(AssetCreatorCollection& collection,
|
|
||||||
Zone& zone,
|
|
||||||
const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir)
|
|
||||||
{
|
|
||||||
auto& memory = *zone.GetMemory();
|
|
||||||
|
|
||||||
if (ImageIPakPostProcessor<AssetImage>::AppliesToZoneDefinition(zoneDefinition))
|
|
||||||
collection.AddAssetPostProcessor(std::make_unique<ImageIPakPostProcessor<AssetImage>>(zoneDefinition, searchPath, zoneStates, outDir));
|
|
||||||
|
|
||||||
if (ImageIwdPostProcessor<AssetImage>::AppliesToZoneDefinition(zoneDefinition))
|
|
||||||
collection.AddAssetPostProcessor(std::make_unique<ImageIwdPostProcessor<AssetImage>>(zoneDefinition, searchPath, zoneStates, outDir));
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void ObjCompiler::ConfigureCreatorCollection(AssetCreatorCollection& collection,
|
|
||||||
Zone& zone,
|
|
||||||
const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
IGdtQueryable& gdt,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir,
|
|
||||||
IOutputPath& cacheDir) const
|
|
||||||
{
|
|
||||||
ConfigureCompilers(collection, zone, zoneDefinition, searchPath, zoneStates);
|
|
||||||
ConfigurePostProcessors(collection, zone, zoneDefinition, searchPath, zoneStates, outDir);
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "IObjCompiler.h"
|
|
||||||
|
|
||||||
namespace T6
|
|
||||||
{
|
|
||||||
class ObjCompiler final : public IObjCompiler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void ConfigureCreatorCollection(AssetCreatorCollection& collection,
|
|
||||||
Zone& zone,
|
|
||||||
const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
IGdtQueryable& gdt,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir,
|
|
||||||
IOutputPath& cacheDir) const override;
|
|
||||||
};
|
|
||||||
} // namespace T6
|
|
@ -1,27 +0,0 @@
|
|||||||
#include "IObjCompiler.h"
|
|
||||||
|
|
||||||
#include "Game/IW3/ObjCompilerIW3.h"
|
|
||||||
#include "Game/IW4/ObjCompilerIW4.h"
|
|
||||||
#include "Game/IW5/ObjCompilerIW5.h"
|
|
||||||
#include "Game/T5/ObjCompilerT5.h"
|
|
||||||
#include "Game/T6/ObjCompilerT6.h"
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
const IObjCompiler* IObjCompiler::GetObjCompilerForGame(GameId game)
|
|
||||||
{
|
|
||||||
static const IObjCompiler* objCompilers[static_cast<unsigned>(GameId::COUNT)]{
|
|
||||||
new IW3::ObjCompiler(),
|
|
||||||
new IW4::ObjCompiler(),
|
|
||||||
new IW5::ObjCompiler(),
|
|
||||||
new T5::ObjCompiler(),
|
|
||||||
new T6::ObjCompiler(),
|
|
||||||
};
|
|
||||||
static_assert(std::extent_v<decltype(objCompilers)> == static_cast<unsigned>(GameId::COUNT));
|
|
||||||
|
|
||||||
assert(static_cast<unsigned>(game) < static_cast<unsigned>(GameId::COUNT));
|
|
||||||
const auto* result = objCompilers[static_cast<unsigned>(game)];
|
|
||||||
assert(result);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Asset/AssetCreatorCollection.h"
|
|
||||||
#include "Asset/IZoneAssetCreationState.h"
|
|
||||||
#include "Asset/ZoneDefinitionContext.h"
|
|
||||||
#include "Gdt/IGdtQueryable.h"
|
|
||||||
#include "SearchPath/IOutputPath.h"
|
|
||||||
#include "SearchPath/ISearchPath.h"
|
|
||||||
#include "Zone/Zone.h"
|
|
||||||
|
|
||||||
class IObjCompiler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
IObjCompiler() = default;
|
|
||||||
virtual ~IObjCompiler() = default;
|
|
||||||
IObjCompiler(const IObjCompiler& other) = default;
|
|
||||||
IObjCompiler(IObjCompiler&& other) noexcept = default;
|
|
||||||
IObjCompiler& operator=(const IObjCompiler& other) = default;
|
|
||||||
IObjCompiler& operator=(IObjCompiler&& other) noexcept = default;
|
|
||||||
|
|
||||||
virtual void ConfigureCreatorCollection(AssetCreatorCollection& collection,
|
|
||||||
Zone& zone,
|
|
||||||
const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
IGdtQueryable& gdt,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir,
|
|
||||||
IOutputPath& cacheDir) const = 0;
|
|
||||||
|
|
||||||
static const IObjCompiler* GetObjCompilerForGame(GameId game);
|
|
||||||
};
|
|
@ -1,436 +0,0 @@
|
|||||||
#include "IPakCreator.h"
|
|
||||||
|
|
||||||
#include "Game/T6/CommonT6.h"
|
|
||||||
#include "Game/T6/GameT6.h"
|
|
||||||
#include "GitVersion.h"
|
|
||||||
#include "ObjContainer/IPak/IPakTypes.h"
|
|
||||||
#include "Utils/Alignment.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cassert>
|
|
||||||
#include <format>
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include <minilzo.h>
|
|
||||||
#include <zlib.h>
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
constexpr auto USE_IPAK_COMPRESSION = true;
|
|
||||||
|
|
||||||
class IPakWriter
|
|
||||||
{
|
|
||||||
static constexpr char BRANDING[] = "Created with OpenAssetTools " GIT_VERSION;
|
|
||||||
static constexpr auto SECTION_COUNT = 3; // Index + Data + Branding
|
|
||||||
|
|
||||||
inline static const std::string PAD_DATA = std::string(256, '\xA7');
|
|
||||||
|
|
||||||
public:
|
|
||||||
IPakWriter(std::ostream& stream, ISearchPath& searchPath, const std::vector<std::string>& images)
|
|
||||||
: m_stream(stream),
|
|
||||||
m_search_path(searchPath),
|
|
||||||
m_images(images),
|
|
||||||
m_current_offset(0),
|
|
||||||
m_total_size(0),
|
|
||||||
m_data_section_offset(0),
|
|
||||||
m_data_section_size(0u),
|
|
||||||
m_index_section_offset(0),
|
|
||||||
m_branding_section_offset(0),
|
|
||||||
m_file_offset(0u),
|
|
||||||
m_chunk_buffer_window_start(0),
|
|
||||||
m_current_block{},
|
|
||||||
m_current_block_header_offset(0)
|
|
||||||
{
|
|
||||||
m_decompressed_buffer = std::make_unique<char[]>(ipak_consts::IPAK_CHUNK_SIZE);
|
|
||||||
m_lzo_work_buffer = std::make_unique<char[]>(LZO1X_1_MEM_COMPRESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Write()
|
|
||||||
{
|
|
||||||
// We will write the header and sections later since they need complementary data
|
|
||||||
GoTo(sizeof(IPakHeader) + sizeof(IPakSection) * SECTION_COUNT);
|
|
||||||
AlignToChunk();
|
|
||||||
|
|
||||||
WriteDataSection();
|
|
||||||
WriteIndexSection();
|
|
||||||
WriteBrandingSection();
|
|
||||||
WriteFileEnding();
|
|
||||||
|
|
||||||
WriteHeaderData();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void GoTo(const int64_t offset)
|
|
||||||
{
|
|
||||||
m_stream.seekp(offset, std::ios::beg);
|
|
||||||
m_current_offset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Write(const void* data, const size_t dataSize)
|
|
||||||
{
|
|
||||||
m_stream.write(static_cast<const char*>(data), dataSize);
|
|
||||||
m_current_offset += dataSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Pad(const size_t paddingSize)
|
|
||||||
{
|
|
||||||
auto paddingSizeLeft = paddingSize;
|
|
||||||
while (paddingSizeLeft > 0)
|
|
||||||
{
|
|
||||||
const auto writeSize = std::min(paddingSizeLeft, PAD_DATA.size());
|
|
||||||
Write(PAD_DATA.data(), writeSize);
|
|
||||||
|
|
||||||
paddingSizeLeft -= writeSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AlignToChunk()
|
|
||||||
{
|
|
||||||
Pad(static_cast<size_t>(utils::Align(m_current_offset, static_cast<int64_t>(ipak_consts::IPAK_CHUNK_SIZE)) - m_current_offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AlignToBlockHeader()
|
|
||||||
{
|
|
||||||
Pad(static_cast<size_t>(utils::Align(m_current_offset, static_cast<int64_t>(sizeof(IPakDataBlockHeader))) - m_current_offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteHeaderData()
|
|
||||||
{
|
|
||||||
GoTo(0);
|
|
||||||
|
|
||||||
const IPakHeader header{ipak_consts::IPAK_MAGIC, ipak_consts::IPAK_VERSION, static_cast<uint32_t>(m_total_size), SECTION_COUNT};
|
|
||||||
|
|
||||||
const IPakSection dataSection{
|
|
||||||
ipak_consts::IPAK_DATA_SECTION,
|
|
||||||
static_cast<uint32_t>(m_data_section_offset),
|
|
||||||
static_cast<uint32_t>(m_data_section_size),
|
|
||||||
static_cast<uint32_t>(m_index_entries.size()),
|
|
||||||
};
|
|
||||||
|
|
||||||
const IPakSection indexSection{
|
|
||||||
ipak_consts::IPAK_INDEX_SECTION,
|
|
||||||
static_cast<uint32_t>(m_index_section_offset),
|
|
||||||
static_cast<uint32_t>(sizeof(IPakIndexEntry) * m_index_entries.size()),
|
|
||||||
static_cast<uint32_t>(m_index_entries.size()),
|
|
||||||
};
|
|
||||||
|
|
||||||
const IPakSection brandingSection{
|
|
||||||
ipak_consts::IPAK_BRANDING_SECTION,
|
|
||||||
static_cast<uint32_t>(m_branding_section_offset),
|
|
||||||
std::extent_v<decltype(BRANDING)>,
|
|
||||||
1,
|
|
||||||
};
|
|
||||||
|
|
||||||
Write(&header, sizeof(header));
|
|
||||||
Write(&dataSection, sizeof(dataSection));
|
|
||||||
Write(&indexSection, sizeof(indexSection));
|
|
||||||
Write(&brandingSection, sizeof(brandingSection));
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string ImageFileName(const std::string& imageName)
|
|
||||||
{
|
|
||||||
return std::format("images/{}.iwi", imageName);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<char[]> ReadImageDataFromSearchPath(const std::string& imageName, size_t& imageSize) const
|
|
||||||
{
|
|
||||||
const auto fileName = ImageFileName(imageName);
|
|
||||||
|
|
||||||
const auto openFile = m_search_path.Open(fileName);
|
|
||||||
if (!openFile.IsOpen())
|
|
||||||
{
|
|
||||||
std::cerr << std::format("Failed to open file for ipak: {}\n", fileName);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
imageSize = static_cast<size_t>(openFile.m_length);
|
|
||||||
auto imageData = std::make_unique<char[]>(imageSize);
|
|
||||||
openFile.m_stream->read(imageData.get(), imageSize);
|
|
||||||
|
|
||||||
return imageData;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlushBlock()
|
|
||||||
{
|
|
||||||
if (m_current_block_header_offset > 0)
|
|
||||||
{
|
|
||||||
const auto previousOffset = m_current_offset;
|
|
||||||
|
|
||||||
GoTo(m_current_block_header_offset);
|
|
||||||
Write(&m_current_block, sizeof(m_current_block));
|
|
||||||
GoTo(previousOffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlushChunk()
|
|
||||||
{
|
|
||||||
FlushBlock();
|
|
||||||
AlignToBlockHeader();
|
|
||||||
|
|
||||||
const auto nextChunkOffset = utils::Align(m_current_offset, static_cast<int64_t>(ipak_consts::IPAK_CHUNK_SIZE));
|
|
||||||
const auto sizeToSkip = static_cast<size_t>(nextChunkOffset - m_current_offset);
|
|
||||||
|
|
||||||
if (sizeToSkip >= sizeof(IPakDataBlockHeader))
|
|
||||||
{
|
|
||||||
IPakDataBlockHeader skipBlockHeader{};
|
|
||||||
skipBlockHeader.countAndOffset.count = 1;
|
|
||||||
skipBlockHeader.commands[0].compressed = ipak_consts::IPAK_COMMAND_SKIP;
|
|
||||||
skipBlockHeader.commands[0].size = sizeToSkip - sizeof(IPakDataBlockHeader);
|
|
||||||
Write(&skipBlockHeader, sizeof(skipBlockHeader));
|
|
||||||
}
|
|
||||||
|
|
||||||
AlignToChunk();
|
|
||||||
m_chunk_buffer_window_start = m_current_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StartNewBlock()
|
|
||||||
{
|
|
||||||
AlignToBlockHeader();
|
|
||||||
|
|
||||||
// Skip to the next chunk when only the header could fit into the current chunk anyway
|
|
||||||
if (static_cast<size_t>(utils::Align(m_current_offset, static_cast<int64_t>(ipak_consts::IPAK_CHUNK_SIZE)) - m_current_offset)
|
|
||||||
<= sizeof(IPakDataBlockHeader))
|
|
||||||
FlushChunk();
|
|
||||||
|
|
||||||
m_current_block_header_offset = m_current_offset;
|
|
||||||
m_current_block = {};
|
|
||||||
m_current_block.countAndOffset.offset = static_cast<uint32_t>(m_file_offset);
|
|
||||||
|
|
||||||
// Reserve space to later write actual block header data
|
|
||||||
GoTo(m_current_offset + sizeof(IPakDataBlockHeader));
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteChunkData(const void* data, const size_t dataSize)
|
|
||||||
{
|
|
||||||
auto dataOffset = 0u;
|
|
||||||
while (dataOffset < dataSize)
|
|
||||||
{
|
|
||||||
if (m_current_block.countAndOffset.count >= std::extent_v<decltype(IPakDataBlockHeader::commands)>)
|
|
||||||
{
|
|
||||||
FlushBlock();
|
|
||||||
StartNewBlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto remainingSize = dataSize - dataOffset;
|
|
||||||
const auto remainingChunkBufferWindowSize = std::max((ipak_consts::IPAK_CHUNK_COUNT_PER_READ * ipak_consts::IPAK_CHUNK_SIZE)
|
|
||||||
- static_cast<size_t>(m_current_offset - m_chunk_buffer_window_start),
|
|
||||||
0uz);
|
|
||||||
|
|
||||||
if (remainingChunkBufferWindowSize == 0)
|
|
||||||
{
|
|
||||||
FlushChunk();
|
|
||||||
StartNewBlock();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto commandSize = std::min(std::min(remainingSize, ipak_consts::IPAK_COMMAND_DEFAULT_SIZE), remainingChunkBufferWindowSize);
|
|
||||||
|
|
||||||
auto writeUncompressed = true;
|
|
||||||
if (USE_IPAK_COMPRESSION)
|
|
||||||
{
|
|
||||||
auto outLen = static_cast<lzo_uint>(ipak_consts::IPAK_CHUNK_SIZE);
|
|
||||||
const auto result = lzo1x_1_compress(&static_cast<const unsigned char*>(data)[dataOffset],
|
|
||||||
commandSize,
|
|
||||||
reinterpret_cast<unsigned char*>(m_decompressed_buffer.get()),
|
|
||||||
&outLen,
|
|
||||||
m_lzo_work_buffer.get());
|
|
||||||
|
|
||||||
if (result == LZO_E_OK && outLen < commandSize)
|
|
||||||
{
|
|
||||||
writeUncompressed = false;
|
|
||||||
Write(m_decompressed_buffer.get(), outLen);
|
|
||||||
|
|
||||||
const auto currentCommand = m_current_block.countAndOffset.count;
|
|
||||||
m_current_block.commands[currentCommand].size = static_cast<uint32_t>(outLen);
|
|
||||||
m_current_block.commands[currentCommand].compressed = ipak_consts::IPAK_COMMAND_COMPRESSED;
|
|
||||||
m_current_block.countAndOffset.count = currentCommand + 1u;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (writeUncompressed)
|
|
||||||
{
|
|
||||||
Write(&static_cast<const char*>(data)[dataOffset], commandSize);
|
|
||||||
|
|
||||||
const auto currentCommand = m_current_block.countAndOffset.count;
|
|
||||||
m_current_block.commands[currentCommand].size = commandSize;
|
|
||||||
m_current_block.commands[currentCommand].compressed = ipak_consts::IPAK_COMMAND_UNCOMPRESSED;
|
|
||||||
m_current_block.countAndOffset.count = currentCommand + 1u;
|
|
||||||
}
|
|
||||||
|
|
||||||
dataOffset += commandSize;
|
|
||||||
m_file_offset += commandSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StartNewFile()
|
|
||||||
{
|
|
||||||
FlushBlock();
|
|
||||||
|
|
||||||
m_file_offset = 0u;
|
|
||||||
StartNewBlock();
|
|
||||||
m_chunk_buffer_window_start = utils::AlignToPrevious(m_current_offset, static_cast<int64_t>(ipak_consts::IPAK_CHUNK_SIZE));
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteImageData(const std::string& imageName)
|
|
||||||
{
|
|
||||||
size_t imageSize;
|
|
||||||
const auto imageData = ReadImageDataFromSearchPath(imageName, imageSize);
|
|
||||||
if (!imageData)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const auto nameHash = T6::Common::R_HashString(imageName.c_str(), 0);
|
|
||||||
const auto dataHash = static_cast<unsigned>(crc32(0u, reinterpret_cast<const Bytef*>(imageData.get()), imageSize));
|
|
||||||
|
|
||||||
StartNewFile();
|
|
||||||
const auto startOffset = m_current_block_header_offset;
|
|
||||||
|
|
||||||
IPakIndexEntry indexEntry;
|
|
||||||
indexEntry.key.nameHash = nameHash;
|
|
||||||
indexEntry.key.dataHash = dataHash & 0x1FFFFFFF;
|
|
||||||
indexEntry.offset = static_cast<uint32_t>(startOffset - m_data_section_offset);
|
|
||||||
|
|
||||||
WriteChunkData(imageData.get(), imageSize);
|
|
||||||
const auto writtenImageSize = static_cast<size_t>(m_current_offset - startOffset);
|
|
||||||
|
|
||||||
indexEntry.size = writtenImageSize;
|
|
||||||
m_index_entries.emplace_back(indexEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteDataSection()
|
|
||||||
{
|
|
||||||
AlignToChunk();
|
|
||||||
m_data_section_offset = m_current_offset;
|
|
||||||
m_data_section_size = 0u;
|
|
||||||
|
|
||||||
m_index_entries.reserve(m_images.size());
|
|
||||||
|
|
||||||
for (const auto& imageName : m_images)
|
|
||||||
WriteImageData(imageName);
|
|
||||||
|
|
||||||
FlushBlock();
|
|
||||||
m_data_section_size = static_cast<size_t>(m_current_offset - m_data_section_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool CompareIndices(const IPakIndexEntry& entry1, const IPakIndexEntry& entry2)
|
|
||||||
{
|
|
||||||
return entry1.key.combinedKey < entry2.key.combinedKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SortIndexSectionEntries()
|
|
||||||
{
|
|
||||||
std::ranges::sort(m_index_entries, CompareIndices);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteIndexSection()
|
|
||||||
{
|
|
||||||
AlignToChunk();
|
|
||||||
m_index_section_offset = m_current_offset;
|
|
||||||
|
|
||||||
SortIndexSectionEntries();
|
|
||||||
|
|
||||||
for (const auto& indexEntry : m_index_entries)
|
|
||||||
Write(&indexEntry, sizeof(indexEntry));
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteBrandingSection()
|
|
||||||
{
|
|
||||||
AlignToChunk();
|
|
||||||
m_branding_section_offset = m_current_offset;
|
|
||||||
|
|
||||||
Write(BRANDING, std::extent_v<decltype(BRANDING)>);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteFileEnding()
|
|
||||||
{
|
|
||||||
AlignToChunk();
|
|
||||||
m_total_size = m_current_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& m_stream;
|
|
||||||
ISearchPath& m_search_path;
|
|
||||||
const std::vector<std::string>& m_images;
|
|
||||||
|
|
||||||
int64_t m_current_offset;
|
|
||||||
std::vector<IPakIndexEntry> m_index_entries;
|
|
||||||
int64_t m_total_size;
|
|
||||||
int64_t m_data_section_offset;
|
|
||||||
size_t m_data_section_size;
|
|
||||||
int64_t m_index_section_offset;
|
|
||||||
int64_t m_branding_section_offset;
|
|
||||||
|
|
||||||
std::unique_ptr<char[]> m_decompressed_buffer;
|
|
||||||
std::unique_ptr<char[]> m_lzo_work_buffer;
|
|
||||||
size_t m_file_offset;
|
|
||||||
int64_t m_chunk_buffer_window_start;
|
|
||||||
IPakDataBlockHeader m_current_block;
|
|
||||||
int64_t m_current_block_header_offset;
|
|
||||||
};
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
IPakToCreate::IPakToCreate(std::string name)
|
|
||||||
: m_name(std::move(name))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void IPakToCreate::AddImage(std::string imageName)
|
|
||||||
{
|
|
||||||
m_image_names.emplace_back(std::move(imageName));
|
|
||||||
}
|
|
||||||
|
|
||||||
void IPakToCreate::Build(ISearchPath& searchPath, IOutputPath& outPath)
|
|
||||||
{
|
|
||||||
const auto file = outPath.Open(std::format("{}.ipak", m_name));
|
|
||||||
if (!file)
|
|
||||||
{
|
|
||||||
std::cerr << std::format("Failed to open file for ipak {}\n", m_name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPakWriter writer(*file, searchPath, m_image_names);
|
|
||||||
writer.Write();
|
|
||||||
|
|
||||||
std::cout << std::format("Created ipak {} with {} entries\n", m_name, m_image_names.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<std::string>& IPakToCreate::GetImageNames() const
|
|
||||||
{
|
|
||||||
return m_image_names;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPakCreator::IPakCreator()
|
|
||||||
: m_kvp_creator(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void IPakCreator::Inject(ZoneAssetCreationInjection& inject)
|
|
||||||
{
|
|
||||||
m_kvp_creator = &inject.m_zone_states.GetZoneAssetCreationState<KeyValuePairsCreator>();
|
|
||||||
}
|
|
||||||
|
|
||||||
IPakToCreate* IPakCreator::GetOrAddIPak(const std::string& ipakName)
|
|
||||||
{
|
|
||||||
const auto existingIPak = m_ipak_lookup.find(ipakName);
|
|
||||||
if (existingIPak != m_ipak_lookup.end())
|
|
||||||
return existingIPak->second;
|
|
||||||
|
|
||||||
auto newIPak = std::make_unique<IPakToCreate>(ipakName);
|
|
||||||
auto* result = newIPak.get();
|
|
||||||
m_ipak_lookup.emplace(ipakName, result);
|
|
||||||
m_ipaks.emplace_back(std::move(newIPak));
|
|
||||||
|
|
||||||
assert(m_kvp_creator);
|
|
||||||
m_kvp_creator->AddKeyValuePair(CommonKeyValuePair("ipak_read", ipakName));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IPakCreator::Finalize(ISearchPath& searchPath, IOutputPath& outPath)
|
|
||||||
{
|
|
||||||
for (const auto& ipakToCreate : m_ipaks)
|
|
||||||
ipakToCreate->Build(searchPath, outPath);
|
|
||||||
|
|
||||||
m_ipaks.clear();
|
|
||||||
m_ipak_lookup.clear();
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Asset/IZoneAssetCreationState.h"
|
|
||||||
#include "KeyValuePairs/KeyValuePairsCreator.h"
|
|
||||||
#include "SearchPath/IOutputPath.h"
|
|
||||||
#include "SearchPath/ISearchPath.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
class IPakToCreate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit IPakToCreate(std::string name);
|
|
||||||
|
|
||||||
void AddImage(std::string imageName);
|
|
||||||
void Build(ISearchPath& searchPath, IOutputPath& outPath);
|
|
||||||
[[nodiscard]] const std::vector<std::string>& GetImageNames() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string m_name;
|
|
||||||
std::vector<std::string> m_image_names;
|
|
||||||
};
|
|
||||||
|
|
||||||
class IPakCreator final : public IZoneAssetCreationState
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
IPakCreator();
|
|
||||||
|
|
||||||
void Inject(ZoneAssetCreationInjection& inject) override;
|
|
||||||
|
|
||||||
IPakToCreate* GetOrAddIPak(const std::string& ipakName);
|
|
||||||
void Finalize(ISearchPath& searchPath, IOutputPath& outPath);
|
|
||||||
|
|
||||||
private:
|
|
||||||
KeyValuePairsCreator* m_kvp_creator;
|
|
||||||
std::unordered_map<std::string, IPakToCreate*> m_ipak_lookup;
|
|
||||||
std::vector<std::unique_ptr<IPakToCreate>> m_ipaks;
|
|
||||||
};
|
|
@ -1,66 +0,0 @@
|
|||||||
#include "ImageIPakPostProcessor.h"
|
|
||||||
|
|
||||||
#include "IPak/IPakCreator.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
AbstractImageIPakPostProcessor::AbstractImageIPakPostProcessor(const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir)
|
|
||||||
: m_zone_definition(zoneDefinition),
|
|
||||||
m_search_path(searchPath),
|
|
||||||
m_ipak_creator(zoneStates.GetZoneAssetCreationState<IPakCreator>()),
|
|
||||||
m_out_dir(outDir),
|
|
||||||
m_obj_container_index(0u),
|
|
||||||
m_current_ipak(nullptr),
|
|
||||||
m_current_ipak_start_index(0u),
|
|
||||||
m_current_ipak_end_index(0u)
|
|
||||||
{
|
|
||||||
FindNextObjContainer();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AbstractImageIPakPostProcessor::AppliesToZoneDefinition(const ZoneDefinitionContext& zoneDefinition)
|
|
||||||
{
|
|
||||||
return std::ranges::any_of(zoneDefinition.m_zone_definition.m_obj_containers,
|
|
||||||
[](const ZoneDefinitionObjContainer& objContainer)
|
|
||||||
{
|
|
||||||
return objContainer.m_type == ZoneDefinitionObjContainerType::IPAK;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void AbstractImageIPakPostProcessor::FindNextObjContainer()
|
|
||||||
{
|
|
||||||
const auto objContainerCount = m_zone_definition.m_zone_definition.m_obj_containers.size();
|
|
||||||
while (m_obj_container_index < objContainerCount)
|
|
||||||
{
|
|
||||||
const auto& objContainer = m_zone_definition.m_zone_definition.m_obj_containers[m_obj_container_index++];
|
|
||||||
|
|
||||||
if (objContainer.m_type != ZoneDefinitionObjContainerType::IPAK)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
m_current_ipak = m_ipak_creator.GetOrAddIPak(objContainer.m_name);
|
|
||||||
m_current_ipak_start_index = objContainer.m_asset_start;
|
|
||||||
m_current_ipak_end_index = objContainer.m_asset_end;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_current_ipak = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AbstractImageIPakPostProcessor::PostProcessAsset(XAssetInfoGeneric& assetInfo, AssetCreationContext& context)
|
|
||||||
{
|
|
||||||
if (assetInfo.m_name.empty() || assetInfo.m_name[0] == ',')
|
|
||||||
return;
|
|
||||||
|
|
||||||
while (m_current_ipak && m_zone_definition.m_asset_index_in_definition >= m_current_ipak_end_index)
|
|
||||||
FindNextObjContainer();
|
|
||||||
|
|
||||||
if (m_current_ipak && m_zone_definition.m_asset_index_in_definition >= m_current_ipak_start_index)
|
|
||||||
m_current_ipak->AddImage(assetInfo.m_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AbstractImageIPakPostProcessor::FinalizeZone(AssetCreationContext& context)
|
|
||||||
{
|
|
||||||
m_ipak_creator.Finalize(m_search_path, m_out_dir);
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Asset/IAssetPostProcessor.h"
|
|
||||||
#include "Asset/ZoneDefinitionContext.h"
|
|
||||||
#include "Image/IPak/IPakCreator.h"
|
|
||||||
#include "SearchPath/IOutputPath.h"
|
|
||||||
|
|
||||||
class AbstractImageIPakPostProcessor : public IAssetPostProcessor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AbstractImageIPakPostProcessor(const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir);
|
|
||||||
|
|
||||||
static bool AppliesToZoneDefinition(const ZoneDefinitionContext& zoneDefinition);
|
|
||||||
|
|
||||||
void PostProcessAsset(XAssetInfoGeneric& assetInfo, AssetCreationContext& context) override;
|
|
||||||
void FinalizeZone(AssetCreationContext& context) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void FindNextObjContainer();
|
|
||||||
|
|
||||||
const ZoneDefinitionContext& m_zone_definition;
|
|
||||||
ISearchPath& m_search_path;
|
|
||||||
IPakCreator& m_ipak_creator;
|
|
||||||
IOutputPath& m_out_dir;
|
|
||||||
|
|
||||||
unsigned m_obj_container_index;
|
|
||||||
IPakToCreate* m_current_ipak;
|
|
||||||
unsigned m_current_ipak_start_index;
|
|
||||||
unsigned m_current_ipak_end_index;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename AssetType> class ImageIPakPostProcessor final : public AbstractImageIPakPostProcessor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
|
|
||||||
|
|
||||||
ImageIPakPostProcessor(const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir)
|
|
||||||
: AbstractImageIPakPostProcessor(zoneDefinition, searchPath, zoneStates, outDir)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] asset_type_t GetHandlingAssetType() const override
|
|
||||||
{
|
|
||||||
return AssetType::EnumEntry;
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,67 +0,0 @@
|
|||||||
#include "ImageIwdPostProcessor.h"
|
|
||||||
|
|
||||||
#include "Iwd/IwdCreator.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <format>
|
|
||||||
|
|
||||||
AbstractImageIwdPostProcessor::AbstractImageIwdPostProcessor(const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir)
|
|
||||||
: m_zone_definition(zoneDefinition),
|
|
||||||
m_search_path(searchPath),
|
|
||||||
m_iwd_creator(zoneStates.GetZoneAssetCreationState<IwdCreator>()),
|
|
||||||
m_out_dir(outDir),
|
|
||||||
m_obj_container_index(0u),
|
|
||||||
m_current_iwd(nullptr),
|
|
||||||
m_current_iwd_start_index(0u),
|
|
||||||
m_current_iwd_end_index(0u)
|
|
||||||
{
|
|
||||||
FindNextObjContainer();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AbstractImageIwdPostProcessor::AppliesToZoneDefinition(const ZoneDefinitionContext& zoneDefinition)
|
|
||||||
{
|
|
||||||
return std::ranges::any_of(zoneDefinition.m_zone_definition.m_obj_containers,
|
|
||||||
[](const ZoneDefinitionObjContainer& objContainer)
|
|
||||||
{
|
|
||||||
return objContainer.m_type == ZoneDefinitionObjContainerType::IWD;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void AbstractImageIwdPostProcessor::FindNextObjContainer()
|
|
||||||
{
|
|
||||||
const auto objContainerCount = m_zone_definition.m_zone_definition.m_obj_containers.size();
|
|
||||||
while (m_obj_container_index < objContainerCount)
|
|
||||||
{
|
|
||||||
const auto& objContainer = m_zone_definition.m_zone_definition.m_obj_containers[m_obj_container_index++];
|
|
||||||
|
|
||||||
if (objContainer.m_type != ZoneDefinitionObjContainerType::IWD)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
m_current_iwd = m_iwd_creator.GetOrAddIwd(objContainer.m_name);
|
|
||||||
m_current_iwd_start_index = objContainer.m_asset_start;
|
|
||||||
m_current_iwd_end_index = objContainer.m_asset_end;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_current_iwd = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AbstractImageIwdPostProcessor::PostProcessAsset(XAssetInfoGeneric& assetInfo, AssetCreationContext& context)
|
|
||||||
{
|
|
||||||
if (assetInfo.m_name.empty() || assetInfo.m_name[0] == ',')
|
|
||||||
return;
|
|
||||||
|
|
||||||
while (m_current_iwd && m_zone_definition.m_asset_index_in_definition >= m_current_iwd_end_index)
|
|
||||||
FindNextObjContainer();
|
|
||||||
|
|
||||||
if (m_current_iwd && m_zone_definition.m_asset_index_in_definition >= m_current_iwd_start_index)
|
|
||||||
m_current_iwd->AddFile(std::format("images/{}.iwi", assetInfo.m_name));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AbstractImageIwdPostProcessor::FinalizeZone(AssetCreationContext& context)
|
|
||||||
{
|
|
||||||
m_iwd_creator.Finalize(m_search_path, m_out_dir);
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Asset/IAssetPostProcessor.h"
|
|
||||||
#include "Asset/ZoneDefinitionContext.h"
|
|
||||||
#include "Iwd/IwdCreator.h"
|
|
||||||
#include "SearchPath/IOutputPath.h"
|
|
||||||
|
|
||||||
class AbstractImageIwdPostProcessor : public IAssetPostProcessor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AbstractImageIwdPostProcessor(const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir);
|
|
||||||
|
|
||||||
static bool AppliesToZoneDefinition(const ZoneDefinitionContext& zoneDefinition);
|
|
||||||
|
|
||||||
void PostProcessAsset(XAssetInfoGeneric& assetInfo, AssetCreationContext& context) override;
|
|
||||||
void FinalizeZone(AssetCreationContext& context) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void FindNextObjContainer();
|
|
||||||
|
|
||||||
const ZoneDefinitionContext& m_zone_definition;
|
|
||||||
ISearchPath& m_search_path;
|
|
||||||
IwdCreator& m_iwd_creator;
|
|
||||||
IOutputPath& m_out_dir;
|
|
||||||
|
|
||||||
unsigned m_obj_container_index;
|
|
||||||
IwdToCreate* m_current_iwd;
|
|
||||||
unsigned m_current_iwd_start_index;
|
|
||||||
unsigned m_current_iwd_end_index;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename AssetType> class ImageIwdPostProcessor final : public AbstractImageIwdPostProcessor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
|
|
||||||
|
|
||||||
ImageIwdPostProcessor(const ZoneDefinitionContext& zoneDefinition,
|
|
||||||
ISearchPath& searchPath,
|
|
||||||
ZoneAssetCreationStateContainer& zoneStates,
|
|
||||||
IOutputPath& outDir)
|
|
||||||
: AbstractImageIwdPostProcessor(zoneDefinition, searchPath, zoneStates, outDir)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] asset_type_t GetHandlingAssetType() const override
|
|
||||||
{
|
|
||||||
return AssetType::EnumEntry;
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,109 +0,0 @@
|
|||||||
#include "IwdCreator.h"
|
|
||||||
|
|
||||||
#include "Utils/FileToZlibWrapper.h"
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <format>
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include <zip.h>
|
|
||||||
|
|
||||||
IwdToCreate::IwdToCreate(std::string name)
|
|
||||||
: m_name(std::move(name))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void IwdToCreate::AddFile(std::string filePath)
|
|
||||||
{
|
|
||||||
m_file_paths.emplace_back(std::move(filePath));
|
|
||||||
}
|
|
||||||
|
|
||||||
void IwdToCreate::Build(ISearchPath& searchPath, IOutputPath& outPath)
|
|
||||||
{
|
|
||||||
const auto fileName = std::format("{}.iwd", m_name);
|
|
||||||
const auto file = outPath.Open(fileName);
|
|
||||||
if (!file)
|
|
||||||
{
|
|
||||||
std::cerr << std::format("Failed to open file for iwd {}\n", m_name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto functions = FileToZlibWrapper::CreateFunctions32ForFile(file.get());
|
|
||||||
|
|
||||||
const auto zipFile = zipOpen2(fileName.c_str(), APPEND_STATUS_CREATE, nullptr, &functions);
|
|
||||||
if (!zipFile)
|
|
||||||
{
|
|
||||||
std::cerr << std::format("Failed to open file as zip for iwd {}\n", m_name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& filePath : m_file_paths)
|
|
||||||
{
|
|
||||||
auto readFile = searchPath.Open(filePath);
|
|
||||||
if (!readFile.IsOpen())
|
|
||||||
{
|
|
||||||
std::cerr << std::format("Failed to open file for iwd: {}\n", filePath);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto localNow = std::chrono::zoned_time{std::chrono::current_zone(), std::chrono::system_clock::now()}.get_local_time();
|
|
||||||
auto nowDays = std::chrono::floor<std::chrono::days>(localNow);
|
|
||||||
std::chrono::year_month_day ymd(std::chrono::floor<std::chrono::days>(localNow));
|
|
||||||
std::chrono::hh_mm_ss hms(std::chrono::floor<std::chrono::milliseconds>(localNow - nowDays));
|
|
||||||
|
|
||||||
zip_fileinfo fileInfo{};
|
|
||||||
fileInfo.dosDate = 0u;
|
|
||||||
fileInfo.tmz_date.tm_year = static_cast<int>(ymd.year());
|
|
||||||
fileInfo.tmz_date.tm_mon = static_cast<int>(static_cast<unsigned>(ymd.month()) - static_cast<unsigned>(std::chrono::January));
|
|
||||||
fileInfo.tmz_date.tm_mday = static_cast<int>(static_cast<unsigned>(ymd.day()));
|
|
||||||
fileInfo.tmz_date.tm_hour = static_cast<int>(hms.hours().count());
|
|
||||||
fileInfo.tmz_date.tm_min = static_cast<int>(hms.minutes().count());
|
|
||||||
fileInfo.tmz_date.tm_sec = static_cast<int>(hms.seconds().count());
|
|
||||||
zipOpenNewFileInZip(zipFile, filePath.c_str(), &fileInfo, nullptr, 0, nullptr, 0, nullptr, Z_DEFLATED, Z_DEFAULT_COMPRESSION);
|
|
||||||
|
|
||||||
char tempBuffer[0x1000];
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
readFile.m_stream->read(tempBuffer, sizeof(tempBuffer));
|
|
||||||
const auto readCount = readFile.m_stream->gcount();
|
|
||||||
if (readCount > 0)
|
|
||||||
zipWriteInFileInZip(zipFile, tempBuffer, static_cast<unsigned>(readCount));
|
|
||||||
} while (!readFile.m_stream->eof());
|
|
||||||
|
|
||||||
zipCloseFileInZip(zipFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
zipClose(zipFile, nullptr);
|
|
||||||
|
|
||||||
std::cout << std::format("Created iwd {} with {} entries\n", m_name, m_file_paths.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<std::string>& IwdToCreate::GetFilePaths() const
|
|
||||||
{
|
|
||||||
return m_file_paths;
|
|
||||||
}
|
|
||||||
|
|
||||||
IwdToCreate* IwdCreator::GetOrAddIwd(const std::string& iwdName)
|
|
||||||
{
|
|
||||||
const auto existingIwd = m_iwd_lookup.find(iwdName);
|
|
||||||
if (existingIwd != m_iwd_lookup.end())
|
|
||||||
return existingIwd->second;
|
|
||||||
|
|
||||||
auto newIwd = std::make_unique<IwdToCreate>(iwdName);
|
|
||||||
auto* result = newIwd.get();
|
|
||||||
m_iwd_lookup.emplace(iwdName, result);
|
|
||||||
m_iwds.emplace_back(std::move(newIwd));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IwdCreator::Finalize(ISearchPath& searchPath, IOutputPath& outPath)
|
|
||||||
{
|
|
||||||
std::cout << std::format("Writing {} iwd files to disk\n", m_iwds.size());
|
|
||||||
for (const auto& iwdToCreate : m_iwds)
|
|
||||||
iwdToCreate->Build(searchPath, outPath);
|
|
||||||
|
|
||||||
m_iwds.clear();
|
|
||||||
m_iwd_lookup.clear();
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Asset/IZoneAssetCreationState.h"
|
|
||||||
#include "SearchPath/IOutputPath.h"
|
|
||||||
#include "SearchPath/ISearchPath.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
class IwdToCreate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit IwdToCreate(std::string name);
|
|
||||||
|
|
||||||
void AddFile(std::string filePath);
|
|
||||||
void Build(ISearchPath& searchPath, IOutputPath& outPath);
|
|
||||||
[[nodiscard]] const std::vector<std::string>& GetFilePaths() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string m_name;
|
|
||||||
std::vector<std::string> m_file_paths;
|
|
||||||
};
|
|
||||||
|
|
||||||
class IwdCreator final : public IZoneAssetCreationState
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
IwdToCreate* GetOrAddIwd(const std::string& iwdName);
|
|
||||||
void Finalize(ISearchPath& searchPath, IOutputPath& outPath);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::unordered_map<std::string, IwdToCreate*> m_iwd_lookup;
|
|
||||||
std::vector<std::unique_ptr<IwdToCreate>> m_iwds;
|
|
||||||
};
|
|
@ -1,76 +0,0 @@
|
|||||||
#include "KeyValuePairsCreator.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <format>
|
|
||||||
#include <iostream>
|
|
||||||
#include <ranges>
|
|
||||||
|
|
||||||
CommonKeyValuePair::CommonKeyValuePair(std::string keyStr, std::string value)
|
|
||||||
: m_key_str(std::move(keyStr)),
|
|
||||||
m_value(std::move(value))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CommonKeyValuePair::CommonKeyValuePair(const unsigned keyHash, std::string value)
|
|
||||||
: m_key_hash(keyHash),
|
|
||||||
m_value(std::move(value))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyValuePairsCreator::AddKeyValuePair(CommonKeyValuePair keyValuePair)
|
|
||||||
{
|
|
||||||
m_key_value_pairs.emplace_back(std::move(keyValuePair));
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyValuePairsCreator::Finalize(const ZoneDefinition& zoneDefinition)
|
|
||||||
{
|
|
||||||
for (const auto& metaData : zoneDefinition.m_properties.m_properties)
|
|
||||||
{
|
|
||||||
if (metaData.first.rfind("level.", 0) == 0)
|
|
||||||
{
|
|
||||||
std::string strValue = metaData.first.substr(std::char_traits<char>::length("level."));
|
|
||||||
if (strValue.empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (strValue[0] == '@')
|
|
||||||
{
|
|
||||||
char* endPtr;
|
|
||||||
const unsigned keyHash = strtoul(&strValue[1], &endPtr, 16);
|
|
||||||
|
|
||||||
if (endPtr != &strValue[strValue.size()])
|
|
||||||
{
|
|
||||||
std::cerr << std::format("Could not parse metadata key \"{}\" as hash\n", metaData.first);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_key_value_pairs.emplace_back(keyHash, metaData.second);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_key_value_pairs.emplace_back(std::move(strValue), metaData.second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ranges::sort(m_key_value_pairs,
|
|
||||||
[](const CommonKeyValuePair& v0, const CommonKeyValuePair& v1)
|
|
||||||
{
|
|
||||||
if (v0.m_key_str.has_value())
|
|
||||||
{
|
|
||||||
if (!v1.m_key_str.has_value())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return *v0.m_key_str < *v1.m_key_str;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!v1.m_key_hash.has_value())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return *v0.m_key_hash < *v1.m_key_hash;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<CommonKeyValuePair> KeyValuePairsCreator::GetFinalKeyValuePairs()
|
|
||||||
{
|
|
||||||
return std::move(m_key_value_pairs);
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Asset/IZoneAssetCreationState.h"
|
|
||||||
#include "Zone/Definition/ZoneDefinition.h"
|
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
class CommonKeyValuePair
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CommonKeyValuePair(std::string keyStr, std::string value);
|
|
||||||
CommonKeyValuePair(unsigned keyHash, std::string value);
|
|
||||||
|
|
||||||
std::optional<std::string> m_key_str;
|
|
||||||
std::optional<unsigned> m_key_hash;
|
|
||||||
std::string m_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
class KeyValuePairsCreator final : public IZoneAssetCreationState
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void AddKeyValuePair(CommonKeyValuePair keyValuePair);
|
|
||||||
void Finalize(const ZoneDefinition& zoneDefinition);
|
|
||||||
std::vector<CommonKeyValuePair> GetFinalKeyValuePairs();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<CommonKeyValuePair> m_key_value_pairs;
|
|
||||||
};
|
|
@ -184,11 +184,7 @@ namespace dds
|
|||||||
m_width = header.dwWidth;
|
m_width = header.dwWidth;
|
||||||
m_height = header.dwHeight;
|
m_height = header.dwHeight;
|
||||||
m_depth = header.dwDepth;
|
m_depth = header.dwDepth;
|
||||||
|
m_has_mip_maps = (header.dwCaps & DDSCAPS_MIPMAP) != 0 || header.dwMipMapCount > 1;
|
||||||
// Best thing to do here would be to check (header.dwCaps & DDSCAPS_MIPMAP) != 0 but some tools just create bad files
|
|
||||||
// I encountered both files that have the flag without them actually having mipmaps (mipMapCount == 1)
|
|
||||||
// and also files that have mipMapCount > 1 but not the flag
|
|
||||||
m_has_mip_maps = header.dwMipMapCount > 1;
|
|
||||||
|
|
||||||
if (header.dwCaps2 & DDSCAPS2_CUBEMAP)
|
if (header.dwCaps2 & DDSCAPS2_CUBEMAP)
|
||||||
m_texture_type = TextureType::T_CUBE;
|
m_texture_type = TextureType::T_CUBE;
|
||||||
|
@ -1,196 +0,0 @@
|
|||||||
#include "AssetCreationContext.h"
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <format>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
IgnoredAssetLookup::IgnoredAssetLookup() = default;
|
|
||||||
|
|
||||||
IgnoredAssetLookup::IgnoredAssetLookup(const AssetList& assetList)
|
|
||||||
{
|
|
||||||
m_ignored_asset_lookup.reserve(assetList.m_entries.size());
|
|
||||||
for (const auto& asset : assetList.m_entries)
|
|
||||||
{
|
|
||||||
m_ignored_asset_lookup.emplace(asset.m_name, asset.m_type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IgnoredAssetLookup::IsAssetIgnored(asset_type_t assetType, const std::string& name) const
|
|
||||||
{
|
|
||||||
const auto entries = m_ignored_asset_lookup.equal_range(name);
|
|
||||||
|
|
||||||
for (auto i = entries.first; i != entries.second; ++i)
|
|
||||||
{
|
|
||||||
if (i->second == assetType)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GenericAssetRegistration::GenericAssetRegistration(const asset_type_t type, std::string name, void* asset)
|
|
||||||
: m_type(type),
|
|
||||||
m_name(std::move(name)),
|
|
||||||
m_asset(asset)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void GenericAssetRegistration::AddDependency(XAssetInfoGeneric* dependency)
|
|
||||||
{
|
|
||||||
m_dependencies.emplace(dependency);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GenericAssetRegistration::AddScriptString(scr_string_t scriptString)
|
|
||||||
{
|
|
||||||
m_used_script_strings.emplace(scriptString);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GenericAssetRegistration::AddIndirectAssetReference(IndirectAssetReference indirectAssetReference)
|
|
||||||
{
|
|
||||||
m_indirect_asset_references.emplace(std::move(indirectAssetReference));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<XAssetInfoGeneric> GenericAssetRegistration::CreateXAssetInfo()
|
|
||||||
{
|
|
||||||
assert(m_asset);
|
|
||||||
|
|
||||||
std::vector<XAssetInfoGeneric*> dependencies(m_dependencies.begin(), m_dependencies.end());
|
|
||||||
std::vector<scr_string_t> scriptStrings(m_used_script_strings.begin(), m_used_script_strings.end());
|
|
||||||
std::vector<IndirectAssetReference> indirectAssetReferences(m_indirect_asset_references.begin(), m_indirect_asset_references.end());
|
|
||||||
|
|
||||||
return std::make_unique<XAssetInfoGeneric>(
|
|
||||||
m_type, std::move(m_name), m_asset, std::move(dependencies), std::move(scriptStrings), std::move(indirectAssetReferences));
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetCreationContext::AssetCreationContext(Zone& zone, const AssetCreatorCollection* creators, const IgnoredAssetLookup* ignoredAssetLookup)
|
|
||||||
: ZoneAssetCreationStateContainer(zone),
|
|
||||||
m_zone(zone),
|
|
||||||
m_forced_asset_pools(ZoneAssetPools::CreateForGame(zone.m_game->GetId(), &zone, zone.m_priority)),
|
|
||||||
m_creators(creators),
|
|
||||||
m_ignored_asset_lookup(ignoredAssetLookup),
|
|
||||||
m_forced_load_depth(0u)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
XAssetInfoGeneric* AssetCreationContext::AddAssetGeneric(GenericAssetRegistration registration) const
|
|
||||||
{
|
|
||||||
auto xAssetInfo = registration.CreateXAssetInfo();
|
|
||||||
xAssetInfo->m_zone = &m_zone;
|
|
||||||
|
|
||||||
const auto assetType = xAssetInfo->m_type;
|
|
||||||
const auto* pAssetName = xAssetInfo->m_name.c_str();
|
|
||||||
|
|
||||||
XAssetInfoGeneric* addedAsset;
|
|
||||||
if (m_forced_load_depth > 0)
|
|
||||||
addedAsset = m_forced_asset_pools->AddAsset(std::move(xAssetInfo));
|
|
||||||
else
|
|
||||||
addedAsset = m_zone.m_pools->AddAsset(std::move(xAssetInfo));
|
|
||||||
|
|
||||||
if (addedAsset == nullptr)
|
|
||||||
std::cerr << std::format("Failed to add asset of type \"{}\" to pool: \"{}\"\n", *m_zone.m_pools->GetAssetTypeName(assetType), pAssetName);
|
|
||||||
return addedAsset;
|
|
||||||
}
|
|
||||||
|
|
||||||
XAssetInfoGeneric* AssetCreationContext::LoadDefaultAssetDependency(const asset_type_t assetType, const std::string& assetName)
|
|
||||||
{
|
|
||||||
const auto result = m_creators->CreateDefaultAsset(assetType, assetName, *this);
|
|
||||||
if (result.HasTakenAction() && !result.HasFailed())
|
|
||||||
return result.GetAssetInfo();
|
|
||||||
|
|
||||||
std::cerr << std::format("Failed to create default asset of type {}\n", *m_zone.m_pools->GetAssetTypeName(assetType));
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
XAssetInfoGeneric* AssetCreationContext::LoadDependencyGeneric(const asset_type_t assetType, const std::string& assetName)
|
|
||||||
{
|
|
||||||
auto* alreadyLoadedAsset = m_zone.m_pools->GetAssetOrAssetReference(assetType, assetName);
|
|
||||||
if (alreadyLoadedAsset)
|
|
||||||
return alreadyLoadedAsset;
|
|
||||||
|
|
||||||
if (m_forced_load_depth > 0)
|
|
||||||
{
|
|
||||||
alreadyLoadedAsset = m_forced_asset_pools->GetAssetOrAssetReference(assetType, assetName);
|
|
||||||
if (alreadyLoadedAsset)
|
|
||||||
return alreadyLoadedAsset;
|
|
||||||
|
|
||||||
// If we are already force loading an asset we should not load its dependencies
|
|
||||||
return LoadDefaultAssetDependency(assetType, std::format(",{}", assetName));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_ignored_asset_lookup->IsAssetIgnored(assetType, assetName))
|
|
||||||
return LoadDefaultAssetDependency(assetType, std::format(",{}", assetName));
|
|
||||||
|
|
||||||
const auto result = m_creators->CreateAsset(assetType, assetName, *this);
|
|
||||||
if (result.HasTakenAction())
|
|
||||||
{
|
|
||||||
if (!result.HasFailed())
|
|
||||||
return result.GetAssetInfo();
|
|
||||||
|
|
||||||
std::cerr << std::format("Could not load asset \"{}\" of type \"{}\"\n", assetName, *m_zone.m_pools->GetAssetTypeName(assetType));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::cerr << std::format("Missing asset \"{}\" of type \"{}\"\n", assetName, *m_zone.m_pools->GetAssetTypeName(assetType));
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
IndirectAssetReference AssetCreationContext::LoadIndirectAssetReferenceGeneric(const asset_type_t assetType, const std::string& assetName)
|
|
||||||
{
|
|
||||||
const auto* alreadyLoadedAsset = m_zone.m_pools->GetAssetOrAssetReference(assetType, assetName);
|
|
||||||
if (alreadyLoadedAsset)
|
|
||||||
return IndirectAssetReference(assetType, assetName);
|
|
||||||
|
|
||||||
if (m_ignored_asset_lookup->IsAssetIgnored(assetType, assetName))
|
|
||||||
return IndirectAssetReference(assetType, assetName);
|
|
||||||
|
|
||||||
const auto result = m_creators->CreateAsset(assetType, assetName, *this);
|
|
||||||
if (!result.HasTakenAction() && !result.HasFailed())
|
|
||||||
{
|
|
||||||
std::cerr << std::format("Could not load indirectly referenced asset \"{}\" of type \"{}\"\n", assetName, *m_zone.m_pools->GetAssetTypeName(assetType));
|
|
||||||
}
|
|
||||||
return IndirectAssetReference(assetType, assetName);
|
|
||||||
}
|
|
||||||
|
|
||||||
XAssetInfoGeneric* AssetCreationContext::ForceLoadDependencyGeneric(const asset_type_t assetType, const std::string& assetName)
|
|
||||||
{
|
|
||||||
auto* alreadyLoadedAsset = m_zone.m_pools->GetAssetOrAssetReference(assetType, assetName);
|
|
||||||
if (alreadyLoadedAsset && !alreadyLoadedAsset->IsReference())
|
|
||||||
return alreadyLoadedAsset;
|
|
||||||
alreadyLoadedAsset = m_forced_asset_pools->GetAssetOrAssetReference(assetType, assetName);
|
|
||||||
if (alreadyLoadedAsset && !alreadyLoadedAsset->IsReference())
|
|
||||||
return alreadyLoadedAsset;
|
|
||||||
|
|
||||||
auto result = AssetCreationResult::NoAction();
|
|
||||||
if (m_ignored_asset_lookup->IsAssetIgnored(assetType, assetName))
|
|
||||||
{
|
|
||||||
// Load default asset to zone
|
|
||||||
if (!LoadDefaultAssetDependency(assetType, std::format(",{}", assetName)))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
++m_forced_load_depth;
|
|
||||||
|
|
||||||
result = m_creators->CreateAsset(assetType, assetName, *this);
|
|
||||||
|
|
||||||
assert(m_forced_load_depth > 0);
|
|
||||||
m_forced_load_depth = std::min(m_forced_load_depth - 1u, 0u);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
result = m_creators->CreateAsset(assetType, assetName, *this);
|
|
||||||
|
|
||||||
if (result.HasTakenAction())
|
|
||||||
{
|
|
||||||
if (!result.HasFailed())
|
|
||||||
return result.GetAssetInfo();
|
|
||||||
|
|
||||||
std::cerr << std::format("Could not load asset \"{}\" of type \"{}\"\n", assetName, *m_zone.m_pools->GetAssetTypeName(assetType));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::cerr << std::format("Missing asset \"{}\" of type \"{}\"\n", assetName, *m_zone.m_pools->GetAssetTypeName(assetType));
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
@ -1,95 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Asset/IZoneAssetCreationState.h"
|
|
||||||
#include "AssetRegistration.h"
|
|
||||||
#include "Game/IAsset.h"
|
|
||||||
#include "Pool/XAssetInfo.h"
|
|
||||||
#include "Zone/AssetList/AssetList.h"
|
|
||||||
#include "Zone/ZoneTypes.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <unordered_set>
|
|
||||||
|
|
||||||
class AssetCreatorCollection;
|
|
||||||
|
|
||||||
class IgnoredAssetLookup
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
IgnoredAssetLookup();
|
|
||||||
explicit IgnoredAssetLookup(const AssetList& assetList);
|
|
||||||
|
|
||||||
[[nodiscard]] bool IsAssetIgnored(asset_type_t assetType, const std::string& name) const;
|
|
||||||
|
|
||||||
std::unordered_multimap<std::string, asset_type_t> m_ignored_asset_lookup;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AssetCreationContext : public ZoneAssetCreationStateContainer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AssetCreationContext(Zone& zone, const AssetCreatorCollection* creators, const IgnoredAssetLookup* ignoredAssetLookup);
|
|
||||||
|
|
||||||
template<typename AssetType> XAssetInfo<typename AssetType::Type>* AddAsset(AssetRegistration<AssetType> registration)
|
|
||||||
{
|
|
||||||
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
|
|
||||||
|
|
||||||
return static_cast<XAssetInfo<typename AssetType::Type>*>(AddAssetGeneric(std::move(registration)));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename AssetType> XAssetInfo<typename AssetType::Type>* AddAsset(std::string assetName, typename AssetType::Type* asset)
|
|
||||||
{
|
|
||||||
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
|
|
||||||
|
|
||||||
return static_cast<XAssetInfo<typename AssetType::Type>*>(AddAssetGeneric(AssetRegistration<AssetType>(std::move(assetName), asset)));
|
|
||||||
}
|
|
||||||
|
|
||||||
XAssetInfoGeneric* AddAssetGeneric(GenericAssetRegistration registration) const;
|
|
||||||
|
|
||||||
template<typename AssetType> XAssetInfo<typename AssetType::Type>* LoadDependency(const std::string& assetName)
|
|
||||||
{
|
|
||||||
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
|
|
||||||
|
|
||||||
return static_cast<XAssetInfo<typename AssetType::Type>*>(LoadDependencyGeneric(AssetType::EnumEntry, assetName));
|
|
||||||
}
|
|
||||||
|
|
||||||
XAssetInfoGeneric* LoadDependencyGeneric(asset_type_t assetType, const std::string& assetName);
|
|
||||||
|
|
||||||
template<typename AssetType> IndirectAssetReference LoadIndirectAssetReference(const std::string& assetName)
|
|
||||||
{
|
|
||||||
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
|
|
||||||
|
|
||||||
return LoadIndirectAssetReferenceGeneric(AssetType::EnumEntry, assetName);
|
|
||||||
}
|
|
||||||
|
|
||||||
IndirectAssetReference LoadIndirectAssetReferenceGeneric(asset_type_t assetType, const std::string& assetName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Loads an asset dependency like \c LoadDependency but guarantees that the returned asset is not a reference.
|
|
||||||
* If normally a reference would be created, the actual asset is loaded but a reference is added to the zone.
|
|
||||||
* \tparam AssetType The type of the asset
|
|
||||||
* \param assetName The name of the asset
|
|
||||||
* \return XAssetInfo of the asset that is guaranteed to not be a reference or \c nullptr
|
|
||||||
*/
|
|
||||||
template<typename AssetType> XAssetInfo<typename AssetType::Type>* ForceLoadDependency(const std::string& assetName)
|
|
||||||
{
|
|
||||||
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
|
|
||||||
|
|
||||||
return static_cast<XAssetInfo<typename AssetType::Type>*>(ForceLoadDependencyGeneric(AssetType::EnumEntry, assetName));
|
|
||||||
}
|
|
||||||
|
|
||||||
XAssetInfoGeneric* ForceLoadDependencyGeneric(asset_type_t assetType, const std::string& assetName);
|
|
||||||
|
|
||||||
private:
|
|
||||||
[[nodiscard]] XAssetInfoGeneric* LoadDefaultAssetDependency(asset_type_t assetType, const std::string& assetName);
|
|
||||||
|
|
||||||
Zone& m_zone;
|
|
||||||
std::unique_ptr<ZoneAssetPools> m_forced_asset_pools;
|
|
||||||
const AssetCreatorCollection* m_creators;
|
|
||||||
const IgnoredAssetLookup* m_ignored_asset_lookup;
|
|
||||||
|
|
||||||
unsigned m_forced_load_depth;
|
|
||||||
};
|
|
||||||
|
|
||||||
#include "AssetCreatorCollection.h"
|
|
@ -1,45 +0,0 @@
|
|||||||
#include "AssetCreationResult.h"
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
AssetCreationResult AssetCreationResult::Success(XAssetInfoGeneric* assetInfo)
|
|
||||||
{
|
|
||||||
assert(assetInfo);
|
|
||||||
return AssetCreationResult(true, assetInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetCreationResult AssetCreationResult::Failure()
|
|
||||||
{
|
|
||||||
return AssetCreationResult(true, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetCreationResult AssetCreationResult::NoAction()
|
|
||||||
{
|
|
||||||
return AssetCreationResult(false, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AssetCreationResult::HasBeenSuccessful() const
|
|
||||||
{
|
|
||||||
return m_taken_action && m_asset_info != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AssetCreationResult::HasTakenAction() const
|
|
||||||
{
|
|
||||||
return m_taken_action;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AssetCreationResult::HasFailed() const
|
|
||||||
{
|
|
||||||
return m_taken_action && m_asset_info == nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
XAssetInfoGeneric* AssetCreationResult::GetAssetInfo() const
|
|
||||||
{
|
|
||||||
return m_asset_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetCreationResult::AssetCreationResult(const bool takenAction, XAssetInfoGeneric* assetInfo)
|
|
||||||
: m_taken_action(takenAction),
|
|
||||||
m_asset_info(assetInfo)
|
|
||||||
{
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Pool/XAssetInfo.h"
|
|
||||||
|
|
||||||
class AssetCreationResult
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static AssetCreationResult Success(XAssetInfoGeneric* assetInfo);
|
|
||||||
static AssetCreationResult Failure();
|
|
||||||
static AssetCreationResult NoAction();
|
|
||||||
|
|
||||||
[[nodiscard]] bool HasBeenSuccessful() const;
|
|
||||||
[[nodiscard]] bool HasTakenAction() const;
|
|
||||||
[[nodiscard]] bool HasFailed() const;
|
|
||||||
[[nodiscard]] XAssetInfoGeneric* GetAssetInfo() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
AssetCreationResult(bool takenAction, XAssetInfoGeneric* assetInfo);
|
|
||||||
|
|
||||||
bool m_taken_action;
|
|
||||||
XAssetInfoGeneric* m_asset_info;
|
|
||||||
};
|
|
@ -1,88 +0,0 @@
|
|||||||
#include "AssetCreatorCollection.h"
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
AssetCreatorCollection::AssetCreatorCollection(const Zone& zone)
|
|
||||||
{
|
|
||||||
m_asset_creators_by_type.resize(zone.m_pools->GetAssetTypeCount());
|
|
||||||
m_asset_post_processors_by_type.resize(zone.m_pools->GetAssetTypeCount());
|
|
||||||
m_default_asset_creators_by_type.resize(zone.m_pools->GetAssetTypeCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetCreatorCollection::AddAssetCreator(std::unique_ptr<IAssetCreator> creator)
|
|
||||||
{
|
|
||||||
const auto maybeHandlingAssetType = creator->GetHandlingAssetType();
|
|
||||||
assert(!maybeHandlingAssetType || static_cast<unsigned>(*maybeHandlingAssetType) < m_asset_creators_by_type.size());
|
|
||||||
if (maybeHandlingAssetType && static_cast<unsigned>(*maybeHandlingAssetType) < m_asset_creators_by_type.size())
|
|
||||||
m_asset_creators_by_type[static_cast<unsigned>(*maybeHandlingAssetType)].emplace_back(creator.get());
|
|
||||||
|
|
||||||
m_asset_creators.emplace_back(std::move(creator));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetCreatorCollection::AddAssetPostProcessor(std::unique_ptr<IAssetPostProcessor> postProcessor)
|
|
||||||
{
|
|
||||||
const auto handlingAssetType = postProcessor->GetHandlingAssetType();
|
|
||||||
assert(static_cast<unsigned>(handlingAssetType) < m_asset_post_processors_by_type.size());
|
|
||||||
if (static_cast<unsigned>(handlingAssetType) < m_asset_post_processors_by_type.size())
|
|
||||||
m_asset_post_processors_by_type[static_cast<unsigned>(handlingAssetType)].emplace_back(postProcessor.get());
|
|
||||||
|
|
||||||
m_asset_post_processors.emplace_back(std::move(postProcessor));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetCreatorCollection::AddDefaultAssetCreator(std::unique_ptr<IDefaultAssetCreator> defaultAssetCreator)
|
|
||||||
{
|
|
||||||
const auto handlingAssetType = defaultAssetCreator->GetHandlingAssetType();
|
|
||||||
assert(static_cast<unsigned>(handlingAssetType) < m_default_asset_creators_by_type.size());
|
|
||||||
assert(!m_default_asset_creators_by_type[handlingAssetType]);
|
|
||||||
|
|
||||||
if (static_cast<unsigned>(handlingAssetType) < m_default_asset_creators_by_type.size())
|
|
||||||
m_default_asset_creators_by_type[handlingAssetType] = std::move(defaultAssetCreator);
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetCreationResult AssetCreatorCollection::CreateAsset(const asset_type_t assetType, const std::string& assetName, AssetCreationContext& context) const
|
|
||||||
{
|
|
||||||
assert(assetType >= 0 && static_cast<unsigned>(assetType) < m_asset_creators_by_type.size());
|
|
||||||
|
|
||||||
if (assetType >= 0 && static_cast<unsigned>(assetType) < m_asset_creators_by_type.size())
|
|
||||||
{
|
|
||||||
for (const auto& creator : m_asset_creators_by_type[assetType])
|
|
||||||
{
|
|
||||||
const auto result = creator->CreateAsset(assetName, context);
|
|
||||||
if (result.HasTakenAction())
|
|
||||||
{
|
|
||||||
// Post process asset if creation was successful
|
|
||||||
if (result.HasBeenSuccessful())
|
|
||||||
{
|
|
||||||
assert(static_cast<unsigned>(assetType) < m_asset_post_processors_by_type.size());
|
|
||||||
for (auto* postProcessor : m_asset_post_processors_by_type[assetType])
|
|
||||||
postProcessor->PostProcessAsset(*result.GetAssetInfo(), context);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return result that was either successful or failed
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return AssetCreationResult::NoAction();
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetCreationResult AssetCreatorCollection::CreateDefaultAsset(const asset_type_t assetType, const std::string& assetName, AssetCreationContext& context) const
|
|
||||||
{
|
|
||||||
assert(assetType >= 0 && static_cast<unsigned>(assetType) < m_default_asset_creators_by_type.size());
|
|
||||||
|
|
||||||
if (assetType >= 0 && static_cast<unsigned>(assetType) < m_default_asset_creators_by_type.size() && m_default_asset_creators_by_type[assetType])
|
|
||||||
{
|
|
||||||
return m_default_asset_creators_by_type[assetType]->CreateDefaultAsset(assetName, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
return AssetCreationResult::NoAction();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetCreatorCollection::FinalizeZone(AssetCreationContext& context) const
|
|
||||||
{
|
|
||||||
for (const auto& creator : m_asset_creators)
|
|
||||||
creator->FinalizeZone(context);
|
|
||||||
for (const auto& postProcessor : m_asset_post_processors)
|
|
||||||
postProcessor->FinalizeZone(context);
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "AssetCreationContext.h"
|
|
||||||
#include "Game/IGame.h"
|
|
||||||
#include "IAssetCreator.h"
|
|
||||||
#include "IAssetPostProcessor.h"
|
|
||||||
#include "IDefaultAssetCreator.h"
|
|
||||||
#include "Zone/ZoneTypes.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
class AssetCreationContext;
|
|
||||||
class IAssetCreator;
|
|
||||||
class IAssetPostProcessor;
|
|
||||||
class AssetCreationResult;
|
|
||||||
class IDefaultAssetCreator;
|
|
||||||
|
|
||||||
class AssetCreatorCollection
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit AssetCreatorCollection(const Zone& zone);
|
|
||||||
|
|
||||||
void AddAssetCreator(std::unique_ptr<IAssetCreator> creator);
|
|
||||||
void AddAssetPostProcessor(std::unique_ptr<IAssetPostProcessor> postProcessor);
|
|
||||||
void AddDefaultAssetCreator(std::unique_ptr<IDefaultAssetCreator> defaultAssetCreator);
|
|
||||||
|
|
||||||
AssetCreationResult CreateAsset(asset_type_t assetType, const std::string& assetName, AssetCreationContext& context) const;
|
|
||||||
AssetCreationResult CreateDefaultAsset(asset_type_t assetType, const std::string& assetName, AssetCreationContext& context) const;
|
|
||||||
void FinalizeZone(AssetCreationContext& context) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<std::vector<IAssetCreator*>> m_asset_creators_by_type;
|
|
||||||
std::vector<std::unique_ptr<IAssetCreator>> m_asset_creators;
|
|
||||||
std::vector<std::vector<IAssetPostProcessor*>> m_asset_post_processors_by_type;
|
|
||||||
std::vector<std::unique_ptr<IAssetPostProcessor>> m_asset_post_processors;
|
|
||||||
std::vector<std::unique_ptr<IDefaultAssetCreator>> m_default_asset_creators_by_type;
|
|
||||||
};
|
|
@ -1,61 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Game/IAsset.h"
|
|
||||||
#include "Pool/XAssetInfo.h"
|
|
||||||
#include "Zone/ZoneTypes.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_set>
|
|
||||||
|
|
||||||
class GenericAssetRegistration
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
GenericAssetRegistration(asset_type_t type, std::string name, void* asset);
|
|
||||||
|
|
||||||
public:
|
|
||||||
GenericAssetRegistration(const GenericAssetRegistration& other) = delete;
|
|
||||||
GenericAssetRegistration(GenericAssetRegistration&& other) = default;
|
|
||||||
GenericAssetRegistration& operator=(const GenericAssetRegistration& other) = delete;
|
|
||||||
GenericAssetRegistration& operator=(GenericAssetRegistration&& other) noexcept = default;
|
|
||||||
|
|
||||||
void AddDependency(XAssetInfoGeneric* dependency);
|
|
||||||
void AddScriptString(scr_string_t scriptString);
|
|
||||||
void AddIndirectAssetReference(IndirectAssetReference indirectAssetReference);
|
|
||||||
|
|
||||||
std::unique_ptr<XAssetInfoGeneric> CreateXAssetInfo();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
asset_type_t m_type;
|
|
||||||
std::string m_name;
|
|
||||||
void* m_asset;
|
|
||||||
std::unordered_set<XAssetInfoGeneric*> m_dependencies;
|
|
||||||
std::unordered_set<scr_string_t> m_used_script_strings;
|
|
||||||
std::unordered_set<IndirectAssetReference> m_indirect_asset_references;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename AssetType> class AssetRegistration : public GenericAssetRegistration
|
|
||||||
{
|
|
||||||
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
|
|
||||||
|
|
||||||
public:
|
|
||||||
AssetRegistration(std::string assetName)
|
|
||||||
: GenericAssetRegistration(AssetType::EnumEntry, std::move(assetName), nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetRegistration(std::string assetName, typename AssetType::Type* asset)
|
|
||||||
: GenericAssetRegistration(AssetType::EnumEntry, std::move(assetName), asset)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetRegistration(const AssetRegistration& other) = delete;
|
|
||||||
AssetRegistration(AssetRegistration&& other) = default;
|
|
||||||
AssetRegistration& operator=(const AssetRegistration& other) = delete;
|
|
||||||
AssetRegistration& operator=(AssetRegistration&& other) noexcept = default;
|
|
||||||
|
|
||||||
void SetAsset(typename AssetType::Type* asset)
|
|
||||||
{
|
|
||||||
m_asset = asset;
|
|
||||||
}
|
|
||||||
};
|
|
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