From 191965a970532eac1ad44f782c945e812f876545 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 21 Apr 2024 18:44:28 +0200 Subject: [PATCH] chore: do not only load infostring arrays as pairs but n entries --- .../IW4/AssetLoaders/AssetLoaderWeapon.cpp | 12 +- .../InfoStringToStructConverter.cpp | 227 ++++++++++++++++++ .../T6/AssetLoaders/AssetLoaderWeapon.cpp | 12 +- .../InfoStringToStructConverterBase.cpp | 62 ----- .../InfoStringToStructConverterBase.h | 79 +++++- 5 files changed, 317 insertions(+), 75 deletions(-) diff --git a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderWeapon.cpp b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderWeapon.cpp index 268f9b58..ccc8df95 100644 --- a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderWeapon.cpp +++ b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderWeapon.cpp @@ -84,8 +84,8 @@ namespace _NODISCARD bool ConvertNotetrackMap(const cspField_t& field, const std::string& value, const char* mapName, const size_t keyAndValueCount) { - std::vector> pairs; - if (!ParseAsPairs(value, pairs)) + std::vector> pairs; + if (!ParseAsArray(value, pairs)) { std::cerr << "Failed to parse notetrack" << mapName << "map as pairs\n"; return false; @@ -110,10 +110,10 @@ namespace for (; currentEntryNum < pairs.size(); currentEntryNum++) { const auto& currentValue = pairs[currentEntryNum]; - const auto keyScriptString = !currentValue.first.empty() ? m_zone_script_strings.AddOrGetScriptString(currentValue.first) - : m_zone_script_strings.AddOrGetScriptString(nullptr); - const auto valueScriptString = !currentValue.second.empty() ? m_zone_script_strings.AddOrGetScriptString(currentValue.second) - : m_zone_script_strings.AddOrGetScriptString(nullptr); + const auto keyScriptString = !currentValue[0].empty() ? m_zone_script_strings.AddOrGetScriptString(currentValue[0]) + : m_zone_script_strings.AddOrGetScriptString(nullptr); + const auto valueScriptString = !currentValue[1].empty() ? m_zone_script_strings.AddOrGetScriptString(currentValue[1]) + : m_zone_script_strings.AddOrGetScriptString(nullptr); keys[currentEntryNum] = keyScriptString; m_used_script_string_list.emplace(keyScriptString); diff --git a/src/ObjLoading/Game/IW5/InfoString/InfoStringToStructConverter.cpp b/src/ObjLoading/Game/IW5/InfoString/InfoStringToStructConverter.cpp index b68d2bc9..e6a057f4 100644 --- a/src/ObjLoading/Game/IW5/InfoString/InfoStringToStructConverter.cpp +++ b/src/ObjLoading/Game/IW5/InfoString/InfoStringToStructConverter.cpp @@ -1,3 +1,230 @@ #include "InfoStringToStructConverter.h" +#include +#include + using namespace IW5; + +InfoStringToStructConverter::InfoStringToStructConverter(const InfoString& infoString, + void* structure, + ZoneScriptStrings& zoneScriptStrings, + MemoryManager* memory, + IAssetLoadingManager* manager, + const cspField_t* fields, + const size_t fieldCount) + : InfoStringToStructConverterBase(infoString, structure, zoneScriptStrings, memory), + m_loading_manager(manager), + m_fields(fields), + m_field_count(fieldCount) +{ +} + +bool InfoStringToStructConverter::ConvertBaseField(const cspField_t& field, const std::string& value) +{ + switch (static_cast(field.iFieldType)) + { + case CSPFT_STRING: + return ConvertString(value, field.iOffset); + + case CSPFT_STRING_MAX_STRING_CHARS: + return ConvertStringBuffer(value, field.iOffset, 1024); + + case CSPFT_STRING_MAX_QPATH: + return ConvertStringBuffer(value, field.iOffset, 64); + + case CSPFT_STRING_MAX_OSPATH: + return ConvertStringBuffer(value, field.iOffset, 256); + + case CSPFT_INT: + return ConvertInt(value, field.iOffset); + + case CSPFT_BOOL: + return ConvertBool(value, field.iOffset); + + case CSPFT_QBOOLEAN: + return ConvertQBoolean(value, field.iOffset); + + case CSPFT_FLOAT: + return ConvertFloat(value, field.iOffset); + + case CSPFT_MILLISECONDS: + return ConvertMilliseconds(value, field.iOffset); + + case CSPFT_FX: + { + if (value.empty()) + { + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = nullptr; + return true; + } + + auto* fx = m_loading_manager->LoadDependency(ASSET_TYPE_FX, value); + + if (fx == nullptr) + { + std::cout << "Failed to load fx asset \"" << value << "\"\n"; + return false; + } + + m_dependencies.emplace(fx); + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = fx->m_ptr; + + return true; + } + + case CSPFT_XMODEL: + { + if (value.empty()) + { + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = nullptr; + return true; + } + + auto* xmodel = m_loading_manager->LoadDependency(ASSET_TYPE_XMODEL, value); + + if (xmodel == nullptr) + { + std::cout << "Failed to load xmodel asset \"" << value << "\"\n"; + return false; + } + + m_dependencies.emplace(xmodel); + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = xmodel->m_ptr; + + return true; + } + + case CSPFT_MATERIAL: + { + if (value.empty()) + { + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = nullptr; + return true; + } + + auto* material = m_loading_manager->LoadDependency(ASSET_TYPE_MATERIAL, value); + + if (material == nullptr) + { + std::cout << "Failed to load material asset \"" << value << "\"\n"; + return false; + } + + m_dependencies.emplace(material); + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = material->m_ptr; + + return true; + } + + case CSPFT_TRACER: + { + if (value.empty()) + { + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = nullptr; + return true; + } + + auto* tracer = m_loading_manager->LoadDependency(ASSET_TYPE_TRACER, value); + + if (tracer == nullptr) + { + std::cout << "Failed to load tracer asset \"" << value << "\"\n"; + return false; + } + + m_dependencies.emplace(tracer); + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = tracer->m_ptr; + + return true; + } + + case CSPFT_MPH_TO_INCHES_PER_SEC: + { + char* endPtr; + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = strtof(value.c_str(), &endPtr) * 17.6f; + + if (endPtr != &value[value.size()]) + { + std::cout << "Failed to parse value \"" << value << "\" as mph\n"; + return false; + } + + return true; + } + + case CSPFT_PHYS_COLLMAP: + { + if (value.empty()) + { + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = nullptr; + return true; + } + + auto* collmap = m_loading_manager->LoadDependency(ASSET_TYPE_PHYSCOLLMAP, value); + + if (collmap == nullptr) + { + std::cout << "Failed to load collmap asset \"" << value << "\"\n"; + return false; + } + + m_dependencies.emplace(collmap); + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = collmap->m_ptr; + + return true; + } + + case CSPFT_SOUND: + { + if (value.empty()) + { + reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset)->name = nullptr; + return true; + } + + auto* name = static_cast(m_memory->Alloc(sizeof(snd_alias_list_name))); + name->soundName = m_memory->Dup(value.c_str()); + + reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset)->name = name; + + m_indirect_asset_references.emplace(ASSET_TYPE_SOUND, value); + return true; + } + + case CSPFT_SCRIPT_STRING: + return ConvertScriptString(value, field.iOffset); + + case CSPFT_NUM_BASE_FIELD_TYPES: + default: + assert(false); + return false; + } +} + +bool InfoStringToStructConverter::Convert() +{ + for (auto fieldIndex = 0u; fieldIndex < m_field_count; fieldIndex++) + { + const auto& field = m_fields[fieldIndex]; + assert(field.iFieldType >= 0); + + auto foundValue = false; + const auto& value = m_info_string.GetValueForKey(std::string(field.szName), &foundValue); + + if (foundValue) + { + if (field.iFieldType < CSPFT_NUM_BASE_FIELD_TYPES) + { + if (!ConvertBaseField(field, value)) + return false; + } + else + { + if (!ConvertExtensionField(field, value)) + return false; + } + } + } + + return true; +} diff --git a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderWeapon.cpp b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderWeapon.cpp index 4c0b4c4a..9df4a899 100644 --- a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderWeapon.cpp +++ b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderWeapon.cpp @@ -81,8 +81,8 @@ namespace T6 _NODISCARD bool ConvertNotetrackSoundMap(const cspField_t& field, const std::string& value) { - std::vector> pairs; - if (!ParseAsPairs(value, pairs)) + std::vector> pairs; + if (!ParseAsArray(value, pairs)) { std::cerr << "Failed to parse notetracksoundmap as pairs\n"; return false; @@ -106,10 +106,10 @@ namespace T6 for (; currentEntryNum < pairs.size(); currentEntryNum++) { const auto& currentValue = pairs[currentEntryNum]; - const auto keyScriptString = !currentValue.first.empty() ? m_zone_script_strings.AddOrGetScriptString(currentValue.first) - : m_zone_script_strings.AddOrGetScriptString(nullptr); - const auto valueScriptString = !currentValue.second.empty() ? m_zone_script_strings.AddOrGetScriptString(currentValue.second) - : m_zone_script_strings.AddOrGetScriptString(nullptr); + const auto keyScriptString = !currentValue[0].empty() ? m_zone_script_strings.AddOrGetScriptString(currentValue[0]) + : m_zone_script_strings.AddOrGetScriptString(nullptr); + const auto valueScriptString = !currentValue[1].empty() ? m_zone_script_strings.AddOrGetScriptString(currentValue[1]) + : m_zone_script_strings.AddOrGetScriptString(nullptr); keys[currentEntryNum] = keyScriptString; m_used_script_string_list.emplace(keyScriptString); diff --git a/src/ObjLoading/InfoString/InfoStringToStructConverterBase.cpp b/src/ObjLoading/InfoString/InfoStringToStructConverterBase.cpp index a5d28a0f..02ebfeec 100644 --- a/src/ObjLoading/InfoString/InfoStringToStructConverterBase.cpp +++ b/src/ObjLoading/InfoString/InfoStringToStructConverterBase.cpp @@ -41,68 +41,6 @@ bool InfoStringToStructConverterBase::ParseAsArray(const std::string& value, std return true; } -bool InfoStringToStructConverterBase::ParseAsPairs(const std::string& value, std::vector>& valueArray) -{ - std::string key; - auto isKey = true; - - for (auto ci = 0u; ci < value.size(); ci++) - { - auto c = value[ci]; - - if (c == '\r' && ci + 1 < value.size() && value[ci + 1] == '\n') - c = value[++ci]; - - if (c == '\n' && !isKey) - { - std::cout << "Expected value but got new line\n"; - return false; - } - - if (isspace(c)) - continue; - - int separator; - const auto startPos = ci; - while (true) - { - ci++; - if (ci >= value.size()) - { - separator = EOF; - break; - } - c = value[ci]; - if (c == '\r' && ci + 1 < value.size() && value[ci + 1] == '\n') - c = value[++ci]; - if (isspace(c)) - { - separator = static_cast(static_cast(c)); - break; - } - } - - if (isKey) - { - if (separator == '\n' || separator == EOF) - { - std::cout << "Expected value but got new line\n"; - return false; - } - key = std::string(value, startPos, ci - startPos); - } - else - { - auto parsedValue = std::string(value, startPos, ci - startPos); - valueArray.emplace_back(std::make_pair(std::move(key), std::move(parsedValue))); - key = std::string(); - } - isKey = !isKey; - } - - return true; -} - bool InfoStringToStructConverterBase::ConvertString(const std::string& value, const size_t offset) { *reinterpret_cast(reinterpret_cast(m_structure) + offset) = m_memory->Dup(value.c_str()); diff --git a/src/ObjLoading/InfoString/InfoStringToStructConverterBase.h b/src/ObjLoading/InfoString/InfoStringToStructConverterBase.h index 8d74fcdc..d25e2084 100644 --- a/src/ObjLoading/InfoString/InfoStringToStructConverterBase.h +++ b/src/ObjLoading/InfoString/InfoStringToStructConverterBase.h @@ -6,6 +6,8 @@ #include "Utils/MemoryManager.h" #include "Zone/ZoneScriptStrings.h" +#include +#include #include #include #include @@ -22,7 +24,82 @@ protected: void* m_structure; static bool ParseAsArray(const std::string& value, std::vector& valueArray); - static bool ParseAsPairs(const std::string& value, std::vector>& valueArray); + + template static bool ParseAsArray(const std::string& value, std::vector>& valueArray) + { + static_assert(ARRAY_SIZE >= 1); + + std::array currentEntry; + auto currentEntryOffset = 0u; + + for (auto ci = 0u; ci < value.size(); ci++) + { + auto c = value[ci]; + + if (c == '\r' && ci + 1 < value.size() && value[ci + 1] == '\n') + c = value[++ci]; + + if (c == '\n' && currentEntryOffset != ARRAY_SIZE) + { + std::cerr << "Expected value but got new line\n"; + return false; + } + + if (isspace(c)) + continue; + + int separator; + const auto startPos = ci; + while (true) + { + ci++; + + // If value ends we use EOF as separator + if (ci >= value.size()) + { + separator = EOF; + break; + } + + c = value[ci]; + + // Skip \r from \r\n + if (c == '\r' && ci + 1 < value.size() && value[ci + 1] == '\n') + c = value[++ci]; + + // Newline is considered space + if (isspace(c)) + { + separator = static_cast(static_cast(c)); + break; + } + } + + const auto isNextEntrySeparator = separator == '\n' || separator == EOF; + const auto isLastEntry = currentEntryOffset >= (ARRAY_SIZE - 1); + if (isNextEntrySeparator != isLastEntry) + { + std::cout << "Expected " << ARRAY_SIZE << " values but got new line\n"; + return false; + } + + currentEntry[currentEntryOffset++] = std::string(value, startPos, ci - startPos); + + if (isLastEntry) + { + valueArray.emplace_back(std::move(currentEntry)); + currentEntryOffset = 0u; + } + } + + if (currentEntryOffset > 0) + { + std::cout << "Expected " << ARRAY_SIZE << " values but got new line\n"; + return false; + } + + return true; + } bool ConvertString(const std::string& value, size_t offset); bool ConvertStringBuffer(const std::string& value, size_t offset, size_t bufferSize);