mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2026-09-11 16:37:06 +00:00
chore: align iw3,iw4,iw5 menu code (#987)
* chore: small adjustments to iw3 menu dumper * chore: align iw4 menu loader closer to iw3 * chore: align iw4 menu dumper closer to iw3 * chore: adjust iw4 menu expression dumping * chore: adjust iw4 menu expression converting * chore: align iw5 menu loader closer to iw3 * chore: align iw4 menu dumper closer to iw3 * chore: adjust iw5 menu expression dumping * chore: adjust iw5 menu expression converting * fix: not respecting reference menus when inlining menu list menus * fix: compilation on linux
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <format>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
#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 "Utils/Logging/Log.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <deque>
|
||||
|
||||
using namespace IW4;
|
||||
|
||||
@@ -44,7 +41,8 @@ namespace
|
||||
const auto menuListResult = ParseMenuFile(*file.m_stream, assetName, zoneState);
|
||||
if (menuListResult)
|
||||
{
|
||||
ProcessParsedResults(assetName, context, *menuListResult, zoneState, conversionState, menus, registration);
|
||||
if (!ProcessParsedResults(assetName, context, *menuListResult, zoneState, conversionState, menus, registration))
|
||||
return AssetCreationResult::Failure();
|
||||
|
||||
for (const auto& menuToLoad : menuListResult->m_menus_to_load)
|
||||
menuLoadQueue.emplace_back(menuToLoad);
|
||||
@@ -59,7 +57,8 @@ namespace
|
||||
{
|
||||
const auto& menuFileToLoad = menuLoadQueue.front();
|
||||
|
||||
LoadMenuFileFromQueue(menuFileToLoad, context, zoneState, conversionState, menus, registration);
|
||||
if (!LoadMenuFileFromQueue(menuFileToLoad, context, zoneState, conversionState, menus, registration))
|
||||
return AssetCreationResult::Failure();
|
||||
|
||||
menuLoadQueue.pop_front();
|
||||
}
|
||||
@@ -108,7 +107,8 @@ namespace
|
||||
const auto menuFileResult = ParseMenuFile(*file.m_stream, menuFilePath, zoneState);
|
||||
if (menuFileResult)
|
||||
{
|
||||
ProcessParsedResults(menuFilePath, context, *menuFileResult, zoneState, conversionState, menus, registration);
|
||||
if (!ProcessParsedResults(menuFilePath, context, *menuFileResult, zoneState, conversionState, menus, registration))
|
||||
return false;
|
||||
if (!menuFileResult->m_menus_to_load.empty())
|
||||
con::warn("Menu file has menus to load even though it is not a menu list, ignoring: \"{}\"", menuFilePath);
|
||||
|
||||
@@ -158,8 +158,7 @@ namespace
|
||||
auto* menuAsset = m_memory.Alloc<menuDef_t>();
|
||||
AssetRegistration<AssetMenu> menuRegistration(commonMenu->m_name, menuAsset);
|
||||
|
||||
converter->ConvertMenu(*commonMenu, *menuAsset, menuRegistration);
|
||||
if (menuAsset == nullptr)
|
||||
if (!converter->ConvertMenu(*commonMenu, *menuAsset, menuRegistration))
|
||||
{
|
||||
con::error("Failed to convert menu file \"{}\"", commonMenu->m_name);
|
||||
return false;
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
namespace menu
|
||||
{
|
||||
std::unique_ptr<AssetCreator<IW4::AssetMenuList>> CreateMenuListLoaderIW4(MemoryManager& memory, ISearchPath& searchPath);
|
||||
} // namespace menu
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ const char* MenuConversionZoneState::AddString(const std::string& str)
|
||||
|
||||
void MenuConversionZoneState::AddLoadedFile(std::string loadedFileName, std::vector<XAssetInfo<menuDef_t>*> menusOfFile)
|
||||
{
|
||||
m_menus_by_filename.emplace(std::make_pair(std::move(loadedFileName), std::move(menusOfFile)));
|
||||
m_menus_by_filename.emplace(std::move(loadedFileName), std::move(menusOfFile));
|
||||
}
|
||||
|
||||
void MenuConversionZoneState::FinalizeSupportingData() const
|
||||
|
||||
@@ -3,26 +3,15 @@
|
||||
#include "Asset/IZoneAssetCreationState.h"
|
||||
#include "Game/IW4/IW4.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace IW4
|
||||
{
|
||||
class MenuConversionZoneState final : public IZoneAssetCreationState
|
||||
{
|
||||
Zone* m_zone;
|
||||
std::vector<Statement_s*> m_functions;
|
||||
std::map<std::string, Statement_s*> m_function_by_name;
|
||||
|
||||
std::vector<StaticDvar*> m_static_dvars;
|
||||
std::map<std::string, size_t> m_dvars_by_name;
|
||||
|
||||
std::vector<const char*> m_strings;
|
||||
std::map<std::string, const char*> m_strings_by_value;
|
||||
|
||||
public:
|
||||
std::map<std::string, std::vector<XAssetInfo<menuDef_t>*>> m_menus_by_filename;
|
||||
ExpressionSupportingData* m_supporting_data;
|
||||
|
||||
MenuConversionZoneState();
|
||||
void Inject(ZoneAssetCreationInjection& inject) override;
|
||||
|
||||
@@ -35,5 +24,19 @@ namespace IW4
|
||||
void AddLoadedFile(std::string loadedFileName, std::vector<XAssetInfo<menuDef_t>*> menusOfFile);
|
||||
|
||||
void FinalizeSupportingData() const;
|
||||
|
||||
std::unordered_map<std::string, std::vector<XAssetInfo<menuDef_t>*>> m_menus_by_filename;
|
||||
ExpressionSupportingData* m_supporting_data;
|
||||
|
||||
private:
|
||||
Zone* m_zone;
|
||||
std::vector<Statement_s*> m_functions;
|
||||
std::unordered_map<std::string, Statement_s*> m_function_by_name;
|
||||
|
||||
std::vector<StaticDvar*> m_static_dvars;
|
||||
std::unordered_map<std::string, size_t> m_dvars_by_name;
|
||||
|
||||
std::vector<const char*> m_strings;
|
||||
std::unordered_map<std::string, const char*> m_strings_by_value;
|
||||
};
|
||||
} // namespace IW4
|
||||
|
||||
@@ -13,35 +13,37 @@
|
||||
#include "Parsing/Simple/Expression/SimpleExpressionUnaryOperation.h"
|
||||
#include "Utils/StringUtils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <format>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
using namespace IW4;
|
||||
using namespace menu;
|
||||
|
||||
namespace
|
||||
{
|
||||
class MenuConverter : public AbstractMenuConverter, public IMenuConverter
|
||||
class MenuConverter final : public AbstractMenuConverter, public IMenuConverter
|
||||
{
|
||||
[[nodiscard]] static rectDef_s ConvertRectDef(const CommonRect& rect)
|
||||
{
|
||||
return rectDef_s{
|
||||
static_cast<float>(rect.x),
|
||||
static_cast<float>(rect.y),
|
||||
static_cast<float>(rect.w),
|
||||
static_cast<float>(rect.h),
|
||||
static_cast<unsigned char>(rect.horizontalAlign),
|
||||
static_cast<unsigned char>(rect.verticalAlign),
|
||||
.x = static_cast<float>(rect.x),
|
||||
.y = static_cast<float>(rect.y),
|
||||
.w = static_cast<float>(rect.w),
|
||||
.h = static_cast<float>(rect.h),
|
||||
.horzAlign = static_cast<unsigned char>(rect.horizontalAlign),
|
||||
.vertAlign = static_cast<unsigned char>(rect.verticalAlign),
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] static rectDef_s ConvertRectDefRelativeTo(const rectDef_s& rect, const rectDef_s& rectRelativeTo)
|
||||
[[nodiscard]] static rectDef_s ConvertRectDefRelativeTo(const rectDef_s& rect, const rectDef_s& relativeTo)
|
||||
{
|
||||
return rectDef_s{
|
||||
.x = rectRelativeTo.x + rect.x,
|
||||
.y = rectRelativeTo.y + rect.y,
|
||||
.x = relativeTo.x + rect.x,
|
||||
.y = relativeTo.y + rect.y,
|
||||
.w = static_cast<float>(rect.w),
|
||||
.h = static_cast<float>(rect.h),
|
||||
.horzAlign = static_cast<unsigned char>(rect.horzAlign),
|
||||
@@ -57,7 +59,7 @@ namespace
|
||||
output[3] = static_cast<float>(input.a);
|
||||
}
|
||||
|
||||
static void ApplyFlag(int& flags, const bool shouldApply, const int flagValue)
|
||||
static void ApplyFlag(unsigned& flags, const bool shouldApply, const unsigned flagValue)
|
||||
{
|
||||
if (!shouldApply)
|
||||
return;
|
||||
@@ -65,16 +67,6 @@ namespace
|
||||
flags |= flagValue;
|
||||
}
|
||||
|
||||
static int ConvertItemType(const int input)
|
||||
{
|
||||
return input;
|
||||
}
|
||||
|
||||
static int ConvertTextFont(const int input)
|
||||
{
|
||||
return input;
|
||||
}
|
||||
|
||||
[[nodiscard]] Material* ConvertMaterial(const std::string& materialName, const CommonMenuDef* menu, const CommonItemDef* item = nullptr) const
|
||||
{
|
||||
if (materialName.empty())
|
||||
@@ -99,181 +91,14 @@ namespace
|
||||
return soundDependency->Asset();
|
||||
}
|
||||
|
||||
bool HandleStaticDvarFunctionCall(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const CommonExpressionBaseFunctionCall* functionCall,
|
||||
const int targetFunctionIndex) const
|
||||
{
|
||||
if (functionCall->m_args.size() != 1)
|
||||
return false;
|
||||
|
||||
const auto* dvarNameExpression = functionCall->m_args[0].get();
|
||||
if (!dvarNameExpression->IsStatic())
|
||||
return false;
|
||||
|
||||
const auto staticDvarNameExpressionValue = dvarNameExpression->EvaluateStatic();
|
||||
if (staticDvarNameExpressionValue.m_type != SimpleExpressionValue::Type::STRING)
|
||||
return false;
|
||||
|
||||
expressionEntry functionEntry{};
|
||||
functionEntry.type = EET_OPERATOR;
|
||||
functionEntry.data.op = targetFunctionIndex;
|
||||
entries.emplace_back(functionEntry);
|
||||
|
||||
expressionEntry staticDvarIndexEntry{};
|
||||
staticDvarIndexEntry.type = EET_OPERAND;
|
||||
staticDvarIndexEntry.data.operand.dataType = VAL_INT;
|
||||
staticDvarIndexEntry.data.operand.internals.intVal =
|
||||
static_cast<int>(m_conversion_zone_state.AddStaticDvar(*staticDvarNameExpressionValue.m_string_value));
|
||||
entries.emplace_back(staticDvarIndexEntry);
|
||||
|
||||
expressionEntry parenRight{};
|
||||
parenRight.type = EET_OPERATOR;
|
||||
parenRight.data.op = OP_RIGHTPAREN;
|
||||
entries.emplace_back(parenRight);
|
||||
|
||||
gameStatement->supportingData = m_conversion_zone_state.m_supporting_data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HandleSpecialBaseFunctionCall(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const CommonExpressionBaseFunctionCall* functionCall,
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item) const
|
||||
{
|
||||
switch (functionCall->m_function_index)
|
||||
{
|
||||
case EXP_FUNC_DVAR_INT:
|
||||
return HandleStaticDvarFunctionCall(gameStatement, entries, functionCall, EXP_FUNC_STATIC_DVAR_INT);
|
||||
case EXP_FUNC_DVAR_BOOL:
|
||||
return HandleStaticDvarFunctionCall(gameStatement, entries, functionCall, EXP_FUNC_STATIC_DVAR_BOOL);
|
||||
case EXP_FUNC_DVAR_FLOAT:
|
||||
return HandleStaticDvarFunctionCall(gameStatement, entries, functionCall, EXP_FUNC_STATIC_DVAR_FLOAT);
|
||||
case EXP_FUNC_DVAR_STRING:
|
||||
return HandleStaticDvarFunctionCall(gameStatement, entries, functionCall, EXP_FUNC_STATIC_DVAR_STRING);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConvertExpressionEntryBaseFunctionCall(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const CommonExpressionBaseFunctionCall* functionCall,
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item) const
|
||||
{
|
||||
if (!HandleSpecialBaseFunctionCall(gameStatement, entries, functionCall, menu, item))
|
||||
{
|
||||
expressionEntry functionEntry{};
|
||||
functionEntry.type = EET_OPERATOR;
|
||||
functionEntry.data.op = static_cast<int>(functionCall->m_function_index);
|
||||
entries.emplace_back(functionEntry);
|
||||
|
||||
auto firstArg = true;
|
||||
for (const auto& arg : functionCall->m_args)
|
||||
{
|
||||
if (!firstArg)
|
||||
{
|
||||
expressionEntry argSeparator{};
|
||||
argSeparator.type = EET_OPERATOR;
|
||||
argSeparator.data.op = OP_COMMA;
|
||||
entries.emplace_back(argSeparator);
|
||||
}
|
||||
else
|
||||
firstArg = false;
|
||||
|
||||
ConvertExpressionEntry(gameStatement, entries, arg.get(), menu, item);
|
||||
}
|
||||
|
||||
expressionEntry parenRight{};
|
||||
parenRight.type = EET_OPERATOR;
|
||||
parenRight.data.op = OP_RIGHTPAREN;
|
||||
entries.emplace_back(parenRight);
|
||||
}
|
||||
}
|
||||
|
||||
void ConvertExpressionEntryCustomFunctionCall(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const CommonExpressionCustomFunctionCall* functionCall,
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item) const
|
||||
{
|
||||
std::string lowerCaseFunctionName(functionCall->m_function_name);
|
||||
utils::MakeStringLowerCase(lowerCaseFunctionName);
|
||||
|
||||
Statement_s* functionStatement = m_conversion_zone_state.FindFunction(lowerCaseFunctionName);
|
||||
|
||||
if (functionStatement == nullptr)
|
||||
{
|
||||
// Function was not converted yet: Convert it now
|
||||
const auto foundCommonFunction = m_parsing_zone_state.m_functions_by_name.find(lowerCaseFunctionName);
|
||||
|
||||
if (foundCommonFunction == m_parsing_zone_state.m_functions_by_name.end())
|
||||
throw MenuConversionException("Failed to find definition for custom function \"" + functionCall->m_function_name + "\"", menu, item);
|
||||
|
||||
functionStatement = ConvertExpression(foundCommonFunction->second->m_value.get(), menu, item);
|
||||
functionStatement = m_conversion_zone_state.AddFunction(foundCommonFunction->second->m_name, functionStatement);
|
||||
}
|
||||
|
||||
expressionEntry functionEntry{};
|
||||
functionEntry.type = EET_OPERAND;
|
||||
functionEntry.data.operand.dataType = VAL_FUNCTION;
|
||||
functionEntry.data.operand.internals.function = functionStatement;
|
||||
entries.emplace_back(functionEntry);
|
||||
|
||||
// Statement uses custom function so it needs supporting data
|
||||
gameStatement->supportingData = m_conversion_zone_state.m_supporting_data;
|
||||
}
|
||||
|
||||
constexpr static expressionOperatorType_e UNARY_OPERATION_MAPPING[static_cast<unsigned>(SimpleUnaryOperationId::COUNT)]{
|
||||
constexpr static expressionOperatorType_e UNARY_OPERATION_MAPPING[]{
|
||||
OP_NOT,
|
||||
OP_BITWISENOT,
|
||||
OP_SUBTRACT,
|
||||
};
|
||||
static_assert(std::size(UNARY_OPERATION_MAPPING) == static_cast<unsigned>(SimpleUnaryOperationId::COUNT));
|
||||
|
||||
bool IsOperation(const ISimpleExpression* expression) const
|
||||
{
|
||||
if (!m_disable_optimizations && expression->IsStatic())
|
||||
return false;
|
||||
|
||||
return dynamic_cast<const SimpleExpressionBinaryOperation*>(expression) || dynamic_cast<const SimpleExpressionUnaryOperation*>(expression);
|
||||
}
|
||||
|
||||
void ConvertExpressionEntryUnaryOperation(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const SimpleExpressionUnaryOperation* unaryOperation,
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item) const
|
||||
{
|
||||
assert(static_cast<unsigned>(unaryOperation->m_operation_type->m_id) < static_cast<unsigned>(SimpleUnaryOperationId::COUNT));
|
||||
expressionEntry operation{};
|
||||
operation.type = EET_OPERATOR;
|
||||
operation.data.op = UNARY_OPERATION_MAPPING[static_cast<unsigned>(unaryOperation->m_operation_type->m_id)];
|
||||
entries.emplace_back(operation);
|
||||
|
||||
if (IsOperation(unaryOperation->m_operand.get()))
|
||||
{
|
||||
expressionEntry parenLeft{};
|
||||
parenLeft.type = EET_OPERATOR;
|
||||
parenLeft.data.op = OP_LEFTPAREN;
|
||||
entries.emplace_back(parenLeft);
|
||||
|
||||
ConvertExpressionEntry(gameStatement, entries, unaryOperation->m_operand.get(), menu, item);
|
||||
|
||||
expressionEntry parenRight{};
|
||||
parenRight.type = EET_OPERATOR;
|
||||
parenRight.data.op = OP_RIGHTPAREN;
|
||||
entries.emplace_back(parenRight);
|
||||
}
|
||||
else
|
||||
ConvertExpressionEntry(gameStatement, entries, unaryOperation->m_operand.get(), menu, item);
|
||||
}
|
||||
|
||||
constexpr static expressionOperatorType_e BINARY_OPERATION_MAPPING[static_cast<unsigned>(SimpleBinaryOperationId::COUNT)]{
|
||||
constexpr static expressionOperatorType_e BINARY_OPERATION_MAPPING[]{
|
||||
OP_ADD,
|
||||
OP_SUBTRACT,
|
||||
OP_MULTIPLY,
|
||||
@@ -292,75 +117,195 @@ namespace
|
||||
OP_AND,
|
||||
OP_OR,
|
||||
};
|
||||
static_assert(std::size(BINARY_OPERATION_MAPPING) == static_cast<unsigned>(SimpleBinaryOperationId::COUNT));
|
||||
|
||||
[[nodiscard]] bool IsOperation(const ISimpleExpression* expression) const
|
||||
{
|
||||
if (!m_disable_optimizations && expression->IsStatic())
|
||||
return false;
|
||||
|
||||
return dynamic_cast<const SimpleExpressionBinaryOperation*>(expression) != nullptr
|
||||
|| dynamic_cast<const SimpleExpressionUnaryOperation*>(expression) != nullptr;
|
||||
}
|
||||
|
||||
bool HandleStaticDvarFunctionCall(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const CommonExpressionBaseFunctionCall* functionCall,
|
||||
const int targetFunctionIndex) const
|
||||
{
|
||||
if (functionCall->m_args.size() != 1)
|
||||
return false;
|
||||
|
||||
const auto* dvarNameExpression = functionCall->m_args[0].get();
|
||||
if (!dvarNameExpression->IsStatic())
|
||||
return false;
|
||||
|
||||
const auto staticDvarNameExpressionValue = dvarNameExpression->EvaluateStatic();
|
||||
if (staticDvarNameExpressionValue.m_type != SimpleExpressionValue::Type::STRING)
|
||||
return false;
|
||||
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = targetFunctionIndex}});
|
||||
|
||||
const auto dvarIntVal = static_cast<int>(m_conversion_zone_state.AddStaticDvar(*staticDvarNameExpressionValue.m_string_value));
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERAND, .data = {.operand = {.dataType = VAL_INT, .internals = {.intVal = dvarIntVal}}}});
|
||||
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||
|
||||
gameStatement->supportingData = m_conversion_zone_state.m_supporting_data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HandleSpecialBaseFunctionCall(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const CommonExpressionBaseFunctionCall* baseFunction) const
|
||||
{
|
||||
switch (baseFunction->m_function_index)
|
||||
{
|
||||
case EXP_FUNC_DVAR_INT:
|
||||
return HandleStaticDvarFunctionCall(gameStatement, entries, baseFunction, EXP_FUNC_STATIC_DVAR_INT);
|
||||
case EXP_FUNC_DVAR_BOOL:
|
||||
return HandleStaticDvarFunctionCall(gameStatement, entries, baseFunction, EXP_FUNC_STATIC_DVAR_BOOL);
|
||||
case EXP_FUNC_DVAR_FLOAT:
|
||||
return HandleStaticDvarFunctionCall(gameStatement, entries, baseFunction, EXP_FUNC_STATIC_DVAR_FLOAT);
|
||||
case EXP_FUNC_DVAR_STRING:
|
||||
return HandleStaticDvarFunctionCall(gameStatement, entries, baseFunction, EXP_FUNC_STATIC_DVAR_STRING);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConvertExpressionEntryBaseFunctionCall(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const CommonExpressionBaseFunctionCall* baseFunction,
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item) const
|
||||
{
|
||||
if (!HandleSpecialBaseFunctionCall(gameStatement, entries, baseFunction))
|
||||
{
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = static_cast<int>(baseFunction->m_function_index)}});
|
||||
|
||||
auto firstArg = true;
|
||||
for (const auto& arg : baseFunction->m_args)
|
||||
{
|
||||
if (firstArg)
|
||||
firstArg = false;
|
||||
else
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_COMMA}});
|
||||
|
||||
ConvertExpressionEntry(gameStatement, entries, arg.get(), menu, item);
|
||||
}
|
||||
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||
}
|
||||
}
|
||||
|
||||
void ConvertExpressionEntryCustomFunctionCall(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const CommonExpressionCustomFunctionCall* customFunction,
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item) const
|
||||
{
|
||||
std::string lowerCaseFunctionName(customFunction->m_function_name);
|
||||
utils::MakeStringLowerCase(lowerCaseFunctionName);
|
||||
|
||||
auto* functionStatement = m_conversion_zone_state.FindFunction(lowerCaseFunctionName);
|
||||
|
||||
if (!functionStatement)
|
||||
{
|
||||
// Function was not converted yet: Convert it now
|
||||
const auto foundCommonFunction = m_parsing_zone_state.m_functions_by_name.find(lowerCaseFunctionName);
|
||||
|
||||
if (foundCommonFunction == m_parsing_zone_state.m_functions_by_name.end())
|
||||
{
|
||||
throw MenuConversionException(
|
||||
std::format("Failed to find definition for custom function \"{}\"", customFunction->m_function_name), menu, item);
|
||||
}
|
||||
|
||||
functionStatement = ConvertExpression(foundCommonFunction->second->m_value.get(), menu, item);
|
||||
functionStatement = m_conversion_zone_state.AddFunction(foundCommonFunction->second->m_name, functionStatement);
|
||||
}
|
||||
|
||||
entries.emplace_back(expressionEntry{
|
||||
.type = EET_OPERAND,
|
||||
.data = {.operand = {.dataType = VAL_FUNCTION, .internals = {.function = functionStatement}}},
|
||||
});
|
||||
|
||||
// Statement uses custom function so it needs supporting data
|
||||
gameStatement->supportingData = m_conversion_zone_state.m_supporting_data;
|
||||
}
|
||||
|
||||
void ConvertExpressionEntryUnaryOperation(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const SimpleExpressionUnaryOperation* unary,
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item) const
|
||||
{
|
||||
assert(static_cast<unsigned>(unary->m_operation_type->m_id) < static_cast<unsigned>(SimpleUnaryOperationId::COUNT));
|
||||
|
||||
entries.emplace_back(expressionEntry{
|
||||
.type = EET_OPERATOR,
|
||||
.data = {.op = UNARY_OPERATION_MAPPING[static_cast<unsigned>(unary->m_operation_type->m_id)]},
|
||||
});
|
||||
|
||||
const auto wrapOperand = IsOperation(unary->m_operand.get());
|
||||
if (wrapOperand)
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_LEFTPAREN}});
|
||||
ConvertExpressionEntry(gameStatement, entries, unary->m_operand.get(), menu, item);
|
||||
if (wrapOperand)
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||
}
|
||||
|
||||
void ConvertExpressionEntryBinaryOperation(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const SimpleExpressionBinaryOperation* binaryOperation,
|
||||
const SimpleExpressionBinaryOperation* binary,
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item) const
|
||||
{
|
||||
// Game needs all nested operations to have parenthesis
|
||||
if (IsOperation(binaryOperation->m_operand1.get()))
|
||||
{
|
||||
expressionEntry parenLeft{};
|
||||
parenLeft.type = EET_OPERATOR;
|
||||
parenLeft.data.op = OP_LEFTPAREN;
|
||||
entries.emplace_back(parenLeft);
|
||||
const auto wrapLeft = IsOperation(binary->m_operand1.get());
|
||||
if (wrapLeft)
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_LEFTPAREN}});
|
||||
ConvertExpressionEntry(gameStatement, entries, binary->m_operand1.get(), menu, item);
|
||||
if (wrapLeft)
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||
|
||||
ConvertExpressionEntry(gameStatement, entries, binaryOperation->m_operand1.get(), menu, item);
|
||||
|
||||
expressionEntry parenRight{};
|
||||
parenRight.type = EET_OPERATOR;
|
||||
parenRight.data.op = OP_RIGHTPAREN;
|
||||
entries.emplace_back(parenRight);
|
||||
}
|
||||
else
|
||||
ConvertExpressionEntry(gameStatement, entries, binaryOperation->m_operand1.get(), menu, item);
|
||||
|
||||
assert(static_cast<unsigned>(binaryOperation->m_operation_type->m_id) < static_cast<unsigned>(SimpleBinaryOperationId::COUNT));
|
||||
expressionEntry operation{};
|
||||
operation.type = EET_OPERATOR;
|
||||
operation.data.op = BINARY_OPERATION_MAPPING[static_cast<unsigned>(binaryOperation->m_operation_type->m_id)];
|
||||
entries.emplace_back(operation);
|
||||
assert(static_cast<unsigned>(binary->m_operation_type->m_id) < static_cast<unsigned>(SimpleBinaryOperationId::COUNT));
|
||||
entries.emplace_back(expressionEntry{
|
||||
.type = EET_OPERATOR,
|
||||
.data = {.op = BINARY_OPERATION_MAPPING[static_cast<unsigned>(binary->m_operation_type->m_id)]},
|
||||
});
|
||||
|
||||
// Game needs all nested operations to have parenthesis
|
||||
if (IsOperation(binaryOperation->m_operand2.get()))
|
||||
{
|
||||
expressionEntry parenLeft{};
|
||||
parenLeft.type = EET_OPERATOR;
|
||||
parenLeft.data.op = OP_LEFTPAREN;
|
||||
entries.emplace_back(parenLeft);
|
||||
|
||||
ConvertExpressionEntry(gameStatement, entries, binaryOperation->m_operand2.get(), menu, item);
|
||||
|
||||
expressionEntry parenRight{};
|
||||
parenRight.type = EET_OPERATOR;
|
||||
parenRight.data.op = OP_RIGHTPAREN;
|
||||
entries.emplace_back(parenRight);
|
||||
}
|
||||
else
|
||||
ConvertExpressionEntry(gameStatement, entries, binaryOperation->m_operand2.get(), menu, item);
|
||||
const auto wrapRight = IsOperation(binary->m_operand2.get());
|
||||
if (wrapRight)
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_LEFTPAREN}});
|
||||
ConvertExpressionEntry(gameStatement, entries, binary->m_operand2.get(), menu, item);
|
||||
if (wrapRight)
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||
}
|
||||
|
||||
void ConvertExpressionEntryExpressionValue(std::vector<expressionEntry>& entries, const SimpleExpressionValue* expressionValue) const
|
||||
void ConvertExpressionValue(std::vector<expressionEntry>& entries, const SimpleExpressionValue& value) const
|
||||
{
|
||||
expressionEntry entry{};
|
||||
entry.type = EET_OPERAND;
|
||||
|
||||
if (expressionValue->m_type == SimpleExpressionValue::Type::INT)
|
||||
switch (value.m_type)
|
||||
{
|
||||
case SimpleExpressionValue::Type::INT:
|
||||
entry.data.operand.dataType = VAL_INT;
|
||||
entry.data.operand.internals.intVal = expressionValue->m_int_value;
|
||||
}
|
||||
else if (expressionValue->m_type == SimpleExpressionValue::Type::DOUBLE)
|
||||
{
|
||||
entry.data.operand.internals.intVal = value.m_int_value;
|
||||
break;
|
||||
case SimpleExpressionValue::Type::DOUBLE:
|
||||
entry.data.operand.dataType = VAL_FLOAT;
|
||||
entry.data.operand.internals.floatVal = static_cast<float>(expressionValue->m_double_value);
|
||||
}
|
||||
else if (expressionValue->m_type == SimpleExpressionValue::Type::STRING)
|
||||
{
|
||||
entry.data.operand.internals.floatVal = static_cast<float>(value.m_double_value);
|
||||
break;
|
||||
case SimpleExpressionValue::Type::STRING:
|
||||
entry.data.operand.dataType = VAL_STRING;
|
||||
entry.data.operand.internals.stringVal.string = m_conversion_zone_state.AddString(*expressionValue->m_string_value);
|
||||
entry.data.operand.internals.stringVal.string = m_conversion_zone_state.AddString(*value.m_string_value);
|
||||
break;
|
||||
}
|
||||
|
||||
entries.emplace_back(entry);
|
||||
@@ -374,28 +319,28 @@ namespace
|
||||
{
|
||||
if (!m_disable_optimizations && expression->IsStatic())
|
||||
{
|
||||
const auto expressionStaticValue = expression->EvaluateStatic();
|
||||
ConvertExpressionEntryExpressionValue(entries, &expressionStaticValue);
|
||||
const auto staticValue = expression->EvaluateStatic();
|
||||
ConvertExpressionValue(entries, staticValue);
|
||||
}
|
||||
else if (const auto* expressionValue = dynamic_cast<const SimpleExpressionValue*>(expression))
|
||||
else if (const auto* value = dynamic_cast<const SimpleExpressionValue*>(expression))
|
||||
{
|
||||
ConvertExpressionEntryExpressionValue(entries, expressionValue);
|
||||
ConvertExpressionValue(entries, *value);
|
||||
}
|
||||
else if (const auto* binaryOperation = dynamic_cast<const SimpleExpressionBinaryOperation*>(expression))
|
||||
else if (const auto* binary = dynamic_cast<const SimpleExpressionBinaryOperation*>(expression))
|
||||
{
|
||||
ConvertExpressionEntryBinaryOperation(gameStatement, entries, binaryOperation, menu, item);
|
||||
ConvertExpressionEntryBinaryOperation(gameStatement, entries, binary, menu, item);
|
||||
}
|
||||
else if (const auto* unaryOperation = dynamic_cast<const SimpleExpressionUnaryOperation*>(expression))
|
||||
else if (const auto* unary = dynamic_cast<const SimpleExpressionUnaryOperation*>(expression))
|
||||
{
|
||||
ConvertExpressionEntryUnaryOperation(gameStatement, entries, unaryOperation, menu, item);
|
||||
ConvertExpressionEntryUnaryOperation(gameStatement, entries, unary, menu, item);
|
||||
}
|
||||
else if (const auto* baseFunctionCall = dynamic_cast<const CommonExpressionBaseFunctionCall*>(expression))
|
||||
else if (const auto* baseFunction = dynamic_cast<const CommonExpressionBaseFunctionCall*>(expression))
|
||||
{
|
||||
ConvertExpressionEntryBaseFunctionCall(gameStatement, entries, baseFunctionCall, menu, item);
|
||||
ConvertExpressionEntryBaseFunctionCall(gameStatement, entries, baseFunction, menu, item);
|
||||
}
|
||||
else if (const auto* customFunctionCall = dynamic_cast<const CommonExpressionCustomFunctionCall*>(expression))
|
||||
else if (const auto* customFunction = dynamic_cast<const CommonExpressionCustomFunctionCall*>(expression))
|
||||
{
|
||||
ConvertExpressionEntryCustomFunctionCall(gameStatement, entries, customFunctionCall, menu, item);
|
||||
ConvertExpressionEntryCustomFunctionCall(gameStatement, entries, customFunction, menu, item);
|
||||
}
|
||||
else if (dynamic_cast<const SimpleExpressionConditionalOperator*>(expression))
|
||||
{
|
||||
@@ -414,18 +359,14 @@ namespace
|
||||
return nullptr;
|
||||
|
||||
auto* statement = m_memory.Alloc<Statement_s>();
|
||||
statement->lastResult = Operand{};
|
||||
statement->lastExecuteTime = 0;
|
||||
statement->supportingData = nullptr; // Supporting data is set upon using it
|
||||
std::vector<expressionEntry> entries;
|
||||
ConvertExpressionEntry(statement, entries, expression, menu, item);
|
||||
|
||||
std::vector<expressionEntry> expressionEntries;
|
||||
ConvertExpressionEntry(statement, expressionEntries, expression, menu, item);
|
||||
auto* outEntries = m_memory.Alloc<expressionEntry>(entries.size());
|
||||
std::memcpy(outEntries, entries.data(), sizeof(expressionEntry) * entries.size());
|
||||
|
||||
auto* outputExpressionEntries = m_memory.Alloc<expressionEntry>(expressionEntries.size());
|
||||
std::memcpy(outputExpressionEntries, expressionEntries.data(), sizeof(expressionEntry) * expressionEntries.size());
|
||||
|
||||
statement->entries = outputExpressionEntries;
|
||||
statement->numEntries = static_cast<int>(expressionEntries.size());
|
||||
statement->numEntries = static_cast<int>(entries.size());
|
||||
statement->entries = outEntries;
|
||||
|
||||
return statement;
|
||||
}
|
||||
@@ -435,26 +376,20 @@ namespace
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item = nullptr) const
|
||||
{
|
||||
if (m_disable_optimizations)
|
||||
return ConvertExpression(expression, menu, item);
|
||||
|
||||
if (!expression)
|
||||
return nullptr;
|
||||
|
||||
if (expression->IsStatic())
|
||||
if (!m_disable_optimizations && expression->IsStatic())
|
||||
{
|
||||
const auto value = expression->EvaluateStatic();
|
||||
switch (value.m_type)
|
||||
{
|
||||
case SimpleExpressionValue::Type::DOUBLE:
|
||||
staticValue = static_cast<float>(value.m_double_value);
|
||||
break;
|
||||
case SimpleExpressionValue::Type::INT:
|
||||
|
||||
if (value.m_type == SimpleExpressionValue::Type::INT)
|
||||
staticValue = static_cast<float>(value.m_int_value);
|
||||
break;
|
||||
case SimpleExpressionValue::Type::STRING:
|
||||
else if (value.m_type == SimpleExpressionValue::Type::DOUBLE)
|
||||
staticValue = static_cast<float>(value.m_double_value);
|
||||
else
|
||||
throw MenuConversionException("Cannot convert string expression value to floating point", menu, item);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -466,25 +401,17 @@ namespace
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item = nullptr) const
|
||||
{
|
||||
if (m_disable_optimizations)
|
||||
return ConvertExpression(expression, menu, item);
|
||||
|
||||
if (!expression)
|
||||
return nullptr;
|
||||
|
||||
if (expression->IsStatic())
|
||||
if (!m_disable_optimizations && expression->IsStatic())
|
||||
{
|
||||
const auto value = expression->EvaluateStatic();
|
||||
switch (value.m_type)
|
||||
{
|
||||
case SimpleExpressionValue::Type::STRING:
|
||||
staticValue = m_memory.Dup(value.m_string_value->c_str());
|
||||
break;
|
||||
|
||||
case SimpleExpressionValue::Type::DOUBLE:
|
||||
case SimpleExpressionValue::Type::INT:
|
||||
if (value.m_type != SimpleExpressionValue::Type::STRING)
|
||||
throw MenuConversionException("Cannot convert numeric expression value to string", menu, item);
|
||||
}
|
||||
|
||||
staticValue = m_memory.Dup(value.m_string_value->c_str());
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -496,37 +423,29 @@ namespace
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item = nullptr) const
|
||||
{
|
||||
if (m_disable_optimizations)
|
||||
return ConvertExpression(expression, menu, item);
|
||||
|
||||
if (!expression)
|
||||
return nullptr;
|
||||
|
||||
if (expression->IsStatic())
|
||||
if (!m_disable_optimizations && expression->IsStatic())
|
||||
{
|
||||
const auto value = expression->EvaluateStatic();
|
||||
switch (value.m_type)
|
||||
{
|
||||
case SimpleExpressionValue::Type::STRING:
|
||||
staticValue = ConvertMaterial(*value.m_string_value, menu, item);
|
||||
break;
|
||||
if (value.m_type != SimpleExpressionValue::Type::STRING)
|
||||
throw MenuConversionException("Cannot convert numeric expression value to material", menu, item);
|
||||
|
||||
staticValue = ConvertMaterial(*value.m_string_value, menu, item);
|
||||
|
||||
case SimpleExpressionValue::Type::DOUBLE:
|
||||
case SimpleExpressionValue::Type::INT:
|
||||
throw MenuConversionException("Cannot convert numeric expression value to string", menu, item);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ConvertExpression(expression, menu, item);
|
||||
}
|
||||
|
||||
[[nodiscard]] Statement_s* ConvertVisibleExpression(windowDef_t* window,
|
||||
[[nodiscard]] Statement_s* ConvertVisibleExpression(windowDef_t& window,
|
||||
const ISimpleExpression* expression,
|
||||
const CommonMenuDef* commonMenu,
|
||||
const CommonItemDef* commonItem = nullptr) const
|
||||
{
|
||||
if (expression == nullptr)
|
||||
if (!expression)
|
||||
return nullptr;
|
||||
|
||||
bool isStatic;
|
||||
@@ -547,11 +466,11 @@ namespace
|
||||
if (isStatic)
|
||||
{
|
||||
if (isTruthy)
|
||||
window->dynamicFlags[0] |= WINDOW_FLAG_VISIBLE;
|
||||
window.dynamicFlags[0] |= WINDOW_FLAG_VISIBLE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
window->dynamicFlags[0] |= WINDOW_FLAG_VISIBLE;
|
||||
window.dynamicFlags[0] |= WINDOW_FLAG_VISIBLE;
|
||||
return ConvertExpression(expression, commonMenu, commonItem);
|
||||
}
|
||||
|
||||
@@ -637,7 +556,7 @@ namespace
|
||||
outputCondition->eventExpression = ConvertExpression(condition->m_condition.get(), menu, item);
|
||||
outputCondition->eventHandlerSet = ConvertEventHandlerSet(condition->m_condition_elements.get(), menu, item);
|
||||
|
||||
elements.push_back(outputHandler);
|
||||
elements.emplace_back(outputHandler);
|
||||
|
||||
if (condition->m_else_elements)
|
||||
{
|
||||
@@ -645,7 +564,7 @@ namespace
|
||||
outputElseHandler->eventType = EVENT_ELSE;
|
||||
outputElseHandler->eventData.elseScript = ConvertEventHandlerSet(condition->m_else_elements.get(), menu, item);
|
||||
|
||||
elements.push_back(outputElseHandler);
|
||||
elements.emplace_back(outputElseHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1011,11 +930,11 @@ namespace
|
||||
}
|
||||
|
||||
[[nodiscard]] listBoxDef_s* ConvertListBoxFeatures(itemDef_s* item,
|
||||
CommonItemFeaturesListBox* commonListBox,
|
||||
const CommonItemFeaturesListBox* commonListBox,
|
||||
const CommonMenuDef& parentMenu,
|
||||
const CommonItemDef& commonItem) const
|
||||
{
|
||||
if (commonListBox == nullptr)
|
||||
if (!commonListBox)
|
||||
return nullptr;
|
||||
|
||||
auto* listBox = m_memory.Alloc<listBoxDef_s>();
|
||||
@@ -1030,7 +949,7 @@ namespace
|
||||
ConvertColor(listBox->selectBorder, commonListBox->m_select_border);
|
||||
listBox->selectIcon = ConvertMaterial(commonListBox->m_select_icon, &parentMenu, &commonItem);
|
||||
|
||||
listBox->numColumns = static_cast<int>(std::min(std::extent_v<decltype(listBoxDef_s::columnInfo)>, commonListBox->m_columns.size()));
|
||||
listBox->numColumns = static_cast<int>(std::min(std::size(listBox->columnInfo), commonListBox->m_columns.size()));
|
||||
for (auto i = 0; i < listBox->numColumns; i++)
|
||||
{
|
||||
auto& col = listBox->columnInfo[i];
|
||||
@@ -1045,12 +964,9 @@ namespace
|
||||
return listBox;
|
||||
}
|
||||
|
||||
[[nodiscard]] editFieldDef_s* ConvertEditFieldFeatures(itemDef_s* item,
|
||||
CommonItemFeaturesEditField* commonEditField,
|
||||
const CommonMenuDef& parentMenu,
|
||||
const CommonItemDef& commonItem) const
|
||||
[[nodiscard]] editFieldDef_s* ConvertEditFieldFeatures(itemDef_s* item, const CommonItemFeaturesEditField* commonEditField) const
|
||||
{
|
||||
if (commonEditField == nullptr)
|
||||
if (!commonEditField)
|
||||
return nullptr;
|
||||
|
||||
auto* editField = m_memory.Alloc<editFieldDef_s>();
|
||||
@@ -1065,16 +981,13 @@ namespace
|
||||
return editField;
|
||||
}
|
||||
|
||||
[[nodiscard]] multiDef_s* ConvertMultiValueFeatures(itemDef_s* item,
|
||||
CommonItemFeaturesMultiValue* commonMultiValue,
|
||||
const CommonMenuDef& parentMenu,
|
||||
const CommonItemDef& commonItem) const
|
||||
[[nodiscard]] multiDef_s* ConvertMultiValueFeatures(const CommonItemFeaturesMultiValue* commonMultiValue) const
|
||||
{
|
||||
if (commonMultiValue == nullptr)
|
||||
if (!commonMultiValue)
|
||||
return nullptr;
|
||||
|
||||
auto* multiValue = m_memory.Alloc<multiDef_s>();
|
||||
multiValue->count = static_cast<int>(std::min(std::extent_v<decltype(multiDef_s::dvarList)>, commonMultiValue->m_step_names.size()));
|
||||
multiValue->count = static_cast<int>(std::min(std::size(multiValue->dvarList), commonMultiValue->m_step_names.size()));
|
||||
multiValue->strDef = !commonMultiValue->m_string_values.empty() ? 1 : 0;
|
||||
|
||||
for (auto i = 0; i < multiValue->count; i++)
|
||||
@@ -1096,12 +1009,9 @@ namespace
|
||||
return multiValue;
|
||||
}
|
||||
|
||||
[[nodiscard]] newsTickerDef_s* ConvertNewsTickerFeatures(itemDef_s* item,
|
||||
CommonItemFeaturesNewsTicker* commonNewsTicker,
|
||||
const CommonMenuDef& parentMenu,
|
||||
const CommonItemDef& commonItem) const
|
||||
[[nodiscard]] newsTickerDef_s* ConvertNewsTickerFeatures(const CommonItemFeaturesNewsTicker* commonNewsTicker) const
|
||||
{
|
||||
if (commonNewsTicker == nullptr)
|
||||
if (!commonNewsTicker)
|
||||
return nullptr;
|
||||
|
||||
auto* newsTicker = m_memory.Alloc<newsTickerDef_s>();
|
||||
@@ -1112,7 +1022,7 @@ namespace
|
||||
return newsTicker;
|
||||
}
|
||||
|
||||
[[nodiscard]] itemDef_s* ConvertItem(const CommonMenuDef& commonParentMenu, const menuDef_t& parentMenu, const CommonItemDef& commonItem) const
|
||||
[[nodiscard]] itemDef_s* ConvertItem(const CommonMenuDef& commonParentMenu, menuDef_t& parentMenu, const CommonItemDef& commonItem) const
|
||||
{
|
||||
auto* item = m_memory.Alloc<itemDef_s>();
|
||||
|
||||
@@ -1126,11 +1036,11 @@ namespace
|
||||
ApplyFlag(item->window.staticFlags, commonItem.m_decoration, WINDOW_FLAG_DECORATION);
|
||||
ApplyFlag(item->window.staticFlags, commonItem.m_auto_wrapped, WINDOW_FLAG_AUTO_WRAPPED);
|
||||
ApplyFlag(item->window.staticFlags, commonItem.m_horizontal_scroll, WINDOW_FLAG_HORIZONTAL_SCROLL);
|
||||
item->type = ConvertItemType(commonItem.m_type);
|
||||
item->dataType = item->type;
|
||||
item->type = commonItem.m_type;
|
||||
item->dataType = commonItem.m_type;
|
||||
item->window.border = commonItem.m_border;
|
||||
item->window.borderSize = static_cast<float>(commonItem.m_border_size);
|
||||
item->visibleExp = ConvertVisibleExpression(&item->window, commonItem.m_visible_expression.get(), &commonParentMenu, &commonItem);
|
||||
item->visibleExp = ConvertVisibleExpression(item->window, commonItem.m_visible_expression.get(), &commonParentMenu, &commonItem);
|
||||
item->disabledExp = ConvertExpression(commonItem.m_disabled_expression.get(), &commonParentMenu, &commonItem);
|
||||
item->window.ownerDraw = commonItem.m_owner_draw;
|
||||
item->window.ownerDrawFlags = commonItem.m_owner_draw_flags;
|
||||
@@ -1140,12 +1050,11 @@ namespace
|
||||
item->textaligny = static_cast<float>(commonItem.m_text_align_y);
|
||||
item->textscale = static_cast<float>(commonItem.m_text_scale);
|
||||
item->textStyle = commonItem.m_text_style;
|
||||
item->fontEnum = ConvertTextFont(commonItem.m_text_font);
|
||||
item->fontEnum = commonItem.m_text_font;
|
||||
ConvertColor(item->window.backColor, commonItem.m_back_color);
|
||||
|
||||
ConvertColor(item->window.foreColor, commonItem.m_fore_color);
|
||||
if (!commonItem.m_fore_color.Equals(CommonColor(1.0, 1.0, 1.0, 1.0)))
|
||||
item->window.dynamicFlags[0] |= WINDOW_FLAG_NON_DEFAULT_FORECOLOR;
|
||||
ApplyFlag(item->window.dynamicFlags[0], !commonItem.m_fore_color.Equals(CommonColor(1.0, 1.0, 1.0, 1.0)), WINDOW_FLAG_NON_DEFAULT_FORECOLOR);
|
||||
|
||||
ConvertColor(item->window.borderColor, commonItem.m_border_color);
|
||||
ConvertColor(item->window.outlineColor, commonItem.m_outline_color);
|
||||
@@ -1159,8 +1068,9 @@ namespace
|
||||
item->mouseEnterText = ConvertEventHandlerSet(commonItem.m_on_mouse_enter_text.get(), &commonParentMenu, &commonItem);
|
||||
item->mouseExitText = ConvertEventHandlerSet(commonItem.m_on_mouse_exit_text.get(), &commonParentMenu, &commonItem);
|
||||
item->action = ConvertEventHandlerSet(commonItem.m_on_action.get(), &commonParentMenu, &commonItem);
|
||||
item->accept = ConvertEventHandlerSet(commonItem.m_on_accept.get(), &commonParentMenu, &commonItem);
|
||||
item->onAccept = ConvertEventHandlerSet(commonItem.m_on_accept.get(), &commonParentMenu, &commonItem);
|
||||
item->focusSound = ConvertSound(commonItem.m_focus_sound, &commonParentMenu, &commonItem);
|
||||
item->dvar = ConvertString(commonItem.m_dvar);
|
||||
item->dvarTest = ConvertString(commonItem.m_dvar_test);
|
||||
item->enableDvar = ConvertEnableDvar(commonItem, item->dvarFlags);
|
||||
item->onKey = ConvertKeyHandler(commonItem.m_key_handlers, &commonParentMenu, &commonItem);
|
||||
@@ -1173,7 +1083,6 @@ namespace
|
||||
item->fxLetterTime = commonItem.m_fx_letter_time;
|
||||
item->fxDecayStartTime = commonItem.m_fx_decay_start_time;
|
||||
item->fxDecayDuration = commonItem.m_fx_decay_duration;
|
||||
item->dvar = ConvertString(commonItem.m_dvar);
|
||||
|
||||
switch (commonItem.m_feature_type)
|
||||
{
|
||||
@@ -1182,11 +1091,11 @@ namespace
|
||||
break;
|
||||
|
||||
case CommonItemFeatureType::EDIT_FIELD:
|
||||
item->typeData.editField = ConvertEditFieldFeatures(item, commonItem.m_edit_field_features.get(), commonParentMenu, commonItem);
|
||||
item->typeData.editField = ConvertEditFieldFeatures(item, commonItem.m_edit_field_features.get());
|
||||
break;
|
||||
|
||||
case CommonItemFeatureType::MULTI_VALUE:
|
||||
item->typeData.multi = ConvertMultiValueFeatures(item, commonItem.m_multi_value_features.get(), commonParentMenu, commonItem);
|
||||
item->typeData.multi = ConvertMultiValueFeatures(commonItem.m_multi_value_features.get());
|
||||
break;
|
||||
|
||||
case CommonItemFeatureType::ENUM_DVAR:
|
||||
@@ -1194,7 +1103,7 @@ namespace
|
||||
break;
|
||||
|
||||
case CommonItemFeatureType::NEWS_TICKER:
|
||||
item->typeData.ticker = ConvertNewsTickerFeatures(item, commonItem.m_news_ticker_features.get(), commonParentMenu, commonItem);
|
||||
item->typeData.ticker = ConvertNewsTickerFeatures(commonItem.m_news_ticker_features.get());
|
||||
break;
|
||||
|
||||
case CommonItemFeatureType::NONE:
|
||||
@@ -1208,10 +1117,12 @@ namespace
|
||||
// Do this last so any optimizations are considered
|
||||
item->window.rect = ConvertRectDefRelativeTo(item->window.rectClient, parentMenu.window.rect);
|
||||
|
||||
item->parent = &parentMenu;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
itemDef_s** ConvertMenuItems(const CommonMenuDef& commonMenu, const menuDef_t& menu, int& itemCount) const
|
||||
itemDef_s** ConvertMenuItems(const CommonMenuDef& commonMenu, menuDef_t& menu, int& itemCount) const
|
||||
{
|
||||
if (commonMenu.m_items.empty())
|
||||
{
|
||||
@@ -1236,15 +1147,16 @@ namespace
|
||||
{
|
||||
}
|
||||
|
||||
void ConvertMenu(const menu::CommonMenuDef& commonMenu, menuDef_t& menu, AssetRegistration<AssetMenu>& registration) override
|
||||
bool ConvertMenu(const CommonMenuDef& commonMenu, menuDef_t& menu, AssetRegistration<AssetMenu>& registration) override
|
||||
{
|
||||
try
|
||||
{
|
||||
menu.window.name = m_memory.Dup(commonMenu.m_name.c_str());
|
||||
menu.fullScreen = commonMenu.m_full_screen;
|
||||
menu.fullScreen = commonMenu.m_full_screen ? 1 : 0;
|
||||
ApplyFlag(menu.window.staticFlags, commonMenu.m_screen_space, WINDOW_FLAG_SCREEN_SPACE);
|
||||
ApplyFlag(menu.window.staticFlags, commonMenu.m_decoration, WINDOW_FLAG_DECORATION);
|
||||
menu.window.rect = ConvertRectDef(commonMenu.m_rect);
|
||||
menu.window.rectClient = menu.window.rect;
|
||||
menu.window.style = commonMenu.m_style;
|
||||
menu.window.border = commonMenu.m_border;
|
||||
menu.window.borderSize = static_cast<float>(commonMenu.m_border_size);
|
||||
@@ -1269,7 +1181,7 @@ namespace
|
||||
ApplyFlag(menu.window.staticFlags, commonMenu.m_hidden_during_ui, WINDOW_FLAG_HIDDEN_DURING_UI);
|
||||
menu.allowedBinding = ConvertString(commonMenu.m_allowed_binding);
|
||||
ApplyFlag(menu.window.staticFlags, commonMenu.m_text_only_focus, WINDOW_FLAG_TEXT_ONLY_FOCUS);
|
||||
menu.visibleExp = ConvertVisibleExpression(&menu.window, commonMenu.m_visible_expression.get(), &commonMenu);
|
||||
menu.visibleExp = ConvertVisibleExpression(menu.window, commonMenu.m_visible_expression.get(), &commonMenu);
|
||||
menu.rectXExp = ConvertOrApplyStatement(menu.window.rect.x, commonMenu.m_rect_x_exp.get(), &commonMenu);
|
||||
menu.rectYExp = ConvertOrApplyStatement(menu.window.rect.y, commonMenu.m_rect_y_exp.get(), &commonMenu);
|
||||
menu.rectWExp = ConvertOrApplyStatement(menu.window.rect.w, commonMenu.m_rect_w_exp.get(), &commonMenu);
|
||||
@@ -1287,7 +1199,10 @@ namespace
|
||||
catch (const MenuConversionException& e)
|
||||
{
|
||||
PrintConversionExceptionDetails(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MenuConversionZoneState& m_conversion_zone_state;
|
||||
@@ -1295,7 +1210,8 @@ namespace
|
||||
};
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<IMenuConverter> IMenuConverter::Create(bool disableOptimizations, ISearchPath& searchPath, MemoryManager& memory, AssetCreationContext& context)
|
||||
std::unique_ptr<IMenuConverter>
|
||||
IMenuConverter::Create(const bool disableOptimizations, ISearchPath& searchPath, MemoryManager& memory, AssetCreationContext& context)
|
||||
{
|
||||
return std::make_unique<MenuConverter>(disableOptimizations, searchPath, memory, context);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "SearchPath/ISearchPath.h"
|
||||
#include "Utils/MemoryManager.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace IW4
|
||||
{
|
||||
class IMenuConverter
|
||||
@@ -14,7 +16,7 @@ namespace IW4
|
||||
IMenuConverter() = default;
|
||||
virtual ~IMenuConverter() = default;
|
||||
|
||||
virtual void ConvertMenu(const menu::CommonMenuDef& commonMenu, menuDef_t& menu, AssetRegistration<AssetMenu>& registration) = 0;
|
||||
virtual bool ConvertMenu(const menu::CommonMenuDef& commonMenu, menuDef_t& menu, AssetRegistration<AssetMenu>& registration) = 0;
|
||||
|
||||
static std::unique_ptr<IMenuConverter> Create(bool disableOptimizations, ISearchPath& searchPath, MemoryManager& memory, AssetCreationContext& context);
|
||||
};
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
#include "LoaderMenuListIW5.h"
|
||||
|
||||
#include "Game/IW5/IW5.h"
|
||||
#include "Game/IW5/Menu/MenuConversionZoneStateIW5.h"
|
||||
#include "Game/IW5/Menu/MenuConverterIW5.h"
|
||||
#include "ObjLoading.h"
|
||||
#include "Parsing/Menu/MenuFileReader.h"
|
||||
#include "Utils/Logging/Log.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <deque>
|
||||
|
||||
using namespace IW5;
|
||||
|
||||
@@ -44,7 +41,8 @@ namespace
|
||||
const auto menuListResult = ParseMenuFile(*file.m_stream, assetName, zoneState);
|
||||
if (menuListResult)
|
||||
{
|
||||
ProcessParsedResults(assetName, context, *menuListResult, zoneState, conversionState, menus, registration);
|
||||
if (!ProcessParsedResults(assetName, context, *menuListResult, zoneState, conversionState, menus, registration))
|
||||
return AssetCreationResult::Failure();
|
||||
|
||||
for (const auto& menuToLoad : menuListResult->m_menus_to_load)
|
||||
menuLoadQueue.emplace_back(menuToLoad);
|
||||
@@ -59,7 +57,8 @@ namespace
|
||||
{
|
||||
const auto& menuFileToLoad = menuLoadQueue.front();
|
||||
|
||||
LoadMenuFileFromQueue(menuFileToLoad, context, zoneState, conversionState, menus, registration);
|
||||
if (!LoadMenuFileFromQueue(menuFileToLoad, context, zoneState, conversionState, menus, registration))
|
||||
return AssetCreationResult::Failure();
|
||||
|
||||
menuLoadQueue.pop_front();
|
||||
}
|
||||
@@ -108,7 +107,8 @@ namespace
|
||||
const auto menuFileResult = ParseMenuFile(*file.m_stream, menuFilePath, zoneState);
|
||||
if (menuFileResult)
|
||||
{
|
||||
ProcessParsedResults(menuFilePath, context, *menuFileResult, zoneState, conversionState, menus, registration);
|
||||
if (!ProcessParsedResults(menuFilePath, context, *menuFileResult, zoneState, conversionState, menus, registration))
|
||||
return false;
|
||||
if (!menuFileResult->m_menus_to_load.empty())
|
||||
con::warn("Menu file has menus to load even though it is not a menu list, ignoring: \"{}\"", menuFilePath);
|
||||
|
||||
@@ -158,8 +158,7 @@ namespace
|
||||
auto* menuAsset = m_memory.Alloc<menuDef_t>();
|
||||
AssetRegistration<AssetMenu> menuRegistration(commonMenu->m_name, menuAsset);
|
||||
|
||||
converter->ConvertMenu(*commonMenu, *menuAsset, menuRegistration);
|
||||
if (menuAsset == nullptr)
|
||||
if (!converter->ConvertMenu(*commonMenu, *menuAsset, menuRegistration))
|
||||
{
|
||||
con::error("Failed to convert menu file \"{}\"", commonMenu->m_name);
|
||||
return false;
|
||||
@@ -214,6 +213,7 @@ namespace
|
||||
} // namespace
|
||||
|
||||
namespace menu
|
||||
|
||||
{
|
||||
std::unique_ptr<AssetCreator<AssetMenuList>> CreateMenuListLoaderIW5(MemoryManager& memory, ISearchPath& searchPath)
|
||||
{
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
namespace menu
|
||||
{
|
||||
std::unique_ptr<AssetCreator<IW5::AssetMenuList>> CreateMenuListLoaderIW5(MemoryManager& memory, ISearchPath& searchPath);
|
||||
} // namespace menu
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ const char* MenuConversionZoneState::AddString(const std::string& str)
|
||||
|
||||
void MenuConversionZoneState::AddLoadedFile(std::string loadedFileName, std::vector<XAssetInfo<menuDef_t>*> menusOfFile)
|
||||
{
|
||||
m_menus_by_filename.emplace(std::make_pair(std::move(loadedFileName), std::move(menusOfFile)));
|
||||
m_menus_by_filename.emplace(std::move(loadedFileName), std::move(menusOfFile));
|
||||
}
|
||||
|
||||
void MenuConversionZoneState::FinalizeSupportingData() const
|
||||
|
||||
@@ -3,26 +3,15 @@
|
||||
#include "Asset/IZoneAssetCreationState.h"
|
||||
#include "Game/IW5/IW5.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace IW5
|
||||
{
|
||||
class MenuConversionZoneState final : public IZoneAssetCreationState
|
||||
{
|
||||
Zone* m_zone;
|
||||
std::vector<Statement_s*> m_functions;
|
||||
std::map<std::string, Statement_s*> m_function_by_name;
|
||||
|
||||
std::vector<StaticDvar*> m_static_dvars;
|
||||
std::map<std::string, size_t> m_dvars_by_name;
|
||||
|
||||
std::vector<const char*> m_strings;
|
||||
std::map<std::string, const char*> m_strings_by_value;
|
||||
|
||||
public:
|
||||
std::map<std::string, std::vector<XAssetInfo<menuDef_t>*>> m_menus_by_filename;
|
||||
ExpressionSupportingData* m_supporting_data;
|
||||
|
||||
MenuConversionZoneState();
|
||||
void Inject(ZoneAssetCreationInjection& inject) override;
|
||||
|
||||
@@ -35,5 +24,19 @@ namespace IW5
|
||||
void AddLoadedFile(std::string loadedFileName, std::vector<XAssetInfo<menuDef_t>*> menusOfFile);
|
||||
|
||||
void FinalizeSupportingData() const;
|
||||
|
||||
std::unordered_map<std::string, std::vector<XAssetInfo<menuDef_t>*>> m_menus_by_filename;
|
||||
ExpressionSupportingData* m_supporting_data;
|
||||
|
||||
private:
|
||||
Zone* m_zone;
|
||||
std::vector<Statement_s*> m_functions;
|
||||
std::unordered_map<std::string, Statement_s*> m_function_by_name;
|
||||
|
||||
std::vector<StaticDvar*> m_static_dvars;
|
||||
std::unordered_map<std::string, size_t> m_dvars_by_name;
|
||||
|
||||
std::vector<const char*> m_strings;
|
||||
std::unordered_map<std::string, const char*> m_strings_by_value;
|
||||
};
|
||||
} // namespace IW5
|
||||
|
||||
@@ -13,10 +13,12 @@
|
||||
#include "Parsing/Simple/Expression/SimpleExpressionUnaryOperation.h"
|
||||
#include "Utils/StringUtils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <format>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
using namespace IW5;
|
||||
using namespace menu;
|
||||
@@ -28,20 +30,20 @@ namespace
|
||||
[[nodiscard]] static rectDef_s ConvertRectDef(const CommonRect& rect)
|
||||
{
|
||||
return rectDef_s{
|
||||
static_cast<float>(rect.x),
|
||||
static_cast<float>(rect.y),
|
||||
static_cast<float>(rect.w),
|
||||
static_cast<float>(rect.h),
|
||||
static_cast<unsigned char>(rect.horizontalAlign),
|
||||
static_cast<unsigned char>(rect.verticalAlign),
|
||||
.x = static_cast<float>(rect.x),
|
||||
.y = static_cast<float>(rect.y),
|
||||
.w = static_cast<float>(rect.w),
|
||||
.h = static_cast<float>(rect.h),
|
||||
.horzAlign = static_cast<unsigned char>(rect.horizontalAlign),
|
||||
.vertAlign = static_cast<unsigned char>(rect.verticalAlign),
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] static rectDef_s ConvertRectDefRelativeTo(const rectDef_s& rect, const rectDef_s& rectRelativeTo)
|
||||
[[nodiscard]] static rectDef_s ConvertRectDefRelativeTo(const rectDef_s& rect, const rectDef_s& relativeTo)
|
||||
{
|
||||
return rectDef_s{
|
||||
.x = rectRelativeTo.x + rect.x,
|
||||
.y = rectRelativeTo.y + rect.y,
|
||||
.x = relativeTo.x + rect.x,
|
||||
.y = relativeTo.y + rect.y,
|
||||
.w = static_cast<float>(rect.w),
|
||||
.h = static_cast<float>(rect.h),
|
||||
.horzAlign = static_cast<unsigned char>(rect.horzAlign),
|
||||
@@ -57,7 +59,7 @@ namespace
|
||||
output[3] = static_cast<float>(input.a);
|
||||
}
|
||||
|
||||
static void ApplyFlag(int& flags, const bool shouldApply, const int flagValue)
|
||||
static void ApplyFlag(unsigned& flags, const bool shouldApply, const unsigned flagValue)
|
||||
{
|
||||
if (!shouldApply)
|
||||
return;
|
||||
@@ -65,16 +67,6 @@ namespace
|
||||
flags |= flagValue;
|
||||
}
|
||||
|
||||
static int ConvertItemType(const int input)
|
||||
{
|
||||
return input;
|
||||
}
|
||||
|
||||
static int ConvertTextFont(const int input)
|
||||
{
|
||||
return input;
|
||||
}
|
||||
|
||||
[[nodiscard]] Material* ConvertMaterial(const std::string& materialName, const CommonMenuDef* menu, const CommonItemDef* item = nullptr) const
|
||||
{
|
||||
if (materialName.empty())
|
||||
@@ -99,181 +91,14 @@ namespace
|
||||
return soundDependency->Asset();
|
||||
}
|
||||
|
||||
bool HandleStaticDvarFunctionCall(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const CommonExpressionBaseFunctionCall* functionCall,
|
||||
const int targetFunctionIndex) const
|
||||
{
|
||||
if (functionCall->m_args.size() != 1)
|
||||
return false;
|
||||
|
||||
const auto* dvarNameExpression = functionCall->m_args[0].get();
|
||||
if (!dvarNameExpression->IsStatic())
|
||||
return false;
|
||||
|
||||
const auto staticDvarNameExpressionValue = dvarNameExpression->EvaluateStatic();
|
||||
if (staticDvarNameExpressionValue.m_type != SimpleExpressionValue::Type::STRING)
|
||||
return false;
|
||||
|
||||
expressionEntry functionEntry{};
|
||||
functionEntry.type = EET_OPERATOR;
|
||||
functionEntry.data.op = targetFunctionIndex;
|
||||
entries.emplace_back(functionEntry);
|
||||
|
||||
expressionEntry staticDvarIndexEntry{};
|
||||
staticDvarIndexEntry.type = EET_OPERAND;
|
||||
staticDvarIndexEntry.data.operand.dataType = VAL_INT;
|
||||
staticDvarIndexEntry.data.operand.internals.intVal =
|
||||
static_cast<int>(m_conversion_zone_state.AddStaticDvar(*staticDvarNameExpressionValue.m_string_value));
|
||||
entries.emplace_back(staticDvarIndexEntry);
|
||||
|
||||
expressionEntry parenRight{};
|
||||
parenRight.type = EET_OPERATOR;
|
||||
parenRight.data.op = OP_RIGHTPAREN;
|
||||
entries.emplace_back(parenRight);
|
||||
|
||||
gameStatement->supportingData = m_conversion_zone_state.m_supporting_data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HandleSpecialBaseFunctionCall(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const CommonExpressionBaseFunctionCall* functionCall,
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item) const
|
||||
{
|
||||
switch (functionCall->m_function_index)
|
||||
{
|
||||
case EXP_FUNC_DVAR_INT:
|
||||
return HandleStaticDvarFunctionCall(gameStatement, entries, functionCall, EXP_FUNC_STATIC_DVAR_INT);
|
||||
case EXP_FUNC_DVAR_BOOL:
|
||||
return HandleStaticDvarFunctionCall(gameStatement, entries, functionCall, EXP_FUNC_STATIC_DVAR_BOOL);
|
||||
case EXP_FUNC_DVAR_FLOAT:
|
||||
return HandleStaticDvarFunctionCall(gameStatement, entries, functionCall, EXP_FUNC_STATIC_DVAR_FLOAT);
|
||||
case EXP_FUNC_DVAR_STRING:
|
||||
return HandleStaticDvarFunctionCall(gameStatement, entries, functionCall, EXP_FUNC_STATIC_DVAR_STRING);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConvertExpressionEntryBaseFunctionCall(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const CommonExpressionBaseFunctionCall* functionCall,
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item) const
|
||||
{
|
||||
if (!HandleSpecialBaseFunctionCall(gameStatement, entries, functionCall, menu, item))
|
||||
{
|
||||
expressionEntry functionEntry{};
|
||||
functionEntry.type = EET_OPERATOR;
|
||||
functionEntry.data.op = static_cast<int>(functionCall->m_function_index);
|
||||
entries.emplace_back(functionEntry);
|
||||
|
||||
auto firstArg = true;
|
||||
for (const auto& arg : functionCall->m_args)
|
||||
{
|
||||
if (!firstArg)
|
||||
{
|
||||
expressionEntry argSeparator{};
|
||||
argSeparator.type = EET_OPERATOR;
|
||||
argSeparator.data.op = OP_COMMA;
|
||||
entries.emplace_back(argSeparator);
|
||||
}
|
||||
else
|
||||
firstArg = false;
|
||||
|
||||
ConvertExpressionEntry(gameStatement, entries, arg.get(), menu, item);
|
||||
}
|
||||
|
||||
expressionEntry parenRight{};
|
||||
parenRight.type = EET_OPERATOR;
|
||||
parenRight.data.op = OP_RIGHTPAREN;
|
||||
entries.emplace_back(parenRight);
|
||||
}
|
||||
}
|
||||
|
||||
void ConvertExpressionEntryCustomFunctionCall(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const CommonExpressionCustomFunctionCall* functionCall,
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item) const
|
||||
{
|
||||
std::string lowerCaseFunctionName(functionCall->m_function_name);
|
||||
utils::MakeStringLowerCase(lowerCaseFunctionName);
|
||||
|
||||
Statement_s* functionStatement = m_conversion_zone_state.FindFunction(lowerCaseFunctionName);
|
||||
|
||||
if (functionStatement == nullptr)
|
||||
{
|
||||
// Function was not converted yet: Convert it now
|
||||
const auto foundCommonFunction = m_parsing_zone_state.m_functions_by_name.find(lowerCaseFunctionName);
|
||||
|
||||
if (foundCommonFunction == m_parsing_zone_state.m_functions_by_name.end())
|
||||
throw MenuConversionException("Failed to find definition for custom function \"" + functionCall->m_function_name + "\"", menu, item);
|
||||
|
||||
functionStatement = ConvertExpression(foundCommonFunction->second->m_value.get(), menu, item);
|
||||
functionStatement = m_conversion_zone_state.AddFunction(lowerCaseFunctionName, functionStatement);
|
||||
}
|
||||
|
||||
expressionEntry functionEntry{};
|
||||
functionEntry.type = EET_OPERAND;
|
||||
functionEntry.data.operand.dataType = VAL_FUNCTION;
|
||||
functionEntry.data.operand.internals.function = functionStatement;
|
||||
entries.emplace_back(functionEntry);
|
||||
|
||||
// Statement uses custom function so it needs supporting data
|
||||
gameStatement->supportingData = m_conversion_zone_state.m_supporting_data;
|
||||
}
|
||||
|
||||
constexpr static expressionOperatorType_e UNARY_OPERATION_MAPPING[static_cast<unsigned>(SimpleUnaryOperationId::COUNT)]{
|
||||
constexpr static expressionOperatorType_e UNARY_OPERATION_MAPPING[]{
|
||||
OP_NOT,
|
||||
OP_BITWISENOT,
|
||||
OP_SUBTRACT,
|
||||
};
|
||||
static_assert(std::size(UNARY_OPERATION_MAPPING) == static_cast<unsigned>(SimpleUnaryOperationId::COUNT));
|
||||
|
||||
bool IsOperation(const ISimpleExpression* expression) const
|
||||
{
|
||||
if (!m_disable_optimizations && expression->IsStatic())
|
||||
return false;
|
||||
|
||||
return dynamic_cast<const SimpleExpressionBinaryOperation*>(expression) || dynamic_cast<const SimpleExpressionUnaryOperation*>(expression);
|
||||
}
|
||||
|
||||
void ConvertExpressionEntryUnaryOperation(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const SimpleExpressionUnaryOperation* unaryOperation,
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item) const
|
||||
{
|
||||
assert(static_cast<unsigned>(unaryOperation->m_operation_type->m_id) < static_cast<unsigned>(SimpleUnaryOperationId::COUNT));
|
||||
expressionEntry operation{};
|
||||
operation.type = EET_OPERATOR;
|
||||
operation.data.op = UNARY_OPERATION_MAPPING[static_cast<unsigned>(unaryOperation->m_operation_type->m_id)];
|
||||
entries.emplace_back(operation);
|
||||
|
||||
if (IsOperation(unaryOperation->m_operand.get()))
|
||||
{
|
||||
expressionEntry parenLeft{};
|
||||
parenLeft.type = EET_OPERATOR;
|
||||
parenLeft.data.op = OP_LEFTPAREN;
|
||||
entries.emplace_back(parenLeft);
|
||||
|
||||
ConvertExpressionEntry(gameStatement, entries, unaryOperation->m_operand.get(), menu, item);
|
||||
|
||||
expressionEntry parenRight{};
|
||||
parenRight.type = EET_OPERATOR;
|
||||
parenRight.data.op = OP_RIGHTPAREN;
|
||||
entries.emplace_back(parenRight);
|
||||
}
|
||||
else
|
||||
ConvertExpressionEntry(gameStatement, entries, unaryOperation->m_operand.get(), menu, item);
|
||||
}
|
||||
|
||||
constexpr static expressionOperatorType_e BINARY_OPERATION_MAPPING[static_cast<unsigned>(SimpleBinaryOperationId::COUNT)]{
|
||||
constexpr static expressionOperatorType_e BINARY_OPERATION_MAPPING[]{
|
||||
OP_ADD,
|
||||
OP_SUBTRACT,
|
||||
OP_MULTIPLY,
|
||||
@@ -292,75 +117,195 @@ namespace
|
||||
OP_AND,
|
||||
OP_OR,
|
||||
};
|
||||
static_assert(std::size(BINARY_OPERATION_MAPPING) == static_cast<unsigned>(SimpleBinaryOperationId::COUNT));
|
||||
|
||||
[[nodiscard]] bool IsOperation(const ISimpleExpression* expression) const
|
||||
{
|
||||
if (!m_disable_optimizations && expression->IsStatic())
|
||||
return false;
|
||||
|
||||
return dynamic_cast<const SimpleExpressionBinaryOperation*>(expression) != nullptr
|
||||
|| dynamic_cast<const SimpleExpressionUnaryOperation*>(expression) != nullptr;
|
||||
}
|
||||
|
||||
bool HandleStaticDvarFunctionCall(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const CommonExpressionBaseFunctionCall* functionCall,
|
||||
const int targetFunctionIndex) const
|
||||
{
|
||||
if (functionCall->m_args.size() != 1)
|
||||
return false;
|
||||
|
||||
const auto* dvarNameExpression = functionCall->m_args[0].get();
|
||||
if (!dvarNameExpression->IsStatic())
|
||||
return false;
|
||||
|
||||
const auto staticDvarNameExpressionValue = dvarNameExpression->EvaluateStatic();
|
||||
if (staticDvarNameExpressionValue.m_type != SimpleExpressionValue::Type::STRING)
|
||||
return false;
|
||||
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = targetFunctionIndex}});
|
||||
|
||||
const auto dvarIntVal = static_cast<int>(m_conversion_zone_state.AddStaticDvar(*staticDvarNameExpressionValue.m_string_value));
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERAND, .data = {.operand = {.dataType = VAL_INT, .internals = {.intVal = dvarIntVal}}}});
|
||||
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||
|
||||
gameStatement->supportingData = m_conversion_zone_state.m_supporting_data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HandleSpecialBaseFunctionCall(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const CommonExpressionBaseFunctionCall* baseFunction) const
|
||||
{
|
||||
switch (baseFunction->m_function_index)
|
||||
{
|
||||
case EXP_FUNC_DVAR_INT:
|
||||
return HandleStaticDvarFunctionCall(gameStatement, entries, baseFunction, EXP_FUNC_STATIC_DVAR_INT);
|
||||
case EXP_FUNC_DVAR_BOOL:
|
||||
return HandleStaticDvarFunctionCall(gameStatement, entries, baseFunction, EXP_FUNC_STATIC_DVAR_BOOL);
|
||||
case EXP_FUNC_DVAR_FLOAT:
|
||||
return HandleStaticDvarFunctionCall(gameStatement, entries, baseFunction, EXP_FUNC_STATIC_DVAR_FLOAT);
|
||||
case EXP_FUNC_DVAR_STRING:
|
||||
return HandleStaticDvarFunctionCall(gameStatement, entries, baseFunction, EXP_FUNC_STATIC_DVAR_STRING);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConvertExpressionEntryBaseFunctionCall(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const CommonExpressionBaseFunctionCall* baseFunction,
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item) const
|
||||
{
|
||||
if (!HandleSpecialBaseFunctionCall(gameStatement, entries, baseFunction))
|
||||
{
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = static_cast<int>(baseFunction->m_function_index)}});
|
||||
|
||||
auto firstArg = true;
|
||||
for (const auto& arg : baseFunction->m_args)
|
||||
{
|
||||
if (firstArg)
|
||||
firstArg = false;
|
||||
else
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_COMMA}});
|
||||
|
||||
ConvertExpressionEntry(gameStatement, entries, arg.get(), menu, item);
|
||||
}
|
||||
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||
}
|
||||
}
|
||||
|
||||
void ConvertExpressionEntryCustomFunctionCall(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const CommonExpressionCustomFunctionCall* customFunction,
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item) const
|
||||
{
|
||||
std::string lowerCaseFunctionName(customFunction->m_function_name);
|
||||
utils::MakeStringLowerCase(lowerCaseFunctionName);
|
||||
|
||||
auto* functionStatement = m_conversion_zone_state.FindFunction(lowerCaseFunctionName);
|
||||
|
||||
if (!functionStatement)
|
||||
{
|
||||
// Function was not converted yet: Convert it now
|
||||
const auto foundCommonFunction = m_parsing_zone_state.m_functions_by_name.find(lowerCaseFunctionName);
|
||||
|
||||
if (foundCommonFunction == m_parsing_zone_state.m_functions_by_name.end())
|
||||
{
|
||||
throw MenuConversionException(
|
||||
std::format("Failed to find definition for custom function \"{}\"", customFunction->m_function_name), menu, item);
|
||||
}
|
||||
|
||||
functionStatement = ConvertExpression(foundCommonFunction->second->m_value.get(), menu, item);
|
||||
functionStatement = m_conversion_zone_state.AddFunction(lowerCaseFunctionName, functionStatement);
|
||||
}
|
||||
|
||||
entries.emplace_back(expressionEntry{
|
||||
.type = EET_OPERAND,
|
||||
.data = {.operand = {.dataType = VAL_FUNCTION, .internals = {.function = functionStatement}}},
|
||||
});
|
||||
|
||||
// Statement uses custom function so it needs supporting data
|
||||
gameStatement->supportingData = m_conversion_zone_state.m_supporting_data;
|
||||
}
|
||||
|
||||
void ConvertExpressionEntryUnaryOperation(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const SimpleExpressionUnaryOperation* unary,
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item) const
|
||||
{
|
||||
assert(static_cast<unsigned>(unary->m_operation_type->m_id) < static_cast<unsigned>(SimpleUnaryOperationId::COUNT));
|
||||
|
||||
entries.emplace_back(expressionEntry{
|
||||
.type = EET_OPERATOR,
|
||||
.data = {.op = UNARY_OPERATION_MAPPING[static_cast<unsigned>(unary->m_operation_type->m_id)]},
|
||||
});
|
||||
|
||||
const auto wrapOperand = IsOperation(unary->m_operand.get());
|
||||
if (wrapOperand)
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_LEFTPAREN}});
|
||||
ConvertExpressionEntry(gameStatement, entries, unary->m_operand.get(), menu, item);
|
||||
if (wrapOperand)
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||
}
|
||||
|
||||
void ConvertExpressionEntryBinaryOperation(Statement_s* gameStatement,
|
||||
std::vector<expressionEntry>& entries,
|
||||
const SimpleExpressionBinaryOperation* binaryOperation,
|
||||
const SimpleExpressionBinaryOperation* binary,
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item) const
|
||||
{
|
||||
// Game needs all nested operations to have parenthesis
|
||||
if (IsOperation(binaryOperation->m_operand1.get()))
|
||||
{
|
||||
expressionEntry parenLeft{};
|
||||
parenLeft.type = EET_OPERATOR;
|
||||
parenLeft.data.op = OP_LEFTPAREN;
|
||||
entries.emplace_back(parenLeft);
|
||||
const auto wrapLeft = IsOperation(binary->m_operand1.get());
|
||||
if (wrapLeft)
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_LEFTPAREN}});
|
||||
ConvertExpressionEntry(gameStatement, entries, binary->m_operand1.get(), menu, item);
|
||||
if (wrapLeft)
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||
|
||||
ConvertExpressionEntry(gameStatement, entries, binaryOperation->m_operand1.get(), menu, item);
|
||||
|
||||
expressionEntry parenRight{};
|
||||
parenRight.type = EET_OPERATOR;
|
||||
parenRight.data.op = OP_RIGHTPAREN;
|
||||
entries.emplace_back(parenRight);
|
||||
}
|
||||
else
|
||||
ConvertExpressionEntry(gameStatement, entries, binaryOperation->m_operand1.get(), menu, item);
|
||||
|
||||
assert(static_cast<unsigned>(binaryOperation->m_operation_type->m_id) < static_cast<unsigned>(SimpleBinaryOperationId::COUNT));
|
||||
expressionEntry operation{};
|
||||
operation.type = EET_OPERATOR;
|
||||
operation.data.op = BINARY_OPERATION_MAPPING[static_cast<unsigned>(binaryOperation->m_operation_type->m_id)];
|
||||
entries.emplace_back(operation);
|
||||
assert(static_cast<unsigned>(binary->m_operation_type->m_id) < static_cast<unsigned>(SimpleBinaryOperationId::COUNT));
|
||||
entries.emplace_back(expressionEntry{
|
||||
.type = EET_OPERATOR,
|
||||
.data = {.op = BINARY_OPERATION_MAPPING[static_cast<unsigned>(binary->m_operation_type->m_id)]},
|
||||
});
|
||||
|
||||
// Game needs all nested operations to have parenthesis
|
||||
if (IsOperation(binaryOperation->m_operand2.get()))
|
||||
{
|
||||
expressionEntry parenLeft{};
|
||||
parenLeft.type = EET_OPERATOR;
|
||||
parenLeft.data.op = OP_LEFTPAREN;
|
||||
entries.emplace_back(parenLeft);
|
||||
|
||||
ConvertExpressionEntry(gameStatement, entries, binaryOperation->m_operand2.get(), menu, item);
|
||||
|
||||
expressionEntry parenRight{};
|
||||
parenRight.type = EET_OPERATOR;
|
||||
parenRight.data.op = OP_RIGHTPAREN;
|
||||
entries.emplace_back(parenRight);
|
||||
}
|
||||
else
|
||||
ConvertExpressionEntry(gameStatement, entries, binaryOperation->m_operand2.get(), menu, item);
|
||||
const auto wrapRight = IsOperation(binary->m_operand2.get());
|
||||
if (wrapRight)
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_LEFTPAREN}});
|
||||
ConvertExpressionEntry(gameStatement, entries, binary->m_operand2.get(), menu, item);
|
||||
if (wrapRight)
|
||||
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||
}
|
||||
|
||||
void ConvertExpressionEntryExpressionValue(std::vector<expressionEntry>& entries, const SimpleExpressionValue* expressionValue) const
|
||||
void ConvertExpressionValue(std::vector<expressionEntry>& entries, const SimpleExpressionValue& value) const
|
||||
{
|
||||
expressionEntry entry{};
|
||||
entry.type = EET_OPERAND;
|
||||
|
||||
if (expressionValue->m_type == SimpleExpressionValue::Type::INT)
|
||||
switch (value.m_type)
|
||||
{
|
||||
case SimpleExpressionValue::Type::INT:
|
||||
entry.data.operand.dataType = VAL_INT;
|
||||
entry.data.operand.internals.intVal = expressionValue->m_int_value;
|
||||
}
|
||||
else if (expressionValue->m_type == SimpleExpressionValue::Type::DOUBLE)
|
||||
{
|
||||
entry.data.operand.internals.intVal = value.m_int_value;
|
||||
break;
|
||||
case SimpleExpressionValue::Type::DOUBLE:
|
||||
entry.data.operand.dataType = VAL_FLOAT;
|
||||
entry.data.operand.internals.floatVal = static_cast<float>(expressionValue->m_double_value);
|
||||
}
|
||||
else if (expressionValue->m_type == SimpleExpressionValue::Type::STRING)
|
||||
{
|
||||
entry.data.operand.internals.floatVal = static_cast<float>(value.m_double_value);
|
||||
break;
|
||||
case SimpleExpressionValue::Type::STRING:
|
||||
entry.data.operand.dataType = VAL_STRING;
|
||||
entry.data.operand.internals.stringVal.string = m_conversion_zone_state.AddString(*expressionValue->m_string_value);
|
||||
entry.data.operand.internals.stringVal.string = m_conversion_zone_state.AddString(*value.m_string_value);
|
||||
break;
|
||||
}
|
||||
|
||||
entries.emplace_back(entry);
|
||||
@@ -374,28 +319,28 @@ namespace
|
||||
{
|
||||
if (!m_disable_optimizations && expression->IsStatic())
|
||||
{
|
||||
const auto expressionStaticValue = expression->EvaluateStatic();
|
||||
ConvertExpressionEntryExpressionValue(entries, &expressionStaticValue);
|
||||
const auto staticValue = expression->EvaluateStatic();
|
||||
ConvertExpressionValue(entries, staticValue);
|
||||
}
|
||||
else if (const auto* expressionValue = dynamic_cast<const SimpleExpressionValue*>(expression))
|
||||
else if (const auto* value = dynamic_cast<const SimpleExpressionValue*>(expression))
|
||||
{
|
||||
ConvertExpressionEntryExpressionValue(entries, expressionValue);
|
||||
ConvertExpressionValue(entries, *value);
|
||||
}
|
||||
else if (const auto* binaryOperation = dynamic_cast<const SimpleExpressionBinaryOperation*>(expression))
|
||||
else if (const auto* binary = dynamic_cast<const SimpleExpressionBinaryOperation*>(expression))
|
||||
{
|
||||
ConvertExpressionEntryBinaryOperation(gameStatement, entries, binaryOperation, menu, item);
|
||||
ConvertExpressionEntryBinaryOperation(gameStatement, entries, binary, menu, item);
|
||||
}
|
||||
else if (const auto* unaryOperation = dynamic_cast<const SimpleExpressionUnaryOperation*>(expression))
|
||||
else if (const auto* unary = dynamic_cast<const SimpleExpressionUnaryOperation*>(expression))
|
||||
{
|
||||
ConvertExpressionEntryUnaryOperation(gameStatement, entries, unaryOperation, menu, item);
|
||||
ConvertExpressionEntryUnaryOperation(gameStatement, entries, unary, menu, item);
|
||||
}
|
||||
else if (const auto* baseFunctionCall = dynamic_cast<const CommonExpressionBaseFunctionCall*>(expression))
|
||||
else if (const auto* baseFunction = dynamic_cast<const CommonExpressionBaseFunctionCall*>(expression))
|
||||
{
|
||||
ConvertExpressionEntryBaseFunctionCall(gameStatement, entries, baseFunctionCall, menu, item);
|
||||
ConvertExpressionEntryBaseFunctionCall(gameStatement, entries, baseFunction, menu, item);
|
||||
}
|
||||
else if (const auto* customFunctionCall = dynamic_cast<const CommonExpressionCustomFunctionCall*>(expression))
|
||||
else if (const auto* customFunction = dynamic_cast<const CommonExpressionCustomFunctionCall*>(expression))
|
||||
{
|
||||
ConvertExpressionEntryCustomFunctionCall(gameStatement, entries, customFunctionCall, menu, item);
|
||||
ConvertExpressionEntryCustomFunctionCall(gameStatement, entries, customFunction, menu, item);
|
||||
}
|
||||
else if (dynamic_cast<const SimpleExpressionConditionalOperator*>(expression))
|
||||
{
|
||||
@@ -414,20 +359,15 @@ namespace
|
||||
return nullptr;
|
||||
|
||||
auto* statement = m_memory.Alloc<Statement_s>();
|
||||
for (auto& result : statement->persistentState.lastResult)
|
||||
result = Operand{};
|
||||
for (auto& lastExecutionTime : statement->persistentState.lastExecuteTime)
|
||||
lastExecutionTime = 0;
|
||||
statement->supportingData = nullptr; // Supporting data is set upon using it
|
||||
|
||||
std::vector<expressionEntry> expressionEntries;
|
||||
ConvertExpressionEntry(statement, expressionEntries, expression, menu, item);
|
||||
std::vector<expressionEntry> entries;
|
||||
ConvertExpressionEntry(statement, entries, expression, menu, item);
|
||||
|
||||
auto* outputExpressionEntries = m_memory.Alloc<expressionEntry>(expressionEntries.size());
|
||||
std::memcpy(outputExpressionEntries, expressionEntries.data(), sizeof(expressionEntry) * expressionEntries.size());
|
||||
auto* outEntries = m_memory.Alloc<expressionEntry>(entries.size());
|
||||
std::memcpy(outEntries, entries.data(), sizeof(expressionEntry) * entries.size());
|
||||
|
||||
statement->entries = outputExpressionEntries;
|
||||
statement->numEntries = static_cast<int>(expressionEntries.size());
|
||||
statement->numEntries = static_cast<int>(entries.size());
|
||||
statement->entries = outEntries;
|
||||
|
||||
return statement;
|
||||
}
|
||||
@@ -437,26 +377,20 @@ namespace
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item = nullptr) const
|
||||
{
|
||||
if (m_disable_optimizations)
|
||||
return ConvertExpression(expression, menu, item);
|
||||
|
||||
if (!expression)
|
||||
return nullptr;
|
||||
|
||||
if (expression->IsStatic())
|
||||
if (!m_disable_optimizations && expression->IsStatic())
|
||||
{
|
||||
const auto value = expression->EvaluateStatic();
|
||||
switch (value.m_type)
|
||||
{
|
||||
case SimpleExpressionValue::Type::DOUBLE:
|
||||
staticValue = static_cast<float>(value.m_double_value);
|
||||
break;
|
||||
case SimpleExpressionValue::Type::INT:
|
||||
|
||||
if (value.m_type == SimpleExpressionValue::Type::INT)
|
||||
staticValue = static_cast<float>(value.m_int_value);
|
||||
break;
|
||||
case SimpleExpressionValue::Type::STRING:
|
||||
else if (value.m_type == SimpleExpressionValue::Type::DOUBLE)
|
||||
staticValue = static_cast<float>(value.m_double_value);
|
||||
else
|
||||
throw MenuConversionException("Cannot convert string expression value to floating point", menu, item);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -468,25 +402,17 @@ namespace
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item = nullptr) const
|
||||
{
|
||||
if (m_disable_optimizations)
|
||||
return ConvertExpression(expression, menu, item);
|
||||
|
||||
if (!expression)
|
||||
return nullptr;
|
||||
|
||||
if (expression->IsStatic())
|
||||
if (!m_disable_optimizations && expression->IsStatic())
|
||||
{
|
||||
const auto value = expression->EvaluateStatic();
|
||||
switch (value.m_type)
|
||||
{
|
||||
case SimpleExpressionValue::Type::STRING:
|
||||
staticValue = m_memory.Dup(value.m_string_value->c_str());
|
||||
break;
|
||||
|
||||
case SimpleExpressionValue::Type::DOUBLE:
|
||||
case SimpleExpressionValue::Type::INT:
|
||||
if (value.m_type != SimpleExpressionValue::Type::STRING)
|
||||
throw MenuConversionException("Cannot convert numeric expression value to string", menu, item);
|
||||
}
|
||||
|
||||
staticValue = m_memory.Dup(value.m_string_value->c_str());
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -498,37 +424,29 @@ namespace
|
||||
const CommonMenuDef* menu,
|
||||
const CommonItemDef* item = nullptr) const
|
||||
{
|
||||
if (m_disable_optimizations)
|
||||
return ConvertExpression(expression, menu, item);
|
||||
|
||||
if (!expression)
|
||||
return nullptr;
|
||||
|
||||
if (expression->IsStatic())
|
||||
if (!m_disable_optimizations && expression->IsStatic())
|
||||
{
|
||||
const auto value = expression->EvaluateStatic();
|
||||
switch (value.m_type)
|
||||
{
|
||||
case SimpleExpressionValue::Type::STRING:
|
||||
staticValue = ConvertMaterial(*value.m_string_value, menu, item);
|
||||
break;
|
||||
if (value.m_type != SimpleExpressionValue::Type::STRING)
|
||||
throw MenuConversionException("Cannot convert numeric expression value to material", menu, item);
|
||||
|
||||
staticValue = ConvertMaterial(*value.m_string_value, menu, item);
|
||||
|
||||
case SimpleExpressionValue::Type::DOUBLE:
|
||||
case SimpleExpressionValue::Type::INT:
|
||||
throw MenuConversionException("Cannot convert numeric expression value to string", menu, item);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ConvertExpression(expression, menu, item);
|
||||
}
|
||||
|
||||
[[nodiscard]] Statement_s* ConvertVisibleExpression(windowDef_t* window,
|
||||
[[nodiscard]] Statement_s* ConvertVisibleExpression(windowDef_t& window,
|
||||
const ISimpleExpression* expression,
|
||||
const CommonMenuDef* commonMenu,
|
||||
const CommonItemDef* commonItem = nullptr) const
|
||||
{
|
||||
if (expression == nullptr)
|
||||
if (!expression)
|
||||
return nullptr;
|
||||
|
||||
bool isStatic;
|
||||
@@ -549,11 +467,11 @@ namespace
|
||||
if (isStatic)
|
||||
{
|
||||
if (isTruthy)
|
||||
window->dynamicFlags[0] |= WINDOW_FLAG_VISIBLE;
|
||||
window.dynamicFlags[0] |= WINDOW_FLAG_VISIBLE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
window->dynamicFlags[0] |= WINDOW_FLAG_VISIBLE;
|
||||
window.dynamicFlags[0] |= WINDOW_FLAG_VISIBLE;
|
||||
return ConvertExpression(expression, commonMenu, commonItem);
|
||||
}
|
||||
|
||||
@@ -639,7 +557,7 @@ namespace
|
||||
outputCondition->eventExpression = ConvertExpression(condition->m_condition.get(), menu, item);
|
||||
outputCondition->eventHandlerSet = ConvertEventHandlerSet(condition->m_condition_elements.get(), menu, item);
|
||||
|
||||
elements.push_back(outputHandler);
|
||||
elements.emplace_back(outputHandler);
|
||||
|
||||
if (condition->m_else_elements)
|
||||
{
|
||||
@@ -647,7 +565,7 @@ namespace
|
||||
outputElseHandler->eventType = EVENT_ELSE;
|
||||
outputElseHandler->eventData.elseScript = ConvertEventHandlerSet(condition->m_else_elements.get(), menu, item);
|
||||
|
||||
elements.push_back(outputElseHandler);
|
||||
elements.emplace_back(outputElseHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1013,11 +931,11 @@ namespace
|
||||
}
|
||||
|
||||
[[nodiscard]] listBoxDef_s* ConvertListBoxFeatures(itemDef_s* item,
|
||||
CommonItemFeaturesListBox* commonListBox,
|
||||
const CommonItemFeaturesListBox* commonListBox,
|
||||
const CommonMenuDef& parentMenu,
|
||||
const CommonItemDef& commonItem) const
|
||||
{
|
||||
if (commonListBox == nullptr)
|
||||
if (!commonListBox)
|
||||
return nullptr;
|
||||
|
||||
auto* listBox = m_memory.Alloc<listBoxDef_s>();
|
||||
@@ -1034,7 +952,7 @@ namespace
|
||||
listBox->elementHeightExp =
|
||||
ConvertOrApplyStatement(listBox->elementHeight, commonListBox->m_element_height_expression.get(), &parentMenu, &commonItem);
|
||||
|
||||
listBox->numColumns = static_cast<int>(std::min(std::extent_v<decltype(listBoxDef_s::columnInfo)>, commonListBox->m_columns.size()));
|
||||
listBox->numColumns = static_cast<int>(std::min(std::size(listBox->columnInfo), commonListBox->m_columns.size()));
|
||||
for (auto i = 0; i < listBox->numColumns; i++)
|
||||
{
|
||||
auto& col = listBox->columnInfo[i];
|
||||
@@ -1050,12 +968,9 @@ namespace
|
||||
return listBox;
|
||||
}
|
||||
|
||||
[[nodiscard]] editFieldDef_s* ConvertEditFieldFeatures(itemDef_s* item,
|
||||
CommonItemFeaturesEditField* commonEditField,
|
||||
const CommonMenuDef& parentMenu,
|
||||
const CommonItemDef& commonItem) const
|
||||
[[nodiscard]] editFieldDef_s* ConvertEditFieldFeatures(itemDef_s* item, const CommonItemFeaturesEditField* commonEditField) const
|
||||
{
|
||||
if (commonEditField == nullptr)
|
||||
if (!commonEditField)
|
||||
return nullptr;
|
||||
|
||||
auto* editField = m_memory.Alloc<editFieldDef_s>();
|
||||
@@ -1070,16 +985,13 @@ namespace
|
||||
return editField;
|
||||
}
|
||||
|
||||
[[nodiscard]] multiDef_s* ConvertMultiValueFeatures(itemDef_s* item,
|
||||
CommonItemFeaturesMultiValue* commonMultiValue,
|
||||
const CommonMenuDef& parentMenu,
|
||||
const CommonItemDef& commonItem) const
|
||||
[[nodiscard]] multiDef_s* ConvertMultiValueFeatures(const CommonItemFeaturesMultiValue* commonMultiValue) const
|
||||
{
|
||||
if (commonMultiValue == nullptr)
|
||||
if (!commonMultiValue)
|
||||
return nullptr;
|
||||
|
||||
auto* multiValue = m_memory.Alloc<multiDef_s>();
|
||||
multiValue->count = static_cast<int>(std::min(std::extent_v<decltype(multiDef_s::dvarList)>, commonMultiValue->m_step_names.size()));
|
||||
multiValue->count = static_cast<int>(std::min(std::size(multiValue->dvarList), commonMultiValue->m_step_names.size()));
|
||||
multiValue->strDef = !commonMultiValue->m_string_values.empty() ? 1 : 0;
|
||||
|
||||
for (auto i = 0; i < multiValue->count; i++)
|
||||
@@ -1101,12 +1013,9 @@ namespace
|
||||
return multiValue;
|
||||
}
|
||||
|
||||
[[nodiscard]] newsTickerDef_s* ConvertNewsTickerFeatures(itemDef_s* item,
|
||||
CommonItemFeaturesNewsTicker* commonNewsTicker,
|
||||
const CommonMenuDef& parentMenu,
|
||||
const CommonItemDef& commonItem) const
|
||||
[[nodiscard]] newsTickerDef_s* ConvertNewsTickerFeatures(const CommonItemFeaturesNewsTicker* commonNewsTicker) const
|
||||
{
|
||||
if (commonNewsTicker == nullptr)
|
||||
if (!commonNewsTicker)
|
||||
return nullptr;
|
||||
|
||||
auto* newsTicker = m_memory.Alloc<newsTickerDef_s>();
|
||||
@@ -1117,7 +1026,7 @@ namespace
|
||||
return newsTicker;
|
||||
}
|
||||
|
||||
[[nodiscard]] itemDef_s* ConvertItem(const CommonMenuDef& commonParentMenu, const menuDef_t& parentMenu, const CommonItemDef& commonItem) const
|
||||
[[nodiscard]] itemDef_s* ConvertItem(const CommonMenuDef& commonParentMenu, menuDef_t& parentMenu, const CommonItemDef& commonItem) const
|
||||
{
|
||||
auto* item = m_memory.Alloc<itemDef_s>();
|
||||
memset(item, 0, sizeof(itemDef_s));
|
||||
@@ -1132,11 +1041,11 @@ namespace
|
||||
ApplyFlag(item->window.staticFlags, commonItem.m_decoration, WINDOW_FLAG_DECORATION);
|
||||
ApplyFlag(item->window.staticFlags, commonItem.m_auto_wrapped, WINDOW_FLAG_AUTO_WRAPPED);
|
||||
ApplyFlag(item->window.staticFlags, commonItem.m_horizontal_scroll, WINDOW_FLAG_HORIZONTAL_SCROLL);
|
||||
item->type = ConvertItemType(commonItem.m_type);
|
||||
item->dataType = item->type;
|
||||
item->type = commonItem.m_type;
|
||||
item->dataType = commonItem.m_type;
|
||||
item->window.border = commonItem.m_border;
|
||||
item->window.borderSize = static_cast<float>(commonItem.m_border_size);
|
||||
item->visibleExp = ConvertVisibleExpression(&item->window, commonItem.m_visible_expression.get(), &commonParentMenu, &commonItem);
|
||||
item->visibleExp = ConvertVisibleExpression(item->window, commonItem.m_visible_expression.get(), &commonParentMenu, &commonItem);
|
||||
item->disabledExp = ConvertExpression(commonItem.m_disabled_expression.get(), &commonParentMenu, &commonItem);
|
||||
item->window.ownerDraw = commonItem.m_owner_draw;
|
||||
item->window.ownerDrawFlags = commonItem.m_owner_draw_flags;
|
||||
@@ -1146,12 +1055,11 @@ namespace
|
||||
item->textaligny = static_cast<float>(commonItem.m_text_align_y);
|
||||
item->textscale = static_cast<float>(commonItem.m_text_scale);
|
||||
item->textStyle = commonItem.m_text_style;
|
||||
item->fontEnum = ConvertTextFont(commonItem.m_text_font);
|
||||
item->fontEnum = commonItem.m_text_font;
|
||||
ConvertColor(item->window.backColor, commonItem.m_back_color);
|
||||
|
||||
ConvertColor(item->window.foreColor, commonItem.m_fore_color);
|
||||
if (!commonItem.m_fore_color.Equals(CommonColor(1.0, 1.0, 1.0, 1.0)))
|
||||
item->window.dynamicFlags[0] |= WINDOW_FLAG_NON_DEFAULT_FORECOLOR;
|
||||
ApplyFlag(item->window.dynamicFlags[0], !commonItem.m_fore_color.Equals(CommonColor(1.0, 1.0, 1.0, 1.0)), WINDOW_FLAG_NON_DEFAULT_FORECOLOR);
|
||||
|
||||
ConvertColor(item->window.borderColor, commonItem.m_border_color);
|
||||
ConvertColor(item->window.outlineColor, commonItem.m_outline_color);
|
||||
@@ -1166,8 +1074,9 @@ namespace
|
||||
item->mouseEnterText = ConvertEventHandlerSet(commonItem.m_on_mouse_enter_text.get(), &commonParentMenu, &commonItem);
|
||||
item->mouseExitText = ConvertEventHandlerSet(commonItem.m_on_mouse_exit_text.get(), &commonParentMenu, &commonItem);
|
||||
item->action = ConvertEventHandlerSet(commonItem.m_on_action.get(), &commonParentMenu, &commonItem);
|
||||
item->accept = ConvertEventHandlerSet(commonItem.m_on_accept.get(), &commonParentMenu, &commonItem);
|
||||
item->onAccept = ConvertEventHandlerSet(commonItem.m_on_accept.get(), &commonParentMenu, &commonItem);
|
||||
item->focusSound = ConvertSound(commonItem.m_focus_sound, &commonParentMenu, &commonItem);
|
||||
item->dvar = ConvertString(commonItem.m_dvar);
|
||||
item->dvarTest = ConvertString(commonItem.m_dvar_test);
|
||||
item->enableDvar = ConvertEnableDvar(commonItem, item->dvarFlags);
|
||||
item->onKey = ConvertKeyHandler(commonItem.m_key_handlers, &commonParentMenu, &commonItem);
|
||||
@@ -1181,7 +1090,6 @@ namespace
|
||||
item->fxLetterTime = commonItem.m_fx_letter_time;
|
||||
item->fxDecayStartTime = commonItem.m_fx_decay_start_time;
|
||||
item->fxDecayDuration = commonItem.m_fx_decay_duration;
|
||||
item->dvar = ConvertString(commonItem.m_dvar);
|
||||
|
||||
switch (commonItem.m_feature_type)
|
||||
{
|
||||
@@ -1190,11 +1098,11 @@ namespace
|
||||
break;
|
||||
|
||||
case CommonItemFeatureType::EDIT_FIELD:
|
||||
item->typeData.editField = ConvertEditFieldFeatures(item, commonItem.m_edit_field_features.get(), commonParentMenu, commonItem);
|
||||
item->typeData.editField = ConvertEditFieldFeatures(item, commonItem.m_edit_field_features.get());
|
||||
break;
|
||||
|
||||
case CommonItemFeatureType::MULTI_VALUE:
|
||||
item->typeData.multi = ConvertMultiValueFeatures(item, commonItem.m_multi_value_features.get(), commonParentMenu, commonItem);
|
||||
item->typeData.multi = ConvertMultiValueFeatures(commonItem.m_multi_value_features.get());
|
||||
break;
|
||||
|
||||
case CommonItemFeatureType::ENUM_DVAR:
|
||||
@@ -1202,7 +1110,7 @@ namespace
|
||||
break;
|
||||
|
||||
case CommonItemFeatureType::NEWS_TICKER:
|
||||
item->typeData.ticker = ConvertNewsTickerFeatures(item, commonItem.m_news_ticker_features.get(), commonParentMenu, commonItem);
|
||||
item->typeData.ticker = ConvertNewsTickerFeatures(commonItem.m_news_ticker_features.get());
|
||||
break;
|
||||
|
||||
case CommonItemFeatureType::NONE:
|
||||
@@ -1216,10 +1124,12 @@ namespace
|
||||
// Do this last so any optimizations are considered
|
||||
item->window.rect = ConvertRectDefRelativeTo(item->window.rectClient, parentMenu.window.rect);
|
||||
|
||||
item->parent = &parentMenu;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
itemDef_s** ConvertMenuItems(const CommonMenuDef& commonMenu, const menuDef_t& menu, int& itemCount) const
|
||||
itemDef_s** ConvertMenuItems(const CommonMenuDef& commonMenu, menuDef_t& menu, int& itemCount) const
|
||||
{
|
||||
if (commonMenu.m_items.empty())
|
||||
{
|
||||
@@ -1244,7 +1154,7 @@ namespace
|
||||
{
|
||||
}
|
||||
|
||||
void ConvertMenu(const menu::CommonMenuDef& commonMenu, menuDef_t& menu, AssetRegistration<AssetMenu>& registration) override
|
||||
bool ConvertMenu(const CommonMenuDef& commonMenu, menuDef_t& menu, AssetRegistration<AssetMenu>& registration) override
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1252,10 +1162,11 @@ namespace
|
||||
|
||||
menu.data = menuData;
|
||||
menu.window.name = m_memory.Dup(commonMenu.m_name.c_str());
|
||||
menuData->fullScreen = commonMenu.m_full_screen;
|
||||
menuData->fullScreen = commonMenu.m_full_screen ? 1 : 0;
|
||||
ApplyFlag(menu.window.staticFlags, commonMenu.m_screen_space, WINDOW_FLAG_SCREEN_SPACE);
|
||||
ApplyFlag(menu.window.staticFlags, commonMenu.m_decoration, WINDOW_FLAG_DECORATION);
|
||||
menu.window.rect = ConvertRectDef(commonMenu.m_rect);
|
||||
menu.window.rectClient = menu.window.rect;
|
||||
menu.window.style = commonMenu.m_style;
|
||||
menu.window.border = commonMenu.m_border;
|
||||
menu.window.borderSize = static_cast<float>(commonMenu.m_border_size);
|
||||
@@ -1280,7 +1191,7 @@ namespace
|
||||
ApplyFlag(menu.window.staticFlags, commonMenu.m_hidden_during_ui, WINDOW_FLAG_HIDDEN_DURING_UI);
|
||||
menuData->allowedBinding = ConvertString(commonMenu.m_allowed_binding);
|
||||
ApplyFlag(menu.window.staticFlags, commonMenu.m_text_only_focus, WINDOW_FLAG_TEXT_ONLY_FOCUS);
|
||||
menuData->visibleExp = ConvertVisibleExpression(&menu.window, commonMenu.m_visible_expression.get(), &commonMenu);
|
||||
menuData->visibleExp = ConvertVisibleExpression(menu.window, commonMenu.m_visible_expression.get(), &commonMenu);
|
||||
menuData->rectXExp = ConvertOrApplyStatement(menu.window.rect.x, commonMenu.m_rect_x_exp.get(), &commonMenu);
|
||||
menuData->rectYExp = ConvertOrApplyStatement(menu.window.rect.y, commonMenu.m_rect_y_exp.get(), &commonMenu);
|
||||
menuData->rectWExp = ConvertOrApplyStatement(menu.window.rect.w, commonMenu.m_rect_w_exp.get(), &commonMenu);
|
||||
@@ -1299,7 +1210,10 @@ namespace
|
||||
catch (const MenuConversionException& e)
|
||||
{
|
||||
PrintConversionExceptionDetails(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MenuConversionZoneState& m_conversion_zone_state;
|
||||
@@ -1307,7 +1221,8 @@ namespace
|
||||
};
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<IMenuConverter> IMenuConverter::Create(bool disableOptimizations, ISearchPath& searchPath, MemoryManager& memory, AssetCreationContext& context)
|
||||
std::unique_ptr<IMenuConverter>
|
||||
IMenuConverter::Create(const bool disableOptimizations, ISearchPath& searchPath, MemoryManager& memory, AssetCreationContext& context)
|
||||
{
|
||||
return std::make_unique<MenuConverter>(disableOptimizations, searchPath, memory, context);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "SearchPath/ISearchPath.h"
|
||||
#include "Utils/MemoryManager.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace IW5
|
||||
{
|
||||
class IMenuConverter
|
||||
@@ -14,7 +16,7 @@ namespace IW5
|
||||
IMenuConverter() = default;
|
||||
virtual ~IMenuConverter() = default;
|
||||
|
||||
virtual void ConvertMenu(const ::menu::CommonMenuDef& commonMenu, menuDef_t& menu, AssetRegistration<AssetMenu>& registration) = 0;
|
||||
virtual bool ConvertMenu(const ::menu::CommonMenuDef& commonMenu, menuDef_t& menu, AssetRegistration<AssetMenu>& registration) = 0;
|
||||
|
||||
static std::unique_ptr<IMenuConverter> Create(bool disableOptimizations, ISearchPath& searchPath, MemoryManager& memory, AssetCreationContext& context);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user