diff --git a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuDef.cpp b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuDef.cpp index e69de29b..a3dfabbf 100644 --- a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuDef.cpp +++ b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuDef.cpp @@ -0,0 +1,17 @@ +#include "AssetLoaderMenuDef.h" + +#include + +#include "ObjLoading.h" +#include "Game/IW4/IW4.h" +#include "Pool/GlobalAssetPool.h" + +using namespace IW4; + +void* AssetLoaderMenuDef::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) +{ + auto* menu = memory->Create(); + memset(menu, 0, sizeof(menuDef_t)); + menu->window.name = memory->Dup(assetName.c_str()); + return menu; +} diff --git a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuDef.h b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuDef.h index bc9bd3b8..1c264b99 100644 --- a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuDef.h +++ b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuDef.h @@ -2,7 +2,6 @@ #include "Game/IW4/IW4.h" #include "AssetLoading/BasicAssetLoader.h" -#include "AssetLoading/IAssetLoadingManager.h" #include "SearchPath/ISearchPath.h" namespace IW4 @@ -11,7 +10,5 @@ namespace IW4 { public: _NODISCARD void* CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) override; - _NODISCARD bool CanLoadFromRaw() const override; - bool LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override; }; } diff --git a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuList.cpp b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuList.cpp index ea85d03d..bcc5f162 100644 --- a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuList.cpp +++ b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuList.cpp @@ -12,6 +12,102 @@ using namespace IW4; +namespace IW4 +{ + class MenuLoader + { + public: + static bool ProcessParsedResults(const std::string& fileName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, menu::ParsingResult* parsingResult, + menu::MenuAssetZoneState* zoneState, MenuConversionZoneState* conversionState, std::vector& menus, std::vector& menuListDependencies) + { + 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 << "Successfully read menu file \"" << fileName << "\" (" << menuLoadCount << " loads, " << menuCount << " menus, " << functionCount << " functions, " << totalItemCount << " items)\n"; + + // 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 allMenusOfFile; + allMenusOfFile.reserve(parsingResult->m_menus.size()); + + // Convert all menus and add them as assets + for (auto& menu : parsingResult->m_menus) + { + MenuConverter converter(ObjLoading::Configuration.MenuNoOptimization, searchPath, memory, manager); + auto* menuAsset = converter.ConvertMenu(*menu); + if (menuAsset == nullptr) + { + std::cout << "Failed to convert menu file \"" << menu->m_name << "\"\n"; + return false; + } + + menus.push_back(menuAsset); + allMenusOfFile.push_back(menuAsset); + auto* menuAssetInfo = manager->AddAsset(ASSET_TYPE_MENU, menu->m_name, menuAsset, std::move(converter.GetDependencies()), std::vector()); + + if (menuAssetInfo) + menuListDependencies.push_back(menuAssetInfo); + + zoneState->AddMenu(std::move(menu)); + } + + // Register this file with all loaded menus + conversionState->AddLoadedFile(fileName, std::move(allMenusOfFile)); + + return true; + } + + static MenuList* CreateMenuListAsset(const std::string& assetName, MemoryManager* memory, const std::vector& menus) + { + auto* menuListAsset = memory->Create(); + menuListAsset->name = memory->Dup(assetName.c_str()); + menuListAsset->menuCount = static_cast(menus.size()); + + if (menuListAsset->menuCount > 0) + { + menuListAsset->menus = static_cast(memory->Alloc(sizeof(uintptr_t) * menuListAsset->menuCount)); + for (auto i = 0; i < menuListAsset->menuCount; i++) + menuListAsset->menus[i] = menus[i]; + } + else + menuListAsset->menus = nullptr; + + return menuListAsset; + } + + static std::unique_ptr ParseMenuFile(const std::string& menuFileName, ISearchPath* searchPath, const menu::MenuAssetZoneState* zoneState) + { + const auto file = searchPath->Open(menuFileName); + if (!file.IsOpen()) + { + std::cerr << "Failed to open menu file \"" << menuFileName << "\"\n"; + return nullptr; + } + + menu::MenuFileReader reader(*file.m_stream, menuFileName, menu::FeatureLevel::IW4, [searchPath](const std::string& filename, const std::string& sourceFile) -> std::unique_ptr + { + auto foundFileToInclude = searchPath->Open(filename); + if (!foundFileToInclude.IsOpen() || !foundFileToInclude.m_stream) + return nullptr; + + return std::move(foundFileToInclude.m_stream); + }); + + reader.IncludeZoneState(zoneState); + reader.SetPermissiveMode(ObjLoading::Configuration.MenuPermissiveParsing); + + return reader.ReadMenuFile(); + } + }; +} + void* AssetLoaderMenuList::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) { auto* menuList = memory->Create(); @@ -25,130 +121,45 @@ bool AssetLoaderMenuList::CanLoadFromRaw() const return true; } -bool AssetLoaderMenuList::ShouldLoadMenuFile(const std::string& menuFilePath, menu::MenuAssetZoneState* zoneState) -{ - const auto alreadyLoadedFile = zoneState->m_loaded_files.find(menuFilePath); - if (alreadyLoadedFile == zoneState->m_loaded_files.end()) - { - zoneState->AddLoadedFile(menuFilePath); - return true; - } - - return false; -} - -void AssetLoaderMenuList::AddMenuFilesToLoadToQueue(std::deque& queue, const menu::ParsingResult* parsingResult, menu::MenuAssetZoneState* zoneState) -{ - for(const auto& menuFileToLoad : parsingResult->m_menus_to_load) - { - if(ShouldLoadMenuFile(menuFileToLoad, zoneState)) - { - queue.push_back(menuFileToLoad); - } - } -} - -bool AssetLoaderMenuList::ProcessParsedResults(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, menu::ParsingResult* parsingResult, - menu::MenuAssetZoneState* zoneState, std::vector& menus, std::vector& menuListDependencies) -{ - 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 << "Successfully read menu file \"" << assetName << "\" (" << menuLoadCount << " loads, " << menuCount << " menus, " << functionCount << " functions, " << totalItemCount << " items)\n"; - - for (auto& function : parsingResult->m_functions) - zoneState->AddFunction(std::move(function)); - - for (auto& menu : parsingResult->m_menus) - { - MenuConverter converter(ObjLoading::Configuration.MenuNoOptimization, searchPath, memory, manager); - auto* menuAsset = converter.ConvertMenu(*menu); - if(menuAsset == nullptr) - { - std::cout << "Failed to convert menu \"" << menu->m_name << "\"\n"; - return false; - } - - menus.push_back(menuAsset); - auto* menuAssetInfo = manager->AddAsset(ASSET_TYPE_MENU, menu->m_name, menuAsset, std::move(converter.GetDependencies()), std::vector()); - - if (menuAssetInfo) - menuListDependencies.push_back(menuAssetInfo); - - zoneState->AddMenu(std::move(menu)); - } - - return true; -} - -MenuList* AssetLoaderMenuList::CreateMenuListAsset(const std::string& assetName, MemoryManager* memory, const std::vector& menus) -{ - auto* menuListAsset = memory->Create(); - menuListAsset->name = memory->Dup(assetName.c_str()); - menuListAsset->menuCount = static_cast(menus.size()); - - if (menuListAsset->menuCount > 0) - { - menuListAsset->menus = static_cast(memory->Alloc(sizeof(uintptr_t) * menuListAsset->menuCount)); - for(auto i = 0; i < menuListAsset->menuCount; i++) - menuListAsset->menus[i] = menus[i]; - } - else - menuListAsset->menus = nullptr; - - return menuListAsset; -} - bool AssetLoaderMenuList::LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const { - std::deque menuFileQueue; std::vector menus; std::vector menuListDependencies; auto* zoneState = manager->GetAssetLoadingContext()->GetZoneAssetLoaderState(); - menuFileQueue.push_back(assetName); + auto* conversionState = manager->GetAssetLoadingContext()->GetZoneAssetLoaderState(); - while (!menuFileQueue.empty()) + const auto menuListResult = MenuLoader::ParseMenuFile(assetName, searchPath, zoneState); + if (menuListResult) + MenuLoader::ProcessParsedResults(assetName, searchPath, memory, manager, menuListResult.get(), zoneState, conversionState, menus, menuListDependencies); + else + std::cerr << "Could not read menu list file \"" << assetName << "\"\n"; + + for(const auto& menuFileToLoad : menuListResult->m_menus_to_load) { - const auto& nextMenuFile = menuFileQueue.front(); - const auto file = searchPath->Open(nextMenuFile); - if (!file.IsOpen()) + const auto alreadyLoadedMenuFile = conversionState->m_menus_by_filename.find(menuFileToLoad); + if(alreadyLoadedMenuFile != conversionState->m_menus_by_filename.end()) { - std::cout << "Failed to open menu file \"" << nextMenuFile << "\"\n"; - return false; + std::cout << "Already loaded \"" << menuFileToLoad << "\", skipping\n"; + for (auto* menu : alreadyLoadedMenuFile->second) + menus.push_back(menu); + continue; } - menu::MenuFileReader reader(*file.m_stream, nextMenuFile, menu::FeatureLevel::IW4, [searchPath](const std::string& filename, const std::string& sourceFile) -> std::unique_ptr - { - auto foundFileToInclude = searchPath->Open(filename); - if (!foundFileToInclude.IsOpen() || !foundFileToInclude.m_stream) - return nullptr; - - return std::move(foundFileToInclude.m_stream); - }); - - reader.IncludeZoneState(zoneState); - reader.SetPermissiveMode(ObjLoading::Configuration.MenuPermissiveParsing); - - const auto menuFileResult = reader.ReadMenuFile(); + const auto menuFileResult = MenuLoader::ParseMenuFile(menuFileToLoad, searchPath, zoneState); if (menuFileResult) { - ProcessParsedResults(nextMenuFile, searchPath, memory, manager, menuFileResult.get(), zoneState, menus, menuListDependencies); - AddMenuFilesToLoadToQueue(menuFileQueue, menuFileResult.get(), zoneState); + MenuLoader::ProcessParsedResults(menuFileToLoad, searchPath, memory, manager, menuFileResult.get(), zoneState, conversionState, menus, menuListDependencies); + if (!menuFileResult->m_menus_to_load.empty()) + std::cout << "WARNING: Menu file has menus to load even though it is not a menu list, ignoring: \"" << menuFileToLoad << "\"\n"; } else - std::cout << "Could not read menu file \"" << nextMenuFile << "\"\n"; - - menuFileQueue.pop_front(); + std::cerr << "Could not read menu file \"" << menuFileToLoad << "\"\n"; } - auto* menuListAsset = CreateMenuListAsset(assetName, memory, menus); + auto* menuListAsset = MenuLoader::CreateMenuListAsset(assetName, memory, menus); - if(menuListAsset) + if (menuListAsset) manager->AddAsset(ASSET_TYPE_MENULIST, assetName, menuListAsset); return true; diff --git a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuList.h b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuList.h index c6a716cb..d7d0209c 100644 --- a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuList.h +++ b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuList.h @@ -1,23 +1,14 @@ #pragma once -#include - #include "Game/IW4/IW4.h" #include "AssetLoading/BasicAssetLoader.h" #include "AssetLoading/IAssetLoadingManager.h" -#include "Parsing/Menu/MenuAssetZoneState.h" -#include "Parsing/Menu/Domain/MenuParsingResult.h" #include "SearchPath/ISearchPath.h" namespace IW4 { class AssetLoaderMenuList final : public BasicAssetLoader { - static bool ShouldLoadMenuFile(const std::string& menuFilePath, menu::MenuAssetZoneState* zoneState); - static void AddMenuFilesToLoadToQueue(std::deque& queue, const menu::ParsingResult* parsingResult, menu::MenuAssetZoneState* zoneState); - static bool ProcessParsedResults(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, menu::ParsingResult* parsingResult, menu::MenuAssetZoneState* zoneState, std::vector& menus, std::vector& menuListDependencies); - static MenuList* CreateMenuListAsset(const std::string& assetName, MemoryManager* memory, const std::vector& menus); - public: _NODISCARD void* CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) override; _NODISCARD bool CanLoadFromRaw() const override; diff --git a/src/ObjLoading/Game/IW4/Menu/MenuConversionZoneStateIW4.cpp b/src/ObjLoading/Game/IW4/Menu/MenuConversionZoneStateIW4.cpp index 178c6758..01d02ce7 100644 --- a/src/ObjLoading/Game/IW4/Menu/MenuConversionZoneStateIW4.cpp +++ b/src/ObjLoading/Game/IW4/Menu/MenuConversionZoneStateIW4.cpp @@ -73,6 +73,11 @@ const char* MenuConversionZoneState::AddString(const std::string& str) return strDuped; } +void MenuConversionZoneState::AddLoadedFile(std::string loadedFileName, std::vector menusOfFile) +{ + m_menus_by_filename.emplace(std::make_pair(std::move(loadedFileName), std::move(menusOfFile))); +} + void MenuConversionZoneState::FinalizeSupportingData() const { auto* memory = m_zone->GetMemory(); diff --git a/src/ObjLoading/Game/IW4/Menu/MenuConversionZoneStateIW4.h b/src/ObjLoading/Game/IW4/Menu/MenuConversionZoneStateIW4.h index 46329251..3ead70c4 100644 --- a/src/ObjLoading/Game/IW4/Menu/MenuConversionZoneStateIW4.h +++ b/src/ObjLoading/Game/IW4/Menu/MenuConversionZoneStateIW4.h @@ -20,6 +20,7 @@ namespace IW4 std::map m_strings_by_value; public: + std::map> m_menus_by_filename; ExpressionSupportingData* m_supporting_data; MenuConversionZoneState(); @@ -31,6 +32,8 @@ namespace IW4 size_t AddStaticDvar(const std::string& dvarName); const char* AddString(const std::string& str); + void AddLoadedFile(std::string loadedFileName, std::vector menusOfFile); + void FinalizeSupportingData() const; }; } diff --git a/src/ObjLoading/Parsing/Menu/MenuAssetZoneState.cpp b/src/ObjLoading/Parsing/Menu/MenuAssetZoneState.cpp index 5f2d9387..1d80eaef 100644 --- a/src/ObjLoading/Parsing/Menu/MenuAssetZoneState.cpp +++ b/src/ObjLoading/Parsing/Menu/MenuAssetZoneState.cpp @@ -2,11 +2,6 @@ using namespace menu; -void MenuAssetZoneState::AddLoadedFile(std::string loadedFileName) -{ - m_loaded_files.emplace(std::move(loadedFileName)); -} - void MenuAssetZoneState::AddFunction(std::unique_ptr function) { m_functions_by_name.emplace(std::make_pair(function->m_name, function.get())); diff --git a/src/ObjLoading/Parsing/Menu/MenuAssetZoneState.h b/src/ObjLoading/Parsing/Menu/MenuAssetZoneState.h index 2671032a..b994b681 100644 --- a/src/ObjLoading/Parsing/Menu/MenuAssetZoneState.h +++ b/src/ObjLoading/Parsing/Menu/MenuAssetZoneState.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include "AssetLoading/IZoneAssetLoaderState.h" @@ -12,15 +11,13 @@ namespace menu class MenuAssetZoneState final : public IZoneAssetLoaderState { public: - std::set m_loaded_files; std::vector> m_functions; std::vector> m_menus; std::map m_functions_by_name; MenuAssetZoneState() = default; - - void AddLoadedFile(std::string loadedFileName); + void AddFunction(std::unique_ptr function); void AddMenu(std::unique_ptr menu); };