mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-19 07:42:54 +00:00
221 lines
8.9 KiB
C++
221 lines
8.9 KiB
C++
#include "LoaderMenuListIW4.h"
|
|
|
|
#include "Game/IW4/IW4.h"
|
|
#include "Game/IW4/Menu/MenuConversionZoneStateIW4.h"
|
|
#include "Game/IW4/Menu/MenuConverterIW4.h"
|
|
#include "ObjLoading.h"
|
|
#include "Parsing/Menu/MenuFileReader.h"
|
|
|
|
#include <cstring>
|
|
#include <format>
|
|
#include <iostream>
|
|
|
|
using namespace IW4;
|
|
|
|
namespace
|
|
{
|
|
class MenuListLoader final : public AssetCreator<AssetMenuList>
|
|
{
|
|
public:
|
|
MenuListLoader(MemoryManager& memory, ISearchPath& searchPath)
|
|
: m_memory(memory),
|
|
m_search_path(searchPath)
|
|
{
|
|
}
|
|
|
|
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
|
{
|
|
std::vector<menuDef_t*> menus;
|
|
AssetRegistration<AssetMenuList> registration(assetName);
|
|
|
|
auto* zoneState = context.GetZoneAssetLoaderState<menu::MenuAssetZoneState>();
|
|
auto* conversionState = context.GetZoneAssetLoaderState<MenuConversionZoneState>();
|
|
|
|
std::deque<std::string> menuLoadQueue;
|
|
const auto alreadyLoadedMenuListFileMenus = conversionState->m_menus_by_filename.find(assetName);
|
|
|
|
if (alreadyLoadedMenuListFileMenus == conversionState->m_menus_by_filename.end())
|
|
{
|
|
const auto file = m_search_path.Open(assetName);
|
|
if (!file.IsOpen())
|
|
return AssetCreationResult::NoAction();
|
|
|
|
const auto menuListResult = ParseMenuFile(*file.m_stream, assetName, zoneState);
|
|
if (menuListResult)
|
|
{
|
|
ProcessParsedResults(assetName, context, menuListResult.get(), zoneState, conversionState, menus, registration);
|
|
|
|
for (const auto& menuToLoad : menuListResult->m_menus_to_load)
|
|
menuLoadQueue.emplace_back(menuToLoad);
|
|
|
|
zoneState->AddMenusToLoad(assetName, std::move(menuListResult->m_menus_to_load));
|
|
}
|
|
else
|
|
return AssetCreationResult::Failure();
|
|
}
|
|
|
|
while (!menuLoadQueue.empty())
|
|
{
|
|
const auto& menuFileToLoad = menuLoadQueue.front();
|
|
|
|
LoadMenuFileFromQueue(menuFileToLoad, context, zoneState, conversionState, menus, registration);
|
|
|
|
menuLoadQueue.pop_front();
|
|
}
|
|
|
|
auto* menuListAsset = m_memory.Create<MenuList>();
|
|
menuListAsset->name = m_memory.Dup(assetName.c_str());
|
|
registration.SetAsset(menuListAsset);
|
|
|
|
CreateMenuListAsset(*menuListAsset, menus);
|
|
|
|
return AssetCreationResult::Success(context.AddAsset(std::move(registration)));
|
|
}
|
|
|
|
void FinalizeZone(AssetCreationContext& context) override
|
|
{
|
|
context.GetZoneAssetLoaderState<MenuConversionZoneState>()->FinalizeSupportingData();
|
|
}
|
|
|
|
private:
|
|
bool LoadMenuFileFromQueue(const std::string& menuFilePath,
|
|
AssetCreationContext& context,
|
|
menu::MenuAssetZoneState* zoneState,
|
|
MenuConversionZoneState* conversionState,
|
|
std::vector<menuDef_t*>& menus,
|
|
AssetRegistration<AssetMenuList>& registration)
|
|
{
|
|
const auto alreadyLoadedMenuFile = conversionState->m_menus_by_filename.find(menuFilePath);
|
|
if (alreadyLoadedMenuFile != conversionState->m_menus_by_filename.end())
|
|
{
|
|
std::cout << std::format("Already loaded \"{}\", skipping\n", menuFilePath);
|
|
for (auto* menu : alreadyLoadedMenuFile->second)
|
|
{
|
|
menus.emplace_back(menu->Asset());
|
|
registration.AddDependency(menu);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
const auto file = m_search_path.Open(menuFilePath);
|
|
if (!file.IsOpen())
|
|
{
|
|
std::cerr << std::format("Could not open menu file \"{}\"\n", menuFilePath);
|
|
return false;
|
|
}
|
|
|
|
const auto menuFileResult = ParseMenuFile(*file.m_stream, menuFilePath, zoneState);
|
|
if (menuFileResult)
|
|
{
|
|
ProcessParsedResults(menuFilePath, context, menuFileResult.get(), zoneState, conversionState, menus, registration);
|
|
if (!menuFileResult->m_menus_to_load.empty())
|
|
std::cout << std::format("WARNING: Menu file has menus to load even though it is not a menu list, ignoring: \"{}\"\n", menuFilePath);
|
|
|
|
return true;
|
|
}
|
|
else
|
|
std::cerr << std::format("Could not read menu file \"{}\"\n", menuFilePath);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ProcessParsedResults(const std::string& fileName,
|
|
AssetCreationContext& context,
|
|
menu::ParsingResult* parsingResult,
|
|
menu::MenuAssetZoneState* zoneState,
|
|
MenuConversionZoneState* conversionState,
|
|
std::vector<menuDef_t*>& menus,
|
|
AssetRegistration<AssetMenuList>& registration)
|
|
{
|
|
const auto menuCount = parsingResult->m_menus.size();
|
|
const auto functionCount = parsingResult->m_functions.size();
|
|
const auto menuLoadCount = parsingResult->m_menus_to_load.size();
|
|
auto totalItemCount = 0u;
|
|
for (const auto& menu : parsingResult->m_menus)
|
|
totalItemCount += menu->m_items.size();
|
|
|
|
std::cout << std::format("Successfully read menu file \"{}\" ({} loads, {} menus, {} functions, {} items)\n",
|
|
fileName,
|
|
menuLoadCount,
|
|
menuCount,
|
|
functionCount,
|
|
totalItemCount);
|
|
|
|
// Add all functions to the zone state to make them available for all menus to be converted
|
|
for (auto& function : parsingResult->m_functions)
|
|
zoneState->AddFunction(std::move(function));
|
|
|
|
// Prepare a list of all menus of this file
|
|
std::vector<XAssetInfo<menuDef_t>*> allMenusOfFile;
|
|
allMenusOfFile.reserve(parsingResult->m_menus.size());
|
|
|
|
// Convert all menus and add them as assets
|
|
for (auto& commonMenu : parsingResult->m_menus)
|
|
{
|
|
auto converter = IMenuConverter::Create(ObjLoading::Configuration.MenuNoOptimization, m_search_path, m_memory, context);
|
|
|
|
auto* menuAsset = m_memory.Alloc<menuDef_t>();
|
|
AssetRegistration<AssetMenu> menuRegistration(commonMenu->m_name, menuAsset);
|
|
|
|
converter->ConvertMenu(*commonMenu, *menuAsset, menuRegistration);
|
|
if (menuAsset == nullptr)
|
|
{
|
|
std::cerr << std::format("Failed to convert menu file \"{}\"\n", commonMenu->m_name);
|
|
return false;
|
|
}
|
|
|
|
menus.emplace_back(menuAsset);
|
|
auto* menuAssetInfo = context.AddAsset(std::move(menuRegistration));
|
|
|
|
if (menuAssetInfo)
|
|
{
|
|
allMenusOfFile.emplace_back(menuAssetInfo);
|
|
registration.AddDependency(menuAssetInfo);
|
|
}
|
|
|
|
zoneState->AddMenu(std::move(commonMenu));
|
|
}
|
|
|
|
// Register this file with all loaded menus
|
|
conversionState->AddLoadedFile(fileName, std::move(allMenusOfFile));
|
|
|
|
return true;
|
|
}
|
|
|
|
void CreateMenuListAsset(MenuList& menuList, const std::vector<menuDef_t*>& menus)
|
|
{
|
|
menuList.menuCount = static_cast<int>(menus.size());
|
|
|
|
if (menuList.menuCount > 0)
|
|
{
|
|
menuList.menus = m_memory.Alloc<menuDef_t*>(menuList.menuCount);
|
|
for (auto i = 0; i < menuList.menuCount; i++)
|
|
menuList.menus[i] = menus[i];
|
|
}
|
|
else
|
|
menuList.menus = nullptr;
|
|
}
|
|
|
|
std::unique_ptr<menu::ParsingResult> ParseMenuFile(std::istream& stream, const std::string& menuFileName, const menu::MenuAssetZoneState* zoneState)
|
|
{
|
|
menu::MenuFileReader reader(stream, menuFileName, menu::FeatureLevel::IW4, m_search_path);
|
|
|
|
reader.IncludeZoneState(zoneState);
|
|
reader.SetPermissiveMode(ObjLoading::Configuration.MenuPermissiveParsing);
|
|
|
|
return reader.ReadMenuFile();
|
|
}
|
|
|
|
MemoryManager& m_memory;
|
|
ISearchPath& m_search_path;
|
|
};
|
|
} // namespace
|
|
|
|
namespace IW4
|
|
{
|
|
std::unique_ptr<AssetCreator<AssetMenuList>> CreateMenuListLoader(MemoryManager& memory, ISearchPath& searchPath)
|
|
{
|
|
return std::make_unique<MenuListLoader>(memory, searchPath);
|
|
}
|
|
} // namespace IW4
|