diff --git a/src/Common/Game/CommonAsset.cpp b/src/Common/Game/CommonAsset.cpp new file mode 100644 index 00000000..30bdfd7d --- /dev/null +++ b/src/Common/Game/CommonAsset.cpp @@ -0,0 +1,26 @@ +#include "CommonAsset.h" + +#include "IW3/CommonAssetIW3.h" +#include "IW4/CommonAssetIW4.h" +#include "IW5/CommonAssetIW5.h" +#include "T5/CommonAssetT5.h" +#include "T6/CommonAssetT6.h" + +#include + +ICommonAssetTypeMapper* ICommonAssetTypeMapper::GetCommonAssetMapperByGame(GameId gameId) +{ + static ICommonAssetTypeMapper* assetTypeMappers[static_cast(GameId::COUNT)]{ + new IW3::CommonAssetTypeMapper(), + new IW4::CommonAssetTypeMapper(), + new IW5::CommonAssetTypeMapper(), + new T5::CommonAssetTypeMapper(), + new T6::CommonAssetTypeMapper(), + }; + + assert(static_cast(gameId) < static_cast(GameId::COUNT)); + auto* result = assetTypeMappers[static_cast(gameId)]; + assert(result); + + return result; +} diff --git a/src/Common/Game/CommonAsset.h b/src/Common/Game/CommonAsset.h new file mode 100644 index 00000000..24371e49 --- /dev/null +++ b/src/Common/Game/CommonAsset.h @@ -0,0 +1,181 @@ +#pragma once + +#include "IGame.h" +#include "Zone/ZoneTypes.h" + +#include +#include + +enum class CommonAssetType : std::uint8_t +{ + // IW3, IW4, IW5, T5, T6 + PHYS_PRESET, + // IW3, IW4, IW5, T5, T6 + XANIM, + // IW3, IW4, IW5, T5, T6 + XMODEL, + // IW3, IW4, IW5, T5, T6 + MATERIAL, + // IW3, IW4, IW5, T5, T6 + TECHNIQUE_SET, + // IW3, IW4, IW5, T5, T6 + IMAGE, + // IW3, IW4, IW5, T5, T6 + SOUND, + // IW3, IW4, IW5 + SOUND_CURVE, + // IW3, IW4, IW5 + LOADED_SOUND, + // IW3, IW4, IW5, T5, T6 + CLIP_MAP, + // IW3, IW4, IW5, T5, T6 + COM_WORLD, + // IW3, IW4, T5, T6 + GAME_WORLD_SP, + // IW3, IW4, T5, T6 + GAME_WORLD_MP, + // IW3, IW4, IW5, T5, T6 + MAP_ENTS, + // IW3, IW4, IW5, T5, T6 + GFX_WORLD, + // IW3, IW4, IW5, T5, T6 + LIGHT_DEF, + // IW3, IW4, IW5, T5, T6 + UI_MAP, + // IW3, IW4, IW5, T5, T6 + FONT, + // IW3, IW4, IW5, T5, T6 + MENU_LIST, + // IW3, IW4, IW5, T5, T6 + MENU, + // IW3, IW4, IW5, T5, T6 + LOCALIZE_ENTRY, + // IW3, IW4, IW5, T5, T6 + WEAPON, + // IW3, IW4, IW5, T5, T6 + SOUND_DRIVER_GLOBALS, + // IW3, IW4, IW5, T5, T6 + FX, + // IW3, IW4, IW5, T5, T6 + IMPACT_FX, + // IW3, IW4, IW5, T5, T6 + AI_TYPE, + // IW3, IW4, IW5, T5, T6 + MP_TYPE, + // IW3, IW4, IW5, T5, T6 + CHARACTER, + // IW3, IW4, IW5, T5, T6 + XMODEL_ALIAS, + // IW3, IW4, IW5, T5, T6 + RAW_FILE, + // IW3, IW4, IW5, T5, T6 + STRING_TABLE, + + // IW3, T5, T6 + XMODEL_PIECES, + + // IW4, IW5 + PHYS_COLL_MAP, + // IW4, IW5 + XMODEL_SURFS, + // IW4, IW5 + PIXEL_SHADER, + // IW4, IW5 + VERTEX_SHADER, + // IW4, IW5 + VERTEX_DECL, + // IW4, IW5 + FX_WORLD, + // IW4, IW5, T6 + LEADERBOARD, + // IW4, IW5 + STRUCTURED_DATA_DEF, + // IW4, IW5, T6 + TRACER, + // IW4, IW5, T6 + VEHICLE, + // IW4, IW5, T6 + ADDON_MAP_ENTS, + + // IW5 + GLASS_WORLD, + // IW5 + PATH_DATA, + // IW5 + VEHICLE_TRACK, + // IW5, T6 + ATTACHMENT, + // IW5 + SURFACE_FX, + // IW5, T6 + SCRIPT, + + // T5, T6 + PHYS_CONSTRAINTS, + // T5, T6 + DESTRUCTIBLE_DEF, + // T5, T6 + SOUND_PATCH, + // T5, T6 + WEAPON_DEF, + // T5, T6 + WEAPON_VARIANT, + // T5, T6 + MP_BODY, + // T5, T6 + MP_HEAD, + // T5 + PACK_INDEX, + // T5, T6 + XGLOBALS, + // T5, T6 + DDL, + // T5, T6 + GLASSES, + // T5, T6 + EMBLEM_SET, + + // T6 + FONT_ICON, + // T6 + WEAPON_FULL, + // T6 + ATTACHMENT_UNIQUE, + // T6 + WEAPON_CAMO, + // T6 + KEY_VALUE_PAIRS, + // T6 + MEMORY_BLOCK, + // T6 + SKINNED_VERTS, + // T6 + QDB, + // T6 + SLUG, + // T6 + FOOTSTEP_TABLE, + // T6 + FOOTSTEP_FX_TABLE, + // T6 + ZBARRIER, + + COUNT, +}; + +class ICommonAssetTypeMapper +{ +public: + [[nodiscard]] virtual CommonAssetType GameToCommonAssetType(asset_type_t gameAssetType) const = 0; + [[nodiscard]] virtual std::optional CommonToGameAssetType(CommonAssetType commonAssetType) const = 0; + + static ICommonAssetTypeMapper* GetCommonAssetMapperByGame(GameId gameId); + +protected: + ICommonAssetTypeMapper() = default; + virtual ~ICommonAssetTypeMapper() = default; + ICommonAssetTypeMapper(const ICommonAssetTypeMapper& other) = default; + ICommonAssetTypeMapper(ICommonAssetTypeMapper&& other) noexcept = default; + ICommonAssetTypeMapper& operator=(const ICommonAssetTypeMapper& other) = default; + ICommonAssetTypeMapper& operator=(ICommonAssetTypeMapper&& other) noexcept = default; +}; diff --git a/src/Common/Game/IW3/CommonAssetIW3.cpp b/src/Common/Game/IW3/CommonAssetIW3.cpp new file mode 100644 index 00000000..485657f2 --- /dev/null +++ b/src/Common/Game/IW3/CommonAssetIW3.cpp @@ -0,0 +1,100 @@ +#include "CommonAssetIW3.h" + +#include "IW3.h" + +#include + +namespace IW3 +{ + CommonAssetTypeMapper::CommonAssetTypeMapper() = default; + + CommonAssetType CommonAssetTypeMapper::GameToCommonAssetType(const asset_type_t gameAssetType) const + { + static CommonAssetType lookupTable[static_cast(ASSET_TYPE_COUNT)]{ + CommonAssetType::XMODEL_PIECES, // ASSET_TYPE_XMODELPIECES + CommonAssetType::PHYS_PRESET, // ASSET_TYPE_PHYSPRESET + CommonAssetType::XANIM, // ASSET_TYPE_XANIMPARTS + CommonAssetType::XMODEL, // ASSET_TYPE_XMODEL + CommonAssetType::MATERIAL, // ASSET_TYPE_MATERIAL + CommonAssetType::TECHNIQUE_SET, // ASSET_TYPE_TECHNIQUE_SET + CommonAssetType::IMAGE, // ASSET_TYPE_IMAGE + CommonAssetType::SOUND, // ASSET_TYPE_SOUND + CommonAssetType::SOUND_CURVE, // ASSET_TYPE_SOUND_CURVE + CommonAssetType::LOADED_SOUND, // ASSET_TYPE_LOADED_SOUND + CommonAssetType::CLIP_MAP, // ASSET_TYPE_CLIPMAP + CommonAssetType::CLIP_MAP, // ASSET_TYPE_CLIPMAP_PVS + CommonAssetType::COM_WORLD, // ASSET_TYPE_COMWORLD + CommonAssetType::GAME_WORLD_SP, // ASSET_TYPE_GAMEWORLD_SP + CommonAssetType::GAME_WORLD_MP, // ASSET_TYPE_GAMEWORLD_MP + CommonAssetType::MAP_ENTS, // ASSET_TYPE_MAP_ENTS + CommonAssetType::GFX_WORLD, // ASSET_TYPE_GFXWORLD + CommonAssetType::LIGHT_DEF, // ASSET_TYPE_LIGHT_DEF + CommonAssetType::UI_MAP, // ASSET_TYPE_UI_MAP + CommonAssetType::FONT, // ASSET_TYPE_FONT + CommonAssetType::MENU_LIST, // ASSET_TYPE_MENULIST + CommonAssetType::MENU, // ASSET_TYPE_MENU + CommonAssetType::LOCALIZE_ENTRY, // ASSET_TYPE_LOCALIZE_ENTRY + CommonAssetType::WEAPON, // ASSET_TYPE_WEAPON + CommonAssetType::SOUND_DRIVER_GLOBALS, // ASSET_TYPE_SNDDRIVER_GLOBALS + CommonAssetType::FX, // ASSET_TYPE_FX + CommonAssetType::IMPACT_FX, // ASSET_TYPE_IMPACT_FX + CommonAssetType::AI_TYPE, // ASSET_TYPE_AITYPE + CommonAssetType::MP_TYPE, // ASSET_TYPE_MPTYPE + CommonAssetType::CHARACTER, // ASSET_TYPE_CHARACTER + CommonAssetType::XMODEL_ALIAS, // ASSET_TYPE_XMODELALIAS + CommonAssetType::RAW_FILE, // ASSET_TYPE_RAWFILE + CommonAssetType::STRING_TABLE, // ASSET_TYPE_STRINGTABLE + }; + + assert(gameAssetType < ASSET_TYPE_COUNT); + return lookupTable[gameAssetType]; + } + + std::optional CommonAssetTypeMapper::CommonToGameAssetType(const CommonAssetType commonAssetType) const + { +#define MAP_COMMON(common, game) \ + case common: \ + return game; + + switch (commonAssetType) + { + MAP_COMMON(CommonAssetType::XMODEL_PIECES, ASSET_TYPE_XMODELPIECES) + MAP_COMMON(CommonAssetType::PHYS_PRESET, ASSET_TYPE_PHYSPRESET) + MAP_COMMON(CommonAssetType::XANIM, ASSET_TYPE_XANIMPARTS) + MAP_COMMON(CommonAssetType::XMODEL, ASSET_TYPE_XMODEL) + MAP_COMMON(CommonAssetType::MATERIAL, ASSET_TYPE_MATERIAL) + MAP_COMMON(CommonAssetType::TECHNIQUE_SET, ASSET_TYPE_TECHNIQUE_SET) + MAP_COMMON(CommonAssetType::IMAGE, ASSET_TYPE_IMAGE) + MAP_COMMON(CommonAssetType::SOUND, ASSET_TYPE_SOUND) + MAP_COMMON(CommonAssetType::SOUND_CURVE, ASSET_TYPE_SOUND_CURVE) + MAP_COMMON(CommonAssetType::LOADED_SOUND, ASSET_TYPE_LOADED_SOUND) + MAP_COMMON(CommonAssetType::CLIP_MAP, ASSET_TYPE_CLIPMAP_PVS) + MAP_COMMON(CommonAssetType::COM_WORLD, ASSET_TYPE_COMWORLD) + MAP_COMMON(CommonAssetType::GAME_WORLD_SP, ASSET_TYPE_GAMEWORLD_SP) + MAP_COMMON(CommonAssetType::GAME_WORLD_MP, ASSET_TYPE_GAMEWORLD_MP) + MAP_COMMON(CommonAssetType::MAP_ENTS, ASSET_TYPE_MAP_ENTS) + MAP_COMMON(CommonAssetType::GFX_WORLD, ASSET_TYPE_GFXWORLD) + MAP_COMMON(CommonAssetType::LIGHT_DEF, ASSET_TYPE_LIGHT_DEF) + MAP_COMMON(CommonAssetType::UI_MAP, ASSET_TYPE_UI_MAP) + MAP_COMMON(CommonAssetType::FONT, ASSET_TYPE_FONT) + MAP_COMMON(CommonAssetType::MENU_LIST, ASSET_TYPE_MENULIST) + MAP_COMMON(CommonAssetType::MENU, ASSET_TYPE_MENU) + MAP_COMMON(CommonAssetType::LOCALIZE_ENTRY, ASSET_TYPE_LOCALIZE_ENTRY) + MAP_COMMON(CommonAssetType::WEAPON, ASSET_TYPE_WEAPON) + MAP_COMMON(CommonAssetType::SOUND_DRIVER_GLOBALS, ASSET_TYPE_SNDDRIVER_GLOBALS) + MAP_COMMON(CommonAssetType::FX, ASSET_TYPE_FX) + MAP_COMMON(CommonAssetType::IMPACT_FX, ASSET_TYPE_IMPACT_FX) + MAP_COMMON(CommonAssetType::AI_TYPE, ASSET_TYPE_AITYPE) + MAP_COMMON(CommonAssetType::MP_TYPE, ASSET_TYPE_MPTYPE) + MAP_COMMON(CommonAssetType::CHARACTER, ASSET_TYPE_CHARACTER) + MAP_COMMON(CommonAssetType::XMODEL_ALIAS, ASSET_TYPE_XMODELALIAS) + MAP_COMMON(CommonAssetType::RAW_FILE, ASSET_TYPE_RAWFILE) + MAP_COMMON(CommonAssetType::STRING_TABLE, ASSET_TYPE_STRINGTABLE) + + default: + return std::nullopt; + } + +#undef MAP_COMMON + } +} // namespace IW3 diff --git a/src/Common/Game/IW3/CommonAssetIW3.h b/src/Common/Game/IW3/CommonAssetIW3.h new file mode 100644 index 00000000..bc19e468 --- /dev/null +++ b/src/Common/Game/IW3/CommonAssetIW3.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Game/CommonAsset.h" + +namespace IW3 +{ + class CommonAssetTypeMapper final : public ICommonAssetTypeMapper + { + public: + CommonAssetTypeMapper(); + + [[nodiscard]] CommonAssetType GameToCommonAssetType(asset_type_t gameAssetType) const override; + [[nodiscard]] std::optional CommonToGameAssetType(CommonAssetType commonAssetType) const override; + }; +} // namespace IW3 diff --git a/src/Common/Game/IW4/CommonAssetIW4.cpp b/src/Common/Game/IW4/CommonAssetIW4.cpp new file mode 100644 index 00000000..b8f4172e --- /dev/null +++ b/src/Common/Game/IW4/CommonAssetIW4.cpp @@ -0,0 +1,120 @@ +#include "CommonAssetIW4.h" + +#include "IW4.h" + +#include + +namespace IW4 +{ + CommonAssetTypeMapper::CommonAssetTypeMapper() = default; + + CommonAssetType CommonAssetTypeMapper::GameToCommonAssetType(const asset_type_t gameAssetType) const + { + static CommonAssetType lookupTable[static_cast(ASSET_TYPE_COUNT)]{ + CommonAssetType::PHYS_PRESET, // ASSET_TYPE_PHYSPRESET + CommonAssetType::PHYS_COLL_MAP, // ASSET_TYPE_PHYSCOLLMAP + CommonAssetType::XANIM, // ASSET_TYPE_XANIMPARTS + CommonAssetType::XMODEL_SURFS, // ASSET_TYPE_XMODEL_SURFS + CommonAssetType::XMODEL, // ASSET_TYPE_XMODEL + CommonAssetType::MATERIAL, // ASSET_TYPE_MATERIAL + CommonAssetType::PIXEL_SHADER, // ASSET_TYPE_PIXELSHADER + CommonAssetType::VERTEX_SHADER, // ASSET_TYPE_VERTEXSHADER + CommonAssetType::VERTEX_DECL, // ASSET_TYPE_VERTEXDECL + CommonAssetType::TECHNIQUE_SET, // ASSET_TYPE_TECHNIQUE_SET + CommonAssetType::IMAGE, // ASSET_TYPE_IMAGE + CommonAssetType::SOUND, // ASSET_TYPE_SOUND + CommonAssetType::SOUND_CURVE, // ASSET_TYPE_SOUND_CURVE + CommonAssetType::LOADED_SOUND, // ASSET_TYPE_LOADED_SOUND + CommonAssetType::CLIP_MAP, // ASSET_TYPE_CLIPMAP_SP + CommonAssetType::CLIP_MAP, // ASSET_TYPE_CLIPMAP_MP + CommonAssetType::COM_WORLD, // ASSET_TYPE_COMWORLD + CommonAssetType::GAME_WORLD_SP, // ASSET_TYPE_GAMEWORLD_SP + CommonAssetType::GAME_WORLD_MP, // ASSET_TYPE_GAMEWORLD_MP + CommonAssetType::MAP_ENTS, // ASSET_TYPE_MAP_ENTS + CommonAssetType::FX_WORLD, // ASSET_TYPE_FXWORLD + CommonAssetType::GFX_WORLD, // ASSET_TYPE_GFXWORLD + CommonAssetType::LIGHT_DEF, // ASSET_TYPE_LIGHT_DEF + CommonAssetType::UI_MAP, // ASSET_TYPE_UI_MAP + CommonAssetType::FONT, // ASSET_TYPE_FONT + CommonAssetType::MENU_LIST, // ASSET_TYPE_MENULIST + CommonAssetType::MENU, // ASSET_TYPE_MENU + CommonAssetType::LOCALIZE_ENTRY, // ASSET_TYPE_LOCALIZE_ENTRY + CommonAssetType::WEAPON, // ASSET_TYPE_WEAPON + CommonAssetType::SOUND_DRIVER_GLOBALS, // ASSET_TYPE_SNDDRIVER_GLOBALS + CommonAssetType::FX, // ASSET_TYPE_FX + CommonAssetType::IMPACT_FX, // ASSET_TYPE_IMPACT_FX + CommonAssetType::AI_TYPE, // ASSET_TYPE_AITYPE + CommonAssetType::MP_TYPE, // ASSET_TYPE_MPTYPE + CommonAssetType::CHARACTER, // ASSET_TYPE_CHARACTER + CommonAssetType::XMODEL_ALIAS, // ASSET_TYPE_XMODELALIAS + CommonAssetType::RAW_FILE, // ASSET_TYPE_RAWFILE + CommonAssetType::STRING_TABLE, // ASSET_TYPE_STRINGTABLE + CommonAssetType::LEADERBOARD, // ASSET_TYPE_LEADERBOARD + CommonAssetType::STRUCTURED_DATA_DEF, // ASSET_TYPE_STRUCTURED_DATA_DEF + CommonAssetType::TRACER, // ASSET_TYPE_TRACER + CommonAssetType::VEHICLE, // ASSET_TYPE_VEHICLE + CommonAssetType::ADDON_MAP_ENTS, // ASSET_TYPE_ADDON_MAP_ENTS + }; + + assert(gameAssetType < ASSET_TYPE_COUNT); + return lookupTable[gameAssetType]; + } + + std::optional CommonAssetTypeMapper::CommonToGameAssetType(const CommonAssetType commonAssetType) const + { +#define MAP_COMMON(common, game) \ + case common: \ + return game; + + switch (commonAssetType) + { + MAP_COMMON(CommonAssetType::PHYS_PRESET, ASSET_TYPE_PHYSPRESET) + MAP_COMMON(CommonAssetType::PHYS_COLL_MAP, ASSET_TYPE_PHYSCOLLMAP) + MAP_COMMON(CommonAssetType::XANIM, ASSET_TYPE_XANIMPARTS) + MAP_COMMON(CommonAssetType::XMODEL_SURFS, ASSET_TYPE_XMODEL_SURFS) + MAP_COMMON(CommonAssetType::XMODEL, ASSET_TYPE_XMODEL) + MAP_COMMON(CommonAssetType::MATERIAL, ASSET_TYPE_MATERIAL) + MAP_COMMON(CommonAssetType::PIXEL_SHADER, ASSET_TYPE_PIXELSHADER) + MAP_COMMON(CommonAssetType::VERTEX_SHADER, ASSET_TYPE_VERTEXSHADER) + MAP_COMMON(CommonAssetType::VERTEX_DECL, ASSET_TYPE_VERTEXDECL) + MAP_COMMON(CommonAssetType::TECHNIQUE_SET, ASSET_TYPE_TECHNIQUE_SET) + MAP_COMMON(CommonAssetType::IMAGE, ASSET_TYPE_IMAGE) + MAP_COMMON(CommonAssetType::SOUND, ASSET_TYPE_SOUND) + MAP_COMMON(CommonAssetType::SOUND_CURVE, ASSET_TYPE_SOUND_CURVE) + MAP_COMMON(CommonAssetType::LOADED_SOUND, ASSET_TYPE_LOADED_SOUND) + MAP_COMMON(CommonAssetType::CLIP_MAP, ASSET_TYPE_CLIPMAP_MP) + MAP_COMMON(CommonAssetType::COM_WORLD, ASSET_TYPE_COMWORLD) + MAP_COMMON(CommonAssetType::GAME_WORLD_SP, ASSET_TYPE_GAMEWORLD_SP) + MAP_COMMON(CommonAssetType::GAME_WORLD_MP, ASSET_TYPE_GAMEWORLD_MP) + MAP_COMMON(CommonAssetType::MAP_ENTS, ASSET_TYPE_MAP_ENTS) + MAP_COMMON(CommonAssetType::FX_WORLD, ASSET_TYPE_FXWORLD) + MAP_COMMON(CommonAssetType::GFX_WORLD, ASSET_TYPE_GFXWORLD) + MAP_COMMON(CommonAssetType::LIGHT_DEF, ASSET_TYPE_LIGHT_DEF) + MAP_COMMON(CommonAssetType::UI_MAP, ASSET_TYPE_UI_MAP) + MAP_COMMON(CommonAssetType::FONT, ASSET_TYPE_FONT) + MAP_COMMON(CommonAssetType::MENU_LIST, ASSET_TYPE_MENULIST) + MAP_COMMON(CommonAssetType::MENU, ASSET_TYPE_MENU) + MAP_COMMON(CommonAssetType::LOCALIZE_ENTRY, ASSET_TYPE_LOCALIZE_ENTRY) + MAP_COMMON(CommonAssetType::WEAPON, ASSET_TYPE_WEAPON) + MAP_COMMON(CommonAssetType::SOUND_DRIVER_GLOBALS, ASSET_TYPE_SNDDRIVER_GLOBALS) + MAP_COMMON(CommonAssetType::FX, ASSET_TYPE_FX) + MAP_COMMON(CommonAssetType::IMPACT_FX, ASSET_TYPE_IMPACT_FX) + MAP_COMMON(CommonAssetType::AI_TYPE, ASSET_TYPE_AITYPE) + MAP_COMMON(CommonAssetType::MP_TYPE, ASSET_TYPE_MPTYPE) + MAP_COMMON(CommonAssetType::CHARACTER, ASSET_TYPE_CHARACTER) + MAP_COMMON(CommonAssetType::XMODEL_ALIAS, ASSET_TYPE_XMODELALIAS) + MAP_COMMON(CommonAssetType::RAW_FILE, ASSET_TYPE_RAWFILE) + MAP_COMMON(CommonAssetType::STRING_TABLE, ASSET_TYPE_STRINGTABLE) + MAP_COMMON(CommonAssetType::LEADERBOARD, ASSET_TYPE_LEADERBOARD) + MAP_COMMON(CommonAssetType::STRUCTURED_DATA_DEF, ASSET_TYPE_STRUCTURED_DATA_DEF) + MAP_COMMON(CommonAssetType::TRACER, ASSET_TYPE_TRACER) + MAP_COMMON(CommonAssetType::VEHICLE, ASSET_TYPE_VEHICLE) + MAP_COMMON(CommonAssetType::ADDON_MAP_ENTS, ASSET_TYPE_ADDON_MAP_ENTS) + + default: + return std::nullopt; + } + +#undef MAP_COMMON + } +} // namespace IW4 diff --git a/src/Common/Game/IW4/CommonAssetIW4.h b/src/Common/Game/IW4/CommonAssetIW4.h new file mode 100644 index 00000000..e4d84543 --- /dev/null +++ b/src/Common/Game/IW4/CommonAssetIW4.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Game/CommonAsset.h" + +namespace IW4 +{ + class CommonAssetTypeMapper final : public ICommonAssetTypeMapper + { + public: + CommonAssetTypeMapper(); + + [[nodiscard]] CommonAssetType GameToCommonAssetType(asset_type_t gameAssetType) const override; + [[nodiscard]] std::optional CommonToGameAssetType(CommonAssetType commonAssetType) const override; + }; +} // namespace IW4 diff --git a/src/Common/Game/IW5/CommonAssetIW5.cpp b/src/Common/Game/IW5/CommonAssetIW5.cpp new file mode 100644 index 00000000..bc558b23 --- /dev/null +++ b/src/Common/Game/IW5/CommonAssetIW5.cpp @@ -0,0 +1,127 @@ +#include "CommonAssetIW5.h" + +#include "IW5.h" + +#include + +namespace IW5 +{ + CommonAssetTypeMapper::CommonAssetTypeMapper() = default; + + CommonAssetType CommonAssetTypeMapper::GameToCommonAssetType(const asset_type_t gameAssetType) const + { + static CommonAssetType lookupTable[static_cast(ASSET_TYPE_COUNT)]{ + CommonAssetType::PHYS_PRESET, // ASSET_TYPE_PHYSPRESET + CommonAssetType::PHYS_COLL_MAP, // ASSET_TYPE_PHYSCOLLMAP + CommonAssetType::XANIM, // ASSET_TYPE_XANIMPARTS + CommonAssetType::XMODEL_SURFS, // ASSET_TYPE_XMODEL_SURFS + CommonAssetType::XMODEL, // ASSET_TYPE_XMODEL + CommonAssetType::MATERIAL, // ASSET_TYPE_MATERIAL + CommonAssetType::PIXEL_SHADER, // ASSET_TYPE_PIXELSHADER + CommonAssetType::VERTEX_SHADER, // ASSET_TYPE_VERTEXSHADER + CommonAssetType::VERTEX_DECL, // ASSET_TYPE_VERTEXDECL + CommonAssetType::TECHNIQUE_SET, // ASSET_TYPE_TECHNIQUE_SET + CommonAssetType::IMAGE, // ASSET_TYPE_IMAGE + CommonAssetType::SOUND, // ASSET_TYPE_SOUND + CommonAssetType::SOUND_CURVE, // ASSET_TYPE_SOUND_CURVE + CommonAssetType::LOADED_SOUND, // ASSET_TYPE_LOADED_SOUND + CommonAssetType::CLIP_MAP, // ASSET_TYPE_CLIPMAP + CommonAssetType::COM_WORLD, // ASSET_TYPE_COMWORLD + CommonAssetType::GLASS_WORLD, // ASSET_TYPE_GLASSWORLD + CommonAssetType::PATH_DATA, // ASSET_TYPE_PATHDATA + CommonAssetType::VEHICLE_TRACK, // ASSET_TYPE_VEHICLE_TRACK + CommonAssetType::MAP_ENTS, // ASSET_TYPE_MAP_ENTS + CommonAssetType::FX_WORLD, // ASSET_TYPE_FXWORLD + CommonAssetType::GFX_WORLD, // ASSET_TYPE_GFXWORLD + CommonAssetType::LIGHT_DEF, // ASSET_TYPE_LIGHT_DEF + CommonAssetType::UI_MAP, // ASSET_TYPE_UI_MAP + CommonAssetType::FONT, // ASSET_TYPE_FONT + CommonAssetType::MENU_LIST, // ASSET_TYPE_MENULIST + CommonAssetType::MENU, // ASSET_TYPE_MENU + CommonAssetType::LOCALIZE_ENTRY, // ASSET_TYPE_LOCALIZE_ENTRY + CommonAssetType::ATTACHMENT, // ASSET_TYPE_ATTACHMENT + CommonAssetType::WEAPON, // ASSET_TYPE_WEAPON + CommonAssetType::SOUND_DRIVER_GLOBALS, // ASSET_TYPE_SNDDRIVER_GLOBALS + CommonAssetType::FX, // ASSET_TYPE_FX + CommonAssetType::IMPACT_FX, // ASSET_TYPE_IMPACT_FX + CommonAssetType::SURFACE_FX, // ASSET_TYPE_SURFACE_FX + CommonAssetType::AI_TYPE, // ASSET_TYPE_AITYPE + CommonAssetType::MP_TYPE, // ASSET_TYPE_MPTYPE + CommonAssetType::CHARACTER, // ASSET_TYPE_CHARACTER + CommonAssetType::XMODEL_ALIAS, // ASSET_TYPE_XMODELALIAS + CommonAssetType::RAW_FILE, // ASSET_TYPE_RAWFILE + CommonAssetType::SCRIPT, // ASSET_TYPE_SCRIPTFILE + CommonAssetType::STRING_TABLE, // ASSET_TYPE_STRINGTABLE + CommonAssetType::LEADERBOARD, // ASSET_TYPE_LEADERBOARD + CommonAssetType::STRUCTURED_DATA_DEF, // ASSET_TYPE_STRUCTURED_DATA_DEF + CommonAssetType::TRACER, // ASSET_TYPE_TRACER + CommonAssetType::VEHICLE, // ASSET_TYPE_VEHICLE + CommonAssetType::ADDON_MAP_ENTS, // ASSET_TYPE_ADDON_MAP_ENTS + }; + + assert(gameAssetType < ASSET_TYPE_COUNT); + return lookupTable[gameAssetType]; + } + + std::optional CommonAssetTypeMapper::CommonToGameAssetType(const CommonAssetType commonAssetType) const + { +#define MAP_COMMON(common, game) \ + case common: \ + return game; + + switch (commonAssetType) + { + MAP_COMMON(CommonAssetType::PHYS_PRESET, ASSET_TYPE_PHYSPRESET) + MAP_COMMON(CommonAssetType::PHYS_COLL_MAP, ASSET_TYPE_PHYSCOLLMAP) + MAP_COMMON(CommonAssetType::XANIM, ASSET_TYPE_XANIMPARTS) + MAP_COMMON(CommonAssetType::XMODEL_SURFS, ASSET_TYPE_XMODEL_SURFS) + MAP_COMMON(CommonAssetType::XMODEL, ASSET_TYPE_XMODEL) + MAP_COMMON(CommonAssetType::MATERIAL, ASSET_TYPE_MATERIAL) + MAP_COMMON(CommonAssetType::PIXEL_SHADER, ASSET_TYPE_PIXELSHADER) + MAP_COMMON(CommonAssetType::VERTEX_SHADER, ASSET_TYPE_VERTEXSHADER) + MAP_COMMON(CommonAssetType::VERTEX_DECL, ASSET_TYPE_VERTEXDECL) + MAP_COMMON(CommonAssetType::TECHNIQUE_SET, ASSET_TYPE_TECHNIQUE_SET) + MAP_COMMON(CommonAssetType::IMAGE, ASSET_TYPE_IMAGE) + MAP_COMMON(CommonAssetType::SOUND, ASSET_TYPE_SOUND) + MAP_COMMON(CommonAssetType::SOUND_CURVE, ASSET_TYPE_SOUND_CURVE) + MAP_COMMON(CommonAssetType::LOADED_SOUND, ASSET_TYPE_LOADED_SOUND) + MAP_COMMON(CommonAssetType::CLIP_MAP, ASSET_TYPE_CLIPMAP) + MAP_COMMON(CommonAssetType::COM_WORLD, ASSET_TYPE_COMWORLD) + MAP_COMMON(CommonAssetType::GLASS_WORLD, ASSET_TYPE_GLASSWORLD) + MAP_COMMON(CommonAssetType::PATH_DATA, ASSET_TYPE_PATHDATA) + MAP_COMMON(CommonAssetType::VEHICLE_TRACK, ASSET_TYPE_VEHICLE_TRACK) + MAP_COMMON(CommonAssetType::MAP_ENTS, ASSET_TYPE_MAP_ENTS) + MAP_COMMON(CommonAssetType::FX_WORLD, ASSET_TYPE_FXWORLD) + MAP_COMMON(CommonAssetType::GFX_WORLD, ASSET_TYPE_GFXWORLD) + MAP_COMMON(CommonAssetType::LIGHT_DEF, ASSET_TYPE_LIGHT_DEF) + MAP_COMMON(CommonAssetType::UI_MAP, ASSET_TYPE_UI_MAP) + MAP_COMMON(CommonAssetType::FONT, ASSET_TYPE_FONT) + MAP_COMMON(CommonAssetType::MENU_LIST, ASSET_TYPE_MENULIST) + MAP_COMMON(CommonAssetType::MENU, ASSET_TYPE_MENU) + MAP_COMMON(CommonAssetType::LOCALIZE_ENTRY, ASSET_TYPE_LOCALIZE_ENTRY) + MAP_COMMON(CommonAssetType::ATTACHMENT, ASSET_TYPE_ATTACHMENT) + MAP_COMMON(CommonAssetType::WEAPON, ASSET_TYPE_WEAPON) + MAP_COMMON(CommonAssetType::SOUND_DRIVER_GLOBALS, ASSET_TYPE_SNDDRIVER_GLOBALS) + MAP_COMMON(CommonAssetType::FX, ASSET_TYPE_FX) + MAP_COMMON(CommonAssetType::IMPACT_FX, ASSET_TYPE_IMPACT_FX) + MAP_COMMON(CommonAssetType::SURFACE_FX, ASSET_TYPE_SURFACE_FX) + MAP_COMMON(CommonAssetType::AI_TYPE, ASSET_TYPE_AITYPE) + MAP_COMMON(CommonAssetType::MP_TYPE, ASSET_TYPE_MPTYPE) + MAP_COMMON(CommonAssetType::CHARACTER, ASSET_TYPE_CHARACTER) + MAP_COMMON(CommonAssetType::XMODEL_ALIAS, ASSET_TYPE_XMODELALIAS) + MAP_COMMON(CommonAssetType::RAW_FILE, ASSET_TYPE_RAWFILE) + MAP_COMMON(CommonAssetType::SCRIPT, ASSET_TYPE_SCRIPTFILE) + MAP_COMMON(CommonAssetType::STRING_TABLE, ASSET_TYPE_STRINGTABLE) + MAP_COMMON(CommonAssetType::LEADERBOARD, ASSET_TYPE_LEADERBOARD) + MAP_COMMON(CommonAssetType::STRUCTURED_DATA_DEF, ASSET_TYPE_STRUCTURED_DATA_DEF) + MAP_COMMON(CommonAssetType::TRACER, ASSET_TYPE_TRACER) + MAP_COMMON(CommonAssetType::VEHICLE, ASSET_TYPE_VEHICLE) + MAP_COMMON(CommonAssetType::ADDON_MAP_ENTS, ASSET_TYPE_ADDON_MAP_ENTS) + + default: + return std::nullopt; + } + +#undef MAP_COMMON + } +} // namespace IW5 diff --git a/src/Common/Game/IW5/CommonAssetIW5.h b/src/Common/Game/IW5/CommonAssetIW5.h new file mode 100644 index 00000000..2dbf5c1f --- /dev/null +++ b/src/Common/Game/IW5/CommonAssetIW5.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Game/CommonAsset.h" + +namespace IW5 +{ + class CommonAssetTypeMapper final : public ICommonAssetTypeMapper + { + public: + CommonAssetTypeMapper(); + + [[nodiscard]] CommonAssetType GameToCommonAssetType(asset_type_t gameAssetType) const override; + [[nodiscard]] std::optional CommonToGameAssetType(CommonAssetType commonAssetType) const override; + }; +} // namespace IW5 diff --git a/src/Common/Game/T5/CommonAssetT5.cpp b/src/Common/Game/T5/CommonAssetT5.cpp new file mode 100644 index 00000000..d671bf1a --- /dev/null +++ b/src/Common/Game/T5/CommonAssetT5.cpp @@ -0,0 +1,120 @@ +#include "CommonAssetT5.h" + +#include "T5.h" + +#include + +namespace T5 +{ + CommonAssetTypeMapper::CommonAssetTypeMapper() = default; + + CommonAssetType CommonAssetTypeMapper::GameToCommonAssetType(const asset_type_t gameAssetType) const + { + static CommonAssetType lookupTable[static_cast(ASSET_TYPE_COUNT)]{ + CommonAssetType::XMODEL_PIECES, // ASSET_TYPE_XMODELPIECES + CommonAssetType::PHYS_PRESET, // ASSET_TYPE_PHYSPRESET + CommonAssetType::PHYS_CONSTRAINTS, // ASSET_TYPE_PHYSCONSTRAINTS + CommonAssetType::DESTRUCTIBLE_DEF, // ASSET_TYPE_DESTRUCTIBLEDEF + CommonAssetType::XANIM, // ASSET_TYPE_XANIMPARTS + CommonAssetType::XMODEL, // ASSET_TYPE_XMODEL + CommonAssetType::MATERIAL, // ASSET_TYPE_MATERIAL + CommonAssetType::TECHNIQUE_SET, // ASSET_TYPE_TECHNIQUE_SET + CommonAssetType::IMAGE, // ASSET_TYPE_IMAGE + CommonAssetType::SOUND, // ASSET_TYPE_SOUND + CommonAssetType::SOUND_PATCH, // ASSET_TYPE_SOUND_PATCH + CommonAssetType::CLIP_MAP, // ASSET_TYPE_CLIPMAP + CommonAssetType::CLIP_MAP, // ASSET_TYPE_CLIPMAP_PVS + CommonAssetType::COM_WORLD, // ASSET_TYPE_COMWORLD + CommonAssetType::GAME_WORLD_SP, // ASSET_TYPE_GAMEWORLD_SP + CommonAssetType::GAME_WORLD_MP, // ASSET_TYPE_GAMEWORLD_MP + CommonAssetType::MAP_ENTS, // ASSET_TYPE_MAP_ENTS + CommonAssetType::GFX_WORLD, // ASSET_TYPE_GFXWORLD + CommonAssetType::LIGHT_DEF, // ASSET_TYPE_LIGHT_DEF + CommonAssetType::UI_MAP, // ASSET_TYPE_UI_MAP + CommonAssetType::FONT, // ASSET_TYPE_FONT + CommonAssetType::MENU_LIST, // ASSET_TYPE_MENULIST + CommonAssetType::MENU, // ASSET_TYPE_MENU + CommonAssetType::LOCALIZE_ENTRY, // ASSET_TYPE_LOCALIZE_ENTRY + CommonAssetType::WEAPON, // ASSET_TYPE_WEAPON + CommonAssetType::WEAPON_DEF, // ASSET_TYPE_WEAPONDEF + CommonAssetType::WEAPON_VARIANT, // ASSET_TYPE_WEAPON_VARIANT + CommonAssetType::SOUND_DRIVER_GLOBALS, // ASSET_TYPE_SNDDRIVER_GLOBALS + CommonAssetType::FX, // ASSET_TYPE_FX + CommonAssetType::IMPACT_FX, // ASSET_TYPE_IMPACT_FX + CommonAssetType::AI_TYPE, // ASSET_TYPE_AITYPE + CommonAssetType::MP_TYPE, // ASSET_TYPE_MPTYPE + CommonAssetType::MP_BODY, // ASSET_TYPE_MPBODY + CommonAssetType::MP_HEAD, // ASSET_TYPE_MPHEAD + CommonAssetType::CHARACTER, // ASSET_TYPE_CHARACTER + CommonAssetType::XMODEL_ALIAS, // ASSET_TYPE_XMODELALIAS + CommonAssetType::RAW_FILE, // ASSET_TYPE_RAWFILE + CommonAssetType::STRING_TABLE, // ASSET_TYPE_STRINGTABLE + CommonAssetType::PACK_INDEX, // ASSET_TYPE_PACK_INDEX + CommonAssetType::XGLOBALS, // ASSET_TYPE_XGLOBALS + CommonAssetType::DDL, // ASSET_TYPE_DDL + CommonAssetType::GLASSES, // ASSET_TYPE_GLASSES + CommonAssetType::EMBLEM_SET, // ASSET_TYPE_EMBLEMSET + }; + + assert(gameAssetType < ASSET_TYPE_COUNT); + return lookupTable[gameAssetType]; + } + + std::optional CommonAssetTypeMapper::CommonToGameAssetType(const CommonAssetType commonAssetType) const + { +#define MAP_COMMON(common, game) \ + case common: \ + return game; + + switch (commonAssetType) + { + MAP_COMMON(CommonAssetType::XMODEL_PIECES, ASSET_TYPE_XMODELPIECES) + MAP_COMMON(CommonAssetType::PHYS_PRESET, ASSET_TYPE_PHYSPRESET) + MAP_COMMON(CommonAssetType::PHYS_CONSTRAINTS, ASSET_TYPE_PHYSCONSTRAINTS) + MAP_COMMON(CommonAssetType::DESTRUCTIBLE_DEF, ASSET_TYPE_DESTRUCTIBLEDEF) + MAP_COMMON(CommonAssetType::XANIM, ASSET_TYPE_XANIMPARTS) + MAP_COMMON(CommonAssetType::XMODEL, ASSET_TYPE_XMODEL) + MAP_COMMON(CommonAssetType::MATERIAL, ASSET_TYPE_MATERIAL) + MAP_COMMON(CommonAssetType::TECHNIQUE_SET, ASSET_TYPE_TECHNIQUE_SET) + MAP_COMMON(CommonAssetType::IMAGE, ASSET_TYPE_IMAGE) + MAP_COMMON(CommonAssetType::SOUND, ASSET_TYPE_SOUND) + MAP_COMMON(CommonAssetType::SOUND_PATCH, ASSET_TYPE_SOUND_PATCH) + MAP_COMMON(CommonAssetType::CLIP_MAP, ASSET_TYPE_CLIPMAP_PVS) + MAP_COMMON(CommonAssetType::COM_WORLD, ASSET_TYPE_COMWORLD) + MAP_COMMON(CommonAssetType::GAME_WORLD_SP, ASSET_TYPE_GAMEWORLD_SP) + MAP_COMMON(CommonAssetType::GAME_WORLD_MP, ASSET_TYPE_GAMEWORLD_MP) + MAP_COMMON(CommonAssetType::MAP_ENTS, ASSET_TYPE_MAP_ENTS) + MAP_COMMON(CommonAssetType::GFX_WORLD, ASSET_TYPE_GFXWORLD) + MAP_COMMON(CommonAssetType::LIGHT_DEF, ASSET_TYPE_LIGHT_DEF) + MAP_COMMON(CommonAssetType::UI_MAP, ASSET_TYPE_UI_MAP) + MAP_COMMON(CommonAssetType::FONT, ASSET_TYPE_FONT) + MAP_COMMON(CommonAssetType::MENU_LIST, ASSET_TYPE_MENULIST) + MAP_COMMON(CommonAssetType::MENU, ASSET_TYPE_MENU) + MAP_COMMON(CommonAssetType::LOCALIZE_ENTRY, ASSET_TYPE_LOCALIZE_ENTRY) + MAP_COMMON(CommonAssetType::WEAPON, ASSET_TYPE_WEAPON) + MAP_COMMON(CommonAssetType::WEAPON_DEF, ASSET_TYPE_WEAPONDEF) + MAP_COMMON(CommonAssetType::WEAPON_VARIANT, ASSET_TYPE_WEAPON_VARIANT) + MAP_COMMON(CommonAssetType::SOUND_DRIVER_GLOBALS, ASSET_TYPE_SNDDRIVER_GLOBALS) + MAP_COMMON(CommonAssetType::FX, ASSET_TYPE_FX) + MAP_COMMON(CommonAssetType::IMPACT_FX, ASSET_TYPE_IMPACT_FX) + MAP_COMMON(CommonAssetType::AI_TYPE, ASSET_TYPE_AITYPE) + MAP_COMMON(CommonAssetType::MP_TYPE, ASSET_TYPE_MPTYPE) + MAP_COMMON(CommonAssetType::MP_BODY, ASSET_TYPE_MPBODY) + MAP_COMMON(CommonAssetType::MP_HEAD, ASSET_TYPE_MPHEAD) + MAP_COMMON(CommonAssetType::CHARACTER, ASSET_TYPE_CHARACTER) + MAP_COMMON(CommonAssetType::XMODEL_ALIAS, ASSET_TYPE_XMODELALIAS) + MAP_COMMON(CommonAssetType::RAW_FILE, ASSET_TYPE_RAWFILE) + MAP_COMMON(CommonAssetType::STRING_TABLE, ASSET_TYPE_STRINGTABLE) + MAP_COMMON(CommonAssetType::PACK_INDEX, ASSET_TYPE_PACK_INDEX) + MAP_COMMON(CommonAssetType::XGLOBALS, ASSET_TYPE_XGLOBALS) + MAP_COMMON(CommonAssetType::DDL, ASSET_TYPE_DDL) + MAP_COMMON(CommonAssetType::GLASSES, ASSET_TYPE_GLASSES) + MAP_COMMON(CommonAssetType::EMBLEM_SET, ASSET_TYPE_EMBLEMSET) + + default: + return std::nullopt; + } + +#undef MAP_COMMON + } +} // namespace T5 diff --git a/src/Common/Game/T5/CommonAssetT5.h b/src/Common/Game/T5/CommonAssetT5.h new file mode 100644 index 00000000..551f8255 --- /dev/null +++ b/src/Common/Game/T5/CommonAssetT5.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Game/CommonAsset.h" + +namespace T5 +{ + class CommonAssetTypeMapper final : public ICommonAssetTypeMapper + { + public: + CommonAssetTypeMapper(); + + [[nodiscard]] CommonAssetType GameToCommonAssetType(asset_type_t gameAssetType) const override; + [[nodiscard]] std::optional CommonToGameAssetType(CommonAssetType commonAssetType) const override; + }; +} // namespace T5 diff --git a/src/Common/Game/T6/CommonAssetT6.cpp b/src/Common/Game/T6/CommonAssetT6.cpp new file mode 100644 index 00000000..5ea16b24 --- /dev/null +++ b/src/Common/Game/T6/CommonAssetT6.cpp @@ -0,0 +1,154 @@ +#include "CommonAssetT6.h" + +#include "T6.h" + +#include + +namespace T6 +{ + CommonAssetTypeMapper::CommonAssetTypeMapper() = default; + + CommonAssetType CommonAssetTypeMapper::GameToCommonAssetType(const asset_type_t gameAssetType) const + { + static CommonAssetType lookupTable[static_cast(ASSET_TYPE_COUNT)]{ + CommonAssetType::XMODEL_PIECES, // ASSET_TYPE_XMODELPIECES + CommonAssetType::PHYS_PRESET, // ASSET_TYPE_PHYSPRESET + CommonAssetType::PHYS_CONSTRAINTS, // ASSET_TYPE_PHYSCONSTRAINTS + CommonAssetType::DESTRUCTIBLE_DEF, // ASSET_TYPE_DESTRUCTIBLEDEF + CommonAssetType::XANIM, // ASSET_TYPE_XANIMPARTS + CommonAssetType::XMODEL, // ASSET_TYPE_XMODEL + CommonAssetType::MATERIAL, // ASSET_TYPE_MATERIAL + CommonAssetType::TECHNIQUE_SET, // ASSET_TYPE_TECHNIQUE_SET + CommonAssetType::IMAGE, // ASSET_TYPE_IMAGE + CommonAssetType::SOUND, // ASSET_TYPE_SOUND + CommonAssetType::SOUND_PATCH, // ASSET_TYPE_SOUND_PATCH + CommonAssetType::CLIP_MAP, // ASSET_TYPE_CLIPMAP + CommonAssetType::CLIP_MAP, // ASSET_TYPE_CLIPMAP_PVS + CommonAssetType::COM_WORLD, // ASSET_TYPE_COMWORLD + CommonAssetType::GAME_WORLD_SP, // ASSET_TYPE_GAMEWORLD_SP + CommonAssetType::GAME_WORLD_MP, // ASSET_TYPE_GAMEWORLD_MP + CommonAssetType::MAP_ENTS, // ASSET_TYPE_MAP_ENTS + CommonAssetType::GFX_WORLD, // ASSET_TYPE_GFXWORLD + CommonAssetType::LIGHT_DEF, // ASSET_TYPE_LIGHT_DEF + CommonAssetType::UI_MAP, // ASSET_TYPE_UI_MAP + CommonAssetType::FONT, // ASSET_TYPE_FONT + CommonAssetType::FONT_ICON, // ASSET_TYPE_FONTICON + CommonAssetType::MENU_LIST, // ASSET_TYPE_MENULIST + CommonAssetType::MENU, // ASSET_TYPE_MENU + CommonAssetType::LOCALIZE_ENTRY, // ASSET_TYPE_LOCALIZE_ENTRY + CommonAssetType::WEAPON, // ASSET_TYPE_WEAPON + CommonAssetType::WEAPON_DEF, // ASSET_TYPE_WEAPONDEF + CommonAssetType::WEAPON_VARIANT, // ASSET_TYPE_WEAPON_VARIANT + CommonAssetType::WEAPON_FULL, // ASSET_TYPE_WEAPON_FULL + CommonAssetType::ATTACHMENT, // ASSET_TYPE_ATTACHMENT + CommonAssetType::ATTACHMENT_UNIQUE, // ASSET_TYPE_ATTACHMENT_UNIQUE + CommonAssetType::WEAPON_CAMO, // ASSET_TYPE_WEAPON_CAMO + CommonAssetType::SOUND_DRIVER_GLOBALS, // ASSET_TYPE_SNDDRIVER_GLOBALS + CommonAssetType::FX, // ASSET_TYPE_FX + CommonAssetType::IMPACT_FX, // ASSET_TYPE_IMPACT_FX + CommonAssetType::AI_TYPE, // ASSET_TYPE_AITYPE + CommonAssetType::MP_TYPE, // ASSET_TYPE_MPTYPE + CommonAssetType::MP_BODY, // ASSET_TYPE_MPBODY + CommonAssetType::MP_HEAD, // ASSET_TYPE_MPHEAD + CommonAssetType::CHARACTER, // ASSET_TYPE_CHARACTER + CommonAssetType::XMODEL_ALIAS, // ASSET_TYPE_XMODELALIAS + CommonAssetType::RAW_FILE, // ASSET_TYPE_RAWFILE + CommonAssetType::STRING_TABLE, // ASSET_TYPE_STRINGTABLE + CommonAssetType::LEADERBOARD, // ASSET_TYPE_LEADERBOARD + CommonAssetType::XGLOBALS, // ASSET_TYPE_XGLOBALS + CommonAssetType::DDL, // ASSET_TYPE_DDL + CommonAssetType::GLASSES, // ASSET_TYPE_GLASSES + CommonAssetType::EMBLEM_SET, // ASSET_TYPE_EMBLEMSET + CommonAssetType::SCRIPT, // ASSET_TYPE_SCRIPTPARSETREE + CommonAssetType::KEY_VALUE_PAIRS, // ASSET_TYPE_KEYVALUEPAIRS + CommonAssetType::VEHICLE, // ASSET_TYPE_VEHICLEDEF + CommonAssetType::MEMORY_BLOCK, // ASSET_TYPE_MEMORYBLOCK + CommonAssetType::ADDON_MAP_ENTS, // ASSET_TYPE_ADDON_MAP_ENTS + CommonAssetType::TRACER, // ASSET_TYPE_TRACER + CommonAssetType::SKINNED_VERTS, // ASSET_TYPE_SKINNEDVERTS + CommonAssetType::QDB, // ASSET_TYPE_QDB + CommonAssetType::SLUG, // ASSET_TYPE_SLUG + CommonAssetType::FOOTSTEP_TABLE, // ASSET_TYPE_FOOTSTEP_TABLE + CommonAssetType::FOOTSTEP_FX_TABLE, // ASSET_TYPE_FOOTSTEPFX_TABLE + CommonAssetType::ZBARRIER, // ASSET_TYPE_ZBARRIER + }; + + assert(gameAssetType < ASSET_TYPE_COUNT); + return lookupTable[gameAssetType]; + } + + std::optional CommonAssetTypeMapper::CommonToGameAssetType(const CommonAssetType commonAssetType) const + { +#define MAP_COMMON(common, game) \ + case common: \ + return game; + + switch (commonAssetType) + { + MAP_COMMON(CommonAssetType::XMODEL_PIECES, ASSET_TYPE_XMODELPIECES) + MAP_COMMON(CommonAssetType::PHYS_PRESET, ASSET_TYPE_PHYSPRESET) + MAP_COMMON(CommonAssetType::PHYS_CONSTRAINTS, ASSET_TYPE_PHYSCONSTRAINTS) + MAP_COMMON(CommonAssetType::DESTRUCTIBLE_DEF, ASSET_TYPE_DESTRUCTIBLEDEF) + MAP_COMMON(CommonAssetType::XANIM, ASSET_TYPE_XANIMPARTS) + MAP_COMMON(CommonAssetType::XMODEL, ASSET_TYPE_XMODEL) + MAP_COMMON(CommonAssetType::MATERIAL, ASSET_TYPE_MATERIAL) + MAP_COMMON(CommonAssetType::TECHNIQUE_SET, ASSET_TYPE_TECHNIQUE_SET) + MAP_COMMON(CommonAssetType::IMAGE, ASSET_TYPE_IMAGE) + MAP_COMMON(CommonAssetType::SOUND, ASSET_TYPE_SOUND) + MAP_COMMON(CommonAssetType::SOUND_PATCH, ASSET_TYPE_SOUND_PATCH) + MAP_COMMON(CommonAssetType::CLIP_MAP, ASSET_TYPE_CLIPMAP_PVS) + MAP_COMMON(CommonAssetType::COM_WORLD, ASSET_TYPE_COMWORLD) + MAP_COMMON(CommonAssetType::GAME_WORLD_SP, ASSET_TYPE_GAMEWORLD_SP) + MAP_COMMON(CommonAssetType::GAME_WORLD_MP, ASSET_TYPE_GAMEWORLD_MP) + MAP_COMMON(CommonAssetType::MAP_ENTS, ASSET_TYPE_MAP_ENTS) + MAP_COMMON(CommonAssetType::GFX_WORLD, ASSET_TYPE_GFXWORLD) + MAP_COMMON(CommonAssetType::LIGHT_DEF, ASSET_TYPE_LIGHT_DEF) + MAP_COMMON(CommonAssetType::UI_MAP, ASSET_TYPE_UI_MAP) + MAP_COMMON(CommonAssetType::FONT, ASSET_TYPE_FONT) + MAP_COMMON(CommonAssetType::FONT_ICON, ASSET_TYPE_FONTICON) + MAP_COMMON(CommonAssetType::MENU_LIST, ASSET_TYPE_MENULIST) + MAP_COMMON(CommonAssetType::MENU, ASSET_TYPE_MENU) + MAP_COMMON(CommonAssetType::LOCALIZE_ENTRY, ASSET_TYPE_LOCALIZE_ENTRY) + MAP_COMMON(CommonAssetType::WEAPON, ASSET_TYPE_WEAPON) + MAP_COMMON(CommonAssetType::WEAPON_DEF, ASSET_TYPE_WEAPONDEF) + MAP_COMMON(CommonAssetType::WEAPON_VARIANT, ASSET_TYPE_WEAPON_VARIANT) + MAP_COMMON(CommonAssetType::WEAPON_FULL, ASSET_TYPE_WEAPON_FULL) + MAP_COMMON(CommonAssetType::ATTACHMENT, ASSET_TYPE_ATTACHMENT) + MAP_COMMON(CommonAssetType::ATTACHMENT_UNIQUE, ASSET_TYPE_ATTACHMENT_UNIQUE) + MAP_COMMON(CommonAssetType::WEAPON_CAMO, ASSET_TYPE_WEAPON_CAMO) + MAP_COMMON(CommonAssetType::SOUND_DRIVER_GLOBALS, ASSET_TYPE_SNDDRIVER_GLOBALS) + MAP_COMMON(CommonAssetType::FX, ASSET_TYPE_FX) + MAP_COMMON(CommonAssetType::IMPACT_FX, ASSET_TYPE_IMPACT_FX) + MAP_COMMON(CommonAssetType::AI_TYPE, ASSET_TYPE_AITYPE) + MAP_COMMON(CommonAssetType::MP_TYPE, ASSET_TYPE_MPTYPE) + MAP_COMMON(CommonAssetType::MP_BODY, ASSET_TYPE_MPBODY) + MAP_COMMON(CommonAssetType::MP_HEAD, ASSET_TYPE_MPHEAD) + MAP_COMMON(CommonAssetType::CHARACTER, ASSET_TYPE_CHARACTER) + MAP_COMMON(CommonAssetType::XMODEL_ALIAS, ASSET_TYPE_XMODELALIAS) + MAP_COMMON(CommonAssetType::RAW_FILE, ASSET_TYPE_RAWFILE) + MAP_COMMON(CommonAssetType::STRING_TABLE, ASSET_TYPE_STRINGTABLE) + MAP_COMMON(CommonAssetType::LEADERBOARD, ASSET_TYPE_LEADERBOARD) + MAP_COMMON(CommonAssetType::XGLOBALS, ASSET_TYPE_XGLOBALS) + MAP_COMMON(CommonAssetType::DDL, ASSET_TYPE_DDL) + MAP_COMMON(CommonAssetType::GLASSES, ASSET_TYPE_GLASSES) + MAP_COMMON(CommonAssetType::EMBLEM_SET, ASSET_TYPE_EMBLEMSET) + MAP_COMMON(CommonAssetType::SCRIPT, ASSET_TYPE_SCRIPTPARSETREE) + MAP_COMMON(CommonAssetType::KEY_VALUE_PAIRS, ASSET_TYPE_KEYVALUEPAIRS) + MAP_COMMON(CommonAssetType::VEHICLE, ASSET_TYPE_VEHICLEDEF) + MAP_COMMON(CommonAssetType::MEMORY_BLOCK, ASSET_TYPE_MEMORYBLOCK) + MAP_COMMON(CommonAssetType::ADDON_MAP_ENTS, ASSET_TYPE_ADDON_MAP_ENTS) + MAP_COMMON(CommonAssetType::TRACER, ASSET_TYPE_TRACER) + MAP_COMMON(CommonAssetType::SKINNED_VERTS, ASSET_TYPE_SKINNEDVERTS) + MAP_COMMON(CommonAssetType::QDB, ASSET_TYPE_QDB) + MAP_COMMON(CommonAssetType::SLUG, ASSET_TYPE_SLUG) + MAP_COMMON(CommonAssetType::FOOTSTEP_TABLE, ASSET_TYPE_FOOTSTEP_TABLE) + MAP_COMMON(CommonAssetType::FOOTSTEP_FX_TABLE, ASSET_TYPE_FOOTSTEPFX_TABLE) + MAP_COMMON(CommonAssetType::ZBARRIER, ASSET_TYPE_ZBARRIER) + + default: + return std::nullopt; + } + +#undef MAP_COMMON + } +} // namespace T6 diff --git a/src/Common/Game/T6/CommonAssetT6.h b/src/Common/Game/T6/CommonAssetT6.h new file mode 100644 index 00000000..a6b5d242 --- /dev/null +++ b/src/Common/Game/T6/CommonAssetT6.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Game/CommonAsset.h" + +namespace T6 +{ + class CommonAssetTypeMapper final : public ICommonAssetTypeMapper + { + public: + CommonAssetTypeMapper(); + + [[nodiscard]] CommonAssetType GameToCommonAssetType(asset_type_t gameAssetType) const override; + [[nodiscard]] std::optional CommonToGameAssetType(CommonAssetType commonAssetType) const override; + }; +} // namespace T6 diff --git a/src/Linker/ZoneCreation/ZoneCreator.cpp b/src/Linker/ZoneCreation/ZoneCreator.cpp index 5d32c9a4..c7cb4d5c 100644 --- a/src/Linker/ZoneCreation/ZoneCreator.cpp +++ b/src/Linker/ZoneCreation/ZoneCreator.cpp @@ -11,7 +11,7 @@ namespace { std::unique_ptr CreateZone(const ZoneCreationContext& context, const GameId gameId) { - return std::make_unique(context.m_definition->m_name, 0, gameId); + return std::make_unique(context.m_definition->m_name, 0, gameId, GamePlatform::PC); } std::vector CreateGdtList(const ZoneCreationContext& context) diff --git a/src/ModMan/Context/FastFileContext.cpp b/src/ModMan/Context/FastFileContext.cpp index 2a5f8112..1027b488 100644 --- a/src/ModMan/Context/FastFileContext.cpp +++ b/src/ModMan/Context/FastFileContext.cpp @@ -10,7 +10,7 @@ namespace fs = std::filesystem; namespace { - constexpr double MIN_PROGRESS_TO_REPORT = 0.005; + constexpr double MIN_PROGRESS_TO_REPORT = 0.5; class LoadingEventProgressReporter : public ProgressCallback { @@ -23,7 +23,7 @@ namespace void OnProgress(const size_t current, const size_t total) override { - const double percentage = static_cast(current) / static_cast(total); + const double percentage = static_cast(current) / static_cast(total) * 100.0; if (percentage - m_last_progress >= MIN_PROGRESS_TO_REPORT) { @@ -38,38 +38,53 @@ namespace }; } // namespace +LoadedZone::LoadedZone(std::unique_ptr zone, std::string filePath) + : m_zone(std::move(zone)), + m_file_path(std::move(filePath)) +{ +} + void FastFileContext::Destroy() { // Unload all zones m_loaded_zones.clear(); } -result::Expected FastFileContext::LoadFastFile(const std::string& path) +result::Expected FastFileContext::LoadFastFile(const std::string& path) { auto zone = ZoneLoading::LoadZone(path, std::make_unique(fs::path(path).filename().replace_extension().string())); if (!zone) return result::Unexpected(std::move(zone.error())); - auto* result = m_loaded_zones.emplace_back(std::move(*zone)).get(); + auto loadedZone = std::make_unique(std::move(*zone), path); - ui::NotifyZoneLoaded(result->m_name, path); + LoadedZone* result; + { + std::lock_guard lock(m_zone_lock); + result = m_loaded_zones.emplace_back(std::move(loadedZone)).get(); + } + + ui::NotifyZoneLoaded(*result); return result; } result::Expected FastFileContext::UnloadZone(const std::string& zoneName) { - const auto existingZone = std::ranges::find_if(m_loaded_zones, - [&zoneName](const std::unique_ptr& zone) - { - return zone->m_name == zoneName; - }); - - if (existingZone != m_loaded_zones.end()) { - m_loaded_zones.erase(existingZone); - ui::NotifyZoneUnloaded(zoneName); - return NoResult(); + std::lock_guard lock(m_zone_lock); + const auto existingZone = std::ranges::find_if(m_loaded_zones, + [&zoneName](const std::unique_ptr& loadedZone) + { + return loadedZone->m_zone->m_name == zoneName; + }); + + if (existingZone != m_loaded_zones.end()) + { + m_loaded_zones.erase(existingZone); + ui::NotifyZoneUnloaded(zoneName); + return NoResult(); + } } return result::Unexpected(std::format("No zone with name {} loaded", zoneName)); diff --git a/src/ModMan/Context/FastFileContext.h b/src/ModMan/Context/FastFileContext.h index a3f87a42..e769e34f 100644 --- a/src/ModMan/Context/FastFileContext.h +++ b/src/ModMan/Context/FastFileContext.h @@ -4,15 +4,26 @@ #include "Zone/Zone.h" #include +#include #include +class LoadedZone +{ +public: + std::unique_ptr m_zone; + std::string m_file_path; + + LoadedZone(std::unique_ptr zone, std::string filePath); +}; + class FastFileContext { public: void Destroy(); - result::Expected LoadFastFile(const std::string& path); + result::Expected LoadFastFile(const std::string& path); result::Expected UnloadZone(const std::string& zoneName); - std::vector> m_loaded_zones; + std::vector> m_loaded_zones; + std::shared_mutex m_zone_lock; }; diff --git a/src/ModMan/Web/Binds/AssetBinds.cpp b/src/ModMan/Web/Binds/AssetBinds.cpp new file mode 100644 index 00000000..31769a01 --- /dev/null +++ b/src/ModMan/Web/Binds/AssetBinds.cpp @@ -0,0 +1,174 @@ +#include "AssetBinds.h" + +#include "Context/ModManContext.h" +#include "Game/CommonAsset.h" +#include "Web/UiCommunication.h" + +#include "Json/JsonExtension.h" +#include + +NLOHMANN_JSON_SERIALIZE_ENUM(CommonAssetType, + { + {CommonAssetType::PHYS_PRESET, "PHYS_PRESET" }, + {CommonAssetType::XANIM, "XANIM" }, + {CommonAssetType::XMODEL, "XMODEL" }, + {CommonAssetType::MATERIAL, "MATERIAL" }, + {CommonAssetType::TECHNIQUE_SET, "TECHNIQUE_SET" }, + {CommonAssetType::IMAGE, "IMAGE" }, + {CommonAssetType::SOUND, "SOUND" }, + {CommonAssetType::SOUND_CURVE, "SOUND_CURVE" }, + {CommonAssetType::LOADED_SOUND, "LOADED_SOUND" }, + {CommonAssetType::CLIP_MAP, "CLIP_MAP" }, + {CommonAssetType::COM_WORLD, "COM_WORLD" }, + {CommonAssetType::GAME_WORLD_SP, "GAME_WORLD_SP" }, + {CommonAssetType::GAME_WORLD_MP, "GAME_WORLD_MP" }, + {CommonAssetType::MAP_ENTS, "MAP_ENTS" }, + {CommonAssetType::GFX_WORLD, "GFX_WORLD" }, + {CommonAssetType::LIGHT_DEF, "LIGHT_DEF" }, + {CommonAssetType::UI_MAP, "UI_MAP" }, + {CommonAssetType::FONT, "FONT" }, + {CommonAssetType::MENU_LIST, "MENU_LIST" }, + {CommonAssetType::MENU, "MENU" }, + {CommonAssetType::LOCALIZE_ENTRY, "LOCALIZE_ENTRY" }, + {CommonAssetType::WEAPON, "WEAPON" }, + {CommonAssetType::SOUND_DRIVER_GLOBALS, "SOUND_DRIVER_GLOBALS"}, + {CommonAssetType::FX, "FX" }, + {CommonAssetType::IMPACT_FX, "IMPACT_FX" }, + {CommonAssetType::AI_TYPE, "AI_TYPE" }, + {CommonAssetType::MP_TYPE, "MP_TYPE" }, + {CommonAssetType::CHARACTER, "CHARACTER" }, + {CommonAssetType::XMODEL_ALIAS, "XMODEL_ALIAS" }, + {CommonAssetType::RAW_FILE, "RAW_FILE" }, + {CommonAssetType::STRING_TABLE, "STRING_TABLE" }, + {CommonAssetType::XMODEL_PIECES, "XMODEL_PIECES" }, + {CommonAssetType::PHYS_COLL_MAP, "PHYS_COLL_MAP" }, + {CommonAssetType::XMODEL_SURFS, "XMODEL_SURFS" }, + {CommonAssetType::PIXEL_SHADER, "PIXEL_SHADER" }, + {CommonAssetType::VERTEX_SHADER, "VERTEX_SHADER" }, + {CommonAssetType::VERTEX_DECL, "VERTEX_DECL" }, + {CommonAssetType::FX_WORLD, "FX_WORLD" }, + {CommonAssetType::LEADERBOARD, "LEADERBOARD" }, + {CommonAssetType::STRUCTURED_DATA_DEF, "STRUCTURED_DATA_DEF" }, + {CommonAssetType::TRACER, "TRACER" }, + {CommonAssetType::VEHICLE, "VEHICLE" }, + {CommonAssetType::ADDON_MAP_ENTS, "ADDON_MAP_ENTS" }, + {CommonAssetType::GLASS_WORLD, "GLASS_WORLD" }, + {CommonAssetType::PATH_DATA, "PATH_DATA" }, + {CommonAssetType::VEHICLE_TRACK, "VEHICLE_TRACK" }, + {CommonAssetType::ATTACHMENT, "ATTACHMENT" }, + {CommonAssetType::SURFACE_FX, "SURFACE_FX" }, + {CommonAssetType::SCRIPT, "SCRIPT" }, + {CommonAssetType::PHYS_CONSTRAINTS, "PHYS_CONSTRAINTS" }, + {CommonAssetType::DESTRUCTIBLE_DEF, "DESTRUCTIBLE_DEF" }, + {CommonAssetType::SOUND_PATCH, "SOUND_PATCH" }, + {CommonAssetType::WEAPON_DEF, "WEAPON_DEF" }, + {CommonAssetType::WEAPON_VARIANT, "WEAPON_VARIANT" }, + {CommonAssetType::MP_BODY, "MP_BODY" }, + {CommonAssetType::MP_HEAD, "MP_HEAD" }, + {CommonAssetType::PACK_INDEX, "PACK_INDEX" }, + {CommonAssetType::XGLOBALS, "XGLOBALS" }, + {CommonAssetType::DDL, "DDL" }, + {CommonAssetType::GLASSES, "GLASSES" }, + {CommonAssetType::EMBLEM_SET, "EMBLEM_SET" }, + {CommonAssetType::FONT_ICON, "FONT_ICON" }, + {CommonAssetType::WEAPON_FULL, "WEAPON_FULL" }, + {CommonAssetType::ATTACHMENT_UNIQUE, "ATTACHMENT_UNIQUE" }, + {CommonAssetType::WEAPON_CAMO, "WEAPON_CAMO" }, + {CommonAssetType::KEY_VALUE_PAIRS, "KEY_VALUE_PAIRS" }, + {CommonAssetType::MEMORY_BLOCK, "MEMORY_BLOCK" }, + {CommonAssetType::SKINNED_VERTS, "SKINNED_VERTS" }, + {CommonAssetType::QDB, "QDB" }, + {CommonAssetType::SLUG, "SLUG" }, + {CommonAssetType::FOOTSTEP_TABLE, "FOOTSTEP_TABLE" }, + {CommonAssetType::FOOTSTEP_FX_TABLE, "FOOTSTEP_FX_TABLE" }, + {CommonAssetType::ZBARRIER, "ZBARRIER" }, +}); + +namespace +{ + class AssetDto + { + public: + CommonAssetType type; + std::string name; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(AssetDto, type, name); + + class ZoneAssetsDto + { + public: + std::vector assets; + std::vector references; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(ZoneAssetsDto, assets, references); + + ZoneAssetsDto CreateZoneAssetsDto(const Zone& zone) + { + std::vector assets; + std::vector references; + + // Reserve some entries already. Numbers are arbitrary. + const auto assetCount = zone.m_pools->GetTotalAssetCount(); + assets.reserve(assetCount / 2); + references.reserve(assetCount / 8); + + const auto& assetTypeMapper = *ICommonAssetTypeMapper::GetCommonAssetMapperByGame(zone.m_game_id); + for (const auto& asset : *zone.m_pools) + { + if (asset->IsReference()) + { + references.emplace_back(AssetDto{ + .type = assetTypeMapper.GameToCommonAssetType(asset->m_type), + .name = asset->ReferencedAssetName(), + }); + } + else + { + assets.emplace_back(AssetDto{ + .type = assetTypeMapper.GameToCommonAssetType(asset->m_type), + .name = asset->m_name, + }); + } + } + + return ZoneAssetsDto{ + .assets = std::move(assets), + .references = std::move(references), + }; + } + + std::optional GetZonesForZone(const std::string& zoneName) + { + auto& context = ModManContext::Get().m_fast_file; + + ZoneAssetsDto result; + + { + std::shared_lock lock(context.m_zone_lock); + + for (const auto& loadedZone : context.m_loaded_zones) + { + const auto& zone = *loadedZone->m_zone; + if (zone.m_name == zoneName) + return CreateZoneAssetsDto(zone); + } + } + + return std::nullopt; + } +} // namespace + +namespace ui +{ + void RegisterAssetBinds(webview::webview& wv) + { + Bind>(wv, + "getAssetsForZone", + [](const std::string& zoneName) + { + return GetZonesForZone(zoneName); + }); + } +} // namespace ui diff --git a/src/ModMan/Web/Binds/AssetBinds.h b/src/ModMan/Web/Binds/AssetBinds.h new file mode 100644 index 00000000..282e2a5d --- /dev/null +++ b/src/ModMan/Web/Binds/AssetBinds.h @@ -0,0 +1,8 @@ +#pragma once + +#include "Web/WebViewLib.h" + +namespace ui +{ + void RegisterAssetBinds(webview::webview& wv); +} // namespace ui diff --git a/src/ModMan/Web/Binds/Binds.cpp b/src/ModMan/Web/Binds/Binds.cpp index 7ae5ab9c..e1a13a8c 100644 --- a/src/ModMan/Web/Binds/Binds.cpp +++ b/src/ModMan/Web/Binds/Binds.cpp @@ -1,13 +1,15 @@ #include "Binds.h" +#include "AssetBinds.h" +#include "DialogBinds.h" #include "UnlinkingBinds.h" -#include "Web/Binds/DialogBinds.h" #include "ZoneBinds.h" namespace ui { void RegisterAllBinds(webview::webview& wv) { + RegisterAssetBinds(wv); RegisterDialogHandlerBinds(wv); RegisterUnlinkingBinds(wv); RegisterZoneBinds(wv); diff --git a/src/ModMan/Web/Binds/UnlinkingBinds.cpp b/src/ModMan/Web/Binds/UnlinkingBinds.cpp index 82d9d9b2..ba3f7a58 100644 --- a/src/ModMan/Web/Binds/UnlinkingBinds.cpp +++ b/src/ModMan/Web/Binds/UnlinkingBinds.cpp @@ -23,7 +23,7 @@ namespace NLOHMANN_DEFINE_TYPE_EXTENSION(ZoneUnlinkProgressDto, zoneName, percentage); - constexpr double MIN_PROGRESS_TO_REPORT = 0.005; + constexpr double MIN_PROGRESS_TO_REPORT = 0.5; class UnlinkingEventProgressReporter : public ProgressCallback { @@ -36,7 +36,7 @@ namespace void OnProgress(const size_t current, const size_t total) override { - const double percentage = static_cast(current) / static_cast(total); + const double percentage = static_cast(current) / static_cast(total) * 100.0; if (percentage - m_last_progress >= MIN_PROGRESS_TO_REPORT) { @@ -54,17 +54,17 @@ namespace { const auto& context = ModManContext::Get().m_fast_file; const auto existingZone = std::ranges::find_if(context.m_loaded_zones, - [&zoneName](const std::unique_ptr& zone) + [&zoneName](const std::unique_ptr& loadedZone) { - return zone->m_name == zoneName; + return loadedZone->m_zone->m_name == zoneName; }); if (existingZone == context.m_loaded_zones.end()) return result::Unexpected(std::format("No zone with name {} loaded", zoneName)); - const auto& zone = *existingZone->get(); + const auto& loadedZone = *existingZone->get(); - const auto* objWriter = IObjWriter::GetObjWriterForGame(zone.m_game_id); + const auto* objWriter = IObjWriter::GetObjWriterForGame(loadedZone.m_zone->m_game_id); const auto outputFolderPath = fs::path(utils::GetExecutablePath()).parent_path() / "zone_dump" / zoneName; const auto outputFolderPathStr = outputFolderPath.string(); @@ -72,7 +72,7 @@ namespace OutputPathFilesystem outputFolderOutputPath(outputFolderPath); SearchPaths searchPaths; AssetDumpingContext dumpingContext( - zone, outputFolderPathStr, outputFolderOutputPath, searchPaths, std::make_unique(zoneName)); + *loadedZone.m_zone, outputFolderPathStr, outputFolderOutputPath, searchPaths, std::make_unique(zoneName)); objWriter->DumpZone(dumpingContext); return NoResult(); diff --git a/src/ModMan/Web/Binds/ZoneBinds.cpp b/src/ModMan/Web/Binds/ZoneBinds.cpp index fd538376..31b93b6e 100644 --- a/src/ModMan/Web/Binds/ZoneBinds.cpp +++ b/src/ModMan/Web/Binds/ZoneBinds.cpp @@ -5,8 +5,35 @@ #include "Json/JsonExtension.h" +NLOHMANN_JSON_SERIALIZE_ENUM(GameId, + { + {GameId::IW3, "IW3"}, + {GameId::IW4, "IW4"}, + {GameId::IW5, "IW5"}, + {GameId::T5, "T5" }, + {GameId::T6, "T6" }, +}); + +NLOHMANN_JSON_SERIALIZE_ENUM(GamePlatform, + { + {GamePlatform::PC, "PC" }, + {GamePlatform::XBOX, "XBOX"}, + {GamePlatform::PS3, "PS3" }, +}); + namespace { + class ZoneDto + { + public: + std::string name; + std::string filePath; + GameId game; + GamePlatform platform; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(ZoneDto, name, filePath, game, platform); + class ZoneLoadProgressDto { public: @@ -19,11 +46,10 @@ namespace class ZoneLoadedDto { public: - std::string zoneName; - std::string filePath; + ZoneDto zone; }; - NLOHMANN_DEFINE_TYPE_EXTENSION(ZoneLoadedDto, zoneName, filePath); + NLOHMANN_DEFINE_TYPE_EXTENSION(ZoneLoadedDto, zone); class ZoneUnloadedDto { @@ -33,6 +59,35 @@ namespace NLOHMANN_DEFINE_TYPE_EXTENSION(ZoneUnloadedDto, zoneName); + ZoneDto CreateZoneDto(const LoadedZone& loadedZone) + { + return ZoneDto{ + .name = loadedZone.m_zone->m_name, + .filePath = loadedZone.m_file_path, + .game = loadedZone.m_zone->m_game_id, + .platform = loadedZone.m_zone->m_platform, + }; + } + + std::vector GetLoadedZones() + { + auto& context = ModManContext::Get().m_fast_file; + + std::vector result; + + { + std::shared_lock lock(context.m_zone_lock); + result.reserve(context.m_loaded_zones.size()); + + for (const auto& loadedZone : context.m_loaded_zones) + { + result.emplace_back(CreateZoneDto(*loadedZone)); + } + } + + return result; + } + void LoadFastFile(webview::webview& wv, std::string id, std::string path) // NOLINT(performance-unnecessary-value-param) Copy is made for thread safety { ModManContext::Get().m_db_thread.Dispatch( @@ -45,10 +100,9 @@ namespace ui::PromiseResolve(wv, id, ZoneLoadedDto{ - .zoneName = maybeZone.value()->m_name, - .filePath = path, + .zone = CreateZoneDto(*maybeZone.value()), }); - con::debug("Loaded zone \"{}\"", maybeZone.value()->m_name); + con::debug("Loaded zone \"{}\"", maybeZone.value()->m_zone->m_name); } else { @@ -89,11 +143,10 @@ namespace ui Notify(*ModManContext::Get().m_main_webview, "zoneLoadProgress", dto); } - void NotifyZoneLoaded(std::string zoneName, std::string fastFilePath) + void NotifyZoneLoaded(const LoadedZone& loadedZone) { const ZoneLoadedDto dto{ - .zoneName = std::move(zoneName), - .filePath = std::move(fastFilePath), + .zone = CreateZoneDto(loadedZone), }; Notify(*ModManContext::Get().m_main_webview, "zoneLoaded", dto); } @@ -108,6 +161,13 @@ namespace ui void RegisterZoneBinds(webview::webview& wv) { + BindRetOnly>(wv, + "getZones", + [] + { + return GetLoadedZones(); + }); + BindAsync(wv, "loadFastFile", [&wv](const std::string& id, std::string path) diff --git a/src/ModMan/Web/Binds/ZoneBinds.h b/src/ModMan/Web/Binds/ZoneBinds.h index 142d5e5b..ee2efda8 100644 --- a/src/ModMan/Web/Binds/ZoneBinds.h +++ b/src/ModMan/Web/Binds/ZoneBinds.h @@ -1,11 +1,12 @@ #pragma once +#include "Context/FastFileContext.h" #include "Web/WebViewLib.h" namespace ui { void NotifyZoneLoadProgress(std::string zoneName, double percentage); - void NotifyZoneLoaded(std::string zoneName, std::string fastFilePath); + void NotifyZoneLoaded(const LoadedZone& loadedZone); void NotifyZoneUnloaded(std::string zoneName); void RegisterZoneBinds(webview::webview& wv); diff --git a/src/ModMan/main.cpp b/src/ModMan/main.cpp index cd0e838d..b7f82fa6 100644 --- a/src/ModMan/main.cpp +++ b/src/ModMan/main.cpp @@ -63,7 +63,7 @@ namespace newWindow.set_title("OpenAssetTools ModMan"); newWindow.set_size(1280, 640, WEBVIEW_HINT_NONE); - newWindow.set_size(480, 320, WEBVIEW_HINT_MIN); + newWindow.set_size(640, 480, WEBVIEW_HINT_MIN); InstallAssetHandler(newWindow); ui::RegisterAllBinds(newWindow); diff --git a/src/ModManUi/build/HeaderTransformationPlugin.ts b/src/ModManUi/build/HeaderTransformationPlugin.ts index 4d6fba3c..ca19ed12 100644 --- a/src/ModManUi/build/HeaderTransformationPlugin.ts +++ b/src/ModManUi/build/HeaderTransformationPlugin.ts @@ -1,4 +1,4 @@ -import type { Plugin } from "vite"; +import type { Plugin, UserConfig } from "vite"; import type { OutputAsset, OutputChunk } from "rollup"; import path from "node:path"; import fs from "node:fs"; @@ -7,8 +7,35 @@ type MinimalOutputAsset = Pick; type MinimalOutputChunk = Pick; type MinimalOutputBundle = Record; +interface PublicDirFile { + fullPath: string; + relativePath: string; +} + +function getPublicDirFiles(publicDir?: string): PublicDirFile[] { + if (!publicDir) return []; + + const result: PublicDirFile[] = []; + const files = fs.readdirSync(publicDir, { recursive: true, withFileTypes: true }); + for (const file of files) { + if (!file.isFile()) continue; + const fullPath = path.join(file.parentPath, file.name); + let relativePath = path.relative(publicDir, fullPath).replaceAll(/\\/g, "/"); + if (relativePath.startsWith("./")) { + relativePath = relativePath.substring(2); + } + + result.push({ + fullPath, + relativePath, + }); + } + + return result; +} + function createVarName(fileName: string) { - return fileName.replaceAll(".", "_").toUpperCase(); + return fileName.replaceAll(/[\\/]/g, "__").replaceAll(/[\.-]/g, "_").toUpperCase(); } function transformAsset(asset: MinimalOutputAsset) { @@ -33,10 +60,19 @@ function transformChunk(chunk: MinimalOutputChunk) { `; } +function transformPublicFile(publicFile: PublicDirFile) { + const varName = createVarName(publicFile.relativePath); + const bytes = [...fs.readFileSync(publicFile.fullPath)].map((v) => String(v)).join(","); + + return `constexpr const unsigned char ${varName}[] {${bytes}}; +`; +} + function writeHeader( bundle: MinimalOutputBundle, outputDir?: string, options?: HeaderTransformationPluginOptions, + publicDir?: string, devServerPort?: number, ) { const outputPath = options?.outputPath ?? path.join(outputDir ?? "dist", "ViteAssets.h"); @@ -71,12 +107,18 @@ constexpr auto VITE_DEV_SERVER_PORT = ${devServerPort ? String(devServerPort) : `, ); + const fileNames: string[] = []; for (const curBundle of Object.values(bundle)) { if (curBundle.type === "asset") { fs.writeSync(fd, transformAsset(curBundle)); } else { fs.writeSync(fd, transformChunk(curBundle)); } + fileNames.push(curBundle.fileName); + } + for (const publicDirFile of getPublicDirFiles(publicDir)) { + fs.writeSync(fd, transformPublicFile(publicDirFile)); + fileNames.push(publicDirFile.relativePath); } if (includeFileEnumeration) { @@ -95,8 +137,7 @@ static inline const UiFile MOD_MAN_UI_FILES[] { ); let index = 0; - for (const curBundle of Object.values(bundle)) { - const fileName = curBundle.fileName; + for (const fileName of fileNames) { const varName = createVarName(fileName); let prefix = " "; @@ -133,16 +174,21 @@ export default function headerTransformationPlugin( ): Plugin { let writeServerActive = false; let writeBundleActive = false; + let publicDir: string | undefined = undefined; return { name: "vite-plugin-header-transformation", enforce: "post", - config(_userOptions, env) { + config(userOptions: UserConfig, env) { if (env.command === "serve") { writeServerActive = true; } else { writeBundleActive = true; } + + if (typeof userOptions.publicDir === "string") { + publicDir = userOptions.publicDir; + } }, configureServer(server) { if (!writeServerActive) { @@ -156,6 +202,7 @@ export default function headerTransformationPlugin( }, server.config.build.outDir, options, + publicDir, server.config.server.port, ); }); @@ -165,7 +212,7 @@ export default function headerTransformationPlugin( return; } - writeHeader(bundle, outputOptions.dir, options); + writeHeader(bundle, outputOptions.dir, options, publicDir); }, }; } diff --git a/src/ModManUi/index.html b/src/ModManUi/index.html index 27a13611..945cf0e6 100644 --- a/src/ModManUi/index.html +++ b/src/ModManUi/index.html @@ -2,9 +2,10 @@ - + + - Tauri + Vue + Typescript App + OpenAssetTools ModMan
diff --git a/src/ModManUi/package-lock.json b/src/ModManUi/package-lock.json index d64a29a2..14a58f0d 100644 --- a/src/ModManUi/package-lock.json +++ b/src/ModManUi/package-lock.json @@ -8,8 +8,12 @@ "name": "openassettools", "version": "0.1.0", "dependencies": { + "@fontsource/inter": "^5.2.8", + "@primeuix/themes": "^1.2.5", "pinia": "3.0.3", - "vue": "3.5.22" + "primevue": "^4.4.1", + "vue": "3.5.22", + "vue-router": "4.6.3" }, "devDependencies": { "@tsconfig/node22": "^22.0.2", @@ -1324,6 +1328,15 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@fontsource/inter": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-5.2.8.tgz", + "integrity": "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1829,6 +1842,74 @@ "dev": true, "license": "MIT" }, + "node_modules/@primeuix/styled": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@primeuix/styled/-/styled-0.7.4.tgz", + "integrity": "sha512-QSO/NpOQg8e9BONWRBx9y8VGMCMYz0J/uKfNJEya/RGEu7ARx0oYW0ugI1N3/KB1AAvyGxzKBzGImbwg0KUiOQ==", + "license": "MIT", + "dependencies": { + "@primeuix/utils": "^0.6.1" + }, + "engines": { + "node": ">=12.11.0" + } + }, + "node_modules/@primeuix/styles": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@primeuix/styles/-/styles-1.2.5.tgz", + "integrity": "sha512-nypFRct/oaaBZqP4jinT0puW8ZIfs4u+l/vqUFmJEPU332fl5ePj6DoOpQgTLzo3OfmvSmz5a5/5b4OJJmmi7Q==", + "license": "MIT", + "dependencies": { + "@primeuix/styled": "^0.7.3" + } + }, + "node_modules/@primeuix/themes": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@primeuix/themes/-/themes-1.2.5.tgz", + "integrity": "sha512-n3YkwJrHQaEESc/D/A/iD815sxp8cKnmzscA6a8Tm8YvMtYU32eCahwLLe6h5rywghVwxASWuG36XBgISYOIjQ==", + "license": "MIT", + "dependencies": { + "@primeuix/styled": "^0.7.3" + } + }, + "node_modules/@primeuix/utils": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@primeuix/utils/-/utils-0.6.1.tgz", + "integrity": "sha512-tQL/ZOPgCdD+NTimlUmhyD0ey8J1XmpZE4hDHM+/fnuBicVVmlKOd5HpS748LcOVRUKbWjmEPdHX4hi5XZoC1Q==", + "license": "MIT", + "engines": { + "node": ">=12.11.0" + } + }, + "node_modules/@primevue/core": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@primevue/core/-/core-4.4.1.tgz", + "integrity": "sha512-RG56iDKIJT//EtntjQzOiWOHZZJczw/qWWtdL5vFvw8/QDS9DPKn8HLpXK7N5Le6KK1MLXUsxoiGTZK+poUFUg==", + "license": "MIT", + "dependencies": { + "@primeuix/styled": "^0.7.4", + "@primeuix/utils": "^0.6.1" + }, + "engines": { + "node": ">=12.11.0" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/@primevue/icons": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@primevue/icons/-/icons-4.4.1.tgz", + "integrity": "sha512-UfDimrIjVdY6EziwieyV4zPKzW6mnKHKhy4Dgyjv2oI6pNeuim+onbJo1ce22PEGXW78vfblG/3/JIzVHFweqQ==", + "license": "MIT", + "dependencies": { + "@primeuix/utils": "^0.6.1", + "@primevue/core": "4.4.1" + }, + "engines": { + "node": ">=12.11.0" + } + }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.29", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.29.tgz", @@ -5369,6 +5450,22 @@ "node": ">=6.0.0" } }, + "node_modules/primevue": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/primevue/-/primevue-4.4.1.tgz", + "integrity": "sha512-JbHBa5k30pZ7mn/z4vYBOnyt5GrR15eM3X0wa3VanonxnFLYkTEx8OMh33aU6ndWeOfi7Ef57dOL3bTH+3f4hQ==", + "license": "MIT", + "dependencies": { + "@primeuix/styled": "^0.7.4", + "@primeuix/styles": "^1.2.5", + "@primeuix/utils": "^0.6.1", + "@primevue/core": "4.4.1", + "@primevue/icons": "4.4.1" + }, + "engines": { + "node": ">=12.11.0" + } + }, "node_modules/proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -6553,6 +6650,27 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/vue-router": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.3.tgz", + "integrity": "sha512-ARBedLm9YlbvQomnmq91Os7ck6efydTSpRP3nuOKCvgJOHNrhRoJDSKtee8kcL1Vf7nz6U+PMBL+hTvR3bTVQg==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/vue-router/node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, "node_modules/vue-tsc": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.1.2.tgz", diff --git a/src/ModManUi/package.json b/src/ModManUi/package.json index aaba126d..78ef8bad 100644 --- a/src/ModManUi/package.json +++ b/src/ModManUi/package.json @@ -13,8 +13,12 @@ "format": "prettier --write **/*.{js,ts,vue,html,json,yml,yaml,md}" }, "dependencies": { + "@fontsource/inter": "^5.2.8", + "@primeuix/themes": "^1.2.5", "pinia": "3.0.3", - "vue": "3.5.22" + "primevue": "^4.4.1", + "vue": "3.5.22", + "vue-router": "4.6.3" }, "devDependencies": { "@tsconfig/node22": "^22.0.2", diff --git a/src/ModManUi/public/favicon.ico b/src/ModManUi/public/favicon.ico index df36fcfb..b2f2e9f9 100644 Binary files a/src/ModManUi/public/favicon.ico and b/src/ModManUi/public/favicon.ico differ diff --git a/src/ModManUi/public/logo_circle.svg b/src/ModManUi/public/logo_circle.svg new file mode 100644 index 00000000..98d88ab3 --- /dev/null +++ b/src/ModManUi/public/logo_circle.svg @@ -0,0 +1,77 @@ + + + + diff --git a/src/ModManUi/src/App.vue b/src/ModManUi/src/App.vue index 73f92c86..cd4ba26e 100644 --- a/src/ModManUi/src/App.vue +++ b/src/ModManUi/src/App.vue @@ -1,163 +1,56 @@ diff --git a/src/ModManUi/src/PrimeVue.ts b/src/ModManUi/src/PrimeVue.ts new file mode 100644 index 00000000..0afa4311 --- /dev/null +++ b/src/ModManUi/src/PrimeVue.ts @@ -0,0 +1,51 @@ +import type { App } from "vue"; +import PrimeVue from "primevue/config"; +import Aura from "@primeuix/themes/aura"; +import { definePreset } from "@primeuix/themes"; +import type { ColorScale } from "@primeuix/styled"; + +const ModManTheme = definePreset(Aura, { + primitive: { + brand: { + 50: "var(--color-brand-50)", + 100: "var(--color-brand-100)", + 200: "var(--color-brand-200)", + 300: "var(--color-brand-300)", + 400: "var(--color-brand-400)", + 500: "var(--color-brand-500)", + 600: "var(--color-brand-600)", + 700: "var(--color-brand-700)", + 800: "var(--color-brand-800)", + 900: "var(--color-brand-900)", + 950: "var(--color-brand-950)", + } satisfies ColorScale, + }, + semantic: { + primary: { + 50: "{orange.50}", + 100: "{orange.100}", + 200: "{orange.200}", + 300: "{orange.300}", + 400: "{orange.400}", + 500: "{orange.500}", + 600: "{orange.600}", + 700: "{orange.700}", + 800: "{orange.800}", + 900: "{orange.900}", + 950: "{orange.950}", + }, + }, +}); + +export function configurePrimeVue(app: App) { + app.use(PrimeVue, { + theme: { + preset: ModManTheme, + options: { + darkModeSelector: ".dark", + }, + }, + }); + // Always make dark mode for now + document.documentElement.classList.add("dark"); +} diff --git a/src/ModManUi/src/components/header/ModManHeader.vue b/src/ModManUi/src/components/header/ModManHeader.vue new file mode 100644 index 00000000..6aee9f00 --- /dev/null +++ b/src/ModManUi/src/components/header/ModManHeader.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/src/ModManUi/src/components/icons/IconArrowLeft.vue b/src/ModManUi/src/components/icons/IconArrowLeft.vue new file mode 100644 index 00000000..3e37cfb5 --- /dev/null +++ b/src/ModManUi/src/components/icons/IconArrowLeft.vue @@ -0,0 +1,9 @@ + diff --git a/src/ModManUi/src/components/icons/IconGear.vue b/src/ModManUi/src/components/icons/IconGear.vue new file mode 100644 index 00000000..6ba8ca16 --- /dev/null +++ b/src/ModManUi/src/components/icons/IconGear.vue @@ -0,0 +1,9 @@ + diff --git a/src/ModManUi/src/main.scss b/src/ModManUi/src/main.scss deleted file mode 100644 index bfd40850..00000000 --- a/src/ModManUi/src/main.scss +++ /dev/null @@ -1,124 +0,0 @@ -:root { - font-family: Inter, Avenir, Helvetica, Arial, sans-serif; - font-size: 16px; - line-height: 24px; - font-weight: 400; - - color: #0f0f0f; - background-color: #f6f6f6; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-text-size-adjust: 100%; -} - -* { - box-sizing: border-box; -} - -body { - margin: 0; -} - -.container { - margin: 0; - padding-top: 10vh; - display: flex; - position: relative; - flex-direction: column; - justify-content: start; - text-align: center; - - height: 100vh; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: 0.75s; -} - -.logo.tauri:hover { - filter: drop-shadow(0 0 2em #24c8db); -} - -.row { - display: flex; - justify-content: center; -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} - -a:hover { - color: #535bf2; -} - -h1 { - text-align: center; -} - -input, -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - color: #0f0f0f; - background-color: #ffffff; - transition: border-color 0.25s; - box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2); -} - -button { - cursor: pointer; -} - -button:not(:disabled):hover { - border-color: #396cd8; -} -button:not(:disabled):active { - border-color: #396cd8; - background-color: #e8e8e8; -} -button:disabled { - opacity: 0.6; - cursor: not-allowed; -} - -input, -button { - outline: none; -} - -#greet-input { - margin-right: 5px; -} - -@media (prefers-color-scheme: dark) { - :root { - color: #f6f6f6; - background-color: #2f2f2f; - } - - a:hover { - color: #24c8db; - } - - input, - button { - color: #ffffff; - background-color: #0f0f0f98; - } - button:not(:disabled):active { - background-color: #0f0f0f69; - } -} \ No newline at end of file diff --git a/src/ModManUi/src/main.ts b/src/ModManUi/src/main.ts index d1a7b243..fb8b13d7 100644 --- a/src/ModManUi/src/main.ts +++ b/src/ModManUi/src/main.ts @@ -1,13 +1,17 @@ -import "../public/favicon.ico"; -import "./main.scss"; +import "@style/main.scss"; import { createApp } from "vue"; import { createPinia } from "pinia"; +import { configurePrimeVue } from "./PrimeVue.ts"; import App from "./App.vue"; +import { createModManRouter } from "./router/Router.ts"; const app = createApp(App); app.use(createPinia()); +app.use(createModManRouter()); + +configurePrimeVue(app); app.mount("#app"); diff --git a/src/ModManUi/src/native/AssetBinds.ts b/src/ModManUi/src/native/AssetBinds.ts new file mode 100644 index 00000000..ce8a2f6c --- /dev/null +++ b/src/ModManUi/src/native/AssetBinds.ts @@ -0,0 +1,89 @@ +export enum CommonAssetType { + PHYS_PRESET = "PHYS_PRESET", + XANIM = "XANIM", + XMODEL = "XMODEL", + MATERIAL = "MATERIAL", + TECHNIQUE_SET = "TECHNIQUE_SET", + IMAGE = "IMAGE", + SOUND = "SOUND", + SOUND_CURVE = "SOUND_CURVE", + LOADED_SOUND = "LOADED_SOUND", + CLIP_MAP = "CLIP_MAP", + COM_WORLD = "COM_WORLD", + GAME_WORLD_SP = "GAME_WORLD_SP", + GAME_WORLD_MP = "GAME_WORLD_MP", + MAP_ENTS = "MAP_ENTS", + GFX_WORLD = "GFX_WORLD", + LIGHT_DEF = "LIGHT_DEF", + UI_MAP = "UI_MAP", + FONT = "FONT", + MENU_LIST = "MENU_LIST", + MENU = "MENU", + LOCALIZE_ENTRY = "LOCALIZE_ENTRY", + WEAPON = "WEAPON", + SOUND_DRIVER_GLOBALS = "SOUND_DRIVER_GLOBALS", + FX = "FX", + IMPACT_FX = "IMPACT_FX", + AI_TYPE = "AI_TYPE", + MP_TYPE = "MP_TYPE", + CHARACTER = "CHARACTER", + XMODEL_ALIAS = "XMODEL_ALIAS", + RAW_FILE = "RAW_FILE", + STRING_TABLE = "STRING_TABLE", + XMODEL_PIECES = "XMODEL_PIECES", + PHYS_COLL_MAP = "PHYS_COLL_MAP", + XMODEL_SURFS = "XMODEL_SURFS", + PIXEL_SHADER = "PIXEL_SHADER", + VERTEX_SHADER = "VERTEX_SHADER", + VERTEX_DECL = "VERTEX_DECL", + FX_WORLD = "FX_WORLD", + LEADERBOARD = "LEADERBOARD", + STRUCTURED_DATA_DEF = "STRUCTURED_DATA_DEF", + TRACER = "TRACER", + VEHICLE = "VEHICLE", + ADDON_MAP_ENTS = "ADDON_MAP_ENTS", + GLASS_WORLD = "GLASS_WORLD", + PATH_DATA = "PATH_DATA", + VEHICLE_TRACK = "VEHICLE_TRACK", + ATTACHMENT = "ATTACHMENT", + SURFACE_FX = "SURFACE_FX", + SCRIPT = "SCRIPT", + PHYS_CONSTRAINTS = "PHYS_CONSTRAINTS", + DESTRUCTIBLE_DEF = "DESTRUCTIBLE_DEF", + SOUND_PATCH = "SOUND_PATCH", + WEAPON_DEF = "WEAPON_DEF", + WEAPON_VARIANT = "WEAPON_VARIANT", + MP_BODY = "MP_BODY", + MP_HEAD = "MP_HEAD", + PACK_INDEX = "PACK_INDEX", + XGLOBALS = "XGLOBALS", + DDL = "DDL", + GLASSES = "GLASSES", + EMBLEM_SET = "EMBLEM_SET", + FONT_ICON = "FONT_ICON", + WEAPON_FULL = "WEAPON_FULL", + ATTACHMENT_UNIQUE = "ATTACHMENT_UNIQUE", + WEAPON_CAMO = "WEAPON_CAMO", + KEY_VALUE_PAIRS = "KEY_VALUE_PAIRS", + MEMORY_BLOCK = "MEMORY_BLOCK", + SKINNED_VERTS = "SKINNED_VERTS", + QDB = "QDB", + SLUG = "SLUG", + FOOTSTEP_TABLE = "FOOTSTEP_TABLE", + FOOTSTEP_FX_TABLE = "FOOTSTEP_FX_TABLE", + ZBARRIER = "ZBARRIER", +} + +export interface AssetDto { + type: CommonAssetType; + name: string; +} + +export interface ZoneAssetsDto { + assets: AssetDto[]; + references: AssetDto[]; +} + +export interface AssetBinds { + getAssetsForZone(zoneName: string): Promise; +} diff --git a/src/ModManUi/src/native/UnlinkingBinds.ts b/src/ModManUi/src/native/UnlinkingBinds.ts index 68559d7a..838282ca 100644 --- a/src/ModManUi/src/native/UnlinkingBinds.ts +++ b/src/ModManUi/src/native/UnlinkingBinds.ts @@ -1,5 +1,8 @@ export interface ZoneUnlinkProgressDto { zoneName: string; + /** + * Between 0-100 + */ percentage: number; } diff --git a/src/ModManUi/src/native/ZoneBinds.ts b/src/ModManUi/src/native/ZoneBinds.ts index d775479b..1be14aad 100644 --- a/src/ModManUi/src/native/ZoneBinds.ts +++ b/src/ModManUi/src/native/ZoneBinds.ts @@ -1,11 +1,34 @@ +export enum GameId { + IW3 = "IW3", + IW4 = "IW4", + IW5 = "IW5", + T5 = "T5", + T6 = "T6", +} + +export enum GamePlatform { + PC = "PC", + XBOX = "XBOX", + PS3 = "PS3", +} + +export interface ZoneDto { + name: string; + filePath: string; + game: GameId; + platform: GamePlatform; +} + export interface ZoneLoadProgressDto { zoneName: string; + /** + * Between 0-100 + */ percentage: number; } export interface ZoneLoadedDto { - zoneName: string; - filePath: string; + zone: ZoneDto; } export interface ZoneUnloadedDto { @@ -13,6 +36,7 @@ export interface ZoneUnloadedDto { } export interface ZoneBinds { + getZones(): Promise; loadFastFile(path: string): Promise; unloadZone(zoneName: string): Promise; } diff --git a/src/ModManUi/src/native/index.ts b/src/ModManUi/src/native/index.ts index 09a0683e..ca0c185f 100644 --- a/src/ModManUi/src/native/index.ts +++ b/src/ModManUi/src/native/index.ts @@ -1,8 +1,9 @@ +import type { AssetBinds } from "./AssetBinds"; import type { DialogBinds } from "./DialogBinds"; import type { UnlinkingBinds, UnlinkingEventMap } from "./UnlinkingBinds"; import type { ZoneBinds, ZoneEventMap } from "./ZoneBinds"; -export type NativeMethods = DialogBinds & UnlinkingBinds & ZoneBinds; +export type NativeMethods = AssetBinds & DialogBinds & UnlinkingBinds & ZoneBinds; type NativeEventMap = UnlinkingEventMap & ZoneEventMap; diff --git a/src/ModManUi/src/router/Page.ts b/src/ModManUi/src/router/Page.ts new file mode 100644 index 00000000..0acc9db6 --- /dev/null +++ b/src/ModManUi/src/router/Page.ts @@ -0,0 +1,8 @@ +export const PAGE = { + HOME: "Home", + INSPECT: { + SELECT_ZONE: "Inspect zone", + ZONE_DETAILS: "Zone details", + }, + OPTIONS: "Options", +}; diff --git a/src/ModManUi/src/router/RouteMeta.ts b/src/ModManUi/src/router/RouteMeta.ts new file mode 100644 index 00000000..cf0e924d --- /dev/null +++ b/src/ModManUi/src/router/RouteMeta.ts @@ -0,0 +1,30 @@ +import { type Component, computed } from "vue"; +import { useRoute, type RouteLocationNormalizedGeneric } from "vue-router"; + +type HeaderTitleFunc = (route: RouteLocationNormalizedGeneric) => string; +export interface TypedRouteMeta { + backTo?: string; + headerTitleFunc?: HeaderTitleFunc; + headerTitleComponent?: Component; +} + +export type RouteMeta = TypedRouteMeta & Record; + +export function useRouteMeta() { + const route = useRoute(); + const meta = computed(() => route.meta as RouteMeta); + + const headerTitle = computed(() => { + if (meta.value.headerTitleFunc) { + return meta.value.headerTitleFunc(route); + } else if (meta.value.headerTitleComponent) { + return meta.value.headerTitleComponent; + } + + return String(route.name); + }); + + const routeNavigateBackTo = computed(() => meta.value.backTo ?? null); + + return { headerTitle, routeNavigateBackTo }; +} diff --git a/src/ModManUi/src/router/Router.ts b/src/ModManUi/src/router/Router.ts new file mode 100644 index 00000000..2c8f2121 --- /dev/null +++ b/src/ModManUi/src/router/Router.ts @@ -0,0 +1,36 @@ +import { createRouter, createWebHashHistory, type RouteRecordRaw } from "vue-router"; +import { PAGE } from "./Page"; +import ZoneInspector from "@/view/inspect/ZoneInspector.vue"; +import InspectDetails from "@/view/inspect_details/InspectDetails.vue"; +import type { RouteMeta } from "./RouteMeta"; +import InspectDetailsHeader from "@/view/inspect_details/InspectDetailsHeader.vue"; + +const ROUTES: RouteRecordRaw[] = [ + { + path: "/", + children: [ + { + path: "", + name: PAGE.INSPECT.SELECT_ZONE, + component: ZoneInspector, + }, + { + path: ":zoneName", + name: PAGE.INSPECT.ZONE_DETAILS, + component: InspectDetails, + meta: { + backTo: PAGE.INSPECT.SELECT_ZONE, + headerTitleComponent: InspectDetailsHeader, + } satisfies RouteMeta, + props: true, + }, + ], + }, +]; + +export function createModManRouter() { + return createRouter({ + history: createWebHashHistory(), + routes: ROUTES, + }); +} diff --git a/src/ModManUi/src/stores/AssetStore.ts b/src/ModManUi/src/stores/AssetStore.ts new file mode 100644 index 00000000..80117f97 --- /dev/null +++ b/src/ModManUi/src/stores/AssetStore.ts @@ -0,0 +1,32 @@ +import { computed, ref } from "vue"; +import { defineStore } from "pinia"; +import type { ZoneAssetsDto } from "@/native/AssetBinds"; +import { webviewBinds } from "@/native"; + +export const useAssetStore = defineStore("asset", () => { + const zoneName = ref(null); + const assetsOfZone = ref(null); + + const isLoading = computed(() => Boolean(assetsOfZone.value)); + const assetCount = computed(() => assetsOfZone.value?.assets.length ?? 0); + const referenceCount = computed(() => assetsOfZone.value?.references.length ?? 0); + + function loadAssetsForZone(newZoneName: string | null) { + // Skip if assets are already loaded + if (newZoneName === zoneName.value) return; + + // Reset current state + zoneName.value = newZoneName; + assetsOfZone.value = null; + + // Only load assets when there is a new zone name specified + if (!newZoneName) return; + webviewBinds.getAssetsForZone(newZoneName).then((res) => { + if (zoneName.value === newZoneName) { + assetsOfZone.value = res; + } + }); + } + + return { zoneName, isLoading, assetsOfZone, assetCount, referenceCount, loadAssetsForZone }; +}); diff --git a/src/ModManUi/src/stores/UnlinkingStore.ts b/src/ModManUi/src/stores/UnlinkingStore.ts new file mode 100644 index 00000000..6f10cc27 --- /dev/null +++ b/src/ModManUi/src/stores/UnlinkingStore.ts @@ -0,0 +1,31 @@ +import { ref } from "vue"; +import { defineStore } from "pinia"; +import { webviewAddEventListener, webviewBinds } from "@/native"; + +export const useUnlinkingStore = defineStore("unlinking", () => { + const isUnlinking = ref(false); + const lastPercentage = ref(0); + const failureMessage = ref(null); + + function unlinkZone(zoneName: string) { + isUnlinking.value = true; + lastPercentage.value = 0; + failureMessage.value = null; + return webviewBinds + .unlinkZone(zoneName) + .catch((e: string) => { + console.error("Failed to unlink fastfile:", e); + failureMessage.value = e; + }) + .finally(() => { + isUnlinking.value = false; + lastPercentage.value = 100; + }); + } + + webviewAddEventListener("zoneUnlinkProgress", (dto) => { + lastPercentage.value = dto.percentage; + }); + + return { isUnlinking, lastPercentage, unlinkZone }; +}); diff --git a/src/ModManUi/src/stores/ZoneStore.ts b/src/ModManUi/src/stores/ZoneStore.ts index 3877ab87..b8a5f4b5 100644 --- a/src/ModManUi/src/stores/ZoneStore.ts +++ b/src/ModManUi/src/stores/ZoneStore.ts @@ -1,20 +1,77 @@ -import { readonly, ref } from "vue"; +import { computed, ref } from "vue"; import { defineStore } from "pinia"; -import { webviewAddEventListener } from "@/native"; +import { webviewAddEventListener, webviewBinds } from "@/native"; +import type { ZoneDto, ZoneLoadedDto } from "@/native/ZoneBinds"; export const useZoneStore = defineStore("zone", () => { - const loadedZones = ref([]); + const loadedZones = ref([]); + const zonesCurrentlyBeingLoaded = ref([]); + const lastPercentageByZoneName = ref>({}); + + const isLoadingZone = computed(() => zonesCurrentlyBeingLoaded.value.length > 0); + + function loadFastFile(fastFilePath: string): Promise { + const lastDirectorySeparator = fastFilePath.replace(/\\/g, "/").lastIndexOf("/"); + const lastDot = fastFilePath.lastIndexOf("."); + const expectedZoneName = fastFilePath.substring( + lastDirectorySeparator >= 0 ? lastDirectorySeparator + 1 : 0, + lastDot > lastDirectorySeparator ? lastDot : fastFilePath.length, + ); + + zonesCurrentlyBeingLoaded.value.push(expectedZoneName); + lastPercentageByZoneName.value[expectedZoneName] = 0; + + return webviewBinds + .loadFastFile(fastFilePath) + .catch((e: string) => { + console.error("Failed to load fastfile:", e); + }) + .finally(() => { + zonesCurrentlyBeingLoaded.value.splice( + zonesCurrentlyBeingLoaded.value.indexOf(expectedZoneName), + 1, + ); + delete lastPercentageByZoneName.value[expectedZoneName]; + }) as Promise; + } + + function getPercentageForZoneBeingLoaded(zoneName: string) { + return lastPercentageByZoneName.value[zoneName] ?? 100; + } + + function getLoadedZoneByName(zoneName: string) { + return loadedZones.value.find((zone) => zone.name === zoneName) ?? null; + } + + // Initially get all loaded zones + webviewBinds.getZones().then((allZones) => { + loadedZones.value = allZones; + }); + + webviewAddEventListener("zoneLoadProgress", (dto) => { + if (lastPercentageByZoneName.value[dto.zoneName] !== undefined) { + lastPercentageByZoneName.value[dto.zoneName] = dto.percentage; + } + }); webviewAddEventListener("zoneLoaded", (dto) => { - loadedZones.value.push(dto.zoneName); + loadedZones.value.push(dto.zone); }); webviewAddEventListener("zoneUnloaded", (dto) => { - const index = loadedZones.value.indexOf(dto.zoneName); + const index = loadedZones.value.findIndex((zone) => zone.name === dto.zoneName); if (index >= 0) { loadedZones.value.splice(index, 1); } }); - return { loadedZones: readonly(loadedZones) }; + return { + loadedZones, + zonesCurrentlyBeingLoaded, + isLoadingZone, + lastPercentageByZoneName, + loadFastFile, + getPercentageForZoneBeingLoaded, + getLoadedZoneByName, + }; }); diff --git a/src/ModManUi/src/style/_colors.scss b/src/ModManUi/src/style/_colors.scss new file mode 100644 index 00000000..a8bb3154 --- /dev/null +++ b/src/ModManUi/src/style/_colors.scss @@ -0,0 +1,5 @@ +@use "colors_primitive"; +@forward "colors_primitive"; + +@use "colors_semantic"; +@forward "colors_semantic"; diff --git a/src/ModManUi/src/style/_colors_primitive.scss b/src/ModManUi/src/style/_colors_primitive.scss new file mode 100644 index 00000000..e5ae558b --- /dev/null +++ b/src/ModManUi/src/style/_colors_primitive.scss @@ -0,0 +1,278 @@ +// Primitive colors are colors that have literal values and they do not change depending on the context. +$color-brand-50: #f7ebdf; +$color-brand-100: #f1dfca; +$color-brand-200: #eaceae; +$color-brand-300: #e0b685; +$color-brand-400: #d59d5d; +$color-brand-500: #cc8838; +$color-brand-600: #b9772c; +$color-brand-700: #784818; +$color-brand-800: #573816; +$color-brand-900: #3d2810; +$color-brand-950: #291b0a; +$color-brand: $color-brand-500; + +// These colors are taken from PrimeVue Aura theme +$color-emerald-50: var(--p-emerald-50); +$color-emerald-100: var(--p-emerald-100); +$color-emerald-200: var(--p-emerald-200); +$color-emerald-300: var(--p-emerald-300); +$color-emerald-400: var(--p-emerald-400); +$color-emerald-500: var(--p-emerald-500); +$color-emerald-600: var(--p-emerald-600); +$color-emerald-700: var(--p-emerald-700); +$color-emerald-800: var(--p-emerald-800); +$color-emerald-900: var(--p-emerald-900); +$color-emerald-950: var(--p-emerald-950); + +$color-green-50: var(--p-green-50); +$color-green-100: var(--p-green-100); +$color-green-200: var(--p-green-200); +$color-green-300: var(--p-green-300); +$color-green-400: var(--p-green-400); +$color-green-500: var(--p-green-500); +$color-green-600: var(--p-green-600); +$color-green-700: var(--p-green-700); +$color-green-800: var(--p-green-800); +$color-green-900: var(--p-green-900); +$color-green-950: var(--p-green-950); + +$color-lime-50: var(--p-lime-50); +$color-lime-100: var(--p-lime-100); +$color-lime-200: var(--p-lime-200); +$color-lime-300: var(--p-lime-300); +$color-lime-400: var(--p-lime-400); +$color-lime-500: var(--p-lime-500); +$color-lime-600: var(--p-lime-600); +$color-lime-700: var(--p-lime-700); +$color-lime-800: var(--p-lime-800); +$color-lime-900: var(--p-lime-900); +$color-lime-950: var(--p-lime-950); + +$color-red-50: var(--p-red-50); +$color-red-100: var(--p-red-100); +$color-red-200: var(--p-red-200); +$color-red-300: var(--p-red-300); +$color-red-400: var(--p-red-400); +$color-red-500: var(--p-red-500); +$color-red-600: var(--p-red-600); +$color-red-700: var(--p-red-700); +$color-red-800: var(--p-red-800); +$color-red-900: var(--p-red-900); +$color-red-950: var(--p-red-950); + +$color-orange-50: var(--p-orange-50); +$color-orange-100: var(--p-orange-100); +$color-orange-200: var(--p-orange-200); +$color-orange-300: var(--p-orange-300); +$color-orange-400: var(--p-orange-400); +$color-orange-500: var(--p-orange-500); +$color-orange-600: var(--p-orange-600); +$color-orange-700: var(--p-orange-700); +$color-orange-800: var(--p-orange-800); +$color-orange-900: var(--p-orange-900); +$color-orange-950: var(--p-orange-950); + +$color-amber-50: var(--p-amber-50); +$color-amber-100: var(--p-amber-100); +$color-amber-200: var(--p-amber-200); +$color-amber-300: var(--p-amber-300); +$color-amber-400: var(--p-amber-400); +$color-amber-500: var(--p-amber-500); +$color-amber-600: var(--p-amber-600); +$color-amber-700: var(--p-amber-700); +$color-amber-800: var(--p-amber-800); +$color-amber-900: var(--p-amber-900); +$color-amber-950: var(--p-amber-950); + +$color-yellow-50: var(--p-yellow-50); +$color-yellow-100: var(--p-yellow-100); +$color-yellow-200: var(--p-yellow-200); +$color-yellow-300: var(--p-yellow-300); +$color-yellow-400: var(--p-yellow-400); +$color-yellow-500: var(--p-yellow-500); +$color-yellow-600: var(--p-yellow-600); +$color-yellow-700: var(--p-yellow-700); +$color-yellow-800: var(--p-yellow-800); +$color-yellow-900: var(--p-yellow-900); +$color-yellow-950: var(--p-yellow-950); + +$color-teal-50: var(--p-teal-50); +$color-teal-100: var(--p-teal-100); +$color-teal-200: var(--p-teal-200); +$color-teal-300: var(--p-teal-300); +$color-teal-400: var(--p-teal-400); +$color-teal-500: var(--p-teal-500); +$color-teal-600: var(--p-teal-600); +$color-teal-700: var(--p-teal-700); +$color-teal-800: var(--p-teal-800); +$color-teal-900: var(--p-teal-900); +$color-teal-950: var(--p-teal-950); + +$color-cyan-50: var(--p-cyan-50); +$color-cyan-100: var(--p-cyan-100); +$color-cyan-200: var(--p-cyan-200); +$color-cyan-300: var(--p-cyan-300); +$color-cyan-400: var(--p-cyan-400); +$color-cyan-500: var(--p-cyan-500); +$color-cyan-600: var(--p-cyan-600); +$color-cyan-700: var(--p-cyan-700); +$color-cyan-800: var(--p-cyan-800); +$color-cyan-900: var(--p-cyan-900); +$color-cyan-950: var(--p-cyan-950); + +$color-sky-50: var(--p-sky-50); +$color-sky-100: var(--p-sky-100); +$color-sky-200: var(--p-sky-200); +$color-sky-300: var(--p-sky-300); +$color-sky-400: var(--p-sky-400); +$color-sky-500: var(--p-sky-500); +$color-sky-600: var(--p-sky-600); +$color-sky-700: var(--p-sky-700); +$color-sky-800: var(--p-sky-800); +$color-sky-900: var(--p-sky-900); +$color-sky-950: var(--p-sky-950); + +$color-blue-50: var(--p-blue-50); +$color-blue-100: var(--p-blue-100); +$color-blue-200: var(--p-blue-200); +$color-blue-300: var(--p-blue-300); +$color-blue-400: var(--p-blue-400); +$color-blue-500: var(--p-blue-500); +$color-blue-600: var(--p-blue-600); +$color-blue-700: var(--p-blue-700); +$color-blue-800: var(--p-blue-800); +$color-blue-900: var(--p-blue-900); +$color-blue-950: var(--p-blue-950); + +$color-indigo-50: var(--p-indigo-50); +$color-indigo-100: var(--p-indigo-100); +$color-indigo-200: var(--p-indigo-200); +$color-indigo-300: var(--p-indigo-300); +$color-indigo-400: var(--p-indigo-400); +$color-indigo-500: var(--p-indigo-500); +$color-indigo-600: var(--p-indigo-600); +$color-indigo-700: var(--p-indigo-700); +$color-indigo-800: var(--p-indigo-800); +$color-indigo-900: var(--p-indigo-900); +$color-indigo-950: var(--p-indigo-950); + +$color-violet-50: var(--p-violet-50); +$color-violet-100: var(--p-violet-100); +$color-violet-200: var(--p-violet-200); +$color-violet-300: var(--p-violet-300); +$color-violet-400: var(--p-violet-400); +$color-violet-500: var(--p-violet-500); +$color-violet-600: var(--p-violet-600); +$color-violet-700: var(--p-violet-700); +$color-violet-800: var(--p-violet-800); +$color-violet-900: var(--p-violet-900); +$color-violet-950: var(--p-violet-950); + +$color-purple-50: var(--p-purple-50); +$color-purple-100: var(--p-purple-100); +$color-purple-200: var(--p-purple-200); +$color-purple-300: var(--p-purple-300); +$color-purple-400: var(--p-purple-400); +$color-purple-500: var(--p-purple-500); +$color-purple-600: var(--p-purple-600); +$color-purple-700: var(--p-purple-700); +$color-purple-800: var(--p-purple-800); +$color-purple-900: var(--p-purple-900); +$color-purple-950: var(--p-purple-950); + +$color-fuchsia-50: var(--p-fuchsia-50); +$color-fuchsia-100: var(--p-fuchsia-100); +$color-fuchsia-200: var(--p-fuchsia-200); +$color-fuchsia-300: var(--p-fuchsia-300); +$color-fuchsia-400: var(--p-fuchsia-400); +$color-fuchsia-500: var(--p-fuchsia-500); +$color-fuchsia-600: var(--p-fuchsia-600); +$color-fuchsia-700: var(--p-fuchsia-700); +$color-fuchsia-800: var(--p-fuchsia-800); +$color-fuchsia-900: var(--p-fuchsia-900); +$color-fuchsia-950: var(--p-fuchsia-950); + +$color-pink-50: var(--p-pink-50); +$color-pink-100: var(--p-pink-100); +$color-pink-200: var(--p-pink-200); +$color-pink-300: var(--p-pink-300); +$color-pink-400: var(--p-pink-400); +$color-pink-500: var(--p-pink-500); +$color-pink-600: var(--p-pink-600); +$color-pink-700: var(--p-pink-700); +$color-pink-800: var(--p-pink-800); +$color-pink-900: var(--p-pink-900); +$color-pink-950: var(--p-pink-950); + +$color-rose-50: var(--p-rose-50); +$color-rose-100: var(--p-rose-100); +$color-rose-200: var(--p-rose-200); +$color-rose-300: var(--p-rose-300); +$color-rose-400: var(--p-rose-400); +$color-rose-500: var(--p-rose-500); +$color-rose-600: var(--p-rose-600); +$color-rose-700: var(--p-rose-700); +$color-rose-800: var(--p-rose-800); +$color-rose-900: var(--p-rose-900); +$color-rose-950: var(--p-rose-950); + +$color-slate-50: var(--p-slate-50); +$color-slate-100: var(--p-slate-100); +$color-slate-200: var(--p-slate-200); +$color-slate-300: var(--p-slate-300); +$color-slate-400: var(--p-slate-400); +$color-slate-500: var(--p-slate-500); +$color-slate-600: var(--p-slate-600); +$color-slate-700: var(--p-slate-700); +$color-slate-800: var(--p-slate-800); +$color-slate-900: var(--p-slate-900); +$color-slate-950: var(--p-slate-950); + +$color-gray-50: var(--p-gray-50); +$color-gray-100: var(--p-gray-100); +$color-gray-200: var(--p-gray-200); +$color-gray-300: var(--p-gray-300); +$color-gray-400: var(--p-gray-400); +$color-gray-500: var(--p-gray-500); +$color-gray-600: var(--p-gray-600); +$color-gray-700: var(--p-gray-700); +$color-gray-800: var(--p-gray-800); +$color-gray-900: var(--p-gray-900); +$color-gray-950: var(--p-gray-950); + +$color-zinc-50: var(--p-zinc-50); +$color-zinc-100: var(--p-zinc-100); +$color-zinc-200: var(--p-zinc-200); +$color-zinc-300: var(--p-zinc-300); +$color-zinc-400: var(--p-zinc-400); +$color-zinc-500: var(--p-zinc-500); +$color-zinc-600: var(--p-zinc-600); +$color-zinc-700: var(--p-zinc-700); +$color-zinc-800: var(--p-zinc-800); +$color-zinc-900: var(--p-zinc-900); +$color-zinc-950: var(--p-zinc-950); + +$color-neutral-50: var(--p-neutral-50); +$color-neutral-100: var(--p-neutral-100); +$color-neutral-200: var(--p-neutral-200); +$color-neutral-300: var(--p-neutral-300); +$color-neutral-400: var(--p-neutral-400); +$color-neutral-500: var(--p-neutral-500); +$color-neutral-600: var(--p-neutral-600); +$color-neutral-700: var(--p-neutral-700); +$color-neutral-800: var(--p-neutral-800); +$color-neutral-900: var(--p-neutral-900); +$color-neutral-950: var(--p-neutral-950); + +$color-stone-50: var(--p-stone-50); +$color-stone-100: var(--p-stone-100); +$color-stone-200: var(--p-stone-200); +$color-stone-300: var(--p-stone-300); +$color-stone-400: var(--p-stone-400); +$color-stone-500: var(--p-stone-500); +$color-stone-600: var(--p-stone-600); +$color-stone-700: var(--p-stone-700); +$color-stone-800: var(--p-stone-800); +$color-stone-900: var(--p-stone-900); +$color-stone-950: var(--p-stone-950); diff --git a/src/ModManUi/src/style/_colors_semantic.scss b/src/ModManUi/src/style/_colors_semantic.scss new file mode 100644 index 00000000..d474a295 --- /dev/null +++ b/src/ModManUi/src/style/_colors_semantic.scss @@ -0,0 +1,28 @@ +// Semantic colors are colors that may be different depending on the context. +// They have to be used via CSS variables (which is what the SASS variables access). +$color-surface-0: var(--color-surface-0); +$color-surface-50: var(--color-surface-50); +$color-surface-100: var(--color-surface-100); +$color-surface-200: var(--color-surface-200); +$color-surface-300: var(--color-surface-300); +$color-surface-400: var(--color-surface-400); +$color-surface-500: var(--color-surface-500); +$color-surface-600: var(--color-surface-600); +$color-surface-700: var(--color-surface-700); +$color-surface-800: var(--color-surface-800); +$color-surface-900: var(--color-surface-900); +$color-surface-950: var(--color-surface-950); + +$color-primary: var(--color-primary); +$color-primary-contrast: var(--color-primary-contrast); +$color-primary-hover: var(--color-primary-hover); +$color-primary-active: var(--color-primary-active); + +$color-content-background: var(--color-content-background); +$color-content-hover-background: var(--color-content-hover-background); +$color-content-border: var(--color-content-border); + +$color-text: var(--color-text); +$color-text-hover: var(--color-text-hover); +$color-text-muted: var(--color-text-muted); +$color-text-hover-muted: var(--color-text-hover-muted); diff --git a/src/ModManUi/src/style/_variables.scss b/src/ModManUi/src/style/_variables.scss new file mode 100644 index 00000000..dede5bb8 --- /dev/null +++ b/src/ModManUi/src/style/_variables.scss @@ -0,0 +1,7 @@ +$border-radius-xs: 0.125rem; +$border-radius-sm: 0.25rem; +$border-radius-md: 0.375rem; +$border-radius-lg: 0.5rem; +$border-radius-xl: 0.75rem; + +$transition-duration: 0.2s; diff --git a/src/ModManUi/src/style/css_vars.scss b/src/ModManUi/src/style/css_vars.scss new file mode 100644 index 00000000..83223e26 --- /dev/null +++ b/src/ModManUi/src/style/css_vars.scss @@ -0,0 +1,68 @@ +@use "colors"; +@use "colors_primitive"; +@use "sass:meta"; +@use "sass:string"; + +:root { + @each $name, $value in meta.module-variables(colors_primitive) { + --#{string.to-lower-case($name)}: #{$value}; + } +} + +:root:not(.dark) { + --color-surface-0: #ffffff; + --color-surface-50: #{colors.$color-slate-50}; + --color-surface-100: #{colors.$color-slate-100}; + --color-surface-200: #{colors.$color-slate-200}; + --color-surface-300: #{colors.$color-slate-300}; + --color-surface-400: #{colors.$color-slate-400}; + --color-surface-500: #{colors.$color-slate-500}; + --color-surface-600: #{colors.$color-slate-600}; + --color-surface-700: #{colors.$color-slate-700}; + --color-surface-800: #{colors.$color-slate-800}; + --color-surface-900: #{colors.$color-slate-900}; + --color-surface-950: #{colors.$color-slate-950}; + + --color-primary: #{colors.$color-brand-500}; + --color-primary-contrast: #ffffff; + --color-primary-hover: var(--color-brand-600); + --color-primary-active: var(--color-brand-700); + + --color-content-background: var(--color-surface-0); + --color-content-hover-background: var(--color-surface-100); + --color-content-border: var(--color-surface-200); + + --color-text: var(--color-surface-700); + --color-text-hover: var(--color-surface-800); + --color-text-muted: var(--color-surface-500); + --color-text-hover-muted: var(--color-surface-600); +} + +:root.dark { + --color-surface-0: #ffffff; + --color-surface-50: #{colors.$color-zinc-50}; + --color-surface-100: #{colors.$color-zinc-100}; + --color-surface-200: #{colors.$color-zinc-200}; + --color-surface-300: #{colors.$color-zinc-300}; + --color-surface-400: #{colors.$color-zinc-400}; + --color-surface-500: #{colors.$color-zinc-500}; + --color-surface-600: #{colors.$color-zinc-600}; + --color-surface-700: #{colors.$color-zinc-700}; + --color-surface-800: #{colors.$color-zinc-800}; + --color-surface-900: #{colors.$color-zinc-900}; + --color-surface-950: #{colors.$color-zinc-950}; + + --color-primary: #{colors.$color-brand-400}; + --color-primary-contrast: var(--color-surface-900); + --color-primary-hover: var(--color-brand-300); + --color-primary-active: var(--color-brand-200); + + --color-content-background: var(--color-surface-900); + --color-content-hover-background: var(--color-surface-800); + --color-content-border: var(--color-surface-700); + + --color-text: var(--color-surface-0); + --color-text-hover: var(--color-surface-0); + --color-text-muted: var(--color-surface-400); + --color-text-hover-muted: var(--color-surface-300); +} diff --git a/src/ModManUi/src/style/main.scss b/src/ModManUi/src/style/main.scss new file mode 100644 index 00000000..be5bc42a --- /dev/null +++ b/src/ModManUi/src/style/main.scss @@ -0,0 +1,36 @@ +@use "colors"; +@use "css_vars"; +@use "utils.scss"; + +@import "@fontsource/inter/latin-300.css"; +@import "@fontsource/inter/latin-300-italic.css"; +@import "@fontsource/inter/latin-400.css"; +@import "@fontsource/inter/latin-400-italic.css"; +@import "@fontsource/inter/latin-600.css"; +@import "@fontsource/inter/latin-600-italic.css"; +@import "@fontsource/inter/latin-700.css"; +@import "@fontsource/inter/latin-700-italic.css"; + +:root { + font-family: Inter, Avenir, Helvetica, Arial, sans-serif; + font-size: 16px; + line-height: 24px; + font-weight: 400; + + color: colors.$color-text; + background-color: colors.$color-content-background; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; +} diff --git a/src/ModManUi/src/style/utils.scss b/src/ModManUi/src/style/utils.scss new file mode 100644 index 00000000..e7d7bfd5 --- /dev/null +++ b/src/ModManUi/src/style/utils.scss @@ -0,0 +1,3 @@ +.icon { + height: 1lh; +} diff --git a/src/ModManUi/src/utils/AssetTypeName.ts b/src/ModManUi/src/utils/AssetTypeName.ts new file mode 100644 index 00000000..d4c3e8d7 --- /dev/null +++ b/src/ModManUi/src/utils/AssetTypeName.ts @@ -0,0 +1,85 @@ +import { CommonAssetType } from "@/native/AssetBinds"; + +const LOOKUP_CAPITALIZED: Record = { + [CommonAssetType.PHYS_PRESET]: "Phys preset", + [CommonAssetType.XANIM]: "XAnim", + [CommonAssetType.XMODEL]: "XModel", + [CommonAssetType.MATERIAL]: "Material", + [CommonAssetType.TECHNIQUE_SET]: "Technique set", + [CommonAssetType.IMAGE]: "Image", + [CommonAssetType.SOUND]: "Sound", + [CommonAssetType.SOUND_CURVE]: "Sound curve", + [CommonAssetType.LOADED_SOUND]: "Loaded sound", + [CommonAssetType.CLIP_MAP]: "Clip map", + [CommonAssetType.COM_WORLD]: "Com world", + [CommonAssetType.GAME_WORLD_SP]: "Game world SP", + [CommonAssetType.GAME_WORLD_MP]: "Game world MP", + [CommonAssetType.MAP_ENTS]: "Map ents", + [CommonAssetType.GFX_WORLD]: "Gfx world", + [CommonAssetType.LIGHT_DEF]: "Light def", + [CommonAssetType.UI_MAP]: "UI map", + [CommonAssetType.FONT]: "Font", + [CommonAssetType.MENU_LIST]: "Menu list", + [CommonAssetType.MENU]: "Menu", + [CommonAssetType.LOCALIZE_ENTRY]: "Localize entry", + [CommonAssetType.WEAPON]: "Weapon", + [CommonAssetType.SOUND_DRIVER_GLOBALS]: "Sound driver globals", + [CommonAssetType.FX]: "FX", + [CommonAssetType.IMPACT_FX]: "Impact FX", + [CommonAssetType.AI_TYPE]: "AI type", + [CommonAssetType.MP_TYPE]: "MP type", + [CommonAssetType.CHARACTER]: "Character", + [CommonAssetType.XMODEL_ALIAS]: "XModel alias", + [CommonAssetType.RAW_FILE]: "Raw file", + [CommonAssetType.STRING_TABLE]: "String table", + [CommonAssetType.XMODEL_PIECES]: "XModel pieces", + [CommonAssetType.PHYS_COLL_MAP]: "Phys coll map", + [CommonAssetType.XMODEL_SURFS]: "XModel surfs", + [CommonAssetType.PIXEL_SHADER]: "Pixel shader", + [CommonAssetType.VERTEX_SHADER]: "Vertex shader", + [CommonAssetType.VERTEX_DECL]: "Vertex decl", + [CommonAssetType.FX_WORLD]: "FX world", + [CommonAssetType.LEADERBOARD]: "Leaderboard", + [CommonAssetType.STRUCTURED_DATA_DEF]: "Structured data def", + [CommonAssetType.TRACER]: "Tracer", + [CommonAssetType.VEHICLE]: "Vehicle", + [CommonAssetType.ADDON_MAP_ENTS]: "Addon map ents", + [CommonAssetType.GLASS_WORLD]: "Glass world", + [CommonAssetType.PATH_DATA]: "Path data", + [CommonAssetType.VEHICLE_TRACK]: "Vehicle track", + [CommonAssetType.ATTACHMENT]: "Attachment", + [CommonAssetType.SURFACE_FX]: "Surface FX", + [CommonAssetType.SCRIPT]: "Script", + [CommonAssetType.PHYS_CONSTRAINTS]: "Phys constraints", + [CommonAssetType.DESTRUCTIBLE_DEF]: "Destructible def", + [CommonAssetType.SOUND_PATCH]: "Sound patch", + [CommonAssetType.WEAPON_DEF]: "Weapon def", + [CommonAssetType.WEAPON_VARIANT]: "Weapon variant", + [CommonAssetType.MP_BODY]: "MP body", + [CommonAssetType.MP_HEAD]: "MP head", + [CommonAssetType.PACK_INDEX]: "Pack index", + [CommonAssetType.XGLOBALS]: "XGlobals", + [CommonAssetType.DDL]: "DDL", + [CommonAssetType.GLASSES]: "Glasses", + [CommonAssetType.EMBLEM_SET]: "Emblem set", + [CommonAssetType.FONT_ICON]: "Font icon", + [CommonAssetType.WEAPON_FULL]: "Weapon full", + [CommonAssetType.ATTACHMENT_UNIQUE]: "Attachment unique", + [CommonAssetType.WEAPON_CAMO]: "Weapon camo", + [CommonAssetType.KEY_VALUE_PAIRS]: "Key value pairs", + [CommonAssetType.MEMORY_BLOCK]: "Memory block", + [CommonAssetType.SKINNED_VERTS]: "Skinned verts", + [CommonAssetType.QDB]: "Qdb", + [CommonAssetType.SLUG]: "Slug", + [CommonAssetType.FOOTSTEP_TABLE]: "Footstep table", + [CommonAssetType.FOOTSTEP_FX_TABLE]: "Footstep FX table", + [CommonAssetType.ZBARRIER]: "ZBarrier", +}; + +export function getAssetTypeNameCapitalized(assetType: CommonAssetType): string { + return LOOKUP_CAPITALIZED[assetType]; +} + +export function getAssetTypeNameLower(assetType: CommonAssetType): string { + return getAssetTypeNameCapitalized(assetType).toLocaleLowerCase(); +} diff --git a/src/ModManUi/src/view/inspect/ZoneInspector.vue b/src/ModManUi/src/view/inspect/ZoneInspector.vue new file mode 100644 index 00000000..ed626058 --- /dev/null +++ b/src/ModManUi/src/view/inspect/ZoneInspector.vue @@ -0,0 +1,52 @@ + + + + + diff --git a/src/ModManUi/src/view/inspect/ZoneInspectorDetails.vue b/src/ModManUi/src/view/inspect/ZoneInspectorDetails.vue new file mode 100644 index 00000000..f5fac169 --- /dev/null +++ b/src/ModManUi/src/view/inspect/ZoneInspectorDetails.vue @@ -0,0 +1,151 @@ + + + + + diff --git a/src/ModManUi/src/view/inspect/ZoneInspectorZoneList.vue b/src/ModManUi/src/view/inspect/ZoneInspectorZoneList.vue new file mode 100644 index 00000000..4a10814d --- /dev/null +++ b/src/ModManUi/src/view/inspect/ZoneInspectorZoneList.vue @@ -0,0 +1,111 @@ + + + + + diff --git a/src/ModManUi/src/view/inspect_details/InspectDetails.vue b/src/ModManUi/src/view/inspect_details/InspectDetails.vue new file mode 100644 index 00000000..aeefee59 --- /dev/null +++ b/src/ModManUi/src/view/inspect_details/InspectDetails.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/src/ModManUi/src/view/inspect_details/InspectDetailsHeader.vue b/src/ModManUi/src/view/inspect_details/InspectDetailsHeader.vue new file mode 100644 index 00000000..5bd5daf9 --- /dev/null +++ b/src/ModManUi/src/view/inspect_details/InspectDetailsHeader.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/src/ModManUi/src/view/inspect_details/components/AssetListOption.vue b/src/ModManUi/src/view/inspect_details/components/AssetListOption.vue new file mode 100644 index 00000000..ceeaed63 --- /dev/null +++ b/src/ModManUi/src/view/inspect_details/components/AssetListOption.vue @@ -0,0 +1,37 @@ + + + + + diff --git a/src/ModManUi/src/view/inspect_details/components/InspectAssetDetails.vue b/src/ModManUi/src/view/inspect_details/components/InspectAssetDetails.vue new file mode 100644 index 00000000..60c4e2af --- /dev/null +++ b/src/ModManUi/src/view/inspect_details/components/InspectAssetDetails.vue @@ -0,0 +1,39 @@ + + + + + diff --git a/src/ModManUi/src/view/inspect_details/components/InspectPreview.vue b/src/ModManUi/src/view/inspect_details/components/InspectPreview.vue new file mode 100644 index 00000000..d76e14da --- /dev/null +++ b/src/ModManUi/src/view/inspect_details/components/InspectPreview.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/ModManUi/src/view/inspect_details/components/InspectZoneAssets.vue b/src/ModManUi/src/view/inspect_details/components/InspectZoneAssets.vue new file mode 100644 index 00000000..2d4cf40e --- /dev/null +++ b/src/ModManUi/src/view/inspect_details/components/InspectZoneAssets.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/src/ModManUi/tsconfig.app.json b/src/ModManUi/tsconfig.app.json index 913b8f27..7f4e553c 100644 --- a/src/ModManUi/tsconfig.app.json +++ b/src/ModManUi/tsconfig.app.json @@ -6,7 +6,8 @@ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", "paths": { - "@/*": ["./src/*"] + "@/*": ["./src/*"], + "@style/*": ["./src/style/*"] } } } diff --git a/src/ModManUi/vite.config.ts b/src/ModManUi/vite.config.ts index f5edcd61..0409fc43 100644 --- a/src/ModManUi/vite.config.ts +++ b/src/ModManUi/vite.config.ts @@ -8,7 +8,6 @@ import headerTransformationPlugin from "./build/HeaderTransformationPlugin"; // https://vite.dev/config/ export default defineConfig({ build: { - copyPublicDir: false, emptyOutDir: true, rollupOptions: { output: { @@ -18,6 +17,7 @@ export default defineConfig({ }, }, }, + publicDir: fileURLToPath(new URL("./public", import.meta.url)), plugins: [ vue(), vueDevTools(), @@ -30,6 +30,7 @@ export default defineConfig({ resolve: { alias: { "@": fileURLToPath(new URL("./src", import.meta.url)), + "@style": fileURLToPath(new URL("./src/style", import.meta.url)), }, }, }); diff --git a/src/ZoneCommon/Pool/XAssetInfo.cpp b/src/ZoneCommon/Pool/XAssetInfo.cpp index c9d94955..7ed5213e 100644 --- a/src/ZoneCommon/Pool/XAssetInfo.cpp +++ b/src/ZoneCommon/Pool/XAssetInfo.cpp @@ -98,6 +98,11 @@ bool XAssetInfoGeneric::IsReference() const return !m_name.empty() && m_name[0] == ','; } +std::string XAssetInfoGeneric::ReferencedAssetName() const +{ + return m_name.substr(1); +} + std::string XAssetInfoGeneric::NormalizeAssetName(std::string input) { utils::MakeStringLowerCase(input); diff --git a/src/ZoneCommon/Pool/XAssetInfo.h b/src/ZoneCommon/Pool/XAssetInfo.h index 16a3edbb..30946927 100644 --- a/src/ZoneCommon/Pool/XAssetInfo.h +++ b/src/ZoneCommon/Pool/XAssetInfo.h @@ -55,6 +55,7 @@ public: XAssetInfoGeneric& operator=(XAssetInfoGeneric&& other) noexcept = default; [[nodiscard]] bool IsReference() const; + [[nodiscard]] std::string ReferencedAssetName() const; static std::string NormalizeAssetName(std::string input); diff --git a/src/ZoneCommon/Pool/ZoneAssetPools.h b/src/ZoneCommon/Pool/ZoneAssetPools.h index 97c94ff9..824498dd 100644 --- a/src/ZoneCommon/Pool/ZoneAssetPools.h +++ b/src/ZoneCommon/Pool/ZoneAssetPools.h @@ -1,5 +1,5 @@ #pragma once -#include "Utils/ClassUtils.h" + #include "XAssetInfo.h" #include "Zone/Zone.h" #include "Zone/ZoneTypes.h" @@ -33,16 +33,16 @@ public: std::vector dependencies, std::vector usedScriptStrings, std::vector indirectAssetReferences); - _NODISCARD virtual XAssetInfoGeneric* GetAsset(asset_type_t type, const std::string& name) const = 0; - _NODISCARD virtual XAssetInfoGeneric* GetAssetOrAssetReference(asset_type_t type, const std::string& name) const; + [[nodiscard]] virtual XAssetInfoGeneric* GetAsset(asset_type_t type, const std::string& name) const = 0; + [[nodiscard]] virtual XAssetInfoGeneric* GetAssetOrAssetReference(asset_type_t type, const std::string& name) const; - _NODISCARD virtual asset_type_t GetAssetTypeCount() const = 0; - _NODISCARD virtual std::optional GetAssetTypeName(asset_type_t assetType) const = 0; + [[nodiscard]] virtual asset_type_t GetAssetTypeCount() const = 0; + [[nodiscard]] virtual std::optional GetAssetTypeName(asset_type_t assetType) const = 0; - _NODISCARD size_t GetTotalAssetCount() const; + [[nodiscard]] size_t GetTotalAssetCount() const; - _NODISCARD iterator begin() const; - _NODISCARD iterator end() const; + [[nodiscard]] iterator begin() const; + [[nodiscard]] iterator end() const; static std::unique_ptr CreateForGame(GameId game, Zone* zone, zone_priority_t priority); diff --git a/src/ZoneCommon/Zone/Zone.cpp b/src/ZoneCommon/Zone/Zone.cpp index 8c160d89..4f0fe2b5 100644 --- a/src/ZoneCommon/Zone/Zone.cpp +++ b/src/ZoneCommon/Zone/Zone.cpp @@ -2,11 +2,12 @@ #include "ZoneRegistry.h" -Zone::Zone(std::string name, const zone_priority_t priority, GameId gameId) +Zone::Zone(std::string name, const zone_priority_t priority, const GameId gameId, const GamePlatform platform) : m_name(std::move(name)), m_priority(priority), m_language(GameLanguage::LANGUAGE_NONE), m_game_id(gameId), + m_platform(platform), m_pools(ZoneAssetPools::CreateForGame(gameId, this, priority)), m_memory(std::make_unique()), m_registered(false) diff --git a/src/ZoneCommon/Zone/Zone.h b/src/ZoneCommon/Zone/Zone.h index 658bb412..a4f57018 100644 --- a/src/ZoneCommon/Zone/Zone.h +++ b/src/ZoneCommon/Zone/Zone.h @@ -15,7 +15,7 @@ class ZoneAssetPools; class Zone { public: - Zone(std::string name, zone_priority_t priority, GameId gameId); + Zone(std::string name, zone_priority_t priority, GameId gameId, GamePlatform platform); ~Zone(); Zone(const Zone& other) = delete; Zone(Zone&& other) noexcept = default; @@ -30,6 +30,7 @@ public: zone_priority_t m_priority; GameLanguage m_language; GameId m_game_id; + GamePlatform m_platform; ZoneScriptStrings m_script_strings; std::unique_ptr m_pools; diff --git a/src/ZoneLoading/Game/IW3/ZoneLoaderFactoryIW3.cpp b/src/ZoneLoading/Game/IW3/ZoneLoaderFactoryIW3.cpp index ae0708d5..0a81643c 100644 --- a/src/ZoneLoading/Game/IW3/ZoneLoaderFactoryIW3.cpp +++ b/src/ZoneLoading/Game/IW3/ZoneLoaderFactoryIW3.cpp @@ -69,7 +69,7 @@ std::unique_ptr ZoneLoaderFactory::CreateLoaderForHeader(const ZoneH return nullptr; // Create new zone - auto zone = std::make_unique(fileName, 0, GameId::IW3); + auto zone = std::make_unique(fileName, 0, GameId::IW3, inspectResult->m_platform); auto* zonePtr = zone.get(); zone->m_pools = std::make_unique(zonePtr, 0); zone->m_language = GameLanguage::LANGUAGE_NONE; diff --git a/src/ZoneLoading/Game/IW4/ZoneLoaderFactoryIW4.cpp b/src/ZoneLoading/Game/IW4/ZoneLoaderFactoryIW4.cpp index 3a23cbc9..78116b19 100644 --- a/src/ZoneLoading/Game/IW4/ZoneLoaderFactoryIW4.cpp +++ b/src/ZoneLoading/Game/IW4/ZoneLoaderFactoryIW4.cpp @@ -211,7 +211,7 @@ std::unique_ptr ZoneLoaderFactory::CreateLoaderForHeader(const ZoneH return nullptr; // Create new zone - auto zone = std::make_unique(fileName, 0, GameId::IW4); + auto zone = std::make_unique(fileName, 0, GameId::IW4, inspectResult->m_generic_result.m_platform); auto* zonePtr = zone.get(); zone->m_pools = std::make_unique(zonePtr, 0); zone->m_language = GameLanguage::LANGUAGE_NONE; diff --git a/src/ZoneLoading/Game/IW5/ZoneLoaderFactoryIW5.cpp b/src/ZoneLoading/Game/IW5/ZoneLoaderFactoryIW5.cpp index d3d3cbb7..557d5537 100644 --- a/src/ZoneLoading/Game/IW5/ZoneLoaderFactoryIW5.cpp +++ b/src/ZoneLoading/Game/IW5/ZoneLoaderFactoryIW5.cpp @@ -165,7 +165,7 @@ std::unique_ptr ZoneLoaderFactory::CreateLoaderForHeader(const ZoneH return nullptr; // Create new zone - auto zone = std::make_unique(fileName, 0, GameId::IW5); + auto zone = std::make_unique(fileName, 0, GameId::IW5, inspectResult->m_platform); auto* zonePtr = zone.get(); zone->m_pools = std::make_unique(zonePtr, 0); zone->m_language = GameLanguage::LANGUAGE_NONE; diff --git a/src/ZoneLoading/Game/T5/ZoneLoaderFactoryT5.cpp b/src/ZoneLoading/Game/T5/ZoneLoaderFactoryT5.cpp index 861a0d4d..7d93b5d2 100644 --- a/src/ZoneLoading/Game/T5/ZoneLoaderFactoryT5.cpp +++ b/src/ZoneLoading/Game/T5/ZoneLoaderFactoryT5.cpp @@ -68,7 +68,7 @@ std::unique_ptr ZoneLoaderFactory::CreateLoaderForHeader(const ZoneH return nullptr; // Create new zone - auto zone = std::make_unique(fileName, 0, GameId::T5); + auto zone = std::make_unique(fileName, 0, GameId::T5, inspectResult->m_platform); auto* zonePtr = zone.get(); zone->m_pools = std::make_unique(zonePtr, 0); zone->m_language = GameLanguage::LANGUAGE_NONE; diff --git a/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.cpp b/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.cpp index b4023dc0..f4a40755 100644 --- a/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.cpp +++ b/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.cpp @@ -284,7 +284,7 @@ std::unique_ptr ZoneLoaderFactory::CreateLoaderForHeader(const ZoneH return nullptr; // Create new zone - auto zone = std::make_unique(fileName, 0, GameId::T6); + auto zone = std::make_unique(fileName, 0, GameId::T6, inspectResult->m_generic_result.m_platform); auto* zonePtr = zone.get(); zone->m_pools = std::make_unique(zonePtr, 0); zone->m_language = GetZoneLanguage(fileName); diff --git a/test/ObjCompilingTests/Game/T6/KeyValuePairs/KeyValuePairsCompilerT6Test.cpp b/test/ObjCompilingTests/Game/T6/KeyValuePairs/KeyValuePairsCompilerT6Test.cpp index 4d5ab4fa..7e81cf1b 100644 --- a/test/ObjCompilingTests/Game/T6/KeyValuePairs/KeyValuePairsCompilerT6Test.cpp +++ b/test/ObjCompilingTests/Game/T6/KeyValuePairs/KeyValuePairsCompilerT6Test.cpp @@ -20,7 +20,7 @@ namespace public: TestContext() : m_memory(), - m_zone("test", 0, GameId::T6), + m_zone("test", 0, GameId::T6, GamePlatform::PC), m_zone_definition(), m_zone_states(m_zone), m_creators(m_zone), diff --git a/test/ObjCompilingTests/Image/IPak/IPakCreatorTest.cpp b/test/ObjCompilingTests/Image/IPak/IPakCreatorTest.cpp index fc423589..1f2d74df 100644 --- a/test/ObjCompilingTests/Image/IPak/IPakCreatorTest.cpp +++ b/test/ObjCompilingTests/Image/IPak/IPakCreatorTest.cpp @@ -20,7 +20,7 @@ namespace { public: TestContext() - : m_zone("test", 0, GameId::T6), + : m_zone("test", 0, GameId::T6, GamePlatform::PC), m_zone_states(m_zone), m_out_dir() { diff --git a/test/ObjCompilingTests/Image/ImageIPakPostProcessorTest.cpp b/test/ObjCompilingTests/Image/ImageIPakPostProcessorTest.cpp index c9c6b82c..d92899bf 100644 --- a/test/ObjCompilingTests/Image/ImageIPakPostProcessorTest.cpp +++ b/test/ObjCompilingTests/Image/ImageIPakPostProcessorTest.cpp @@ -20,7 +20,7 @@ namespace { public: TestContext() - : m_zone("test", 0, GameId::T6), + : m_zone("test", 0, GameId::T6, GamePlatform::PC), m_zone_definition(), m_zone_definition_context(m_zone_definition), m_zone_states(m_zone), diff --git a/test/ObjCompilingTests/Image/ImageIwdPostProcessorTest.cpp b/test/ObjCompilingTests/Image/ImageIwdPostProcessorTest.cpp index adfef729..c9b1ddc4 100644 --- a/test/ObjCompilingTests/Image/ImageIwdPostProcessorTest.cpp +++ b/test/ObjCompilingTests/Image/ImageIwdPostProcessorTest.cpp @@ -19,7 +19,7 @@ namespace { public: TestContext() - : m_zone("test", 0, GameId::T6), + : m_zone("test", 0, GameId::T6, GamePlatform::PC), m_zone_definition(), m_zone_definition_context(m_zone_definition), m_zone_states(m_zone), diff --git a/test/ObjCompilingTests/Iwd/IwdCreatorTest.cpp b/test/ObjCompilingTests/Iwd/IwdCreatorTest.cpp index 33421760..a15cc0c4 100644 --- a/test/ObjCompilingTests/Iwd/IwdCreatorTest.cpp +++ b/test/ObjCompilingTests/Iwd/IwdCreatorTest.cpp @@ -23,7 +23,7 @@ namespace { public: TestContext() - : m_zone("test", 0, GameId::T6), + : m_zone("test", 0, GameId::T6, GamePlatform::PC), m_zone_states(m_zone), m_out_dir() { diff --git a/test/ObjLoadingTests/Game/IW3/Material/LoaderMaterialIW3Test.cpp b/test/ObjLoadingTests/Game/IW3/Material/LoaderMaterialIW3Test.cpp index 4c88b469..28806ca1 100644 --- a/test/ObjLoadingTests/Game/IW3/Material/LoaderMaterialIW3Test.cpp +++ b/test/ObjLoadingTests/Game/IW3/Material/LoaderMaterialIW3Test.cpp @@ -274,7 +274,7 @@ namespace ] })MATERIAL"); - Zone zone("MockZone", 0, GameId::IW3); + Zone zone("MockZone", 0, GameId::IW3, GamePlatform::PC); MemoryManager memory; AssetCreatorCollection creatorCollection(zone); diff --git a/test/ObjLoadingTests/Game/IW3/StringTable/AssetLoaderStringTableIW3Test.cpp b/test/ObjLoadingTests/Game/IW3/StringTable/AssetLoaderStringTableIW3Test.cpp index 4bfd7172..c98e09be 100644 --- a/test/ObjLoadingTests/Game/IW3/StringTable/AssetLoaderStringTableIW3Test.cpp +++ b/test/ObjLoadingTests/Game/IW3/StringTable/AssetLoaderStringTableIW3Test.cpp @@ -20,7 +20,7 @@ namespace "test,data,lol\n" "lorem,ipsum"); - Zone zone("MockZone", 0, GameId::IW3); + Zone zone("MockZone", 0, GameId::IW3, GamePlatform::PC); MemoryManager memory; AssetCreatorCollection creatorCollection(zone); diff --git a/test/ObjLoadingTests/Game/IW4/AssetLoaders/LoaderStringTableIW4Test.cpp b/test/ObjLoadingTests/Game/IW4/AssetLoaders/LoaderStringTableIW4Test.cpp index e6fdf9db..1585b4ea 100644 --- a/test/ObjLoadingTests/Game/IW4/AssetLoaders/LoaderStringTableIW4Test.cpp +++ b/test/ObjLoadingTests/Game/IW4/AssetLoaders/LoaderStringTableIW4Test.cpp @@ -20,7 +20,7 @@ namespace "test,data,lol\n" "lorem,ipsum"); - Zone zone("MockZone", 0, GameId::IW4); + Zone zone("MockZone", 0, GameId::IW4, GamePlatform::PC); MemoryManager memory; AssetCreatorCollection creatorCollection(zone); diff --git a/test/ObjLoadingTests/Game/IW4/Material/LoaderMaterialIW4Test.cpp b/test/ObjLoadingTests/Game/IW4/Material/LoaderMaterialIW4Test.cpp index 39fd6075..fcb765de 100644 --- a/test/ObjLoadingTests/Game/IW4/Material/LoaderMaterialIW4Test.cpp +++ b/test/ObjLoadingTests/Game/IW4/Material/LoaderMaterialIW4Test.cpp @@ -277,7 +277,7 @@ namespace ] })MATERIAL"); - Zone zone("MockZone", 0, GameId::IW4); + Zone zone("MockZone", 0, GameId::IW4, GamePlatform::PC); MemoryManager memory; AssetCreatorCollection creatorCollection(zone); diff --git a/test/ObjLoadingTests/Game/IW4/Menu/LoaderMenuListIW4Test.cpp b/test/ObjLoadingTests/Game/IW4/Menu/LoaderMenuListIW4Test.cpp index dcd495f1..ec4cc5bb 100644 --- a/test/ObjLoadingTests/Game/IW4/Menu/LoaderMenuListIW4Test.cpp +++ b/test/ObjLoadingTests/Game/IW4/Menu/LoaderMenuListIW4Test.cpp @@ -30,7 +30,7 @@ namespace test::game::iw4::menu::parsing::it public: MenuParsingItHelper() - : m_zone("MockZone", 0, GameId::IW4), + : m_zone("MockZone", 0, GameId::IW4, GamePlatform::PC), m_creator_collection(m_zone), m_ignored_asset_lookup(), m_context(m_zone, &m_creator_collection, &m_ignored_asset_lookup) diff --git a/test/ObjLoadingTests/Game/IW5/AssetLoaders/LoaderStringTableIW5Test.cpp b/test/ObjLoadingTests/Game/IW5/AssetLoaders/LoaderStringTableIW5Test.cpp index 6aadc816..7b94170c 100644 --- a/test/ObjLoadingTests/Game/IW5/AssetLoaders/LoaderStringTableIW5Test.cpp +++ b/test/ObjLoadingTests/Game/IW5/AssetLoaders/LoaderStringTableIW5Test.cpp @@ -19,7 +19,7 @@ namespace "test,data,lol\n" "lorem,ipsum"); - Zone zone("MockZone", 0, GameId::IW5); + Zone zone("MockZone", 0, GameId::IW5, GamePlatform::PC); MemoryManager memory; AssetCreatorCollection creatorCollection(zone); diff --git a/test/ObjLoadingTests/Game/IW5/Material/LoaderMaterialIW5Test.cpp b/test/ObjLoadingTests/Game/IW5/Material/LoaderMaterialIW5Test.cpp index 8105f4ee..67a12e83 100644 --- a/test/ObjLoadingTests/Game/IW5/Material/LoaderMaterialIW5Test.cpp +++ b/test/ObjLoadingTests/Game/IW5/Material/LoaderMaterialIW5Test.cpp @@ -301,7 +301,7 @@ namespace ] })MATERIAL"); - Zone zone("MockZone", 0, GameId::IW5); + Zone zone("MockZone", 0, GameId::IW5, GamePlatform::PC); MemoryManager memory; AssetCreatorCollection creatorCollection(zone); diff --git a/test/ObjLoadingTests/Game/T5/AssetLoaders/LoaderStringTableT5Test.cpp b/test/ObjLoadingTests/Game/T5/AssetLoaders/LoaderStringTableT5Test.cpp index 7db27a83..86ce69ad 100644 --- a/test/ObjLoadingTests/Game/T5/AssetLoaders/LoaderStringTableT5Test.cpp +++ b/test/ObjLoadingTests/Game/T5/AssetLoaders/LoaderStringTableT5Test.cpp @@ -19,7 +19,7 @@ namespace "test,data,lol\n" "lorem,ipsum"); - Zone zone("MockZone", 0, GameId::T5); + Zone zone("MockZone", 0, GameId::T5, GamePlatform::PC); MemoryManager memory; AssetCreatorCollection creatorCollection(zone); diff --git a/test/ObjLoadingTests/Game/T5/Material/LoaderMaterialT5Test.cpp b/test/ObjLoadingTests/Game/T5/Material/LoaderMaterialT5Test.cpp index 4847e225..ce0d8fa5 100644 --- a/test/ObjLoadingTests/Game/T5/Material/LoaderMaterialT5Test.cpp +++ b/test/ObjLoadingTests/Game/T5/Material/LoaderMaterialT5Test.cpp @@ -358,7 +358,7 @@ namespace ] })MATERIAL"); - Zone zone("MockZone", 0, GameId::T5); + Zone zone("MockZone", 0, GameId::T5, GamePlatform::PC); MemoryManager memory; AssetCreatorCollection creatorCollection(zone); diff --git a/test/ObjLoadingTests/Game/T6/AssetLoaders/LoaderStringTableT6Test.cpp b/test/ObjLoadingTests/Game/T6/AssetLoaders/LoaderStringTableT6Test.cpp index e26e8b74..ec8c0500 100644 --- a/test/ObjLoadingTests/Game/T6/AssetLoaders/LoaderStringTableT6Test.cpp +++ b/test/ObjLoadingTests/Game/T6/AssetLoaders/LoaderStringTableT6Test.cpp @@ -19,7 +19,7 @@ namespace "test,data,lol\n" "lorem,ipsum"); - Zone zone("MockZone", 0, GameId::T6); + Zone zone("MockZone", 0, GameId::T6, GamePlatform::PC); MemoryManager memory; AssetCreatorCollection creatorCollection(zone); diff --git a/test/ObjLoadingTests/Game/T6/FontIcon/JsonLoaderFontIconT6Test.cpp b/test/ObjLoadingTests/Game/T6/FontIcon/JsonLoaderFontIconT6Test.cpp index 24311566..a75adfe2 100644 --- a/test/ObjLoadingTests/Game/T6/FontIcon/JsonLoaderFontIconT6Test.cpp +++ b/test/ObjLoadingTests/Game/T6/FontIcon/JsonLoaderFontIconT6Test.cpp @@ -79,7 +79,7 @@ namespace ] })FONT_ICON"); - Zone zone("MockZone", 0, GameId::T6); + Zone zone("MockZone", 0, GameId::T6, GamePlatform::PC); MemoryManager memory; AssetCreatorCollection creatorCollection(zone); diff --git a/test/ObjLoadingTests/Game/T6/Material/LoaderMaterialT6Test.cpp b/test/ObjLoadingTests/Game/T6/Material/LoaderMaterialT6Test.cpp index 95b3bfa1..24340f67 100644 --- a/test/ObjLoadingTests/Game/T6/Material/LoaderMaterialT6Test.cpp +++ b/test/ObjLoadingTests/Game/T6/Material/LoaderMaterialT6Test.cpp @@ -241,7 +241,7 @@ namespace ] })MATERIAL"); - Zone zone("MockZone", 0, GameId::T6); + Zone zone("MockZone", 0, GameId::T6, GamePlatform::PC); MemoryManager memory; AssetCreatorCollection creatorCollection(zone); diff --git a/test/ObjWritingTests/Game/IW3/Material/MaterialJsonDumperIW3Test.cpp b/test/ObjWritingTests/Game/IW3/Material/MaterialJsonDumperIW3Test.cpp index fda33fe2..0a1ad83c 100644 --- a/test/ObjWritingTests/Game/IW3/Material/MaterialJsonDumperIW3Test.cpp +++ b/test/ObjWritingTests/Game/IW3/Material/MaterialJsonDumperIW3Test.cpp @@ -551,7 +551,7 @@ namespace ] })MATERIAL"); - Zone zone("MockZone", 0, GameId::IW3); + Zone zone("MockZone", 0, GameId::IW3, GamePlatform::PC); MemoryManager memory; MockSearchPath mockObjPath; diff --git a/test/ObjWritingTests/Game/IW4/Material/MaterialJsonDumperIW4Test.cpp b/test/ObjWritingTests/Game/IW4/Material/MaterialJsonDumperIW4Test.cpp index adbbc517..f5397cd0 100644 --- a/test/ObjWritingTests/Game/IW4/Material/MaterialJsonDumperIW4Test.cpp +++ b/test/ObjWritingTests/Game/IW4/Material/MaterialJsonDumperIW4Test.cpp @@ -532,7 +532,7 @@ namespace ] })MATERIAL"); - Zone zone("MockZone", 0, GameId::IW4); + Zone zone("MockZone", 0, GameId::IW4, GamePlatform::PC); MemoryManager memory; MockSearchPath mockObjPath; diff --git a/test/ObjWritingTests/Game/IW5/Material/MaterialJsonDumperIW5Test.cpp b/test/ObjWritingTests/Game/IW5/Material/MaterialJsonDumperIW5Test.cpp index 9c003335..3196f28a 100644 --- a/test/ObjWritingTests/Game/IW5/Material/MaterialJsonDumperIW5Test.cpp +++ b/test/ObjWritingTests/Game/IW5/Material/MaterialJsonDumperIW5Test.cpp @@ -585,7 +585,7 @@ namespace ] })MATERIAL"); - Zone zone("MockZone", 0, GameId::IW5); + Zone zone("MockZone", 0, GameId::IW5, GamePlatform::PC); MemoryManager memory; MockSearchPath mockObjPath; diff --git a/test/ObjWritingTests/Game/T5/Material/MaterialJsonDumperT5Test.cpp b/test/ObjWritingTests/Game/T5/Material/MaterialJsonDumperT5Test.cpp index 0036b78e..d2664be6 100644 --- a/test/ObjWritingTests/Game/T5/Material/MaterialJsonDumperT5Test.cpp +++ b/test/ObjWritingTests/Game/T5/Material/MaterialJsonDumperT5Test.cpp @@ -614,7 +614,7 @@ namespace ] })MATERIAL"); - Zone zone("MockZone", 0, GameId::T5); + Zone zone("MockZone", 0, GameId::T5, GamePlatform::PC); MemoryManager memory; MockSearchPath mockObjPath; diff --git a/test/ObjWritingTests/Game/T6/FontIcon/FontIconJsonDumperT6Test.cpp b/test/ObjWritingTests/Game/T6/FontIcon/FontIconJsonDumperT6Test.cpp index 91b6b1f3..db107bca 100644 --- a/test/ObjWritingTests/Game/T6/FontIcon/FontIconJsonDumperT6Test.cpp +++ b/test/ObjWritingTests/Game/T6/FontIcon/FontIconJsonDumperT6Test.cpp @@ -141,7 +141,7 @@ namespace ] })FONT_ICON"); - Zone zone("MockZone", 0, GameId::T6); + Zone zone("MockZone", 0, GameId::T6, GamePlatform::PC); MemoryManager memory; MockSearchPath mockObjPath; diff --git a/test/ObjWritingTests/Game/T6/Material/MaterialJsonDumperT6Test.cpp b/test/ObjWritingTests/Game/T6/Material/MaterialJsonDumperT6Test.cpp index bfefddb1..49b4a59b 100644 --- a/test/ObjWritingTests/Game/T6/Material/MaterialJsonDumperT6Test.cpp +++ b/test/ObjWritingTests/Game/T6/Material/MaterialJsonDumperT6Test.cpp @@ -462,7 +462,7 @@ namespace ] })MATERIAL"); - Zone zone("MockZone", 0, GameId::T6); + Zone zone("MockZone", 0, GameId::T6, GamePlatform::PC); MemoryManager memory; MockSearchPath mockObjPath;