2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2025-11-25 14:12:06 +00:00

Merge pull request #559 from Laupetin/modman-zone-details

feat: modman zone details
This commit is contained in:
Jan
2025-10-28 23:42:36 +01:00
committed by GitHub
97 changed files with 3108 additions and 361 deletions

View File

@@ -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 <cassert>
ICommonAssetTypeMapper* ICommonAssetTypeMapper::GetCommonAssetMapperByGame(GameId gameId)
{
static ICommonAssetTypeMapper* assetTypeMappers[static_cast<unsigned>(GameId::COUNT)]{
new IW3::CommonAssetTypeMapper(),
new IW4::CommonAssetTypeMapper(),
new IW5::CommonAssetTypeMapper(),
new T5::CommonAssetTypeMapper(),
new T6::CommonAssetTypeMapper(),
};
assert(static_cast<unsigned>(gameId) < static_cast<unsigned>(GameId::COUNT));
auto* result = assetTypeMappers[static_cast<unsigned>(gameId)];
assert(result);
return result;
}

View File

@@ -0,0 +1,181 @@
#pragma once
#include "IGame.h"
#include "Zone/ZoneTypes.h"
#include <cstdint>
#include <optional>
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<asset_type_t> 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;
};

View File

@@ -0,0 +1,100 @@
#include "CommonAssetIW3.h"
#include "IW3.h"
#include <cassert>
namespace IW3
{
CommonAssetTypeMapper::CommonAssetTypeMapper() = default;
CommonAssetType CommonAssetTypeMapper::GameToCommonAssetType(const asset_type_t gameAssetType) const
{
static CommonAssetType lookupTable[static_cast<unsigned>(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<asset_type_t> 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

View File

@@ -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<asset_type_t> CommonToGameAssetType(CommonAssetType commonAssetType) const override;
};
} // namespace IW3

View File

@@ -0,0 +1,120 @@
#include "CommonAssetIW4.h"
#include "IW4.h"
#include <cassert>
namespace IW4
{
CommonAssetTypeMapper::CommonAssetTypeMapper() = default;
CommonAssetType CommonAssetTypeMapper::GameToCommonAssetType(const asset_type_t gameAssetType) const
{
static CommonAssetType lookupTable[static_cast<unsigned>(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<asset_type_t> 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

View File

@@ -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<asset_type_t> CommonToGameAssetType(CommonAssetType commonAssetType) const override;
};
} // namespace IW4

View File

@@ -0,0 +1,127 @@
#include "CommonAssetIW5.h"
#include "IW5.h"
#include <cassert>
namespace IW5
{
CommonAssetTypeMapper::CommonAssetTypeMapper() = default;
CommonAssetType CommonAssetTypeMapper::GameToCommonAssetType(const asset_type_t gameAssetType) const
{
static CommonAssetType lookupTable[static_cast<unsigned>(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<asset_type_t> 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

View File

@@ -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<asset_type_t> CommonToGameAssetType(CommonAssetType commonAssetType) const override;
};
} // namespace IW5

View File

@@ -0,0 +1,120 @@
#include "CommonAssetT5.h"
#include "T5.h"
#include <cassert>
namespace T5
{
CommonAssetTypeMapper::CommonAssetTypeMapper() = default;
CommonAssetType CommonAssetTypeMapper::GameToCommonAssetType(const asset_type_t gameAssetType) const
{
static CommonAssetType lookupTable[static_cast<unsigned>(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<asset_type_t> 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

View File

@@ -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<asset_type_t> CommonToGameAssetType(CommonAssetType commonAssetType) const override;
};
} // namespace T5

View File

@@ -0,0 +1,154 @@
#include "CommonAssetT6.h"
#include "T6.h"
#include <cassert>
namespace T6
{
CommonAssetTypeMapper::CommonAssetTypeMapper() = default;
CommonAssetType CommonAssetTypeMapper::GameToCommonAssetType(const asset_type_t gameAssetType) const
{
static CommonAssetType lookupTable[static_cast<unsigned>(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<asset_type_t> 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

View File

@@ -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<asset_type_t> CommonToGameAssetType(CommonAssetType commonAssetType) const override;
};
} // namespace T6

View File

@@ -11,7 +11,7 @@ namespace
{
std::unique_ptr<Zone> CreateZone(const ZoneCreationContext& context, const GameId gameId)
{
return std::make_unique<Zone>(context.m_definition->m_name, 0, gameId);
return std::make_unique<Zone>(context.m_definition->m_name, 0, gameId, GamePlatform::PC);
}
std::vector<Gdt*> CreateGdtList(const ZoneCreationContext& context)

View File

@@ -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<double>(current) / static_cast<double>(total);
const double percentage = static_cast<double>(current) / static_cast<double>(total) * 100.0;
if (percentage - m_last_progress >= MIN_PROGRESS_TO_REPORT)
{
@@ -38,38 +38,53 @@ namespace
};
} // namespace
LoadedZone::LoadedZone(std::unique_ptr<Zone> 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<Zone*, std::string> FastFileContext::LoadFastFile(const std::string& path)
result::Expected<LoadedZone*, std::string> FastFileContext::LoadFastFile(const std::string& path)
{
auto zone = ZoneLoading::LoadZone(path, std::make_unique<LoadingEventProgressReporter>(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<LoadedZone>(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<NoResult, std::string> FastFileContext::UnloadZone(const std::string& zoneName)
{
const auto existingZone = std::ranges::find_if(m_loaded_zones,
[&zoneName](const std::unique_ptr<Zone>& 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>& 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));

View File

@@ -4,15 +4,26 @@
#include "Zone/Zone.h"
#include <memory>
#include <shared_mutex>
#include <vector>
class LoadedZone
{
public:
std::unique_ptr<Zone> m_zone;
std::string m_file_path;
LoadedZone(std::unique_ptr<Zone> zone, std::string filePath);
};
class FastFileContext
{
public:
void Destroy();
result::Expected<Zone*, std::string> LoadFastFile(const std::string& path);
result::Expected<LoadedZone*, std::string> LoadFastFile(const std::string& path);
result::Expected<NoResult, std::string> UnloadZone(const std::string& zoneName);
std::vector<std::unique_ptr<Zone>> m_loaded_zones;
std::vector<std::unique_ptr<LoadedZone>> m_loaded_zones;
std::shared_mutex m_zone_lock;
};

View File

@@ -0,0 +1,174 @@
#include "AssetBinds.h"
#include "Context/ModManContext.h"
#include "Game/CommonAsset.h"
#include "Web/UiCommunication.h"
#include "Json/JsonExtension.h"
#include <cstdint>
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<AssetDto> assets;
std::vector<AssetDto> references;
};
NLOHMANN_DEFINE_TYPE_EXTENSION(ZoneAssetsDto, assets, references);
ZoneAssetsDto CreateZoneAssetsDto(const Zone& zone)
{
std::vector<AssetDto> assets;
std::vector<AssetDto> 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<ZoneAssetsDto> 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<std::string, std::optional<ZoneAssetsDto>>(wv,
"getAssetsForZone",
[](const std::string& zoneName)
{
return GetZonesForZone(zoneName);
});
}
} // namespace ui

View File

@@ -0,0 +1,8 @@
#pragma once
#include "Web/WebViewLib.h"
namespace ui
{
void RegisterAssetBinds(webview::webview& wv);
} // namespace ui

View File

@@ -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);

View File

@@ -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<double>(current) / static_cast<double>(total);
const double percentage = static_cast<double>(current) / static_cast<double>(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>& zone)
[&zoneName](const std::unique_ptr<LoadedZone>& 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<UnlinkingEventProgressReporter>(zoneName));
*loadedZone.m_zone, outputFolderPathStr, outputFolderOutputPath, searchPaths, std::make_unique<UnlinkingEventProgressReporter>(zoneName));
objWriter->DumpZone(dumpingContext);
return NoResult();

View File

@@ -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<ZoneDto> GetLoadedZones()
{
auto& context = ModManContext::Get().m_fast_file;
std::vector<ZoneDto> 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<std::vector<ZoneDto>>(wv,
"getZones",
[]
{
return GetLoadedZones();
});
BindAsync<std::string>(wv,
"loadFastFile",
[&wv](const std::string& id, std::string path)

View File

@@ -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);

View File

@@ -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);

View File

@@ -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<OutputAsset, "type" | "fileName" | "source">;
type MinimalOutputChunk = Pick<OutputChunk, "type" | "fileName" | "code">;
type MinimalOutputBundle = Record<string, MinimalOutputAsset | MinimalOutputChunk>;
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);
},
};
}

View File

@@ -2,9 +2,10 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<link rel="icon" href="/favicon.ico" sizes="512x512 256x256 128x128 64x64" />
<link rel="icon" href="/logo_circle.svg" sizes="any" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tauri + Vue + Typescript App</title>
<title>OpenAssetTools ModMan</title>
</head>
<body>
<div id="app"></div>

View File

@@ -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",

View File

@@ -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",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 130 KiB

View File

@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="300mm"
height="300mm"
viewBox="0 0 300 300"
version="1.1"
id="svg1"
xml:space="preserve"
inkscape:version="1.4.2 (f4327f4, 2025-05-13)"
sodipodi:docname="oat_circle.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#999999"
borderopacity="1"
inkscape:showpageshadow="2"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="0.55748644"
inkscape:cx="452.02893"
inkscape:cy="637.68367"
inkscape:window-width="1920"
inkscape:window-height="1129"
inkscape:window-x="1672"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" /><defs
id="defs1"><filter
style="color-interpolation-filters:sRGB;"
inkscape:label="Drop Shadow"
id="filter19"
x="-0.16704432"
y="-0.08986926"
width="1.3601893"
height="1.1937806"><feFlood
result="flood"
in="SourceGraphic"
flood-opacity="0.403922"
flood-color="rgb(0,0,0)"
id="feFlood18" /><feGaussianBlur
result="blur"
in="SourceGraphic"
stdDeviation="8.000000"
id="feGaussianBlur18" /><feOffset
result="offset"
in="blur"
dx="3.000000"
dy="3.000000"
id="feOffset18" /><feComposite
result="comp1"
operator="in"
in="flood"
in2="offset"
id="feComposite18" /><feComposite
result="comp2"
operator="over"
in="SourceGraphic"
in2="comp1"
id="feComposite19" /></filter></defs><g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"><circle
style="fill:#ca893d;stroke-width:0.264583;fill-opacity:1"
id="path2"
cx="149.73645"
cy="151.63484"
r="128" /><path
style="fill:#ffffff;stroke:none;stroke-width:0.724;fill-opacity:1;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter19)"
d="m 157.15533,40.658523 c -7.16528,10.302747 -12.51327,22.617436 -16.6111,34.458658 -2.54917,7.366211 -4.77329,15.607101 -4.02076,23.482935 0.33817,3.539174 1.30988,7.672094 3.18904,10.720474 0.97925,1.58854 3.26203,2.91006 3.81397,4.59843 0.92967,2.84378 0.74731,6.23647 0.87645,9.18503 0.18554,4.23723 0.42148,8.50748 0.23514,12.76248 -0.30007,6.85199 -2.86584,14.43633 -5.6082,20.67519 -1.68147,3.82534 -4.42564,7.76492 -4.84697,11.99672 h -0.25525 c -0.30662,-7.14028 -1.15672,-13.81779 -4.08399,-20.41995 8.36198,-3.90966 7.24983,-15.18254 4.89917,-22.46194 -4.29583,-13.3031 -14.22445,-24.31606 -23.76379,-34.193176 -3.48045,-3.603683 -6.90971,-8.097499 -10.999551,-10.985956 0.986581,12.07896 2.622311,24.405512 5.251911,36.245412 1.24134,5.58915 2.55471,11.99777 5.22415,17.1017 2.58771,4.94766 5.31606,9.73231 10.19914,12.74592 1.43929,0.88826 2.9245,1.43029 4.59448,1.69122 0.9658,0.15091 2.16541,-0.0811 2.89736,0.70371 0.96354,1.03323 1.26089,2.94912 1.69713,4.2581 1.39158,4.17553 1.97461,8.38492 2.2744,12.76246 1.2066,17.61936 -5.6512,33.88753 -11.62428,50.02887 -1.81237,4.89764 -1.57442,10.20759 -3.63514,15.05971 -1.97356,4.64688 -4.14099,8.76759 -6.87617,13.01397 -1.95003,3.02741 -4.3974,6.00391 -4.89799,9.70322 2.02855,-0.15628 2.49496,-2.32202 3.60382,-3.75586 3.20156,-4.13988 6.3358,-8.3512 8.59123,-13.0906 2.73623,-5.74976 3.07562,-12.18903 5.18474,-18.12269 2.31458,-6.51166 6.40216,-12.47781 8.29107,-19.14371 1.96809,-6.94523 2.59545,-15.58781 6.73339,-21.68733 1.20177,-1.77146 5.24937,0.88445 7.15939,1.15809 5.04845,0.72321 10.70726,-0.88082 15.0597,-3.41613 12.21808,-7.11703 21.95698,-18.17281 30.34514,-29.37889 2.98928,-3.99351 6.48878,-7.93184 8.96326,-12.27481 -14.38224,4.6782 -29.79304,6.53244 -43.13713,13.95008 -6.39539,3.55503 -13.16101,8.2226 -16.65797,14.89309 -2.10395,4.01331 -3.43865,9.81381 -4.01723,14.29396 h -0.25524 c 0.50501,-6.34574 3.0145,-14.93411 6.77553,-20.12136 3.07929,-4.24698 7.25737,-7.62116 10.75375,-11.50671 1.94533,-2.16185 4.00931,-4.21297 5.91938,-6.40782 1.02315,-1.17568 2.09515,-2.89626 3.60777,-3.49746 0.98879,-0.393 2.11738,0.39715 3.06298,0.65289 1.52673,0.4129 3.27852,0.39838 4.84974,0.27199 4.6473,-0.37383 9.54534,-3.67807 13.00767,-6.56341 6.74442,-5.62047 11.67306,-14.04755 15.64624,-21.74543 4.64046,-8.990734 9.24016,-18.310406 12.69648,-27.822182 -6.07512,2.546043 -11.99754,6.635251 -17.6122,10.092786 -11.19017,6.890952 -23.12624,14.591936 -30.0038,26.152626 -1.81972,3.05881 -3.46108,6.64757 -3.90458,10.20997 -0.26495,2.12833 0.60659,5.94362 -0.46067,7.65728 -4.32991,6.95238 -12.89408,11.33384 -16.68082,18.6334 h -0.25524 c 2.92582,-7.9652 4.54429,-16.23824 4.33549,-24.75919 -0.0764,-3.12012 -0.19346,-6.34209 -0.57942,-9.44422 -0.17134,-1.37703 -0.87961,-3.43476 -0.46619,-4.79164 0.36474,-1.19717 4.30109,-2.11927 5.38859,-2.98795 3.08532,-2.46452 5.37666,-6.17729 6.78243,-9.83261 3.74161,-9.72902 3.6403,-20.912802 2.93989,-31.140425 -0.67532,-9.861296 -1.19822,-19.875516 -3.08584,-29.608922 h -0.5105 M 110.44471,144.0345 c -3.75903,11.55249 -8.14701,22.91376 -11.097041,34.71391 -1.534837,6.13935 -3.100637,12.50907 -3.015727,18.88845 0.0736,5.52842 0.41629,11.16231 3.261717,16.07972 0.917211,1.58511 2.191701,2.95005 3.704061,3.97665 0.86062,0.58419 2.09474,1.23975 1.85628,2.44889 -1.65212,8.37718 -6.089111,17.15329 -6.194528,25.73687 -0.0257,2.09216 -0.15445,4.03486 -0.007,6.12597 0.0519,0.73659 0.0476,2.07414 1.056448,2.15781 1.85965,0.15424 1.41636,-6.42184 1.50865,-7.77329 0.58862,-8.61903 3.54759,-17.30601 5.13276,-25.77544 0.33859,-1.80907 4.17634,-2.90995 5.57136,-4.04146 3.02114,-2.45045 5.08063,-5.89062 6.45548,-9.4915 5.74688,-15.05154 1.24022,-33.42794 -3.19868,-48.24212 -0.92396,-3.08358 -1.99799,-6.1122 -2.9391,-9.18897 -0.56904,-1.86034 -0.90105,-4.03706 -2.0944,-5.61549 m 56.15486,37.01115 c -5.76022,4.69086 -11.15297,9.97993 -16.59121,15.03687 -10.80773,10.04991 -24.26466,21.75848 -25.44202,37.54449 -0.19124,2.56417 0.42114,5.79387 1.38655,8.16798 0.44584,1.0964 1.53285,2.14209 1.69181,3.31824 0.41267,3.05318 -2.88452,5.79996 -1.88503,9.18898 h 0.25525 c 1.3389,-2.30487 2.3407,-5.50659 2.5525,-8.16798 2.19882,0.32473 4.09594,1.02573 6.38123,0.68894 6.47079,-0.95364 11.28708,-7.14598 14.68157,-12.17516 7.17889,-10.63603 10.7098,-23.84247 13.50438,-36.2454 0.93663,-4.15697 1.96349,-8.31019 2.72048,-12.50722 0.26038,-1.44356 1.17447,-3.43379 0.74449,-4.84974 z"
id="path1" /></g></svg>

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -1,163 +1,56 @@
<script setup lang="ts">
import { computed, ref } from "vue";
import { webviewAddEventListener, webviewBinds } from "@/native";
import { useZoneStore } from "@/stores/ZoneStore";
import SpinningLoader from "@/components/SpinningLoader.vue";
const zoneStore = useZoneStore();
const loadingFastFile = ref(false);
const unlinkingFastFile = ref(false);
const lastPercentage = ref<number>(0);
const performingAction = computed<boolean>(() => loadingFastFile.value || unlinkingFastFile.value);
const progressBarWidth = computed<string>(() => `${lastPercentage.value * 100}%`);
async function openFastFileSelect() {
return await webviewBinds.openFileDialog({ filters: [{ name: "Fastfiles", filter: "*.ff" }] });
}
async function onOpenFastFileClick() {
if (performingAction.value) return;
const fastFilePath = await openFastFileSelect();
if (!fastFilePath) return;
loadingFastFile.value = true;
lastPercentage.value = 0;
webviewBinds
.loadFastFile(fastFilePath)
.catch((e: string) => {
console.error("Failed to load fastfile:", e);
})
.finally(() => {
loadingFastFile.value = false;
lastPercentage.value = 1;
});
}
async function onUnlinkFastFileClick() {
if (performingAction.value) return;
const fastFilePath = await openFastFileSelect();
if (!fastFilePath) return;
try {
unlinkingFastFile.value = true;
let loadedZoneName: string;
try {
lastPercentage.value = 0;
loadedZoneName = (await webviewBinds.loadFastFile(fastFilePath)).zoneName;
} catch (e: unknown) {
console.error("Failed to load fastfile:", e as string);
return;
}
try {
lastPercentage.value = 0;
await webviewBinds.unlinkZone(loadedZoneName);
} catch (e: unknown) {
console.error("Failed to unlink fastfile:", e as string);
return;
} finally {
webviewBinds.unloadZone(loadedZoneName);
}
} finally {
unlinkingFastFile.value = false;
lastPercentage.value = 1;
}
}
function onUnloadClicked(zoneName: string) {
webviewBinds.unloadZone(zoneName).catch((e: string) => {
console.error("Failed to unload zone:", e);
});
}
webviewAddEventListener("zoneLoadProgress", (dto) => {
lastPercentage.value = dto.percentage;
});
webviewAddEventListener("zoneUnlinkProgress", (dto) => {
lastPercentage.value = dto.percentage;
});
import ModManHeader from "./components/header/ModManHeader.vue";
</script>
<template>
<main class="container">
<h1>Welcome to ModMan</h1>
<small>Nothing to see here yet, this is mainly for testing</small>
<ModManHeader />
<div class="actions">
<button :disabled="performingAction" @click="onOpenFastFileClick">
<SpinningLoader v-if="loadingFastFile" class="loading" />
<span>Load fastfile</span>
</button>
<button :disabled="performingAction" @click="onUnlinkFastFileClick">
<SpinningLoader v-if="unlinkingFastFile" class="loading" />
<span>Unlink fastfile</span>
</button>
</div>
<div>
<h3>Loaded zones:</h3>
<div class="zone-list">
<div v-for="zone in zoneStore.loadedZones" :key="zone" class="zone">
<span>{{ zone }}</span>
<button :disabled="performingAction" @click="onUnloadClicked(zone)">Unload</button>
</div>
</div>
</div>
<div class="progressbar-wrapper">
<div
class="progressbar"
:class="{ visible: performingAction }"
:style="{ width: progressBarWidth }"
></div>
<div class="router-wrapper">
<RouterView v-slot="{ Component, route }">
<Transition name="blend">
<div class="router-rewrapper" :key="route.name">
<component :is="Component" />
</div>
</Transition>
</RouterView>
</div>
</main>
</template>
<style scoped lang="scss">
.actions {
display: flex;
justify-content: center;
column-gap: 0.5em;
}
@use "@style/variables";
.loading {
margin-right: 0.2em;
}
.zone-list {
.container {
margin: 0;
display: flex;
position: relative;
flex-direction: column;
row-gap: 0.5em;
height: 100vh;
}
.zone > button {
margin-left: 0.5em;
.router-wrapper {
position: relative;
height: 100%;
}
.progressbar-wrapper {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 0.35rem 0.4rem;
.router-rewrapper {
height: 100%;
}
.progressbar {
.blend-enter-from,
.blend-leave-to {
opacity: 0;
height: 0.4rem;
border-radius: 2.5rem;
background-color: #b9772c;
transition: opacity 0.2s ease-in-out;
}
&.visible {
opacity: 1;
}
.blend-enter-active,
.blend-leave-active {
transition: opacity 0.25s ease-in-out;
}
.blend-leave-active {
position: absolute;
inset: 0;
}
</style>

View File

@@ -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");
}

View File

@@ -0,0 +1,78 @@
<script setup lang="ts">
import Button from "primevue/button";
import { useRoute, useRouter } from "vue-router";
import IconArrowLeft from "../icons/IconArrowLeft.vue";
import IconGear from "../icons/IconGear.vue";
import { useRouteMeta } from "@/router/RouteMeta.ts";
const route = useRoute();
const { headerTitle, routeNavigateBackTo } = useRouteMeta();
const router = useRouter();
function onClickBack() {
if (!routeNavigateBackTo.value) return;
router.push({ name: routeNavigateBackTo.value });
}
</script>
<template>
<header class="header">
<div class="header-section left">
<Button
v-if="routeNavigateBackTo"
variant="text"
severity="secondary"
aria-label="Back"
@click="onClickBack"
>
<template #icon>
<IconArrowLeft class="icon" />
</template>
</Button>
</div>
<h1 class="title">
<span v-if="typeof headerTitle === 'string'">{{ headerTitle }}</span>
<component v-else :is="headerTitle" v-bind="route.params" />
</h1>
<div class="header-section right">
<Button variant="text" severity="secondary" aria-label="Settings">
<template #icon>
<IconGear class="icon" />
</template>
</Button>
</div>
</header>
</template>
<style scoped lang="scss">
@use "@style/colors";
.header {
background-color: colors.$color-content-background;
text-align: center;
padding: 0.25rem 0.25rem;
display: flex;
justify-content: space-between;
border-bottom: 1px solid colors.$color-content-border;
}
.header-section {
width: 12em;
&.left {
text-align: left;
}
&.right {
text-align: right;
}
}
.title {
font-size: 1rem;
line-height: 1;
}
</style>

View File

@@ -0,0 +1,9 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640">
<!--!Font Awesome Free v7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
<path
d="M73.4 297.4C60.9 309.9 60.9 330.2 73.4 342.7L233.4 502.7C245.9 515.2 266.2 515.2 278.7 502.7C291.2 490.2 291.2 469.9 278.7 457.4L173.3 352L544 352C561.7 352 576 337.7 576 320C576 302.3 561.7 288 544 288L173.3 288L278.7 182.6C291.2 170.1 291.2 149.8 278.7 137.3C266.2 124.8 245.9 124.8 233.4 137.3L73.4 297.3z"
fill="currentColor"
/>
</svg>
</template>

View File

@@ -0,0 +1,9 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640">
<!--!Font Awesome Free v7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
<path
d="M259.1 73.5C262.1 58.7 275.2 48 290.4 48L350.2 48C365.4 48 378.5 58.7 381.5 73.5L396 143.5C410.1 149.5 423.3 157.2 435.3 166.3L503.1 143.8C517.5 139 533.3 145 540.9 158.2L570.8 210C578.4 223.2 575.7 239.8 564.3 249.9L511 297.3C511.9 304.7 512.3 312.3 512.3 320C512.3 327.7 511.8 335.3 511 342.7L564.4 390.2C575.8 400.3 578.4 417 570.9 430.1L541 481.9C533.4 495 517.6 501.1 503.2 496.3L435.4 473.8C423.3 482.9 410.1 490.5 396.1 496.6L381.7 566.5C378.6 581.4 365.5 592 350.4 592L290.6 592C275.4 592 262.3 581.3 259.3 566.5L244.9 496.6C230.8 490.6 217.7 482.9 205.6 473.8L137.5 496.3C123.1 501.1 107.3 495.1 99.7 481.9L69.8 430.1C62.2 416.9 64.9 400.3 76.3 390.2L129.7 342.7C128.8 335.3 128.4 327.7 128.4 320C128.4 312.3 128.9 304.7 129.7 297.3L76.3 249.8C64.9 239.7 62.3 223 69.8 209.9L99.7 158.1C107.3 144.9 123.1 138.9 137.5 143.7L205.3 166.2C217.4 157.1 230.6 149.5 244.6 143.4L259.1 73.5zM320.3 400C364.5 399.8 400.2 363.9 400 319.7C399.8 275.5 363.9 239.8 319.7 240C275.5 240.2 239.8 276.1 240 320.3C240.2 364.5 276.1 400.2 320.3 400z"
fill="currentColor"
/>
</svg>
</template>

View File

@@ -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;
}
}

View File

@@ -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");

View File

@@ -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<ZoneAssetsDto | null>;
}

View File

@@ -1,5 +1,8 @@
export interface ZoneUnlinkProgressDto {
zoneName: string;
/**
* Between 0-100
*/
percentage: number;
}

View File

@@ -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<ZoneDto[]>;
loadFastFile(path: string): Promise<ZoneLoadedDto>;
unloadZone(zoneName: string): Promise<void>;
}

View File

@@ -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;

View File

@@ -0,0 +1,8 @@
export const PAGE = {
HOME: "Home",
INSPECT: {
SELECT_ZONE: "Inspect zone",
ZONE_DETAILS: "Zone details",
},
OPTIONS: "Options",
};

View File

@@ -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<string, unknown>;
export function useRouteMeta() {
const route = useRoute();
const meta = computed<RouteMeta>(() => route.meta as RouteMeta);
const headerTitle = computed<string | Component>(() => {
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<string | null>(() => meta.value.backTo ?? null);
return { headerTitle, routeNavigateBackTo };
}

View File

@@ -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,
});
}

View File

@@ -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<string | null>(null);
const assetsOfZone = ref<ZoneAssetsDto | null>(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 };
});

View File

@@ -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<number>(0);
const failureMessage = ref<string | null>(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 };
});

View File

@@ -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<string[]>([]);
const loadedZones = ref<ZoneDto[]>([]);
const zonesCurrentlyBeingLoaded = ref<string[]>([]);
const lastPercentageByZoneName = ref<Record<string, number>>({});
const isLoadingZone = computed(() => zonesCurrentlyBeingLoaded.value.length > 0);
function loadFastFile(fastFilePath: string): Promise<ZoneLoadedDto> {
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<ZoneLoadedDto>;
}
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,
};
});

View File

@@ -0,0 +1,5 @@
@use "colors_primitive";
@forward "colors_primitive";
@use "colors_semantic";
@forward "colors_semantic";

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -0,0 +1,3 @@
.icon {
height: 1lh;
}

View File

@@ -0,0 +1,85 @@
import { CommonAssetType } from "@/native/AssetBinds";
const LOOKUP_CAPITALIZED: Record<CommonAssetType, string> = {
[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();
}

View File

@@ -0,0 +1,52 @@
<script setup lang="ts">
import { ref, watch } from "vue";
import { useZoneStore } from "@/stores/ZoneStore";
import ZoneInspectorDetails from "./ZoneInspectorDetails.vue";
import ZoneInspectorZoneList from "./ZoneInspectorZoneList.vue";
import { useAssetStore } from "@/stores/AssetStore";
const assetStore = useAssetStore();
const zoneStore = useZoneStore();
const selectedZone = ref<string | null>(null);
// Make sure we preselect the zone that was last loaded assets for
// if there is one
if (
assetStore.zoneName &&
zoneStore.loadedZones.findIndex((zone) => zone.name === assetStore.zoneName) >= 0
) {
selectedZone.value = assetStore.zoneName;
}
watch(
() => zoneStore.loadedZones,
(newValue) => {
// Reset selection if unloaded
if (!selectedZone.value) return;
if (newValue.findIndex((loadedZone) => loadedZone.name === selectedZone.value) >= 0) return;
selectedZone.value = null;
},
{ deep: true },
);
</script>
<template>
<div class="zone-inspector">
<ZoneInspectorZoneList v-model:selected-zone="selectedZone" />
<ZoneInspectorDetails :selected-zone="selectedZone" />
</div>
</template>
<style lang="scss" scoped>
.zone-inspector {
display: flex;
flex-direction: row;
width: 100%;
& > * {
width: 50%;
padding: 1rem 2rem;
}
}
</style>

View File

@@ -0,0 +1,151 @@
<script setup lang="ts">
import Button from "primevue/button";
import Tag from "primevue/tag";
import MeterGroup, { type MeterItem } from "primevue/metergroup";
import Skeleton from "primevue/skeleton";
import { dt } from "@primeuix/themes";
import type { ZoneDto } from "@/native/ZoneBinds";
import { useZoneStore } from "@/stores/ZoneStore";
import { computed, watch } from "vue";
import type { CommonAssetType } from "@/native/AssetBinds";
import { getAssetTypeNameCapitalized } from "@/utils/AssetTypeName";
import { useRouter } from "vue-router";
import { PAGE } from "@/router/Page";
import { useAssetStore } from "@/stores/AssetStore";
import { storeToRefs } from "pinia";
const assetStore = useAssetStore();
const zoneStore = useZoneStore();
const { assetsOfZone, assetCount, referenceCount } = storeToRefs(assetStore);
const props = defineProps<{
selectedZone: string | null;
}>();
const METER_COLORS = [
dt("blue.600"),
dt("red.600"),
dt("yellow.600"),
dt("green.600"),
dt("purple.600"),
dt("orange.600"),
dt("teal.600"),
dt("lime.600"),
dt("pink.600"),
];
const meterItems = computed<MeterItem[]>(() => {
const assetTypeCounts: Partial<Record<CommonAssetType, number>> = {};
for (const asset of assetsOfZone.value?.assets ?? []) {
if (!assetTypeCounts[asset.type]) {
assetTypeCounts[asset.type] = 1;
} else {
assetTypeCounts[asset.type]!++;
}
}
// Do not display asset types with under 3 percent representation
const minItemCountForDisplay = Math.floor(assetCount.value * 0.03);
const assetMeterItems: MeterItem[] = Object.entries(assetTypeCounts)
.filter((entry) => entry[1] > minItemCountForDisplay)
.sort((e0, e1) => e1[1] - e0[1])
.map((entry) => ({
label: getAssetTypeNameCapitalized(entry[0] as CommonAssetType),
value: Math.round((entry[1] / assetCount.value) * 100),
}));
// Since the PrimeVue component rounds to percent we want to fill up the bar completely
const otherCount = 100 - assetMeterItems.reduce((val, entry) => val + entry.value, 0);
if (otherCount > 0) {
assetMeterItems.push({
label: "Other",
value: otherCount,
});
}
return assetMeterItems.map(
(item, index) =>
({
...item,
color: METER_COLORS[index % METER_COLORS.length],
}) satisfies MeterItem,
);
});
const selectedZoneDetails = computed<ZoneDto | null>(() =>
props.selectedZone ? zoneStore.getLoadedZoneByName(props.selectedZone) : null,
);
const router = useRouter();
function onClickShowAssets() {
if (!props.selectedZone) return;
router.push({
name: PAGE.INSPECT.ZONE_DETAILS,
params: {
zoneName: props.selectedZone,
},
});
}
watch(
() => props.selectedZone,
(newValue) => {
assetStore.loadAssetsForZone(newValue);
},
{ immediate: true },
);
</script>
<template>
<div class="zone-details">
<h2>{{ selectedZone ?? "No zone selected" }}</h2>
<Button label="Show assets" :disabled="!selectedZone" @click="onClickShowAssets" />
<div v-if="selectedZoneDetails" class="zone-tags">
<Tag :value="selectedZoneDetails.game" />
<Tag :value="selectedZoneDetails.platform" />
</div>
<div class="zone-assets">
<template v-if="assetsOfZone">
<div>{{ assetCount }} assets</div>
<div>{{ referenceCount }} references</div>
<MeterGroup class="asset-meter" :value="meterItems" />
</template>
<template v-else-if="selectedZone">
<Skeleton class="count-skeleton" width="10em" />
<Skeleton class="count-skeleton" width="10em" />
<Skeleton class="count-skeleton" height="0.5lh" />
</template>
</div>
</div>
</template>
<style lang="scss" scoped>
.zone-tags {
display: flex;
margin-top: 0.5em;
column-gap: 0.5em;
row-gap: 0.5em;
}
.zone-assets {
margin-top: 0.5em;
display: flex;
flex-direction: column;
}
.asset-meter {
padding-top: 0.5em;
font-size: 0.8em;
line-height: 1.25;
--p-metergroup-gap: 1em;
--p-metergroup-label-list-horizontal-gap: 0.8em;
}
.count-skeleton {
margin-bottom: 0.5em;
}
</style>

View File

@@ -0,0 +1,111 @@
<script setup lang="ts">
import Button from "primevue/button";
import ProgressBar from "primevue/progressbar";
import Listbox from "primevue/listbox";
import { computed } from "vue";
import { useZoneStore } from "@/stores/ZoneStore";
import { webviewBinds } from "@/native";
interface SelectableZone {
isLoading: boolean;
zoneName: string;
}
const zoneStore = useZoneStore();
const selectedZone = defineModel<string | null>("selectedZone");
async function openFastFileSelect() {
return await webviewBinds.openFileDialog({ filters: [{ name: "Fastfiles", filter: "*.ff" }] });
}
async function onOpenFastFileClick() {
const fastFilePath = await openFastFileSelect();
if (!fastFilePath) return;
zoneStore.loadFastFile(fastFilePath);
}
const availableZones = computed<SelectableZone[]>(() => {
const result = [
...zoneStore.zonesCurrentlyBeingLoaded.map(
(zoneBeingLoaded) =>
({
isLoading: true,
zoneName: zoneBeingLoaded,
}) satisfies SelectableZone,
),
...zoneStore.loadedZones.map(
(loadedZone) =>
({
isLoading: false,
zoneName: loadedZone.name,
}) satisfies SelectableZone,
),
];
result.sort((a, b) => a.zoneName.localeCompare(b.zoneName));
return result;
});
function onUnloadClicked() {
if (!selectedZone.value) return;
webviewBinds.unloadZone(selectedZone.value).catch((e: string) => {
console.error("Failed to unload zone:", e);
});
}
</script>
<template>
<div class="zone-list">
<div class="zone-list-actions">
<Button label="Load fastfile" @click="onOpenFastFileClick" />
<Button label="Unload" :disabled="!selectedZone" @click="onUnloadClicked" />
</div>
<Listbox
v-model="selectedZone"
:options="availableZones"
option-disabled="isLoading"
option-value="zoneName"
data-key="zoneName"
emptyMessage="No zones loaded"
class="zone"
>
<template #option="{ option }: { option: SelectableZone }">
<div class="selectable-zone">
<span>{{ option.zoneName }}</span>
<ProgressBar
v-if="option.isLoading"
class="zone-progressbar"
:value="zoneStore.getPercentageForZoneBeingLoaded(option.zoneName)"
:show-value="false"
/>
</div>
</template>
</Listbox>
</div>
</template>
<style lang="scss" scoped>
.zone-list-actions {
display: flex;
column-gap: 0.25em;
row-gap: 0.25em;
padding: 0.25em 0;
}
.selectable-zone {
position: relative;
text-align: left;
width: 100%;
}
.zone-progressbar {
position: absolute;
left: 0;
bottom: 0;
right: 0;
height: 0.2em;
}
</style>

View File

@@ -0,0 +1,87 @@
<script setup lang="ts">
import Skeleton from "primevue/skeleton";
import { useAssetStore } from "@/stores/AssetStore";
import { storeToRefs } from "pinia";
import { ref, watch } from "vue";
import InspectPreview from "./components/InspectPreview.vue";
import InspectAssetDetails from "./components/InspectAssetDetails.vue";
import InspectZoneAssets from "./components/InspectZoneAssets.vue";
import type { AssetDto } from "@/native/AssetBinds.ts";
const assetStore = useAssetStore();
const { assetsOfZone } = storeToRefs(assetStore);
const props = defineProps<{
zoneName: string;
}>();
const selectedAsset = ref<AssetDto | null>(null);
watch(
() => props.zoneName,
(newValue) => {
assetStore.loadAssetsForZone(newValue);
},
{ immediate: true },
);
</script>
<template>
<div class="inspect-details">
<template v-if="assetsOfZone">
<InspectPreview class="inspect-area-preview" />
<InspectAssetDetails :selected-asset="selectedAsset" class="inspect-area-details" />
<InspectZoneAssets
v-model:selected-asset="selectedAsset"
:assets="assetsOfZone.assets"
class="inspect-area-assets"
/>
</template>
<template v-else>
<div class="skeleton-wrapper">
<Skeleton class="count-skeleton" width="100%" height="100%" />
</div>
<div class="skeleton-wrapper">
<Skeleton class="count-skeleton" width="100%" height="100%" />
</div>
<div class="skeleton-wrapper list">
<Skeleton v-for="i in 3" :key="i" class="count-skeleton" width="80%" height="1em" />
</div>
</template>
</div>
</template>
<style lang="scss" scoped>
.inspect-details {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: 30% 1fr;
grid-template-rows: 30% 1fr;
grid-template-areas:
"preview details"
"assets details";
gap: 0.5rem;
padding: 0.5rem;
}
.inspect-area-preview {
grid-area: preview;
}
.inspect-area-details {
grid-area: details;
}
.inspect-area-assets {
grid-area: assets;
}
.skeleton-wrapper {
&.list > *:not(:first-child) {
margin-top: calc(1lh - 1em);
}
}
</style>

View File

@@ -0,0 +1,31 @@
<script setup lang="ts">
import { computed } from "vue";
import type { ZoneDto } from "@/native/ZoneBinds.ts";
import { useZoneStore } from "@/stores/ZoneStore.ts";
import Tag from "primevue/tag";
const zoneStore = useZoneStore();
const props = defineProps<{
zoneName: string;
}>();
const zoneDetails = computed<ZoneDto | null>(() =>
props.zoneName ? zoneStore.getLoadedZoneByName(props.zoneName) : null,
);
</script>
<template>
<span>
<span>Inspect zone: {{ zoneName }}</span>
<template v-if="zoneDetails">
<Tag class="zone-header-tag" :value="zoneDetails.game" severity="secondary" />
<Tag class="zone-header-tag" :value="zoneDetails.platform" severity="secondary" />
</template>
</span>
</template>
<style scoped lang="scss">
.zone-header-tag {
margin-left: 0.5em;
}
</style>

View File

@@ -0,0 +1,37 @@
<script setup lang="ts">
import type { AssetDto } from "@/native/AssetBinds.ts";
import { getAssetTypeNameCapitalized } from "@/utils/AssetTypeName.ts";
defineProps<{
asset: AssetDto;
}>();
</script>
<template>
<div class="asset-option">
<span class="asset-type">{{ getAssetTypeNameCapitalized(asset.type) }}</span>
<span class="asset-name">{{ asset.name }}</span>
</div>
</template>
<style scoped lang="scss">
@use "@style/colors";
.asset-option {
font-size: 0.95rem;
max-width: 100%;
overflow-x: clip;
white-space: nowrap;
padding: 0 0.2em;
}
.asset-type {
display: inline-block;
color: colors.$color-text-muted;
min-width: 8em;
}
.asset-name {
margin-left: 0.5em;
}
</style>

View File

@@ -0,0 +1,39 @@
<script setup lang="ts">
import type { AssetDto } from "@/native/AssetBinds.ts";
import Tag from "primevue/tag";
import { getAssetTypeNameCapitalized } from "@/utils/AssetTypeName.ts";
import { computed } from "vue";
const props = defineProps<{
selectedAsset: AssetDto | null;
}>();
const assetTypeName = computed(() =>
props.selectedAsset ? getAssetTypeNameCapitalized(props.selectedAsset.type) : "",
);
</script>
<template>
<div v-if="selectedAsset">
<h2 class="asset-header">
<span>{{ selectedAsset.name }}</span>
<Tag class="asset-type" :value="assetTypeName" />
</h2>
<div>No details available</div>
</div>
<div v-else>
<div>No asset selected</div>
</div>
</template>
<style scoped lang="scss">
.asset-header {
display: flex;
align-items: center;
margin: 0 0 0.5em 0;
}
.asset-type {
margin-left: 0.5em;
}
</style>

View File

@@ -0,0 +1,23 @@
<script setup lang="ts"></script>
<template>
<div class="preview">
<span>No preview available</span>
</div>
</template>
<style lang="scss" scoped>
@use "@style/colors";
@use "@style/variables";
.preview {
height: 100%;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
background-color: colors.$color-content-hover-background;
border-radius: variables.$border-radius-md;
}
</style>

View File

@@ -0,0 +1,44 @@
<script setup lang="ts">
import Listbox from "primevue/listbox";
import type { AssetDto } from "@/native/AssetBinds.ts";
import AssetListOption from "@/view/inspect_details/components/AssetListOption.vue";
const selectedAsset = defineModel<AssetDto | null>("selectedAsset");
defineProps<{
assets: AssetDto[];
}>();
</script>
<template>
<Listbox
v-model="selectedAsset"
class="asset-list"
:options="assets"
option-label="name"
scroll-height="100%"
:virtual-scroller-options="{ itemSize: 24 }"
>
<template #option="{ option }: { option: AssetDto }">
<AssetListOption :asset="option" />
</template>
</Listbox>
</template>
<style scoped lang="scss">
.asset-list {
--p-listbox-option-padding: 0;
}
:deep(.p-virtualscroller) {
overflow-x: hidden;
max-width: 100%;
}
:deep(.p-listbox-list) {
max-width: 100%;
}
:deep(.p-listbox-list-container) {
height: 100%;
}
</style>

View File

@@ -6,7 +6,8 @@
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"paths": {
"@/*": ["./src/*"]
"@/*": ["./src/*"],
"@style/*": ["./src/style/*"]
}
}
}

View File

@@ -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)),
},
},
});

View File

@@ -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);

View File

@@ -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);

View File

@@ -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<XAssetInfoGeneric*> dependencies,
std::vector<scr_string_t> usedScriptStrings,
std::vector<IndirectAssetReference> 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<const char*> GetAssetTypeName(asset_type_t assetType) const = 0;
[[nodiscard]] virtual asset_type_t GetAssetTypeCount() const = 0;
[[nodiscard]] virtual std::optional<const char*> 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<ZoneAssetPools> CreateForGame(GameId game, Zone* zone, zone_priority_t priority);

View File

@@ -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<ZoneMemory>()),
m_registered(false)

View File

@@ -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<ZoneAssetPools> m_pools;

View File

@@ -69,7 +69,7 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(const ZoneH
return nullptr;
// Create new zone
auto zone = std::make_unique<Zone>(fileName, 0, GameId::IW3);
auto zone = std::make_unique<Zone>(fileName, 0, GameId::IW3, inspectResult->m_platform);
auto* zonePtr = zone.get();
zone->m_pools = std::make_unique<GameAssetPoolIW3>(zonePtr, 0);
zone->m_language = GameLanguage::LANGUAGE_NONE;

View File

@@ -211,7 +211,7 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(const ZoneH
return nullptr;
// Create new zone
auto zone = std::make_unique<Zone>(fileName, 0, GameId::IW4);
auto zone = std::make_unique<Zone>(fileName, 0, GameId::IW4, inspectResult->m_generic_result.m_platform);
auto* zonePtr = zone.get();
zone->m_pools = std::make_unique<GameAssetPoolIW4>(zonePtr, 0);
zone->m_language = GameLanguage::LANGUAGE_NONE;

View File

@@ -165,7 +165,7 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(const ZoneH
return nullptr;
// Create new zone
auto zone = std::make_unique<Zone>(fileName, 0, GameId::IW5);
auto zone = std::make_unique<Zone>(fileName, 0, GameId::IW5, inspectResult->m_platform);
auto* zonePtr = zone.get();
zone->m_pools = std::make_unique<GameAssetPoolIW5>(zonePtr, 0);
zone->m_language = GameLanguage::LANGUAGE_NONE;

View File

@@ -68,7 +68,7 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(const ZoneH
return nullptr;
// Create new zone
auto zone = std::make_unique<Zone>(fileName, 0, GameId::T5);
auto zone = std::make_unique<Zone>(fileName, 0, GameId::T5, inspectResult->m_platform);
auto* zonePtr = zone.get();
zone->m_pools = std::make_unique<GameAssetPoolT5>(zonePtr, 0);
zone->m_language = GameLanguage::LANGUAGE_NONE;

View File

@@ -284,7 +284,7 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(const ZoneH
return nullptr;
// Create new zone
auto zone = std::make_unique<Zone>(fileName, 0, GameId::T6);
auto zone = std::make_unique<Zone>(fileName, 0, GameId::T6, inspectResult->m_generic_result.m_platform);
auto* zonePtr = zone.get();
zone->m_pools = std::make_unique<GameAssetPoolT6>(zonePtr, 0);
zone->m_language = GetZoneLanguage(fileName);

View File

@@ -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),

View File

@@ -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()
{

View File

@@ -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),

View File

@@ -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),

View File

@@ -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()
{

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -551,7 +551,7 @@ namespace
]
})MATERIAL");
Zone zone("MockZone", 0, GameId::IW3);
Zone zone("MockZone", 0, GameId::IW3, GamePlatform::PC);
MemoryManager memory;
MockSearchPath mockObjPath;

View File

@@ -532,7 +532,7 @@ namespace
]
})MATERIAL");
Zone zone("MockZone", 0, GameId::IW4);
Zone zone("MockZone", 0, GameId::IW4, GamePlatform::PC);
MemoryManager memory;
MockSearchPath mockObjPath;

View File

@@ -585,7 +585,7 @@ namespace
]
})MATERIAL");
Zone zone("MockZone", 0, GameId::IW5);
Zone zone("MockZone", 0, GameId::IW5, GamePlatform::PC);
MemoryManager memory;
MockSearchPath mockObjPath;

View File

@@ -614,7 +614,7 @@ namespace
]
})MATERIAL");
Zone zone("MockZone", 0, GameId::T5);
Zone zone("MockZone", 0, GameId::T5, GamePlatform::PC);
MemoryManager memory;
MockSearchPath mockObjPath;

View File

@@ -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;

View File

@@ -462,7 +462,7 @@ namespace
]
})MATERIAL");
Zone zone("MockZone", 0, GameId::T6);
Zone zone("MockZone", 0, GameId::T6, GamePlatform::PC);
MemoryManager memory;
MockSearchPath mockObjPath;