mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-20 00:02:55 +00:00
Merge pull request #286 from Laupetin/feature/obj-container-improvements
feat: improve building IWD and IPak obj containers
This commit is contained in:
commit
a781aae1c9
@ -126,6 +126,7 @@ 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"
|
||||||
@ -143,6 +144,7 @@ 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()
|
||||||
@ -168,6 +170,7 @@ group ""
|
|||||||
-- ========================
|
-- ========================
|
||||||
-- Tests
|
-- Tests
|
||||||
-- ========================
|
-- ========================
|
||||||
|
include "test/ObjCommonTestUtils.lua"
|
||||||
include "test/ObjCommonTests.lua"
|
include "test/ObjCommonTests.lua"
|
||||||
include "test/ObjLoadingTests.lua"
|
include "test/ObjLoadingTests.lua"
|
||||||
include "test/ParserTestUtils.lua"
|
include "test/ParserTestUtils.lua"
|
||||||
@ -177,6 +180,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"
|
||||||
|
ObjCommonTestUtils:project()
|
||||||
ObjCommonTests:project()
|
ObjCommonTests:project()
|
||||||
ObjLoadingTests:project()
|
ObjLoadingTests:project()
|
||||||
ParserTestUtils:project()
|
ParserTestUtils:project()
|
||||||
|
6
scripts/check-format-docker.sh
Executable file
6
scripts/check-format-docker.sh
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Go to repository root
|
||||||
|
cd "$(dirname "$0")/.." || exit 2
|
||||||
|
|
||||||
|
docker run --rm -v ".:/code" --user "$(id -u):$(id -g)" silkeh/clang:17 /code/scripts/check-format.sh
|
6
scripts/reformat-all-docker.sh
Executable file
6
scripts/reformat-all-docker.sh
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Go to repository root
|
||||||
|
cd "$(dirname "$0")/.." || exit 2
|
||||||
|
|
||||||
|
docker run --rm -v ".:/code" --user "$(id -u):$(id -g)" silkeh/clang:17 /code/scripts/reformat-all.sh
|
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
#include "Zone/ZoneTypes.h"
|
#include "Zone/ZoneTypes.h"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
struct IAssetBase
|
struct IAssetBase
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
@ -12,3 +15,42 @@ 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,3 +113,32 @@ 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,3 +168,41 @@ 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,3 +179,44 @@ 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,5 +148,38 @@ 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
|
} // namespace T5
|
||||||
|
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetPhysPreset, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetPhysConstraints, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetDestructibleDef, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetXAnim, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetXModel, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetMaterial, info.name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetTechniqueSet, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetImage, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetSoundBank, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetSoundPatch, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetClipMap, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetClipMapPvs, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetComWorld, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetGameWorldSp, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetGameWorldMp, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetMapEnts, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetGfxWorld, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetLightDef, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetFont, fontName);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetMenuList, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetMenu, window.name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetLocalize, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetWeapon, szInternalName);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetSoundDriverGlobals, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetFx, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR_SINGLETON(T5::AssetImpactFx, "ImpactFx");
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetRawFile, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetStringTable, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetPackIndex, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetXGlobals, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetDDL, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR(T5::AssetGlasses, name);
|
||||||
|
DEFINE_ASSET_NAME_ACCESSOR_SINGLETON(T5::AssetEmblemSet, "EmblemSet");
|
||||||
|
@ -1311,7 +1311,7 @@ namespace T5
|
|||||||
|
|
||||||
struct SndPatch
|
struct SndPatch
|
||||||
{
|
{
|
||||||
char* name;
|
const char* name;
|
||||||
unsigned int elementCount;
|
unsigned int elementCount;
|
||||||
unsigned int* elements;
|
unsigned int* elements;
|
||||||
unsigned int fileCount;
|
unsigned int fileCount;
|
||||||
|
@ -209,3 +209,53 @@ 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;
|
||||||
int numVariables;
|
unsigned int numVariables;
|
||||||
KeyValuePair* keyValuePairs;
|
KeyValuePair* keyValuePairs;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -5569,8 +5569,8 @@ namespace T6
|
|||||||
|
|
||||||
struct KeyValuePair
|
struct KeyValuePair
|
||||||
{
|
{
|
||||||
int keyHash;
|
unsigned int keyHash;
|
||||||
int namespaceHash;
|
unsigned int namespaceHash;
|
||||||
const char* value;
|
const char* value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ 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)
|
||||||
@ -46,6 +47,7 @@ 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)
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
#include "ZoneCreatorIW3.h"
|
|
||||||
|
|
||||||
#include "AssetLoading/AssetLoadingContext.h"
|
|
||||||
#include "Game/IW3/GameAssetPoolIW3.h"
|
|
||||||
#include "Game/IW3/GameIW3.h"
|
|
||||||
#include "IObjLoader.h"
|
|
||||||
#include "ObjLoading.h"
|
|
||||||
#include "Utils/StringUtils.h"
|
|
||||||
|
|
||||||
using namespace IW3;
|
|
||||||
|
|
||||||
std::vector<Gdt*> ZoneCreator::CreateGdtList(const ZoneCreationContext& context)
|
|
||||||
{
|
|
||||||
std::vector<Gdt*> gdtList;
|
|
||||||
gdtList.reserve(context.m_gdt_files.size());
|
|
||||||
for (const auto& gdt : context.m_gdt_files)
|
|
||||||
gdtList.push_back(gdt.get());
|
|
||||||
|
|
||||||
return gdtList;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneCreator::ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext)
|
|
||||||
{
|
|
||||||
for (const auto& ignoreEntry : creationContext.m_ignored_assets.m_entries)
|
|
||||||
loadingContext.m_ignored_asset_map[ignoreEntry.m_name] = ignoreEntry.m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneCreator::CreateZoneAssetPools(Zone* zone) const
|
|
||||||
{
|
|
||||||
zone->m_pools = std::make_unique<GameAssetPoolIW3>(zone, zone->m_priority);
|
|
||||||
|
|
||||||
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
|
|
||||||
zone->m_pools->InitPoolDynamic(assetType);
|
|
||||||
}
|
|
||||||
|
|
||||||
GameId ZoneCreator::GetGameId() const
|
|
||||||
{
|
|
||||||
return GameId::IW3;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
|
|
||||||
{
|
|
||||||
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, IGame::GetGameById(GameId::IW3));
|
|
||||||
CreateZoneAssetPools(zone.get());
|
|
||||||
|
|
||||||
for (const auto& assetEntry : context.m_definition->m_assets)
|
|
||||||
{
|
|
||||||
if (!assetEntry.m_is_reference)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
|
|
||||||
ApplyIgnoredAssets(context, *assetLoadingContext);
|
|
||||||
|
|
||||||
const auto* objLoader = IObjLoader::GetObjLoaderForGame(GameId::IW3);
|
|
||||||
for (const auto& assetEntry : context.m_definition->m_assets)
|
|
||||||
{
|
|
||||||
if (!objLoader->LoadAssetForZone(*assetLoadingContext, assetEntry.m_asset_type, assetEntry.m_asset_name))
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
objLoader->FinalizeAssetsForZone(*assetLoadingContext);
|
|
||||||
|
|
||||||
return zone;
|
|
||||||
}
|
|
||||||
|
|
||||||
asset_type_t ZoneCreator::GetImageAssetType() const
|
|
||||||
{
|
|
||||||
return ASSET_TYPE_IMAGE;
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "AssetLoading/AssetLoadingContext.h"
|
|
||||||
#include "Zone/ZoneTypes.h"
|
|
||||||
#include "ZoneCreation/ZoneCreator.h"
|
|
||||||
|
|
||||||
namespace IW3
|
|
||||||
{
|
|
||||||
class ZoneCreator final : public IZoneCreator
|
|
||||||
{
|
|
||||||
static std::vector<Gdt*> CreateGdtList(const ZoneCreationContext& context);
|
|
||||||
static void ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext);
|
|
||||||
void CreateZoneAssetPools(Zone* zone) const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
[[nodiscard]] GameId GetGameId() const override;
|
|
||||||
[[nodiscard]] std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
|
|
||||||
[[nodiscard]] asset_type_t GetImageAssetType() const override;
|
|
||||||
};
|
|
||||||
} // namespace IW3
|
|
@ -1,71 +0,0 @@
|
|||||||
#include "ZoneCreatorIW4.h"
|
|
||||||
|
|
||||||
#include "Game/IW4/GameAssetPoolIW4.h"
|
|
||||||
#include "Game/IW4/GameIW4.h"
|
|
||||||
#include "IObjLoader.h"
|
|
||||||
#include "ObjLoading.h"
|
|
||||||
#include "Utils/StringUtils.h"
|
|
||||||
|
|
||||||
using namespace IW4;
|
|
||||||
|
|
||||||
std::vector<Gdt*> ZoneCreator::CreateGdtList(const ZoneCreationContext& context)
|
|
||||||
{
|
|
||||||
std::vector<Gdt*> gdtList;
|
|
||||||
gdtList.reserve(context.m_gdt_files.size());
|
|
||||||
for (const auto& gdt : context.m_gdt_files)
|
|
||||||
gdtList.push_back(gdt.get());
|
|
||||||
|
|
||||||
return gdtList;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneCreator::ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext)
|
|
||||||
{
|
|
||||||
for (const auto& ignoreEntry : creationContext.m_ignored_assets.m_entries)
|
|
||||||
loadingContext.m_ignored_asset_map[ignoreEntry.m_name] = ignoreEntry.m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneCreator::CreateZoneAssetPools(Zone* zone) const
|
|
||||||
{
|
|
||||||
zone->m_pools = std::make_unique<GameAssetPoolIW4>(zone, zone->m_priority);
|
|
||||||
|
|
||||||
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
|
|
||||||
zone->m_pools->InitPoolDynamic(assetType);
|
|
||||||
}
|
|
||||||
|
|
||||||
GameId ZoneCreator::GetGameId() const
|
|
||||||
{
|
|
||||||
return GameId::IW4;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
|
|
||||||
{
|
|
||||||
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, IGame::GetGameById(GameId::IW4));
|
|
||||||
CreateZoneAssetPools(zone.get());
|
|
||||||
|
|
||||||
for (const auto& assetEntry : context.m_definition->m_assets)
|
|
||||||
{
|
|
||||||
if (!assetEntry.m_is_reference)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
|
|
||||||
ApplyIgnoredAssets(context, *assetLoadingContext);
|
|
||||||
|
|
||||||
const auto* objLoader = IObjLoader::GetObjLoaderForGame(GameId::IW4);
|
|
||||||
for (const auto& assetEntry : context.m_definition->m_assets)
|
|
||||||
{
|
|
||||||
if (!objLoader->LoadAssetForZone(*assetLoadingContext, assetEntry.m_asset_type, assetEntry.m_asset_name))
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
objLoader->FinalizeAssetsForZone(*assetLoadingContext);
|
|
||||||
|
|
||||||
return zone;
|
|
||||||
}
|
|
||||||
|
|
||||||
asset_type_t ZoneCreator::GetImageAssetType() const
|
|
||||||
{
|
|
||||||
return ASSET_TYPE_IMAGE;
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "AssetLoading/AssetLoadingContext.h"
|
|
||||||
#include "Zone/ZoneTypes.h"
|
|
||||||
#include "ZoneCreation/ZoneCreator.h"
|
|
||||||
|
|
||||||
namespace IW4
|
|
||||||
{
|
|
||||||
class ZoneCreator final : public IZoneCreator
|
|
||||||
{
|
|
||||||
static std::vector<Gdt*> CreateGdtList(const ZoneCreationContext& context);
|
|
||||||
static void ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext);
|
|
||||||
void CreateZoneAssetPools(Zone* zone) const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
[[nodiscard]] GameId GetGameId() const override;
|
|
||||||
[[nodiscard]] std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
|
|
||||||
[[nodiscard]] asset_type_t GetImageAssetType() const override;
|
|
||||||
};
|
|
||||||
} // namespace IW4
|
|
@ -1,71 +0,0 @@
|
|||||||
#include "ZoneCreatorIW5.h"
|
|
||||||
|
|
||||||
#include "Game/IW5/GameAssetPoolIW5.h"
|
|
||||||
#include "Game/IW5/GameIW5.h"
|
|
||||||
#include "IObjLoader.h"
|
|
||||||
#include "ObjLoading.h"
|
|
||||||
#include "Utils/StringUtils.h"
|
|
||||||
|
|
||||||
using namespace IW5;
|
|
||||||
|
|
||||||
std::vector<Gdt*> ZoneCreator::CreateGdtList(const ZoneCreationContext& context)
|
|
||||||
{
|
|
||||||
std::vector<Gdt*> gdtList;
|
|
||||||
gdtList.reserve(context.m_gdt_files.size());
|
|
||||||
for (const auto& gdt : context.m_gdt_files)
|
|
||||||
gdtList.push_back(gdt.get());
|
|
||||||
|
|
||||||
return gdtList;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneCreator::ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext)
|
|
||||||
{
|
|
||||||
for (const auto& ignoreEntry : creationContext.m_ignored_assets.m_entries)
|
|
||||||
loadingContext.m_ignored_asset_map[ignoreEntry.m_name] = ignoreEntry.m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneCreator::CreateZoneAssetPools(Zone* zone) const
|
|
||||||
{
|
|
||||||
zone->m_pools = std::make_unique<GameAssetPoolIW5>(zone, zone->m_priority);
|
|
||||||
|
|
||||||
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
|
|
||||||
zone->m_pools->InitPoolDynamic(assetType);
|
|
||||||
}
|
|
||||||
|
|
||||||
GameId ZoneCreator::GetGameId() const
|
|
||||||
{
|
|
||||||
return GameId::IW5;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
|
|
||||||
{
|
|
||||||
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, IGame::GetGameById(GameId::IW5));
|
|
||||||
CreateZoneAssetPools(zone.get());
|
|
||||||
|
|
||||||
for (const auto& assetEntry : context.m_definition->m_assets)
|
|
||||||
{
|
|
||||||
if (!assetEntry.m_is_reference)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
|
|
||||||
ApplyIgnoredAssets(context, *assetLoadingContext);
|
|
||||||
|
|
||||||
const auto* objLoader = IObjLoader::GetObjLoaderForGame(GameId::IW5);
|
|
||||||
for (const auto& assetEntry : context.m_definition->m_assets)
|
|
||||||
{
|
|
||||||
if (!objLoader->LoadAssetForZone(*assetLoadingContext, assetEntry.m_asset_type, assetEntry.m_asset_name))
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
objLoader->FinalizeAssetsForZone(*assetLoadingContext);
|
|
||||||
|
|
||||||
return zone;
|
|
||||||
}
|
|
||||||
|
|
||||||
asset_type_t ZoneCreator::GetImageAssetType() const
|
|
||||||
{
|
|
||||||
return ASSET_TYPE_IMAGE;
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "AssetLoading/AssetLoadingContext.h"
|
|
||||||
#include "Zone/ZoneTypes.h"
|
|
||||||
#include "ZoneCreation/ZoneCreator.h"
|
|
||||||
|
|
||||||
namespace IW5
|
|
||||||
{
|
|
||||||
class ZoneCreator final : public IZoneCreator
|
|
||||||
{
|
|
||||||
static std::vector<Gdt*> CreateGdtList(const ZoneCreationContext& context);
|
|
||||||
static void ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext);
|
|
||||||
void CreateZoneAssetPools(Zone* zone) const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
[[nodiscard]] GameId GetGameId() const override;
|
|
||||||
[[nodiscard]] std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
|
|
||||||
[[nodiscard]] asset_type_t GetImageAssetType() const override;
|
|
||||||
};
|
|
||||||
} // namespace IW5
|
|
@ -1,72 +0,0 @@
|
|||||||
#include "ZoneCreatorT5.h"
|
|
||||||
|
|
||||||
#include "AssetLoading/AssetLoadingContext.h"
|
|
||||||
#include "Game/T5/GameAssetPoolT5.h"
|
|
||||||
#include "Game/T5/GameT5.h"
|
|
||||||
#include "IObjLoader.h"
|
|
||||||
#include "ObjLoading.h"
|
|
||||||
#include "Utils/StringUtils.h"
|
|
||||||
|
|
||||||
using namespace T5;
|
|
||||||
|
|
||||||
std::vector<Gdt*> ZoneCreator::CreateGdtList(ZoneCreationContext& context)
|
|
||||||
{
|
|
||||||
std::vector<Gdt*> gdtList;
|
|
||||||
gdtList.reserve(context.m_gdt_files.size());
|
|
||||||
for (const auto& gdt : context.m_gdt_files)
|
|
||||||
gdtList.push_back(gdt.get());
|
|
||||||
|
|
||||||
return gdtList;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneCreator::ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext)
|
|
||||||
{
|
|
||||||
for (const auto& ignoreEntry : creationContext.m_ignored_assets.m_entries)
|
|
||||||
loadingContext.m_ignored_asset_map[ignoreEntry.m_name] = ignoreEntry.m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneCreator::CreateZoneAssetPools(Zone* zone) const
|
|
||||||
{
|
|
||||||
zone->m_pools = std::make_unique<GameAssetPoolT5>(zone, zone->m_priority);
|
|
||||||
|
|
||||||
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
|
|
||||||
zone->m_pools->InitPoolDynamic(assetType);
|
|
||||||
}
|
|
||||||
|
|
||||||
GameId ZoneCreator::GetGameId() const
|
|
||||||
{
|
|
||||||
return GameId::T5;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
|
|
||||||
{
|
|
||||||
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, IGame::GetGameById(GameId::T5));
|
|
||||||
CreateZoneAssetPools(zone.get());
|
|
||||||
|
|
||||||
for (const auto& assetEntry : context.m_definition->m_assets)
|
|
||||||
{
|
|
||||||
if (!assetEntry.m_is_reference)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
|
|
||||||
ApplyIgnoredAssets(context, *assetLoadingContext);
|
|
||||||
|
|
||||||
const auto* objLoader = IObjLoader::GetObjLoaderForGame(GameId::T5);
|
|
||||||
for (const auto& assetEntry : context.m_definition->m_assets)
|
|
||||||
{
|
|
||||||
if (!objLoader->LoadAssetForZone(*assetLoadingContext, assetEntry.m_asset_type, assetEntry.m_asset_name))
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
objLoader->FinalizeAssetsForZone(*assetLoadingContext);
|
|
||||||
|
|
||||||
return zone;
|
|
||||||
}
|
|
||||||
|
|
||||||
asset_type_t ZoneCreator::GetImageAssetType() const
|
|
||||||
{
|
|
||||||
return ASSET_TYPE_IMAGE;
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "AssetLoading/AssetLoadingContext.h"
|
|
||||||
#include "Zone/ZoneTypes.h"
|
|
||||||
#include "ZoneCreation/ZoneCreator.h"
|
|
||||||
|
|
||||||
namespace T5
|
|
||||||
{
|
|
||||||
class ZoneCreator final : public IZoneCreator
|
|
||||||
{
|
|
||||||
static std::vector<Gdt*> CreateGdtList(ZoneCreationContext& context);
|
|
||||||
static void ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext);
|
|
||||||
void CreateZoneAssetPools(Zone* zone) const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
[[nodiscard]] GameId GetGameId() const override;
|
|
||||||
[[nodiscard]] std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
|
|
||||||
[[nodiscard]] asset_type_t GetImageAssetType() const override;
|
|
||||||
};
|
|
||||||
} // namespace T5
|
|
@ -1,125 +0,0 @@
|
|||||||
#include "ZoneCreatorT6.h"
|
|
||||||
|
|
||||||
#include "Game/T6/CommonT6.h"
|
|
||||||
#include "Game/T6/GameAssetPoolT6.h"
|
|
||||||
#include "Game/T6/GameT6.h"
|
|
||||||
#include "Game/T6/T6.h"
|
|
||||||
#include "IObjLoader.h"
|
|
||||||
#include "ObjLoading.h"
|
|
||||||
#include "Utils/StringUtils.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using namespace T6;
|
|
||||||
|
|
||||||
std::vector<Gdt*> ZoneCreator::CreateGdtList(const ZoneCreationContext& context)
|
|
||||||
{
|
|
||||||
std::vector<Gdt*> gdtList;
|
|
||||||
gdtList.reserve(context.m_gdt_files.size());
|
|
||||||
for (const auto& gdt : context.m_gdt_files)
|
|
||||||
gdtList.push_back(gdt.get());
|
|
||||||
|
|
||||||
return gdtList;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneCreator::ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext)
|
|
||||||
{
|
|
||||||
for (const auto& ignoreEntry : creationContext.m_ignored_assets.m_entries)
|
|
||||||
loadingContext.m_ignored_asset_map[ignoreEntry.m_name] = ignoreEntry.m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneCreator::CreateZoneAssetPools(Zone* zone) const
|
|
||||||
{
|
|
||||||
zone->m_pools = std::make_unique<GameAssetPoolT6>(zone, zone->m_priority);
|
|
||||||
|
|
||||||
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
|
|
||||||
zone->m_pools->InitPoolDynamic(assetType);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneCreator::HandleMetadata(Zone* zone, const ZoneCreationContext& context) const
|
|
||||||
{
|
|
||||||
std::vector<KeyValuePair> kvpList;
|
|
||||||
|
|
||||||
for (const auto& metaData : context.m_definition->m_properties.m_properties)
|
|
||||||
{
|
|
||||||
if (metaData.first.rfind("level.", 0) == 0)
|
|
||||||
{
|
|
||||||
const std::string strValue = metaData.first.substr(std::char_traits<char>::length("level."));
|
|
||||||
if (strValue.empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int keyHash;
|
|
||||||
if (strValue[0] == '@')
|
|
||||||
{
|
|
||||||
char* endPtr;
|
|
||||||
keyHash = strtol(&strValue[1], &endPtr, 16);
|
|
||||||
|
|
||||||
if (endPtr != &strValue[strValue.size()])
|
|
||||||
{
|
|
||||||
std::cout << "Could not parse metadata key \"" << metaData.first << "\" as hash\n";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
keyHash = Common::Com_HashKey(strValue.c_str(), 64);
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyValuePair kvp{keyHash, Common::Com_HashKey(zone->m_name.c_str(), 64), zone->GetMemory()->Dup(metaData.second.c_str())};
|
|
||||||
kvpList.push_back(kvp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!kvpList.empty())
|
|
||||||
{
|
|
||||||
auto* kvps = zone->GetMemory()->Create<KeyValuePairs>();
|
|
||||||
kvps->name = zone->GetMemory()->Dup(zone->m_name.c_str());
|
|
||||||
kvps->numVariables = kvpList.size();
|
|
||||||
kvps->keyValuePairs = zone->GetMemory()->Alloc<KeyValuePair>(kvpList.size());
|
|
||||||
|
|
||||||
for (auto i = 0u; i < kvpList.size(); i++)
|
|
||||||
kvps->keyValuePairs[i] = kvpList[i];
|
|
||||||
|
|
||||||
zone->m_pools->AddAsset(std::make_unique<XAssetInfo<KeyValuePairs>>(ASSET_TYPE_KEYVALUEPAIRS, zone->m_name, kvps));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GameId ZoneCreator::GetGameId() const
|
|
||||||
{
|
|
||||||
return GameId::T6;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
|
|
||||||
{
|
|
||||||
auto zone = std::make_unique<Zone>(context.m_definition->m_name, 0, IGame::GetGameById(GameId::T6));
|
|
||||||
CreateZoneAssetPools(zone.get());
|
|
||||||
|
|
||||||
for (const auto& assetEntry : context.m_definition->m_assets)
|
|
||||||
{
|
|
||||||
if (!assetEntry.m_is_reference)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
|
|
||||||
ApplyIgnoredAssets(context, *assetLoadingContext);
|
|
||||||
|
|
||||||
HandleMetadata(zone.get(), context);
|
|
||||||
|
|
||||||
const auto* objLoader = IObjLoader::GetObjLoaderForGame(GameId::T6);
|
|
||||||
for (const auto& assetEntry : context.m_definition->m_assets)
|
|
||||||
{
|
|
||||||
if (!objLoader->LoadAssetForZone(*assetLoadingContext, assetEntry.m_asset_type, assetEntry.m_asset_name))
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
objLoader->FinalizeAssetsForZone(*assetLoadingContext);
|
|
||||||
|
|
||||||
return zone;
|
|
||||||
}
|
|
||||||
|
|
||||||
asset_type_t ZoneCreator::GetImageAssetType() const
|
|
||||||
{
|
|
||||||
return ASSET_TYPE_IMAGE;
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "AssetLoading/AssetLoadingContext.h"
|
|
||||||
#include "Zone/ZoneTypes.h"
|
|
||||||
#include "ZoneCreation/ZoneCreator.h"
|
|
||||||
|
|
||||||
namespace T6
|
|
||||||
{
|
|
||||||
class ZoneCreator final : public IZoneCreator
|
|
||||||
{
|
|
||||||
static std::vector<Gdt*> CreateGdtList(const ZoneCreationContext& context);
|
|
||||||
static void ApplyIgnoredAssets(const ZoneCreationContext& creationContext, AssetLoadingContext& loadingContext);
|
|
||||||
void CreateZoneAssetPools(Zone* zone) const;
|
|
||||||
void HandleMetadata(Zone* zone, const ZoneCreationContext& context) const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
[[nodiscard]] GameId GetGameId() const override;
|
|
||||||
[[nodiscard]] std::unique_ptr<Zone> CreateZoneForDefinition(ZoneCreationContext& context) const override;
|
|
||||||
[[nodiscard]] asset_type_t GetImageAssetType() const override;
|
|
||||||
};
|
|
||||||
} // namespace T6
|
|
@ -1,16 +1,13 @@
|
|||||||
#include "Linker.h"
|
#include "Linker.h"
|
||||||
|
|
||||||
#include "LinkerArgs.h"
|
#include "LinkerArgs.h"
|
||||||
#include "LinkerSearchPaths.h"
|
#include "LinkerPaths.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/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/AssetListStream.h"
|
#include "Zone/AssetList/AssetListReader.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"
|
||||||
@ -21,133 +18,157 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <set>
|
#include <unordered_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
|
||||||
{
|
{
|
||||||
LinkerArgs m_args;
|
std::unique_ptr<ZoneDefinition> ReadZoneDefinition(LinkerPathManager& paths, const std::string& targetName, bool logMissing = true) const
|
||||||
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, m_args.m_verbose);
|
ZoneDefinitionInputStream zoneDefinitionInputStream(*definitionStream.m_stream, targetName, definitionFileName, sourceSearchPath);
|
||||||
zoneDefinition = zoneDefinitionInputStream.ReadDefinition();
|
zoneDefinition = zoneDefinitionInputStream.ReadDefinition();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,20 +178,41 @@ 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 ProcessZoneDefinitionIgnores(const std::string& targetName, ZoneCreationContext& context, ISearchPath* sourceSearchPath) const
|
bool ReadIgnoreEntries(LinkerPathManager& paths, const std::string& zoneName, const GameId game, AssetList& assetList) const
|
||||||
|
{
|
||||||
|
{
|
||||||
|
AssetListReader assetListReader(paths.m_source_paths.GetSearchPaths(), game);
|
||||||
|
const auto maybeReadAssetList = assetListReader.ReadAssetList(zoneName, false);
|
||||||
|
if (maybeReadAssetList)
|
||||||
|
{
|
||||||
|
assetList.m_entries.reserve(assetList.m_entries.size() + maybeReadAssetList->m_entries.size());
|
||||||
|
for (auto& entry : maybeReadAssetList->m_entries)
|
||||||
|
assetList.m_entries.emplace_back(std::move(entry));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto zoneDefinition = ReadZoneDefinition(paths, zoneName, false);
|
||||||
|
|
||||||
|
if (zoneDefinition)
|
||||||
|
{
|
||||||
|
assetList.m_entries.reserve(assetList.m_entries.size() + zoneDefinition->m_assets.size());
|
||||||
|
for (const auto& entry : zoneDefinition->m_assets)
|
||||||
|
assetList.m_entries.emplace_back(entry.m_asset_type, entry.m_asset_name, entry.m_is_reference);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProcessZoneDefinitionIgnores(LinkerPathManager& paths, const std::string& targetName, ZoneCreationContext& context) const
|
||||||
{
|
{
|
||||||
if (context.m_definition->m_ignores.empty())
|
if (context.m_definition->m_ignores.empty())
|
||||||
return true;
|
return true;
|
||||||
@ -180,8 +222,7 @@ class LinkerImpl final : public Linker
|
|||||||
if (ignore == targetName)
|
if (ignore == targetName)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::vector<AssetListEntry> assetList;
|
if (!ReadIgnoreEntries(paths, ignore, context.m_definition->m_game, context.m_ignored_assets))
|
||||||
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;
|
||||||
@ -215,38 +256,30 @@ class LinkerImpl final : public Linker
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Zone> CreateZoneForDefinition(const std::string& targetName,
|
std::unique_ptr<Zone> CreateZoneForDefinition(
|
||||||
ZoneDefinition& zoneDefinition,
|
LinkerPathManager& paths, const fs::path& outDir, const fs::path& cacheDir, const std::string& targetName, ZoneDefinition& zoneDefinition) const
|
||||||
ISearchPath* assetSearchPath,
|
|
||||||
ISearchPath* gdtSearchPath,
|
|
||||||
ISearchPath* sourceSearchPath) const
|
|
||||||
{
|
{
|
||||||
const auto context = std::make_unique<ZoneCreationContext>(&zoneDefinition, assetSearchPath);
|
ZoneCreationContext context(&zoneDefinition, &paths.m_asset_paths.GetSearchPaths(), outDir, cacheDir);
|
||||||
if (!ProcessZoneDefinitionIgnores(targetName, *context, sourceSearchPath))
|
if (!ProcessZoneDefinitionIgnores(paths, targetName, context))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (!LoadGdtFilesFromZoneDefinition(context->m_gdt_files, zoneDefinition, gdtSearchPath))
|
if (!LoadGdtFilesFromZoneDefinition(context.m_gdt_files, zoneDefinition, &paths.m_gdt_paths.GetSearchPaths()))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
const auto* creator = IZoneCreator::GetCreatorForGame(zoneDefinition.m_game);
|
return zone_creator::CreateZoneForDefinition(zoneDefinition.m_game, context);
|
||||||
return creator->CreateZoneForDefinition(*context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WriteZoneToFile(const std::string& projectName, Zone* zone) const
|
bool WriteZoneToFile(const LinkerPathManager& paths, const fs::path& outDir, const std::string& projectName, Zone* zone) const
|
||||||
{
|
{
|
||||||
const fs::path zoneFolderPath(m_args.GetOutputFolderPathForProject(projectName));
|
auto zoneFilePath(outDir);
|
||||||
auto zoneFilePath(zoneFolderPath);
|
zoneFilePath.append(std::format("{}.ff", zone->m_name));
|
||||||
zoneFilePath.append(zone->m_name + ".ff");
|
|
||||||
|
|
||||||
fs::create_directories(zoneFolderPath);
|
fs::create_directories(outDir);
|
||||||
|
|
||||||
std::ofstream stream(zoneFilePath, std::fstream::out | std::fstream::binary);
|
std::ofstream stream(zoneFilePath, std::fstream::out | std::fstream::binary);
|
||||||
if (!stream.is_open())
|
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", zoneFilePath.string());
|
||||||
}
|
|
||||||
|
|
||||||
if (!ZoneWriting::WriteZone(stream, zone))
|
if (!ZoneWriting::WriteZone(stream, zone))
|
||||||
{
|
{
|
||||||
@ -261,112 +294,58 @@ class LinkerImpl final : public Linker
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BuildFastFile(const std::string& projectName,
|
bool BuildFastFile(LinkerPathManager& paths, const std::string& projectName, const std::string& targetName, ZoneDefinition& zoneDefinition) const
|
||||||
const std::string& targetName,
|
|
||||||
ZoneDefinition& zoneDefinition,
|
|
||||||
SearchPaths& assetSearchPaths,
|
|
||||||
SearchPaths& gdtSearchPaths,
|
|
||||||
SearchPaths& sourceSearchPaths) const
|
|
||||||
{
|
{
|
||||||
SoundBankWriter::OutputPath = fs::path(m_args.GetOutputFolderPathForProject(projectName));
|
const fs::path outDir(paths.m_linker_paths->BuildOutputFolderPath(projectName, zoneDefinition.m_game));
|
||||||
|
const fs::path cacheDir(paths.m_linker_paths->BuildCacheFolderPath(projectName, zoneDefinition.m_game));
|
||||||
|
SoundBankWriter::OutputPath = outDir;
|
||||||
|
|
||||||
const auto zone = CreateZoneForDefinition(targetName, zoneDefinition, &assetSearchPaths, &gdtSearchPaths, &sourceSearchPaths);
|
const auto zone = CreateZoneForDefinition(paths, outDir, cacheDir, targetName, zoneDefinition);
|
||||||
auto result = zone != nullptr;
|
auto result = zone != nullptr;
|
||||||
if (zone)
|
if (zone)
|
||||||
result = WriteZoneToFile(projectName, zone.get());
|
result = WriteZoneToFile(paths, outDir, projectName, zone.get());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BuildIPak(const std::string& projectName, const ZoneDefinition& zoneDefinition, SearchPaths& assetSearchPaths) const
|
bool BuildProject(LinkerPathManager& paths, const std::string& projectName, const std::string& targetName) const
|
||||||
{
|
{
|
||||||
const fs::path ipakFolderPath(m_args.GetOutputFolderPathForProject(projectName));
|
std::deque<std::string> targetsToBuild;
|
||||||
auto ipakFilePath(ipakFolderPath);
|
std::unordered_set<std::string> alreadyBuiltTargets;
|
||||||
ipakFilePath.append(std::format("{}.ipak", zoneDefinition.m_name));
|
|
||||||
|
|
||||||
fs::create_directories(ipakFolderPath);
|
targetsToBuild.emplace_back(targetName);
|
||||||
|
|
||||||
std::ofstream stream(ipakFilePath, std::fstream::out | std::fstream::binary);
|
while (!targetsToBuild.empty())
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (assetEntry.m_is_reference)
|
const auto currentTarget = std::move(targetsToBuild.front());
|
||||||
continue;
|
targetsToBuild.pop_front();
|
||||||
|
alreadyBuiltTargets.emplace(currentTarget);
|
||||||
|
|
||||||
if (assetEntry.m_asset_type == imageAssetType)
|
PathProjectContext projectContext(paths, projectName);
|
||||||
ipakWriter->AddImage(assetEntry.m_asset_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ipakWriter->Write())
|
const auto zoneDefinition = ReadZoneDefinition(paths, targetName);
|
||||||
{
|
|
||||||
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;
|
||||||
|
|
||||||
auto result = true;
|
PathGameContext gameContext(paths, projectName, zoneDefinition->m_game);
|
||||||
if (zoneDefinition->m_type != ProjectType::NONE)
|
|
||||||
|
if (!zoneDefinition->m_assets.empty())
|
||||||
{
|
{
|
||||||
const auto& gameName = GameId_Names[static_cast<unsigned>(zoneDefinition->m_game)];
|
if (!BuildFastFile(paths, projectName, targetName, *zoneDefinition))
|
||||||
auto assetSearchPaths = m_search_paths.GetAssetSearchPathsForProject(gameName, projectName);
|
return false;
|
||||||
auto gdtSearchPaths = m_search_paths.GetGdtSearchPathsForProject(gameName, projectName);
|
|
||||||
|
|
||||||
switch (zoneDefinition->m_type)
|
for (const auto& referencedTarget : zoneDefinition->m_targets_to_build)
|
||||||
{
|
{
|
||||||
case ProjectType::FASTFILE:
|
if (alreadyBuiltTargets.find(referencedTarget) == alreadyBuiltTargets.end())
|
||||||
result = BuildFastFile(projectName, targetName, *zoneDefinition, assetSearchPaths, gdtSearchPaths, sourceSearchPaths);
|
{
|
||||||
break;
|
targetsToBuild.emplace_back(referencedTarget);
|
||||||
|
std::cout << std::format("Building referenced target \"{}\"\n", referencedTarget);
|
||||||
case ProjectType::IPAK:
|
}
|
||||||
result = BuildIPak(projectName, *zoneDefinition, assetSearchPaths);
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
result = false;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_search_paths.UnloadProjectSpecificSearchPaths();
|
return true;
|
||||||
|
|
||||||
result = result && BuildReferencedTargets(projectName, targetName, *zoneDefinition);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadZones()
|
bool LoadZones()
|
||||||
@ -384,8 +363,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 = std::unique_ptr<Zone>(ZoneLoading::LoadZone(zonePath));
|
auto zone = ZoneLoading::LoadZone(zonePath);
|
||||||
if (zone == nullptr)
|
if (!zone)
|
||||||
{
|
{
|
||||||
std::cerr << std::format("Failed to load zone \"{}\".\n", zonePath);
|
std::cerr << std::format("Failed to load zone \"{}\".\n", zonePath);
|
||||||
return false;
|
return false;
|
||||||
@ -452,11 +431,6 @@ 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;
|
||||||
@ -466,8 +440,7 @@ public:
|
|||||||
if (!shouldContinue)
|
if (!shouldContinue)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!m_search_paths.BuildProjectIndependentSearchPaths())
|
LinkerPathManager paths(m_args);
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!LoadZones())
|
if (!LoadZones())
|
||||||
return false;
|
return false;
|
||||||
@ -483,7 +456,7 @@ public:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!BuildProject(projectName, targetName))
|
if (!BuildProject(paths, projectName, targetName))
|
||||||
{
|
{
|
||||||
result = false;
|
result = false;
|
||||||
break;
|
break;
|
||||||
@ -494,6 +467,10 @@ 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,7 +9,6 @@
|
|||||||
#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;
|
||||||
@ -46,7 +45,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("Specifies the output folder containing the build artifacts. Defaults to \"" + std::string(LinkerArgs::DEFAULT_OUTPUT_FOLDER) + "\".")
|
.WithDescription(std::format("Specifies the output folder containing the build artifacts. Defaults to \"{}\".", LinkerArgs::DEFAULT_OUTPUT_FOLDER))
|
||||||
.WithParameter("outputFolderPath")
|
.WithParameter("outputFolderPath")
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
@ -61,14 +60,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("Specifies the search paths used for assets. Defaults to \"" + std::string(LinkerArgs::DEFAULT_ASSET_SEARCH_PATH) + "\".")
|
.WithDescription(std::format("Specifies the search paths used for assets. Defaults to \"{}\".", LinkerArgs::DEFAULT_ASSET_SEARCH_PATH))
|
||||||
.WithParameter("assetSearchPathString")
|
.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("Specifies the search paths used for gdt files. Defaults to \"" + std::string(LinkerArgs::DEFAULT_GDT_SEARCH_PATH) + "\".")
|
.WithDescription(std::format("Specifies the search paths used for gdt files. Defaults to \"{}\".", LinkerArgs::DEFAULT_GDT_SEARCH_PATH))
|
||||||
.WithParameter("gdtSearchPathString")
|
.WithParameter("gdtSearchPathString")
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
@ -83,7 +82,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("Specifies the search paths used for source files. Defaults to \"" + std::string(LinkerArgs::DEFAULT_SOURCE_SEARCH_PATH) + "\".")
|
.WithDescription(std::format("Specifies the search paths used for source files. Defaults to \"{}\".", LinkerArgs::DEFAULT_SOURCE_SEARCH_PATH))
|
||||||
.WithParameter("sourceSearchPathString")
|
.WithParameter("sourceSearchPathString")
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
@ -129,13 +128,7 @@ const CommandLineOption* const COMMAND_LINE_OPTIONS[]{
|
|||||||
|
|
||||||
LinkerArgs::LinkerArgs()
|
LinkerArgs::LinkerArgs()
|
||||||
: m_verbose(false),
|
: m_verbose(false),
|
||||||
m_base_folder_depends_on_project(false),
|
m_argument_parser(COMMAND_LINE_OPTIONS, std::extent_v<decltype(COMMAND_LINE_OPTIONS)>)
|
||||||
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\?)")
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,76 +165,6 @@ 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;
|
||||||
@ -284,15 +207,13 @@ 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
|
||||||
SetDefaultBasePath();
|
m_base_folder = DEFAULT_BASE_FOLDER;
|
||||||
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))
|
||||||
@ -358,38 +279,3 @@ 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,22 +1,14 @@
|
|||||||
#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_BASE_FOLDER_MOD_TOOLS = "..";
|
static constexpr auto DEFAULT_CACHE_FOLDER = "?base?/.oat/cache/?project?";
|
||||||
static constexpr auto DEFAULT_OUTPUT_FOLDER = "?base?/zone_out/?project?";
|
static constexpr auto DEFAULT_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";
|
||||||
@ -25,21 +17,6 @@ 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;
|
||||||
@ -48,8 +25,6 @@ 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;
|
||||||
@ -63,18 +38,7 @@ 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;
|
|
||||||
};
|
};
|
||||||
|
338
src/Linker/LinkerPaths.cpp
Normal file
338
src/Linker/LinkerPaths.cpp
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
#include "LinkerPaths.h"
|
||||||
|
|
||||||
|
#include "SearchPath/IWD.h"
|
||||||
|
#include "SearchPath/SearchPathFilesystem.h"
|
||||||
|
#include "SearchPath/SearchPaths.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))
|
||||||
|
{
|
||||||
|
auto renderedTemplate = curTemplate.Render(m_bin_dir, m_base_dir, projectName, GameId_Names[static_cast<unsigned>(game)]);
|
||||||
|
if (AddSearchPath(addedSearchPaths, searchPaths, renderedTemplate))
|
||||||
|
hasSearchPath = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasSearchPath)
|
||||||
|
return std::make_unique<SearchPaths>(std::move(searchPaths));
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool AddSearchPath(std::unordered_set<std::string>& existingSearchPaths, SearchPaths& searchPaths, const std::string& path) const
|
||||||
|
{
|
||||||
|
const auto existingSearchPath = existingSearchPaths.find(path);
|
||||||
|
if (existingSearchPath != existingSearchPaths.end())
|
||||||
|
return false;
|
||||||
|
existingSearchPaths.emplace(path);
|
||||||
|
|
||||||
|
if (!fs::is_directory(path))
|
||||||
|
{
|
||||||
|
std::cout << std::format("Adding {} search path (Not found): {}\n", m_type_name, path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::format("Adding {} search path: {}\n", m_type_name, path);
|
||||||
|
searchPaths.CommitSearchPath(std::make_unique<SearchPathFilesystem>(path));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* m_type_name;
|
||||||
|
std::vector<LinkerPathTemplate> m_templates;
|
||||||
|
std::string m_bin_dir;
|
||||||
|
std::string m_base_dir;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LinkerPaths final : public ILinkerPaths
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LinkerPaths(std::string binDir,
|
||||||
|
std::string baseDir,
|
||||||
|
LinkerSearchPathBuilder assetSearchPaths,
|
||||||
|
LinkerSearchPathBuilder gdtSearchPaths,
|
||||||
|
LinkerSearchPathBuilder sourceSearchPaths,
|
||||||
|
LinkerPathTemplate cacheTemplate,
|
||||||
|
LinkerPathTemplate outTemplate)
|
||||||
|
: m_bin_dir(std::move(binDir)),
|
||||||
|
m_base_dir(std::move(baseDir)),
|
||||||
|
m_asset_search_paths(std::move(assetSearchPaths)),
|
||||||
|
m_gdt_search_paths(std::move(gdtSearchPaths)),
|
||||||
|
m_source_search_paths(std::move(sourceSearchPaths)),
|
||||||
|
m_cache_template(std::move(cacheTemplate)),
|
||||||
|
m_out_template(std::move(outTemplate))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const ILinkerSearchPathBuilder& AssetSearchPaths() const override
|
||||||
|
{
|
||||||
|
return m_asset_search_paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const ILinkerSearchPathBuilder& GdtSearchPaths() const override
|
||||||
|
{
|
||||||
|
return m_gdt_search_paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const ILinkerSearchPathBuilder& SourceSearchPaths() const override
|
||||||
|
{
|
||||||
|
return m_source_search_paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::string BuildCacheFolderPath(const std::string& projectName, GameId game) const override
|
||||||
|
{
|
||||||
|
return m_cache_template.Render(m_bin_dir, m_base_dir, projectName, GameId_Names[static_cast<unsigned>(game)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::string BuildOutputFolderPath(const std::string& projectName, GameId game) const override
|
||||||
|
{
|
||||||
|
return m_out_template.Render(m_bin_dir, m_base_dir, projectName, GameId_Names[static_cast<unsigned>(game)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_bin_dir;
|
||||||
|
std::string m_base_dir;
|
||||||
|
LinkerSearchPathBuilder m_asset_search_paths;
|
||||||
|
LinkerSearchPathBuilder m_gdt_search_paths;
|
||||||
|
LinkerSearchPathBuilder m_source_search_paths;
|
||||||
|
LinkerPathTemplate m_cache_template;
|
||||||
|
LinkerPathTemplate m_out_template;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::unique_ptr<ILinkerPaths> ILinkerPaths::FromArgs(const LinkerArgs& args)
|
||||||
|
{
|
||||||
|
std::string normalizedBinPath = fs::canonical(args.m_bin_folder).make_preferred().string();
|
||||||
|
std::string normalizedBasePath = fs::canonical(args.m_base_folder).make_preferred().string();
|
||||||
|
|
||||||
|
LinkerSearchPathBuilder assetSearchPaths("asset", normalizedBinPath, normalizedBasePath);
|
||||||
|
assetSearchPaths.BuildFromArgs(args.m_asset_search_paths);
|
||||||
|
|
||||||
|
LinkerSearchPathBuilder gdtSearchPaths("gdt", normalizedBinPath, normalizedBasePath);
|
||||||
|
gdtSearchPaths.BuildFromArgs(args.m_gdt_search_paths);
|
||||||
|
|
||||||
|
LinkerSearchPathBuilder sourceSearchPaths("source", normalizedBinPath, normalizedBasePath);
|
||||||
|
sourceSearchPaths.BuildFromArgs(args.m_source_search_paths);
|
||||||
|
|
||||||
|
LinkerPathTemplate cacheTemplate;
|
||||||
|
cacheTemplate.CreateFromString(LinkerArgs::DEFAULT_CACHE_FOLDER);
|
||||||
|
|
||||||
|
LinkerPathTemplate outTemplate;
|
||||||
|
outTemplate.CreateFromString(args.m_out_folder);
|
||||||
|
|
||||||
|
return std::make_unique<LinkerPaths>(std::move(normalizedBinPath),
|
||||||
|
std::move(normalizedBasePath),
|
||||||
|
std::move(assetSearchPaths),
|
||||||
|
std::move(gdtSearchPaths),
|
||||||
|
std::move(sourceSearchPaths),
|
||||||
|
std::move(cacheTemplate),
|
||||||
|
std::move(outTemplate));
|
||||||
|
}
|
74
src/Linker/LinkerPaths.h
Normal file
74
src/Linker/LinkerPaths.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Game/IGame.h"
|
||||||
|
#include "LinkerArgs.h"
|
||||||
|
#include "SearchPath/ISearchPath.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class ILinkerSearchPathBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ILinkerSearchPathBuilder() = default;
|
||||||
|
virtual ~ILinkerSearchPathBuilder() = default;
|
||||||
|
ILinkerSearchPathBuilder(const ILinkerSearchPathBuilder& other) = default;
|
||||||
|
ILinkerSearchPathBuilder(ILinkerSearchPathBuilder&& other) noexcept = default;
|
||||||
|
ILinkerSearchPathBuilder& operator=(const ILinkerSearchPathBuilder& other) = default;
|
||||||
|
ILinkerSearchPathBuilder& operator=(ILinkerSearchPathBuilder&& other) noexcept = default;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual std::unique_ptr<ISearchPath> BuildIndependentSearchPaths() const = 0;
|
||||||
|
[[nodiscard]] virtual std::unique_ptr<ISearchPath> BuildSearchPathsSpecificToProject(const std::string& projectName) const = 0;
|
||||||
|
[[nodiscard]] virtual std::unique_ptr<ISearchPath> BuildSearchPathsSpecificToProjectAndGame(const std::string& projectName, GameId game) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ILinkerPaths
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ILinkerPaths() = default;
|
||||||
|
virtual ~ILinkerPaths() = default;
|
||||||
|
ILinkerPaths(const ILinkerPaths& other) = default;
|
||||||
|
ILinkerPaths(ILinkerPaths&& other) noexcept = default;
|
||||||
|
ILinkerPaths& operator=(const ILinkerPaths& other) = default;
|
||||||
|
ILinkerPaths& operator=(ILinkerPaths&& other) noexcept = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Creates linker search paths based on templates from user specified args.
|
||||||
|
* \param args The user specified args.
|
||||||
|
* \return Linker search paths based on user specified templates.
|
||||||
|
*/
|
||||||
|
static std::unique_ptr<ILinkerPaths> FromArgs(const LinkerArgs& args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Grants access to the builder for asset search paths.
|
||||||
|
* \return A builder instance for building asset search paths.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual const ILinkerSearchPathBuilder& AssetSearchPaths() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Grants access to the builder for gdt search paths.
|
||||||
|
* \return A builder instance for building gdt search paths.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual const ILinkerSearchPathBuilder& GdtSearchPaths() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Grants access to the builder for source search paths.
|
||||||
|
* \return A builder instance for building source search paths.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual const ILinkerSearchPathBuilder& SourceSearchPaths() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Builds the cache path based on the specified information.
|
||||||
|
* \param projectName The name of the project to resolve the path input for.
|
||||||
|
* \param game The game to resolve the path input for.
|
||||||
|
* \return A cache path based on the input and preconfigured template.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual std::string BuildCacheFolderPath(const std::string& projectName, GameId game) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Builds the output path based on the specified information.
|
||||||
|
* \param projectName The name of the project to resolve the path input for.
|
||||||
|
* \param game The game to resolve the path input for.
|
||||||
|
* \return An output path based on the input and preconfigured template.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual std::string BuildOutputFolderPath(const std::string& projectName, GameId game) const = 0;
|
||||||
|
};
|
@ -1,190 +0,0 @@
|
|||||||
#include "LinkerSearchPaths.h"
|
|
||||||
|
|
||||||
#include "ObjContainer/IWD/IWD.h"
|
|
||||||
#include "ObjLoading.h"
|
|
||||||
#include "SearchPath/SearchPathFilesystem.h"
|
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
#include <format>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
|
||||||
|
|
||||||
LinkerSearchPaths::LinkerSearchPaths(const LinkerArgs& args)
|
|
||||||
: m_args(args)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void LinkerSearchPaths::LoadSearchPath(ISearchPath& searchPath) const
|
|
||||||
{
|
|
||||||
if (m_args.m_verbose)
|
|
||||||
{
|
|
||||||
std::cout << std::format("Loading search path: \"{}\"\n", searchPath.GetPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjLoading::LoadIWDsInSearchPath(searchPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LinkerSearchPaths::UnloadSearchPath(ISearchPath& searchPath) const
|
|
||||||
{
|
|
||||||
if (m_args.m_verbose)
|
|
||||||
{
|
|
||||||
std::cout << std::format("Unloading search path: \"{}\"\n", searchPath.GetPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjLoading::UnloadIWDsInSearchPath(searchPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchPaths LinkerSearchPaths::GetAssetSearchPathsForProject(const std::string& gameName, const std::string& projectName)
|
|
||||||
{
|
|
||||||
SearchPaths searchPathsForProject;
|
|
||||||
|
|
||||||
for (const auto& searchPathStr : m_args.GetAssetSearchPathsForProject(gameName, projectName))
|
|
||||||
{
|
|
||||||
auto absolutePath = fs::absolute(searchPathStr);
|
|
||||||
|
|
||||||
if (!fs::is_directory(absolutePath))
|
|
||||||
{
|
|
||||||
if (m_args.m_verbose)
|
|
||||||
std::cout << std::format("Adding asset search path (Not found): {}\n", absolutePath.string());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_args.m_verbose)
|
|
||||||
std::cout << std::format("Adding asset search path: {}\n", absolutePath.string());
|
|
||||||
|
|
||||||
auto searchPath = std::make_unique<SearchPathFilesystem>(searchPathStr);
|
|
||||||
LoadSearchPath(*searchPath);
|
|
||||||
searchPathsForProject.IncludeSearchPath(searchPath.get());
|
|
||||||
m_loaded_project_search_paths.emplace_back(std::move(searchPath));
|
|
||||||
}
|
|
||||||
|
|
||||||
searchPathsForProject.IncludeSearchPath(&m_asset_search_paths);
|
|
||||||
|
|
||||||
for (auto* iwd : IWD::Repository)
|
|
||||||
{
|
|
||||||
searchPathsForProject.IncludeSearchPath(iwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return searchPathsForProject;
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchPaths LinkerSearchPaths::GetGdtSearchPathsForProject(const std::string& gameName, const std::string& projectName)
|
|
||||||
{
|
|
||||||
SearchPaths searchPathsForProject;
|
|
||||||
|
|
||||||
for (const auto& searchPathStr : m_args.GetGdtSearchPathsForProject(gameName, projectName))
|
|
||||||
{
|
|
||||||
auto absolutePath = fs::absolute(searchPathStr);
|
|
||||||
|
|
||||||
if (!fs::is_directory(absolutePath))
|
|
||||||
{
|
|
||||||
if (m_args.m_verbose)
|
|
||||||
std::cout << std::format("Adding gdt search path (Not found): {}\n", absolutePath.string());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_args.m_verbose)
|
|
||||||
std::cout << std::format("Adding gdt search path: {}\n", absolutePath.string());
|
|
||||||
|
|
||||||
searchPathsForProject.CommitSearchPath(std::make_unique<SearchPathFilesystem>(searchPathStr));
|
|
||||||
}
|
|
||||||
|
|
||||||
searchPathsForProject.IncludeSearchPath(&m_gdt_search_paths);
|
|
||||||
|
|
||||||
return searchPathsForProject;
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchPaths LinkerSearchPaths::GetSourceSearchPathsForProject(const std::string& projectName)
|
|
||||||
{
|
|
||||||
SearchPaths searchPathsForProject;
|
|
||||||
|
|
||||||
for (const auto& searchPathStr : m_args.GetSourceSearchPathsForProject(projectName))
|
|
||||||
{
|
|
||||||
auto absolutePath = fs::absolute(searchPathStr);
|
|
||||||
|
|
||||||
if (!fs::is_directory(absolutePath))
|
|
||||||
{
|
|
||||||
if (m_args.m_verbose)
|
|
||||||
std::cout << std::format("Adding source search path (Not found): {}\n", absolutePath.string());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_args.m_verbose)
|
|
||||||
std::cout << std::format("Adding source search path: {}\n", absolutePath.string());
|
|
||||||
|
|
||||||
searchPathsForProject.CommitSearchPath(std::make_unique<SearchPathFilesystem>(searchPathStr));
|
|
||||||
}
|
|
||||||
|
|
||||||
searchPathsForProject.IncludeSearchPath(&m_source_search_paths);
|
|
||||||
|
|
||||||
return searchPathsForProject;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LinkerSearchPaths::BuildProjectIndependentSearchPaths()
|
|
||||||
{
|
|
||||||
for (const auto& path : m_args.GetProjectIndependentAssetSearchPaths())
|
|
||||||
{
|
|
||||||
auto absolutePath = fs::absolute(path);
|
|
||||||
|
|
||||||
if (!fs::is_directory(absolutePath))
|
|
||||||
{
|
|
||||||
if (m_args.m_verbose)
|
|
||||||
std::cout << std::format("Adding asset search path (Not found): {}\n", absolutePath.string());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_args.m_verbose)
|
|
||||||
std::cout << std::format("Adding asset search path: {}\n", absolutePath.string());
|
|
||||||
|
|
||||||
auto searchPath = std::make_unique<SearchPathFilesystem>(absolutePath.string());
|
|
||||||
LoadSearchPath(*searchPath);
|
|
||||||
m_asset_search_paths.CommitSearchPath(std::move(searchPath));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& path : m_args.GetProjectIndependentGdtSearchPaths())
|
|
||||||
{
|
|
||||||
auto absolutePath = fs::absolute(path);
|
|
||||||
|
|
||||||
if (!fs::is_directory(absolutePath))
|
|
||||||
{
|
|
||||||
if (m_args.m_verbose)
|
|
||||||
std::cout << std::format("Loading gdt search path (Not found): {}\n", absolutePath.string());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_args.m_verbose)
|
|
||||||
std::cout << std::format("Adding gdt search path: {}\n", absolutePath.string());
|
|
||||||
|
|
||||||
m_gdt_search_paths.CommitSearchPath(std::make_unique<SearchPathFilesystem>(absolutePath.string()));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& path : m_args.GetProjectIndependentSourceSearchPaths())
|
|
||||||
{
|
|
||||||
auto absolutePath = fs::absolute(path);
|
|
||||||
|
|
||||||
if (!fs::is_directory(absolutePath))
|
|
||||||
{
|
|
||||||
if (m_args.m_verbose)
|
|
||||||
std::cout << std::format("Loading source search path (Not found): {}\n", absolutePath.string());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_args.m_verbose)
|
|
||||||
std::cout << std::format("Adding source search path: {}\n", absolutePath.string());
|
|
||||||
|
|
||||||
m_source_search_paths.CommitSearchPath(std::make_unique<SearchPathFilesystem>(absolutePath.string()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LinkerSearchPaths::UnloadProjectSpecificSearchPaths()
|
|
||||||
{
|
|
||||||
for (const auto& loadedSearchPath : m_loaded_project_search_paths)
|
|
||||||
{
|
|
||||||
UnloadSearchPath(*loadedSearchPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_loaded_project_search_paths.clear();
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "LinkerArgs.h"
|
|
||||||
#include "SearchPath/SearchPaths.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
class LinkerSearchPaths
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit LinkerSearchPaths(const LinkerArgs& args);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Loads a search path.
|
|
||||||
* \param searchPath The search path to load.
|
|
||||||
*/
|
|
||||||
void LoadSearchPath(ISearchPath& searchPath) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Unloads a search path.
|
|
||||||
* \param searchPath The search path to unload.
|
|
||||||
*/
|
|
||||||
void UnloadSearchPath(ISearchPath& searchPath) const;
|
|
||||||
|
|
||||||
SearchPaths GetAssetSearchPathsForProject(const std::string& gameName, const std::string& projectName);
|
|
||||||
|
|
||||||
SearchPaths GetGdtSearchPathsForProject(const std::string& gameName, const std::string& projectName);
|
|
||||||
|
|
||||||
SearchPaths GetSourceSearchPathsForProject(const std::string& projectName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Initializes the Linker object's search paths based on the user's input.
|
|
||||||
* \return \c true if building the search paths was successful, otherwise \c false.
|
|
||||||
*/
|
|
||||||
bool BuildProjectIndependentSearchPaths();
|
|
||||||
|
|
||||||
void UnloadProjectSpecificSearchPaths();
|
|
||||||
|
|
||||||
private:
|
|
||||||
const LinkerArgs& m_args;
|
|
||||||
std::vector<std::unique_ptr<ISearchPath>> m_loaded_project_search_paths;
|
|
||||||
SearchPaths m_asset_search_paths;
|
|
||||||
SearchPaths m_gdt_search_paths;
|
|
||||||
SearchPaths m_source_search_paths;
|
|
||||||
};
|
|
@ -1,13 +1,17 @@
|
|||||||
#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)
|
ZoneCreationContext::ZoneCreationContext(ZoneDefinition* definition, ISearchPath* assetSearchPath, fs::path outDir, fs::path cacheDir)
|
||||||
: 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,6 +4,7 @@
|
|||||||
#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>
|
||||||
|
|
||||||
@ -12,9 +13,11 @@ 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);
|
ZoneCreationContext(ZoneDefinition* definition, ISearchPath* assetSearchPath, std::filesystem::path outDir, std::filesystem::path cacheDir);
|
||||||
};
|
};
|
||||||
|
@ -1,27 +1,88 @@
|
|||||||
#include "ZoneCreator.h"
|
#include "ZoneCreator.h"
|
||||||
|
|
||||||
#include "AssetLoading/AssetLoadingContext.h"
|
#include "Gdt/GdtLookup.h"
|
||||||
#include "Game/IW3/ZoneCreatorIW3.h"
|
#include "IObjCompiler.h"
|
||||||
#include "Game/IW4/ZoneCreatorIW4.h"
|
#include "IObjLoader.h"
|
||||||
#include "Game/IW5/ZoneCreatorIW5.h"
|
|
||||||
#include "Game/T5/ZoneCreatorT5.h"
|
|
||||||
#include "Game/T6/ZoneCreatorT6.h"
|
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
const IZoneCreator* IZoneCreator::GetCreatorForGame(GameId game)
|
namespace
|
||||||
{
|
{
|
||||||
static const IZoneCreator* zoneCreators[static_cast<unsigned>(GameId::COUNT)]{
|
std::unique_ptr<Zone> CreateZone(const ZoneCreationContext& context, const GameId gameId)
|
||||||
new IW3::ZoneCreator(),
|
{
|
||||||
new IW4::ZoneCreator(),
|
return std::make_unique<Zone>(context.m_definition->m_name, 0, IGame::GetGameById(gameId));
|
||||||
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);
|
||||||
|
|
||||||
|
objCompiler->ConfigureCreatorCollection(
|
||||||
|
creatorCollection, *zone, zoneDefinitionContext, *context.m_asset_search_path, lookup, creationContext, context.m_out_dir, context.m_cache_dir);
|
||||||
|
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,19 +3,7 @@
|
|||||||
#include "Zone/Zone.h"
|
#include "Zone/Zone.h"
|
||||||
#include "ZoneCreationContext.h"
|
#include "ZoneCreationContext.h"
|
||||||
|
|
||||||
class IZoneCreator
|
namespace zone_creator
|
||||||
{
|
{
|
||||||
public:
|
[[nodiscard]] std::unique_ptr<Zone> CreateZoneForDefinition(GameId game, ZoneCreationContext& context);
|
||||||
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,6 +5,7 @@ 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")
|
||||||
}
|
}
|
||||||
@ -16,6 +17,7 @@ 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,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Game/IW4/IW4.h"
|
#include "Game/IW4/IW4.h"
|
||||||
|
|
||||||
namespace IW4
|
namespace IW4
|
@ -81,4 +81,17 @@ 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,4 +36,9 @@ 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,4 +561,31 @@ 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
|
@ -36,31 +36,11 @@ namespace T6
|
|||||||
"crosshair",
|
"crosshair",
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const char* szWeapInventoryTypeNames[]{
|
inline const char* penetrateTypeNames[]{
|
||||||
"primary",
|
"none",
|
||||||
"offhand",
|
"small",
|
||||||
"item",
|
"medium",
|
||||||
"altmode",
|
"large",
|
||||||
"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[]{
|
||||||
@ -165,6 +145,37 @@ 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",
|
||||||
@ -181,75 +192,13 @@ namespace T6
|
|||||||
"4:1",
|
"4:1",
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const char* szAttachmentTypeNames[]{
|
inline const char* barrelTypeNames[]{
|
||||||
"none", "acog", "dualclip", "dualoptic", "dw", "extbarrel", "extclip", "extramags", "fastads", "fastreload",
|
"Single",
|
||||||
"fmj", "gl", "grip", "holo", "ir", "is", "longbreath", "mk", "mms", "rangefinder",
|
"Dual Barrel",
|
||||||
"reflex", "rf", "sf", "silencer", "stackfire", "stalker", "steadyaim", "swayreduc", "tacknife", "vzoom",
|
"Dual Barrel Alternate",
|
||||||
};
|
"Quad Barrel",
|
||||||
|
"Quad Barrel Alternate",
|
||||||
inline const char* szWeapFireTypeNames[]{
|
"Quad Barrel Double Alternate",
|
||||||
"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[]{
|
||||||
@ -257,4 +206,10 @@ 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
|
@ -7,6 +7,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
class SearchPathOpenFile
|
class SearchPathOpenFile
|
||||||
{
|
{
|
||||||
@ -42,7 +43,7 @@ public:
|
|||||||
* \brief Returns the path to the search path.
|
* \brief Returns the path to the search path.
|
||||||
* \return The path to the search path.
|
* \return The path to the search path.
|
||||||
*/
|
*/
|
||||||
virtual std::string GetPath() = 0;
|
virtual const std::string& GetPath() = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Iterates through all files of the search path.
|
* \brief Iterates through all files of the search path.
|
@ -3,16 +3,18 @@
|
|||||||
#include "Utils/ObjFileStream.h"
|
#include "Utils/ObjFileStream.h"
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <format>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
SearchPathFilesystem::SearchPathFilesystem(std::string path)
|
SearchPathFilesystem::SearchPathFilesystem(std::string path)
|
||||||
|
: m_path(std::move(path))
|
||||||
{
|
{
|
||||||
m_path = std::move(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SearchPathFilesystem::GetPath()
|
const std::string& SearchPathFilesystem::GetPath()
|
||||||
{
|
{
|
||||||
return m_path;
|
return m_path;
|
||||||
}
|
}
|
||||||
@ -23,9 +25,7 @@ SearchPathOpenFile SearchPathFilesystem::Open(const std::string& fileName)
|
|||||||
std::ifstream file(filePath.string(), std::fstream::in | std::fstream::binary);
|
std::ifstream file(filePath.string(), std::fstream::in | std::fstream::binary);
|
||||||
|
|
||||||
if (file.is_open())
|
if (file.is_open())
|
||||||
{
|
|
||||||
return SearchPathOpenFile(std::make_unique<std::ifstream>(std::move(file)), static_cast<int64_t>(file_size(filePath)));
|
return SearchPathOpenFile(std::make_unique<std::ifstream>(std::move(file)), static_cast<int64_t>(file_size(filePath)));
|
||||||
}
|
|
||||||
|
|
||||||
return SearchPathOpenFile();
|
return SearchPathOpenFile();
|
||||||
}
|
}
|
||||||
@ -59,6 +59,6 @@ void SearchPathFilesystem::Find(const SearchPathSearchOptions& options, const st
|
|||||||
}
|
}
|
||||||
catch (std::filesystem::filesystem_error& e)
|
catch (std::filesystem::filesystem_error& e)
|
||||||
{
|
{
|
||||||
printf("Directory Iterator threw error when trying to find files: \"%s\"\n", e.what());
|
std::cerr << std::format("Directory Iterator threw error when trying to find files: \"{}\"\n", e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,6 +12,6 @@ public:
|
|||||||
explicit SearchPathFilesystem(std::string path);
|
explicit SearchPathFilesystem(std::string path);
|
||||||
|
|
||||||
SearchPathOpenFile Open(const std::string& fileName) override;
|
SearchPathOpenFile Open(const std::string& fileName) override;
|
||||||
std::string GetPath() override;
|
const std::string& GetPath() override;
|
||||||
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override;
|
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override;
|
||||||
};
|
};
|
15
src/ObjCommon/SearchPath/SearchPathMultiInputStream.cpp
Normal file
15
src/ObjCommon/SearchPath/SearchPathMultiInputStream.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "SearchPathMultiInputStream.h"
|
||||||
|
|
||||||
|
SearchPathMultiInputStream::SearchPathMultiInputStream(ISearchPath& searchPath)
|
||||||
|
: m_search_path(searchPath)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<std::istream> SearchPathMultiInputStream::OpenIncludedFile(const std::string& filename, const std::string& sourceFile)
|
||||||
|
{
|
||||||
|
auto foundFileToInclude = m_search_path.Open(filename);
|
||||||
|
if (!foundFileToInclude.IsOpen() || !foundFileToInclude.m_stream)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return std::move(foundFileToInclude.m_stream);
|
||||||
|
}
|
15
src/ObjCommon/SearchPath/SearchPathMultiInputStream.h
Normal file
15
src/ObjCommon/SearchPath/SearchPathMultiInputStream.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Parsing/Impl/ParserMultiInputStream.h"
|
||||||
|
#include "SearchPath/ISearchPath.h"
|
||||||
|
|
||||||
|
class SearchPathMultiInputStream : public IInclusionCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit SearchPathMultiInputStream(ISearchPath& searchPath);
|
||||||
|
|
||||||
|
std::unique_ptr<std::istream> OpenIncludedFile(const std::string& filename, const std::string& sourceFile) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ISearchPath& m_search_path;
|
||||||
|
};
|
@ -18,9 +18,10 @@ SearchPathOpenFile SearchPaths::Open(const std::string& fileName)
|
|||||||
return SearchPathOpenFile();
|
return SearchPathOpenFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SearchPaths::GetPath()
|
const std::string& SearchPaths::GetPath()
|
||||||
{
|
{
|
||||||
return "SearchPaths: " + std::to_string(m_search_paths.size()) + " entries";
|
static const std::string STATIC_NAME = "SearchPaths";
|
||||||
|
return STATIC_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchPaths::Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback)
|
void SearchPaths::Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback)
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "ISearchPath.h"
|
#include "ISearchPath.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class SearchPaths final : public ISearchPath
|
class SearchPaths final : public ISearchPath
|
||||||
@ -16,7 +17,7 @@ public:
|
|||||||
~SearchPaths() override = default;
|
~SearchPaths() override = default;
|
||||||
|
|
||||||
SearchPathOpenFile Open(const std::string& fileName) override;
|
SearchPathOpenFile Open(const std::string& fileName) override;
|
||||||
std::string GetPath() override;
|
const std::string& GetPath() override;
|
||||||
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override;
|
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override;
|
||||||
|
|
||||||
SearchPaths(const SearchPaths& other) = delete;
|
SearchPaths(const SearchPaths& other) = delete;
|
58
src/ObjCompiling.lua
Normal file
58
src/ObjCompiling.lua
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
ObjCompiling = {}
|
||||||
|
|
||||||
|
function ObjCompiling:include(includes)
|
||||||
|
if includes:handle(self:name()) then
|
||||||
|
ObjCommon:include(includes)
|
||||||
|
ObjLoading:include(includes)
|
||||||
|
ObjImage:include(includes)
|
||||||
|
ZoneCommon:include(includes)
|
||||||
|
includedirs {
|
||||||
|
path.join(ProjectFolder(), "ObjCompiling")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ObjCompiling:link(links)
|
||||||
|
links:add(self:name())
|
||||||
|
links:linkto(minilzo)
|
||||||
|
links:linkto(Utils)
|
||||||
|
links:linkto(ObjCommon)
|
||||||
|
links:linkto(ObjLoading)
|
||||||
|
links:linkto(ObjImage)
|
||||||
|
links:linkto(ZoneCommon)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ObjCompiling:use()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ObjCompiling:name()
|
||||||
|
return "ObjCompiling"
|
||||||
|
end
|
||||||
|
|
||||||
|
function ObjCompiling:project()
|
||||||
|
local folder = ProjectFolder()
|
||||||
|
local includes = Includes:create()
|
||||||
|
|
||||||
|
project(self:name())
|
||||||
|
targetdir(TargetDirectoryLib)
|
||||||
|
location "%{wks.location}/src/%{prj.name}"
|
||||||
|
kind "StaticLib"
|
||||||
|
language "C++"
|
||||||
|
|
||||||
|
files {
|
||||||
|
path.join(folder, "ObjCompiling/**.h"),
|
||||||
|
path.join(folder, "ObjCompiling/**.cpp")
|
||||||
|
}
|
||||||
|
|
||||||
|
vpaths {
|
||||||
|
["*"] = {
|
||||||
|
path.join(folder, "ObjCompiling")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self:include(includes)
|
||||||
|
minilzo:include(includes)
|
||||||
|
Utils:include(includes)
|
||||||
|
json:include(includes)
|
||||||
|
end
|
44
src/ObjCompiling/Game/IW3/ObjCompilerIW3.cpp
Normal file
44
src/ObjCompiling/Game/IW3/ObjCompilerIW3.cpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include "ObjCompilerIW3.h"
|
||||||
|
|
||||||
|
#include "Game/IW3/IW3.h"
|
||||||
|
#include "Image/ImageIwdPostProcessor.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
using namespace IW3;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
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,
|
||||||
|
const fs::path& 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,
|
||||||
|
const fs::path& outDir,
|
||||||
|
const fs::path& cacheDir) const
|
||||||
|
{
|
||||||
|
ConfigurePostProcessors(collection, zone, zoneDefinition, searchPath, zoneStates, outDir);
|
||||||
|
}
|
19
src/ObjCompiling/Game/IW3/ObjCompilerIW3.h
Normal file
19
src/ObjCompiling/Game/IW3/ObjCompilerIW3.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IObjCompiler.h"
|
||||||
|
|
||||||
|
namespace IW3
|
||||||
|
{
|
||||||
|
class ObjCompiler final : public IObjCompiler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void ConfigureCreatorCollection(AssetCreatorCollection& collection,
|
||||||
|
Zone& zone,
|
||||||
|
const ZoneDefinitionContext& zoneDefinition,
|
||||||
|
ISearchPath& searchPath,
|
||||||
|
IGdtQueryable& gdt,
|
||||||
|
ZoneAssetCreationStateContainer& zoneStates,
|
||||||
|
const std::filesystem::path& outDir,
|
||||||
|
const std::filesystem::path& cacheDir) const override;
|
||||||
|
};
|
||||||
|
} // namespace IW3
|
44
src/ObjCompiling/Game/IW4/ObjCompilerIW4.cpp
Normal file
44
src/ObjCompiling/Game/IW4/ObjCompilerIW4.cpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include "ObjCompilerIW4.h"
|
||||||
|
|
||||||
|
#include "Game/IW4/IW4.h"
|
||||||
|
#include "Image/ImageIwdPostProcessor.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
using namespace IW4;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
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,
|
||||||
|
const fs::path& 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,
|
||||||
|
const fs::path& outDir,
|
||||||
|
const fs::path& cacheDir) const
|
||||||
|
{
|
||||||
|
ConfigurePostProcessors(collection, zone, zoneDefinition, searchPath, zoneStates, outDir);
|
||||||
|
}
|
19
src/ObjCompiling/Game/IW4/ObjCompilerIW4.h
Normal file
19
src/ObjCompiling/Game/IW4/ObjCompilerIW4.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IObjCompiler.h"
|
||||||
|
|
||||||
|
namespace IW4
|
||||||
|
{
|
||||||
|
class ObjCompiler final : public IObjCompiler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void ConfigureCreatorCollection(AssetCreatorCollection& collection,
|
||||||
|
Zone& zone,
|
||||||
|
const ZoneDefinitionContext& zoneDefinition,
|
||||||
|
ISearchPath& searchPath,
|
||||||
|
IGdtQueryable& gdt,
|
||||||
|
ZoneAssetCreationStateContainer& zoneStates,
|
||||||
|
const std::filesystem::path& outDir,
|
||||||
|
const std::filesystem::path& cacheDir) const override;
|
||||||
|
};
|
||||||
|
} // namespace IW4
|
44
src/ObjCompiling/Game/IW5/ObjCompilerIW5.cpp
Normal file
44
src/ObjCompiling/Game/IW5/ObjCompilerIW5.cpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include "ObjCompilerIW5.h"
|
||||||
|
|
||||||
|
#include "Game/IW5/IW5.h"
|
||||||
|
#include "Image/ImageIwdPostProcessor.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
using namespace IW5;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
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,
|
||||||
|
const fs::path& 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,
|
||||||
|
const fs::path& outDir,
|
||||||
|
const fs::path& cacheDir) const
|
||||||
|
{
|
||||||
|
ConfigurePostProcessors(collection, zone, zoneDefinition, searchPath, zoneStates, outDir);
|
||||||
|
}
|
19
src/ObjCompiling/Game/IW5/ObjCompilerIW5.h
Normal file
19
src/ObjCompiling/Game/IW5/ObjCompilerIW5.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IObjCompiler.h"
|
||||||
|
|
||||||
|
namespace IW5
|
||||||
|
{
|
||||||
|
class ObjCompiler final : public IObjCompiler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void ConfigureCreatorCollection(AssetCreatorCollection& collection,
|
||||||
|
Zone& zone,
|
||||||
|
const ZoneDefinitionContext& zoneDefinition,
|
||||||
|
ISearchPath& searchPath,
|
||||||
|
IGdtQueryable& gdt,
|
||||||
|
ZoneAssetCreationStateContainer& zoneStates,
|
||||||
|
const std::filesystem::path& outDir,
|
||||||
|
const std::filesystem::path& cacheDir) const override;
|
||||||
|
};
|
||||||
|
} // namespace IW5
|
44
src/ObjCompiling/Game/T5/ObjCompilerT5.cpp
Normal file
44
src/ObjCompiling/Game/T5/ObjCompilerT5.cpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include "ObjCompilerT5.h"
|
||||||
|
|
||||||
|
#include "Game/T5/T5.h"
|
||||||
|
#include "Image/ImageIwdPostProcessor.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
using namespace T5;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
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,
|
||||||
|
const fs::path& 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,
|
||||||
|
const fs::path& outDir,
|
||||||
|
const fs::path& cacheDir) const
|
||||||
|
{
|
||||||
|
ConfigurePostProcessors(collection, zone, zoneDefinition, searchPath, zoneStates, outDir);
|
||||||
|
}
|
19
src/ObjCompiling/Game/T5/ObjCompilerT5.h
Normal file
19
src/ObjCompiling/Game/T5/ObjCompilerT5.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IObjCompiler.h"
|
||||||
|
|
||||||
|
namespace T5
|
||||||
|
{
|
||||||
|
class ObjCompiler final : public IObjCompiler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void ConfigureCreatorCollection(AssetCreatorCollection& collection,
|
||||||
|
Zone& zone,
|
||||||
|
const ZoneDefinitionContext& zoneDefinition,
|
||||||
|
ISearchPath& searchPath,
|
||||||
|
IGdtQueryable& gdt,
|
||||||
|
ZoneAssetCreationStateContainer& zoneStates,
|
||||||
|
const std::filesystem::path& outDir,
|
||||||
|
const std::filesystem::path& cacheDir) const override;
|
||||||
|
};
|
||||||
|
} // namespace T5
|
@ -0,0 +1,62 @@
|
|||||||
|
#include "KeyValuePairsCompilerT6.h"
|
||||||
|
|
||||||
|
#include "Game/T6/CommonT6.h"
|
||||||
|
#include "Game/T6/T6.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <format>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace T6;
|
||||||
|
|
||||||
|
KeyValuePairsCompiler::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>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<asset_type_t> KeyValuePairsCompiler::GetHandlingAssetType() const
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetCreationResult KeyValuePairsCompiler::CreateAsset(const std::string& assetName, AssetCreationContext& context)
|
||||||
|
{
|
||||||
|
return AssetCreationResult::NoAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyValuePairsCompiler::FinalizeZone(AssetCreationContext& context)
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Asset/IAssetCreator.h"
|
||||||
|
#include "Game/T6/T6.h"
|
||||||
|
#include "KeyValuePairs/KeyValuePairsCreator.h"
|
||||||
|
#include "Utils/MemoryManager.h"
|
||||||
|
#include "Zone/Definition/ZoneDefinition.h"
|
||||||
|
#include "Zone/Zone.h"
|
||||||
|
|
||||||
|
namespace T6
|
||||||
|
{
|
||||||
|
class KeyValuePairsCompiler final : public IAssetCreator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KeyValuePairsCompiler(MemoryManager& memory, const Zone& zone, const ZoneDefinition& zoneDefinition, ZoneAssetCreationStateContainer& zoneStates);
|
||||||
|
|
||||||
|
[[nodiscard]] std::optional<asset_type_t> GetHandlingAssetType() const override;
|
||||||
|
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override;
|
||||||
|
void FinalizeZone(AssetCreationContext& context) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
MemoryManager& m_memory;
|
||||||
|
const Zone& m_zone;
|
||||||
|
const ZoneDefinition& m_zone_definition;
|
||||||
|
KeyValuePairsCreator& m_kvp_creator;
|
||||||
|
};
|
||||||
|
} // namespace T6
|
54
src/ObjCompiling/Game/T6/ObjCompilerT6.cpp
Normal file
54
src/ObjCompiling/Game/T6/ObjCompilerT6.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#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 fs = std::filesystem;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
void ConfigureCompilers(AssetCreatorCollection& collection,
|
||||||
|
Zone& zone,
|
||||||
|
const ZoneDefinitionContext& zoneDefinition,
|
||||||
|
ISearchPath& searchPath,
|
||||||
|
ZoneAssetCreationStateContainer& zoneStates)
|
||||||
|
{
|
||||||
|
auto& memory = *zone.GetMemory();
|
||||||
|
|
||||||
|
collection.AddAssetCreator(std::make_unique<KeyValuePairsCompiler>(memory, zone, zoneDefinition.m_zone_definition, zoneStates));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurePostProcessors(AssetCreatorCollection& collection,
|
||||||
|
Zone& zone,
|
||||||
|
const ZoneDefinitionContext& zoneDefinition,
|
||||||
|
ISearchPath& searchPath,
|
||||||
|
ZoneAssetCreationStateContainer& zoneStates,
|
||||||
|
const fs::path& 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,
|
||||||
|
const fs::path& outDir,
|
||||||
|
const fs::path& cacheDir) const
|
||||||
|
{
|
||||||
|
ConfigureCompilers(collection, zone, zoneDefinition, searchPath, zoneStates);
|
||||||
|
ConfigurePostProcessors(collection, zone, zoneDefinition, searchPath, zoneStates, outDir);
|
||||||
|
}
|
19
src/ObjCompiling/Game/T6/ObjCompilerT6.h
Normal file
19
src/ObjCompiling/Game/T6/ObjCompilerT6.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IObjCompiler.h"
|
||||||
|
|
||||||
|
namespace T6
|
||||||
|
{
|
||||||
|
class ObjCompiler final : public IObjCompiler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void ConfigureCreatorCollection(AssetCreatorCollection& collection,
|
||||||
|
Zone& zone,
|
||||||
|
const ZoneDefinitionContext& zoneDefinition,
|
||||||
|
ISearchPath& searchPath,
|
||||||
|
IGdtQueryable& gdt,
|
||||||
|
ZoneAssetCreationStateContainer& zoneStates,
|
||||||
|
const std::filesystem::path& outDir,
|
||||||
|
const std::filesystem::path& cacheDir) const override;
|
||||||
|
};
|
||||||
|
} // namespace T6
|
27
src/ObjCompiling/IObjCompiler.cpp
Normal file
27
src/ObjCompiling/IObjCompiler.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#include "IObjCompiler.h"
|
||||||
|
|
||||||
|
#include "Game/IW3/ObjCompilerIW3.h"
|
||||||
|
#include "Game/IW4/ObjCompilerIW4.h"
|
||||||
|
#include "Game/IW5/ObjCompilerIW5.h"
|
||||||
|
#include "Game/T5/ObjCompilerT5.h"
|
||||||
|
#include "Game/T6/ObjCompilerT6.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
const IObjCompiler* IObjCompiler::GetObjCompilerForGame(GameId game)
|
||||||
|
{
|
||||||
|
static const IObjCompiler* objCompilers[static_cast<unsigned>(GameId::COUNT)]{
|
||||||
|
new IW3::ObjCompiler(),
|
||||||
|
new IW4::ObjCompiler(),
|
||||||
|
new IW5::ObjCompiler(),
|
||||||
|
new T5::ObjCompiler(),
|
||||||
|
new T6::ObjCompiler(),
|
||||||
|
};
|
||||||
|
static_assert(std::extent_v<decltype(objCompilers)> == static_cast<unsigned>(GameId::COUNT));
|
||||||
|
|
||||||
|
assert(static_cast<unsigned>(game) < static_cast<unsigned>(GameId::COUNT));
|
||||||
|
const auto* result = objCompilers[static_cast<unsigned>(game)];
|
||||||
|
assert(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
35
src/ObjCompiling/IObjCompiler.h
Normal file
35
src/ObjCompiling/IObjCompiler.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Asset/AssetCreatorCollection.h"
|
||||||
|
#include "Asset/IZoneAssetCreationState.h"
|
||||||
|
#include "Asset/ZoneDefinitionContext.h"
|
||||||
|
#include "Gdt/IGdtQueryable.h"
|
||||||
|
#include "SearchPath/ISearchPath.h"
|
||||||
|
#include "Zone/Definition/ZoneDefinition.h"
|
||||||
|
#include "Zone/Zone.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
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,
|
||||||
|
const std::filesystem::path& outDir,
|
||||||
|
const std::filesystem::path& cacheDir) const = 0;
|
||||||
|
|
||||||
|
static const IObjCompiler* GetObjCompilerForGame(GameId game);
|
||||||
|
};
|
431
src/ObjCompiling/Image/IPak/IPakCreator.cpp
Normal file
431
src/ObjCompiling/Image/IPak/IPakCreator.cpp
Normal file
@ -0,0 +1,431 @@
|
|||||||
|
#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),
|
||||||
|
0u);
|
||||||
|
|
||||||
|
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, const std::filesystem::path& outPath)
|
||||||
|
{
|
||||||
|
auto filePath = outPath / std::format("{}.ipak", m_name);
|
||||||
|
std::ofstream file(filePath, std::ios::out | std::ios::binary);
|
||||||
|
if (!file.is_open())
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
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_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, const std::filesystem::path& outPath)
|
||||||
|
{
|
||||||
|
for (const auto& ipakToCreate : m_ipaks)
|
||||||
|
ipakToCreate->Build(searchPath, outPath);
|
||||||
|
|
||||||
|
m_ipaks.clear();
|
||||||
|
m_ipak_lookup.clear();
|
||||||
|
}
|
39
src/ObjCompiling/Image/IPak/IPakCreator.h
Normal file
39
src/ObjCompiling/Image/IPak/IPakCreator.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Asset/IZoneAssetCreationState.h"
|
||||||
|
#include "KeyValuePairs/KeyValuePairsCreator.h"
|
||||||
|
#include "SearchPath/ISearchPath.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
class IPakToCreate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit IPakToCreate(std::string name);
|
||||||
|
|
||||||
|
void AddImage(std::string imageName);
|
||||||
|
void Build(ISearchPath& searchPath, const std::filesystem::path& outPath);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_name;
|
||||||
|
std::vector<std::string> m_image_names;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IPakCreator : public IZoneAssetCreationState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IPakCreator();
|
||||||
|
|
||||||
|
void Inject(ZoneAssetCreationInjection& inject) override;
|
||||||
|
|
||||||
|
IPakToCreate* GetOrAddIPak(const std::string& ipakName);
|
||||||
|
void Finalize(ISearchPath& searchPath, const std::filesystem::path& outPath);
|
||||||
|
|
||||||
|
private:
|
||||||
|
KeyValuePairsCreator* m_kvp_creator;
|
||||||
|
std::unordered_map<std::string, IPakToCreate*> m_ipak_lookup;
|
||||||
|
std::vector<std::unique_ptr<IPakToCreate>> m_ipaks;
|
||||||
|
};
|
75
src/ObjCompiling/Image/ImageIPakPostProcessor.cpp
Normal file
75
src/ObjCompiling/Image/ImageIPakPostProcessor.cpp
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#include "ImageIPakPostProcessor.h"
|
||||||
|
|
||||||
|
#include "IPak/IPakCreator.h"
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
|
||||||
|
AbstractImageIPakPostProcessor::AbstractImageIPakPostProcessor(const ZoneDefinitionContext& zoneDefinition,
|
||||||
|
ISearchPath& searchPath,
|
||||||
|
ZoneAssetCreationStateContainer& zoneStates,
|
||||||
|
const std::filesystem::path& outDir)
|
||||||
|
: m_zone_definition(zoneDefinition),
|
||||||
|
m_search_path(searchPath),
|
||||||
|
m_ipak_creator(zoneStates.GetZoneAssetCreationState<IPakCreator>()),
|
||||||
|
m_out_dir(outDir),
|
||||||
|
m_initialized(false),
|
||||||
|
m_obj_container_index(0u),
|
||||||
|
m_current_ipak(nullptr),
|
||||||
|
m_current_ipak_start_index(0u),
|
||||||
|
m_current_ipak_end_index(0u)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AbstractImageIPakPostProcessor::AppliesToZoneDefinition(const ZoneDefinitionContext& zoneDefinition)
|
||||||
|
{
|
||||||
|
for (const auto& objContainer : zoneDefinition.m_zone_definition.m_obj_containers)
|
||||||
|
{
|
||||||
|
if (objContainer.m_type == ZoneDefinitionObjContainerType::IPAK)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractImageIPakPostProcessor::FindNextObjContainer(AssetCreationContext& context)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Initialize on first image occurance
|
||||||
|
if (!m_initialized)
|
||||||
|
{
|
||||||
|
FindNextObjContainer(context);
|
||||||
|
m_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (m_current_ipak && m_zone_definition.m_asset_index_in_definition >= m_current_ipak_end_index)
|
||||||
|
FindNextObjContainer(context);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
54
src/ObjCompiling/Image/ImageIPakPostProcessor.h
Normal file
54
src/ObjCompiling/Image/ImageIPakPostProcessor.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Asset/IAssetPostProcessor.h"
|
||||||
|
#include "Asset/ZoneDefinitionContext.h"
|
||||||
|
#include "Image/IPak/IPakCreator.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
class AbstractImageIPakPostProcessor : public IAssetPostProcessor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AbstractImageIPakPostProcessor(const ZoneDefinitionContext& zoneDefinition,
|
||||||
|
ISearchPath& searchPath,
|
||||||
|
ZoneAssetCreationStateContainer& zoneStates,
|
||||||
|
const std::filesystem::path& outDir);
|
||||||
|
|
||||||
|
static bool AppliesToZoneDefinition(const ZoneDefinitionContext& zoneDefinition);
|
||||||
|
|
||||||
|
void PostProcessAsset(XAssetInfoGeneric& assetInfo, AssetCreationContext& context) override;
|
||||||
|
void FinalizeZone(AssetCreationContext& context) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void FindNextObjContainer(AssetCreationContext& context);
|
||||||
|
|
||||||
|
const ZoneDefinitionContext& m_zone_definition;
|
||||||
|
ISearchPath& m_search_path;
|
||||||
|
IPakCreator& m_ipak_creator;
|
||||||
|
const std::filesystem::path& m_out_dir;
|
||||||
|
|
||||||
|
bool m_initialized;
|
||||||
|
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,
|
||||||
|
const std::filesystem::path& outDir)
|
||||||
|
: AbstractImageIPakPostProcessor(zoneDefinition, searchPath, zoneStates, outDir)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] asset_type_t GetHandlingAssetType() const override
|
||||||
|
{
|
||||||
|
return AssetType::EnumEntry;
|
||||||
|
};
|
||||||
|
};
|
76
src/ObjCompiling/Image/ImageIwdPostProcessor.cpp
Normal file
76
src/ObjCompiling/Image/ImageIwdPostProcessor.cpp
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#include "ImageIwdPostProcessor.h"
|
||||||
|
|
||||||
|
#include "Iwd/IwdCreator.h"
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
AbstractImageIwdPostProcessor::AbstractImageIwdPostProcessor(const ZoneDefinitionContext& zoneDefinition,
|
||||||
|
ISearchPath& searchPath,
|
||||||
|
ZoneAssetCreationStateContainer& zoneStates,
|
||||||
|
const std::filesystem::path& outDir)
|
||||||
|
: m_zone_definition(zoneDefinition),
|
||||||
|
m_search_path(searchPath),
|
||||||
|
m_iwd_creator(zoneStates.GetZoneAssetCreationState<IwdCreator>()),
|
||||||
|
m_out_dir(outDir),
|
||||||
|
m_initialized(false),
|
||||||
|
m_obj_container_index(0u),
|
||||||
|
m_current_iwd(nullptr),
|
||||||
|
m_current_iwd_start_index(0u),
|
||||||
|
m_current_iwd_end_index(0u)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AbstractImageIwdPostProcessor::AppliesToZoneDefinition(const ZoneDefinitionContext& zoneDefinition)
|
||||||
|
{
|
||||||
|
for (const auto& objContainer : zoneDefinition.m_zone_definition.m_obj_containers)
|
||||||
|
{
|
||||||
|
if (objContainer.m_type == ZoneDefinitionObjContainerType::IWD)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractImageIwdPostProcessor::FindNextObjContainer(AssetCreationContext& context)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Initialize on first image occurance
|
||||||
|
if (!m_initialized)
|
||||||
|
{
|
||||||
|
FindNextObjContainer(context);
|
||||||
|
m_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (m_current_iwd && m_zone_definition.m_asset_index_in_definition >= m_current_iwd_end_index)
|
||||||
|
FindNextObjContainer(context);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
54
src/ObjCompiling/Image/ImageIwdPostProcessor.h
Normal file
54
src/ObjCompiling/Image/ImageIwdPostProcessor.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Asset/IAssetPostProcessor.h"
|
||||||
|
#include "Asset/ZoneDefinitionContext.h"
|
||||||
|
#include "Iwd/IwdCreator.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
class AbstractImageIwdPostProcessor : public IAssetPostProcessor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AbstractImageIwdPostProcessor(const ZoneDefinitionContext& zoneDefinition,
|
||||||
|
ISearchPath& searchPath,
|
||||||
|
ZoneAssetCreationStateContainer& zoneStates,
|
||||||
|
const std::filesystem::path& outDir);
|
||||||
|
|
||||||
|
static bool AppliesToZoneDefinition(const ZoneDefinitionContext& zoneDefinition);
|
||||||
|
|
||||||
|
void PostProcessAsset(XAssetInfoGeneric& assetInfo, AssetCreationContext& context) override;
|
||||||
|
void FinalizeZone(AssetCreationContext& context) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void FindNextObjContainer(AssetCreationContext& context);
|
||||||
|
|
||||||
|
const ZoneDefinitionContext& m_zone_definition;
|
||||||
|
ISearchPath& m_search_path;
|
||||||
|
IwdCreator& m_iwd_creator;
|
||||||
|
const std::filesystem::path& m_out_dir;
|
||||||
|
|
||||||
|
bool m_initialized;
|
||||||
|
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,
|
||||||
|
const std::filesystem::path& outDir)
|
||||||
|
: AbstractImageIwdPostProcessor(zoneDefinition, searchPath, zoneStates, outDir)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] asset_type_t GetHandlingAssetType() const override
|
||||||
|
{
|
||||||
|
return AssetType::EnumEntry;
|
||||||
|
};
|
||||||
|
};
|
103
src/ObjCompiling/Iwd/IwdCreator.cpp
Normal file
103
src/ObjCompiling/Iwd/IwdCreator.cpp
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#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, const std::filesystem::path& outPath)
|
||||||
|
{
|
||||||
|
auto filePath = outPath / std::format("{}.iwd", m_name);
|
||||||
|
std::ofstream file(filePath, std::ios::out | std::ios::binary);
|
||||||
|
if (!file.is_open())
|
||||||
|
{
|
||||||
|
std::cerr << std::format("Failed to open file for iwd {}\n", m_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto functions = FileToZlibWrapper::CreateFunctions32ForFile(&file);
|
||||||
|
|
||||||
|
auto zipFile = zipOpen2(filePath.string().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());
|
||||||
|
}
|
||||||
|
|
||||||
|
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_iwds.emplace_back(std::move(newIwd));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IwdCreator::Finalize(ISearchPath& searchPath, const std::filesystem::path& 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();
|
||||||
|
}
|
33
src/ObjCompiling/Iwd/IwdCreator.h
Normal file
33
src/ObjCompiling/Iwd/IwdCreator.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Asset/IZoneAssetCreationState.h"
|
||||||
|
#include "SearchPath/ISearchPath.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
class IwdToCreate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit IwdToCreate(std::string name);
|
||||||
|
|
||||||
|
void AddFile(std::string filePath);
|
||||||
|
void Build(ISearchPath& searchPath, const std::filesystem::path& outPath);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_name;
|
||||||
|
std::vector<std::string> m_file_paths;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IwdCreator : public IZoneAssetCreationState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IwdToCreate* GetOrAddIwd(const std::string& iwdName);
|
||||||
|
void Finalize(ISearchPath& searchPath, const std::filesystem::path& outPath);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<std::string, IwdToCreate*> m_iwd_lookup;
|
||||||
|
std::vector<std::unique_ptr<IwdToCreate>> m_iwds;
|
||||||
|
};
|
57
src/ObjCompiling/KeyValuePairs/KeyValuePairsCreator.cpp
Normal file
57
src/ObjCompiling/KeyValuePairs/KeyValuePairsCreator.cpp
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#include "KeyValuePairsCreator.h"
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
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::vector<CommonKeyValuePair> KeyValuePairsCreator::GetFinalKeyValuePairs()
|
||||||
|
{
|
||||||
|
return std::move(m_key_value_pairs);
|
||||||
|
}
|
30
src/ObjCompiling/KeyValuePairs/KeyValuePairsCreator.h
Normal file
30
src/ObjCompiling/KeyValuePairs/KeyValuePairsCreator.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#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 : public IZoneAssetCreationState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void AddKeyValuePair(CommonKeyValuePair keyValuePair);
|
||||||
|
void Finalize(const ZoneDefinition& zoneDefinition);
|
||||||
|
std::vector<CommonKeyValuePair> GetFinalKeyValuePairs();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<CommonKeyValuePair> m_key_value_pairs;
|
||||||
|
};
|
139
src/ObjLoading/Asset/AssetCreationContext.cpp
Normal file
139
src/ObjLoading/Asset/AssetCreationContext.cpp
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
#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_creators(creators),
|
||||||
|
m_ignored_asset_lookup(ignoredAssetLookup)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
auto* 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_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(asset_type_t assetType, const std::string& assetName)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
76
src/ObjLoading/Asset/AssetCreationContext.h
Normal file
76
src/ObjLoading/Asset/AssetCreationContext.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#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);
|
||||||
|
|
||||||
|
private:
|
||||||
|
[[nodiscard]] XAssetInfoGeneric* LoadDefaultAssetDependency(asset_type_t assetType, const std::string& assetName);
|
||||||
|
|
||||||
|
Zone& m_zone;
|
||||||
|
const AssetCreatorCollection* m_creators;
|
||||||
|
const IgnoredAssetLookup* m_ignored_asset_lookup;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "AssetCreatorCollection.h"
|
45
src/ObjLoading/Asset/AssetCreationResult.cpp
Normal file
45
src/ObjLoading/Asset/AssetCreationResult.cpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#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)
|
||||||
|
{
|
||||||
|
}
|
22
src/ObjLoading/Asset/AssetCreationResult.h
Normal file
22
src/ObjLoading/Asset/AssetCreationResult.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#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;
|
||||||
|
};
|
88
src/ObjLoading/Asset/AssetCreatorCollection.cpp
Normal file
88
src/ObjLoading/Asset/AssetCreatorCollection.cpp
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#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);
|
||||||
|
}
|
38
src/ObjLoading/Asset/AssetCreatorCollection.h
Normal file
38
src/ObjLoading/Asset/AssetCreatorCollection.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#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;
|
||||||
|
};
|
61
src/ObjLoading/Asset/AssetRegistration.h
Normal file
61
src/ObjLoading/Asset/AssetRegistration.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
|
};
|
46
src/ObjLoading/Asset/GlobalAssetPoolsLoader.h
Normal file
46
src/ObjLoading/Asset/GlobalAssetPoolsLoader.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Asset/IAssetCreator.h"
|
||||||
|
#include "Pool/GlobalAssetPool.h"
|
||||||
|
|
||||||
|
template<typename AssetType> class GlobalAssetPoolsLoader : public AssetCreator<AssetType>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
|
||||||
|
|
||||||
|
GlobalAssetPoolsLoader(Zone& zone)
|
||||||
|
: m_zone(zone)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
||||||
|
{
|
||||||
|
auto* existingAsset = GlobalAssetPool<typename AssetType::Type>::GetAssetByName(assetName);
|
||||||
|
|
||||||
|
if (!existingAsset)
|
||||||
|
return AssetCreationResult::NoAction();
|
||||||
|
|
||||||
|
AssetRegistration<AssetType> registration(assetName, existingAsset->Asset());
|
||||||
|
|
||||||
|
for (const auto* dependency : existingAsset->m_dependencies)
|
||||||
|
{
|
||||||
|
auto* newDependency = context.LoadDependencyGeneric(dependency->m_type, dependency->m_name);
|
||||||
|
if (newDependency)
|
||||||
|
registration.AddDependency(newDependency);
|
||||||
|
else
|
||||||
|
return AssetCreationResult::Failure();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& indirectAssetReference : existingAsset->m_indirect_asset_references)
|
||||||
|
registration.AddIndirectAssetReference(context.LoadIndirectAssetReferenceGeneric(indirectAssetReference.m_type, indirectAssetReference.m_name));
|
||||||
|
|
||||||
|
// Make sure any used script string is available in the created zone
|
||||||
|
// The replacement of the scr_string_t values will be done upon writing
|
||||||
|
for (const auto scrString : existingAsset->m_used_script_strings)
|
||||||
|
m_zone.m_script_strings.AddOrGetScriptString(existingAsset->m_zone->m_script_strings.CValue(scrString));
|
||||||
|
|
||||||
|
return AssetCreationResult::Success(context.AddAsset(std::move(registration)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Zone& m_zone;
|
||||||
|
};
|
40
src/ObjLoading/Asset/IAssetCreator.h
Normal file
40
src/ObjLoading/Asset/IAssetCreator.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AssetCreationContext.h"
|
||||||
|
#include "AssetCreationResult.h"
|
||||||
|
#include "Game/IAsset.h"
|
||||||
|
#include "Pool/XAssetInfo.h"
|
||||||
|
#include "SearchPath/ISearchPath.h"
|
||||||
|
#include "Utils/MemoryManager.h"
|
||||||
|
#include "Zone/ZoneTypes.h"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class AssetCreationContext;
|
||||||
|
|
||||||
|
class IAssetCreator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IAssetCreator() = default;
|
||||||
|
virtual ~IAssetCreator() = default;
|
||||||
|
IAssetCreator(const IAssetCreator& other) = default;
|
||||||
|
IAssetCreator(IAssetCreator&& other) noexcept = default;
|
||||||
|
IAssetCreator& operator=(const IAssetCreator& other) = default;
|
||||||
|
IAssetCreator& operator=(IAssetCreator&& other) noexcept = default;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual std::optional<asset_type_t> GetHandlingAssetType() const = 0;
|
||||||
|
virtual AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) = 0;
|
||||||
|
virtual void FinalizeZone(AssetCreationContext& context){};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename AssetType> class AssetCreator : public IAssetCreator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
|
||||||
|
|
||||||
|
[[nodiscard]] std::optional<asset_type_t> GetHandlingAssetType() const override
|
||||||
|
{
|
||||||
|
return AssetType::EnumEntry;
|
||||||
|
};
|
||||||
|
};
|
29
src/ObjLoading/Asset/IAssetPostProcessor.h
Normal file
29
src/ObjLoading/Asset/IAssetPostProcessor.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AssetCreationContext.h"
|
||||||
|
#include "AssetCreationResult.h"
|
||||||
|
#include "Game/IAsset.h"
|
||||||
|
#include "Pool/XAssetInfo.h"
|
||||||
|
#include "SearchPath/ISearchPath.h"
|
||||||
|
#include "Utils/MemoryManager.h"
|
||||||
|
#include "Zone/ZoneTypes.h"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class AssetCreationContext;
|
||||||
|
|
||||||
|
class IAssetPostProcessor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IAssetPostProcessor() = default;
|
||||||
|
virtual ~IAssetPostProcessor() = default;
|
||||||
|
IAssetPostProcessor(const IAssetPostProcessor& other) = default;
|
||||||
|
IAssetPostProcessor(IAssetPostProcessor&& other) noexcept = default;
|
||||||
|
IAssetPostProcessor& operator=(const IAssetPostProcessor& other) = default;
|
||||||
|
IAssetPostProcessor& operator=(IAssetPostProcessor&& other) noexcept = default;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual asset_type_t GetHandlingAssetType() const = 0;
|
||||||
|
virtual void PostProcessAsset(XAssetInfoGeneric& assetInfo, AssetCreationContext& context) = 0;
|
||||||
|
virtual void FinalizeZone(AssetCreationContext& context){};
|
||||||
|
};
|
52
src/ObjLoading/Asset/IDefaultAssetCreator.h
Normal file
52
src/ObjLoading/Asset/IDefaultAssetCreator.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AssetCreationContext.h"
|
||||||
|
#include "AssetCreationResult.h"
|
||||||
|
#include "Game/IAsset.h"
|
||||||
|
#include "IAssetCreator.h"
|
||||||
|
#include "Utils/MemoryManager.h"
|
||||||
|
#include "Zone/ZoneTypes.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
class IDefaultAssetCreator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IDefaultAssetCreator() = default;
|
||||||
|
virtual ~IDefaultAssetCreator() = default;
|
||||||
|
IDefaultAssetCreator(const IDefaultAssetCreator& other) = default;
|
||||||
|
IDefaultAssetCreator(IDefaultAssetCreator&& other) noexcept = default;
|
||||||
|
IDefaultAssetCreator& operator=(const IDefaultAssetCreator& other) = default;
|
||||||
|
IDefaultAssetCreator& operator=(IDefaultAssetCreator&& other) noexcept = default;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual asset_type_t GetHandlingAssetType() const = 0;
|
||||||
|
virtual AssetCreationResult CreateDefaultAsset(const std::string& assetName, AssetCreationContext& context) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename AssetType> class DefaultAssetCreator : public IDefaultAssetCreator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
|
||||||
|
|
||||||
|
DefaultAssetCreator(MemoryManager& memory)
|
||||||
|
: m_memory(memory)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] asset_type_t GetHandlingAssetType() const override
|
||||||
|
{
|
||||||
|
return AssetType::EnumEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetCreationResult CreateDefaultAsset(const std::string& assetName, AssetCreationContext& context) const override
|
||||||
|
{
|
||||||
|
auto* asset = m_memory.Alloc<typename AssetType::Type>();
|
||||||
|
AssetNameAccessor<AssetType>{}(*asset) = m_memory.Dup(assetName.c_str());
|
||||||
|
|
||||||
|
return AssetCreationResult::Success(context.AddAsset<AssetType>(assetName, asset));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MemoryManager& m_memory;
|
||||||
|
};
|
70
src/ObjLoading/Asset/IZoneAssetCreationState.h
Normal file
70
src/ObjLoading/Asset/IZoneAssetCreationState.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Zone/Zone.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <typeindex>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
class ZoneAssetCreationStateContainer;
|
||||||
|
|
||||||
|
class ZoneAssetCreationInjection
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ZoneAssetCreationInjection(ZoneAssetCreationStateContainer& zoneStates, Zone& zone)
|
||||||
|
: m_zone_states(zoneStates),
|
||||||
|
m_zone(zone)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ZoneAssetCreationStateContainer& m_zone_states;
|
||||||
|
Zone& m_zone;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IZoneAssetCreationState
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
IZoneAssetCreationState() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~IZoneAssetCreationState() = default;
|
||||||
|
IZoneAssetCreationState(const IZoneAssetCreationState& other) = default;
|
||||||
|
IZoneAssetCreationState(IZoneAssetCreationState&& other) noexcept = default;
|
||||||
|
IZoneAssetCreationState& operator=(const IZoneAssetCreationState& other) = default;
|
||||||
|
IZoneAssetCreationState& operator=(IZoneAssetCreationState&& other) noexcept = default;
|
||||||
|
|
||||||
|
virtual void Inject(ZoneAssetCreationInjection& inject)
|
||||||
|
{
|
||||||
|
// Do nothing by default
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ZoneAssetCreationStateContainer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ZoneAssetCreationStateContainer(Zone& zone)
|
||||||
|
: m_injection(*this, zone)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> T& GetZoneAssetCreationState()
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of_v<IZoneAssetCreationState, T>, "T must inherit IZoneAssetCreationState");
|
||||||
|
// T must also have a public default constructor
|
||||||
|
|
||||||
|
const auto foundEntry = m_zone_asset_creation_states.find(typeid(T));
|
||||||
|
if (foundEntry != m_zone_asset_creation_states.end())
|
||||||
|
return *dynamic_cast<T*>(foundEntry->second.get());
|
||||||
|
|
||||||
|
auto newState = std::make_unique<T>();
|
||||||
|
newState->Inject(m_injection);
|
||||||
|
auto* newStatePtr = newState.get();
|
||||||
|
m_zone_asset_creation_states.emplace(std::make_pair<std::type_index, std::unique_ptr<IZoneAssetCreationState>>(typeid(T), std::move(newState)));
|
||||||
|
|
||||||
|
return *newStatePtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ZoneAssetCreationInjection m_injection;
|
||||||
|
std::unordered_map<std::type_index, std::unique_ptr<IZoneAssetCreationState>> m_zone_asset_creation_states;
|
||||||
|
};
|
16
src/ObjLoading/Asset/ZoneDefinitionContext.h
Normal file
16
src/ObjLoading/Asset/ZoneDefinitionContext.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Zone/Definition/ZoneDefinition.h"
|
||||||
|
|
||||||
|
class ZoneDefinitionContext
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ZoneDefinitionContext(const ZoneDefinition& zoneDefinition)
|
||||||
|
: m_zone_definition(zoneDefinition),
|
||||||
|
m_asset_index_in_definition(0u)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const ZoneDefinition& m_zone_definition;
|
||||||
|
unsigned m_asset_index_in_definition;
|
||||||
|
};
|
@ -1,46 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "IGdtQueryable.h"
|
|
||||||
#include "IZoneAssetLoaderState.h"
|
|
||||||
#include "Obj/Gdt/Gdt.h"
|
|
||||||
#include "SearchPath/ISearchPath.h"
|
|
||||||
#include "Zone/Zone.h"
|
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include <typeindex>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
class AssetLoadingContext final : public IGdtQueryable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AssetLoadingContext(Zone& zone, ISearchPath& rawSearchPath, std::vector<Gdt*> gdtFiles);
|
|
||||||
GdtEntry* GetGdtEntryByGdfAndName(const std::string& gdfName, const std::string& entryName) override;
|
|
||||||
|
|
||||||
template<typename T> T* GetZoneAssetLoaderState()
|
|
||||||
{
|
|
||||||
static_assert(std::is_base_of_v<IZoneAssetLoaderState, T>, "T must inherit IZoneAssetLoaderState");
|
|
||||||
// T must also have a public default constructor
|
|
||||||
|
|
||||||
const auto foundEntry = m_zone_asset_loader_states.find(typeid(T));
|
|
||||||
if (foundEntry != m_zone_asset_loader_states.end())
|
|
||||||
return dynamic_cast<T*>(foundEntry->second.get());
|
|
||||||
|
|
||||||
auto newState = std::make_unique<T>();
|
|
||||||
newState->SetZone(&m_zone);
|
|
||||||
auto* newStatePtr = newState.get();
|
|
||||||
m_zone_asset_loader_states.emplace(std::make_pair<std::type_index, std::unique_ptr<IZoneAssetLoaderState>>(typeid(T), std::move(newState)));
|
|
||||||
return newStatePtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void BuildGdtEntryCache();
|
|
||||||
|
|
||||||
public:
|
|
||||||
Zone& m_zone;
|
|
||||||
ISearchPath& m_raw_search_path;
|
|
||||||
const std::vector<Gdt*> m_gdt_files;
|
|
||||||
std::unordered_map<std::string, asset_type_t> m_ignored_asset_map;
|
|
||||||
|
|
||||||
std::unordered_map<std::string, std::unordered_map<std::string, GdtEntry*>> m_entries_by_gdf_and_by_name;
|
|
||||||
std::unordered_map<std::type_index, std::unique_ptr<IZoneAssetLoaderState>> m_zone_asset_loader_states;
|
|
||||||
};
|
|
@ -1,176 +0,0 @@
|
|||||||
#include "AssetLoadingManager.h"
|
|
||||||
|
|
||||||
#include "Utils/StringUtils.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <format>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
AssetLoadingManager::AssetLoadingManager(const std::unordered_map<asset_type_t, std::unique_ptr<IAssetLoader>>& assetLoadersByType,
|
|
||||||
AssetLoadingContext& context)
|
|
||||||
: m_asset_loaders_by_type(assetLoadersByType),
|
|
||||||
m_context(context),
|
|
||||||
m_last_dependency_loaded(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AssetLoadingManager::LoadAssetFromLoader(const asset_type_t assetType, const std::string& assetName)
|
|
||||||
{
|
|
||||||
return LoadDependency(assetType, assetName) != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetLoadingContext* AssetLoadingManager::GetAssetLoadingContext() const
|
|
||||||
{
|
|
||||||
return &m_context;
|
|
||||||
}
|
|
||||||
|
|
||||||
XAssetInfoGeneric* AssetLoadingManager::AddAssetInternal(std::unique_ptr<XAssetInfoGeneric> xAssetInfo)
|
|
||||||
{
|
|
||||||
const auto assetType = xAssetInfo->m_type;
|
|
||||||
const auto* pAssetName = xAssetInfo->m_name.c_str();
|
|
||||||
|
|
||||||
m_last_dependency_loaded = m_context.m_zone.m_pools->AddAsset(std::move(xAssetInfo));
|
|
||||||
if (m_last_dependency_loaded == nullptr)
|
|
||||||
std::cerr << std::format("Failed to add asset of type \"{}\" to pool: \"{}\"\n", *m_context.m_zone.m_pools->GetAssetTypeName(assetType), pAssetName);
|
|
||||||
|
|
||||||
return m_last_dependency_loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
XAssetInfoGeneric* AssetLoadingManager::AddAsset(std::unique_ptr<XAssetInfoGeneric> xAssetInfo)
|
|
||||||
{
|
|
||||||
xAssetInfo->m_zone = &m_context.m_zone;
|
|
||||||
return AddAssetInternal(std::move(xAssetInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
XAssetInfoGeneric* AssetLoadingManager::LoadIgnoredDependency(const asset_type_t assetType, const std::string& assetName, IAssetLoader* loader)
|
|
||||||
{
|
|
||||||
auto* alreadyLoadedAsset = m_context.m_zone.m_pools->GetAssetOrAssetReference(assetType, assetName);
|
|
||||||
if (alreadyLoadedAsset)
|
|
||||||
return alreadyLoadedAsset;
|
|
||||||
|
|
||||||
auto* linkAsset = loader->CreateEmptyAsset(assetName, m_context.m_zone.GetMemory());
|
|
||||||
if (linkAsset)
|
|
||||||
{
|
|
||||||
AddAsset(std::make_unique<XAssetInfoGeneric>(assetType, assetName, linkAsset));
|
|
||||||
auto* lastDependency = m_last_dependency_loaded;
|
|
||||||
m_last_dependency_loaded = nullptr;
|
|
||||||
return lastDependency;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* existingAsset = loader->LoadFromGlobalAssetPools(assetName);
|
|
||||||
if (existingAsset)
|
|
||||||
{
|
|
||||||
AddAssetInternal(std::make_unique<XAssetInfoGeneric>(*existingAsset));
|
|
||||||
auto* lastDependency = m_last_dependency_loaded;
|
|
||||||
m_last_dependency_loaded = nullptr;
|
|
||||||
return lastDependency;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cerr << std::format("Failed to create empty asset \"{}\" for type \"{}\"\n", assetName, *m_context.m_zone.m_pools->GetAssetTypeName(assetType));
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
XAssetInfoGeneric* AssetLoadingManager::LoadAssetDependency(const asset_type_t assetType, const std::string& assetName, const IAssetLoader* loader)
|
|
||||||
{
|
|
||||||
if (loader->CanLoadFromGdt() && !m_context.m_gdt_files.empty()
|
|
||||||
&& loader->LoadFromGdt(assetName, &m_context, m_context.m_zone.GetMemory(), this, &m_context.m_zone))
|
|
||||||
{
|
|
||||||
auto* lastDependency = m_last_dependency_loaded;
|
|
||||||
m_last_dependency_loaded = nullptr;
|
|
||||||
return lastDependency;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loader->CanLoadFromRaw() && loader->LoadFromRaw(assetName, &m_context.m_raw_search_path, m_context.m_zone.GetMemory(), this, &m_context.m_zone))
|
|
||||||
{
|
|
||||||
auto* lastDependency = m_last_dependency_loaded;
|
|
||||||
m_last_dependency_loaded = nullptr;
|
|
||||||
return lastDependency;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* existingAsset = loader->LoadFromGlobalAssetPools(assetName);
|
|
||||||
if (!existingAsset && !assetName.empty() && assetName[0] != ',')
|
|
||||||
existingAsset = loader->LoadFromGlobalAssetPools(',' + assetName);
|
|
||||||
|
|
||||||
if (existingAsset)
|
|
||||||
{
|
|
||||||
std::vector<XAssetInfoGeneric*> dependencies;
|
|
||||||
std::vector<IndirectAssetReference> indirectAssetReferences;
|
|
||||||
for (const auto* dependency : existingAsset->m_dependencies)
|
|
||||||
{
|
|
||||||
auto* newDependency = LoadDependency(dependency->m_type, dependency->m_name);
|
|
||||||
if (newDependency)
|
|
||||||
dependencies.push_back(newDependency);
|
|
||||||
else
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
indirectAssetReferences.reserve(existingAsset->m_indirect_asset_references.size());
|
|
||||||
for (const auto& indirectAssetReference : existingAsset->m_indirect_asset_references)
|
|
||||||
indirectAssetReferences.emplace_back(LoadIndirectAssetReference(indirectAssetReference.m_type, indirectAssetReference.m_name));
|
|
||||||
|
|
||||||
// Make sure any used script string is available in the created zone
|
|
||||||
// The replacement of the scr_string_t values will be done upon writing
|
|
||||||
for (const auto scrString : existingAsset->m_used_script_strings)
|
|
||||||
m_context.m_zone.m_script_strings.AddOrGetScriptString(existingAsset->m_zone->m_script_strings.CValue(scrString));
|
|
||||||
|
|
||||||
AddAssetInternal(std::make_unique<XAssetInfoGeneric>(existingAsset->m_type,
|
|
||||||
existingAsset->m_name,
|
|
||||||
existingAsset->m_ptr,
|
|
||||||
std::move(dependencies),
|
|
||||||
existingAsset->m_used_script_strings,
|
|
||||||
std::move(indirectAssetReferences),
|
|
||||||
existingAsset->m_zone));
|
|
||||||
|
|
||||||
auto* lastDependency = m_last_dependency_loaded;
|
|
||||||
m_last_dependency_loaded = nullptr;
|
|
||||||
return lastDependency;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cerr << std::format("Failed to load asset of type \"{}\": \"{}\"\n", *m_context.m_zone.m_pools->GetAssetTypeName(assetType), assetName);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
XAssetInfoGeneric* AssetLoadingManager::LoadDependency(const asset_type_t assetType, const std::string& assetName)
|
|
||||||
{
|
|
||||||
auto* alreadyLoadedAsset = m_context.m_zone.m_pools->GetAssetOrAssetReference(assetType, assetName);
|
|
||||||
if (alreadyLoadedAsset)
|
|
||||||
return alreadyLoadedAsset;
|
|
||||||
|
|
||||||
const auto loader = m_asset_loaders_by_type.find(assetType);
|
|
||||||
if (loader != m_asset_loaders_by_type.end())
|
|
||||||
{
|
|
||||||
const auto ignoreEntry = m_context.m_ignored_asset_map.find(assetName);
|
|
||||||
if (ignoreEntry != m_context.m_ignored_asset_map.end() && ignoreEntry->second == assetType)
|
|
||||||
{
|
|
||||||
const auto linkAssetName = std::format(",{}", assetName);
|
|
||||||
|
|
||||||
return LoadIgnoredDependency(assetType, linkAssetName, loader->second.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
return LoadAssetDependency(assetType, assetName, loader->second.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cerr << std::format("Failed to find loader for asset type \"{}\"\n", *m_context.m_zone.m_pools->GetAssetTypeName(assetType));
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
IndirectAssetReference AssetLoadingManager::LoadIndirectAssetReference(const asset_type_t assetType, const std::string& assetName)
|
|
||||||
{
|
|
||||||
const auto* alreadyLoadedAsset = m_context.m_zone.m_pools->GetAssetOrAssetReference(assetType, assetName);
|
|
||||||
if (alreadyLoadedAsset)
|
|
||||||
return IndirectAssetReference(assetType, assetName);
|
|
||||||
|
|
||||||
const auto ignoreEntry = m_context.m_ignored_asset_map.find(assetName);
|
|
||||||
if (ignoreEntry != m_context.m_ignored_asset_map.end() && ignoreEntry->second == assetType)
|
|
||||||
return IndirectAssetReference(assetType, assetName);
|
|
||||||
|
|
||||||
const auto loader = m_asset_loaders_by_type.find(assetType);
|
|
||||||
if (loader != m_asset_loaders_by_type.end())
|
|
||||||
{
|
|
||||||
LoadAssetDependency(assetType, assetName, loader->second.get());
|
|
||||||
return IndirectAssetReference(assetType, assetName);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cerr << std::format("Failed to find loader for asset type \"{}\"\n", *m_context.m_zone.m_pools->GetAssetTypeName(assetType));
|
|
||||||
return IndirectAssetReference(assetType, assetName);
|
|
||||||
}
|
|
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