Make use of custom functions when converting menus

This commit is contained in:
Jan 2021-12-28 23:52:42 +01:00
parent 338de302d9
commit 7188b0946d
27 changed files with 459 additions and 143 deletions

View File

@ -1105,9 +1105,9 @@ namespace IW4
VAL_INT = 0x0,
VAL_FLOAT = 0x1,
VAL_STRING = 0x2,
NUM_INTERNAL_DATATYPES = 0x3,
VAL_FUNCTION = 0x3,
NUM_DATATYPES = 0x4,
NUM_DATATYPES,
};
struct Operand

View File

@ -2315,6 +2315,8 @@ namespace IW5
EXP_FUNC_STATIC_DVAR_BOOL,
EXP_FUNC_STATIC_DVAR_FLOAT,
EXP_FUNC_STATIC_DVAR_STRING,
EXP_FUNC_DYN_START
};
enum expressionEntryType : int

View File

@ -37,6 +37,7 @@ public:
return dynamic_cast<T*>(foundEntry->second.get());
auto newState = std::make_unique<T>();
newState->SetZone(m_zone);
auto* newStatePtr = newState.get();
m_zone_asset_loader_states.emplace(std::make_pair<std::type_index, std::unique_ptr<IZoneAssetLoaderState>>(typeid(T), std::move(newState)));
return newStatePtr;

View File

@ -1,4 +1,5 @@
#pragma once
#include "Zone/Zone.h"
class IZoneAssetLoaderState
{
@ -11,4 +12,9 @@ public:
IZoneAssetLoaderState(IZoneAssetLoaderState&& other) noexcept = default;
IZoneAssetLoaderState& operator=(const IZoneAssetLoaderState& other) = default;
IZoneAssetLoaderState& operator=(IZoneAssetLoaderState&& other) noexcept = default;
};
virtual void SetZone(Zone* zone)
{
// Do nothing by default
}
};

View File

@ -29,7 +29,7 @@ bool AssetLoaderMenuList::ShouldLoadMenuFile(const std::string& menuFilePath, me
const auto alreadyLoadedFile = zoneState->m_loaded_files.find(menuFilePath);
if (alreadyLoadedFile == zoneState->m_loaded_files.end())
{
zoneState->m_loaded_files.emplace(menuFilePath);
zoneState->AddLoadedFile(menuFilePath);
return true;
}
@ -50,10 +50,10 @@ void AssetLoaderMenuList::AddMenuFilesToLoadToQueue(std::deque<std::string>& que
void AssetLoaderMenuList::AddResultsToZoneState(menu::ParsingResult* parsingResult, menu::MenuAssetZoneState* zoneState)
{
for (auto& function : parsingResult->m_functions)
zoneState->m_functions.emplace_back(std::move(function));
zoneState->AddFunction(std::move(function));
for (auto& menu : parsingResult->m_menus)
zoneState->m_menus.emplace_back(std::move(menu));
zoneState->AddMenu(std::move(menu));
}
bool AssetLoaderMenuList::ProcessParsedResults(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, menu::ParsingResult* parsingResult,

View File

@ -0,0 +1,114 @@
#include "MenuConversionZoneStateIW4.h"
using namespace IW4;
MenuConversionZoneState::MenuConversionZoneState()
: m_zone(nullptr),
m_supporting_data(nullptr)
{
}
void MenuConversionZoneState::SetZone(Zone* zone)
{
auto* memory = zone->GetMemory();
m_zone = zone;
m_supporting_data = memory->Create<ExpressionSupportingData>();
memset(m_supporting_data, 0, sizeof(ExpressionSupportingData));
}
Statement_s* MenuConversionZoneState::FindFunction(const std::string& functionName)
{
const auto foundFunction = m_function_by_name.find(functionName);
if (foundFunction != m_function_by_name.end())
return foundFunction->second;
return nullptr;
}
Statement_s* MenuConversionZoneState::AddFunction(const std::string& functionName, Statement_s* function)
{
m_functions.push_back(function);
m_function_by_name.emplace(std::make_pair(functionName, function));
return function;
}
size_t MenuConversionZoneState::AddStaticDvar(const std::string& dvarName)
{
const auto foundDvar = m_dvars_by_name.find(dvarName);
if (foundDvar != m_dvars_by_name.end())
return foundDvar->second;
auto* memory = m_zone->GetMemory();
auto* staticDvar = static_cast<StaticDvar*>(memory->Alloc(sizeof(StaticDvar)));
staticDvar->dvarName = memory->Dup(dvarName.c_str());
staticDvar->dvar = nullptr;
const auto staticDvarIndex = m_static_dvars.size();
m_static_dvars.push_back(staticDvar);
m_dvars_by_name.emplace(std::make_pair(dvarName, staticDvarIndex));
return staticDvarIndex;
}
const char* MenuConversionZoneState::AddString(const std::string& str)
{
const auto foundString = m_strings_by_value.find(str);
if (foundString != m_strings_by_value.end())
return foundString->second;
auto* memory = m_zone->GetMemory();
const auto* strDuped = memory->Dup(str.c_str());
m_strings.push_back(strDuped);
m_strings_by_value.emplace(std::make_pair(str, strDuped));
return strDuped;
}
void MenuConversionZoneState::FinalizeSupportingData() const
{
auto* memory = m_zone->GetMemory();
m_supporting_data->uifunctions.totalFunctions = static_cast<int>(m_functions.size());
m_supporting_data->staticDvarList.numStaticDvars = static_cast<int>(m_static_dvars.size());
m_supporting_data->uiStrings.totalStrings = static_cast<int>(m_strings.size());
if (m_supporting_data->uifunctions.functions)
memory->Free(m_supporting_data->uifunctions.functions);
if (m_supporting_data->staticDvarList.staticDvars)
memory->Free(m_supporting_data->staticDvarList.staticDvars);
if (m_supporting_data->uiStrings.strings)
memory->Free(m_supporting_data->uiStrings.strings);
if (!m_functions.empty())
{
m_supporting_data->uifunctions.functions = static_cast<Statement_s**>(memory->Alloc(sizeof(void*) * m_functions.size()));
memcpy(m_supporting_data->uifunctions.functions, &m_functions[0], sizeof(void*) * m_functions.size());
}
else
m_supporting_data->uifunctions.functions = nullptr;
if (!m_static_dvars.empty())
{
m_supporting_data->staticDvarList.staticDvars = static_cast<StaticDvar**>(memory->Alloc(sizeof(void*) * m_static_dvars.size()));
memcpy(m_supporting_data->staticDvarList.staticDvars, &m_static_dvars[0], sizeof(void*) * m_static_dvars.size());
}
else
m_supporting_data->staticDvarList.staticDvars = nullptr;
if (!m_strings.empty())
{
m_supporting_data->uiStrings.strings = static_cast<const char**>(memory->Alloc(sizeof(void*) * m_strings.size()));
memcpy(m_supporting_data->uiStrings.strings, &m_strings[0], sizeof(void*) * m_strings.size());
}
else
m_supporting_data->uiStrings.strings = nullptr;
}

View File

@ -0,0 +1,36 @@
#pragma once
#include <map>
#include "AssetLoading/IZoneAssetLoaderState.h"
#include "Game/IW4/IW4.h"
namespace IW4
{
class MenuConversionZoneState final : public IZoneAssetLoaderState
{
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:
ExpressionSupportingData* m_supporting_data;
MenuConversionZoneState();
void SetZone(Zone* zone) override;
Statement_s* FindFunction(const std::string& functionName);
Statement_s* AddFunction(const std::string& functionName, Statement_s* function);
size_t AddStaticDvar(const std::string& dvarName);
const char* AddString(const std::string& str);
void FinalizeSupportingData() const;
};
}

View File

@ -3,14 +3,16 @@
#include <cassert>
#include <cstring>
#include "MenuConversionZoneStateIW4.h"
#include "Game/IW4/MenuConstantsIW4.h"
#include "Game/T5/T5_Assets.h"
#include "Utils/ClassUtils.h"
#include "Menu/AbstractMenuConverter.h"
#include "Parsing/Menu/MenuAssetZoneState.h"
#include "Parsing/Menu/Domain/EventHandler/CommonEventHandlerCondition.h"
#include "Parsing/Menu/Domain/EventHandler/CommonEventHandlerScript.h"
#include "Parsing/Menu/Domain/EventHandler/CommonEventHandlerSetLocalVar.h"
#include "Parsing/Menu/Domain/Expression/CommonExpressionFunctionCall.h"
#include "Parsing/Menu/Domain/Expression/CommonExpressionBaseFunctionCall.h"
#include "Parsing/Menu/Domain/Expression/CommonExpressionCustomFunctionCall.h"
#include "Parsing/Simple/Expression/SimpleExpressionBinaryOperation.h"
#include "Parsing/Simple/Expression/SimpleExpressionConditionalOperator.h"
#include "Parsing/Simple/Expression/SimpleExpressionUnaryOperation.h"
@ -22,6 +24,9 @@ namespace IW4
{
class MenuConverterImpl : public AbstractMenuConverter
{
MenuConversionZoneState* m_conversion_zone_state;
MenuAssetZoneState* m_parsing_zone_state;
static void ApplyMenuDefaults(menuDef_t* menu)
{
memset(menu, 0, sizeof(menuDef_t));
@ -90,39 +95,16 @@ namespace IW4
return static_cast<Material*>(materialDependency->m_ptr);
}
static const std::map<std::string, int>& GetFunctionMap()
void ConvertExpressionEntryBaseFunctionCall(Statement_s* gameStatement, std::vector<expressionEntry>& entries, const CommonExpressionBaseFunctionCall* functionCall, const CommonMenuDef* menu,
const CommonItemDef* item) const
{
static std::map<std::string, int> mappings;
static bool initialized = false;
if(!initialized)
{
for(size_t i = EXP_FUNC_DYN_START; i < std::extent_v<decltype(g_expFunctionNames)>; i++)
{
mappings[g_expFunctionNames[i]] = static_cast<int>(i);
}
initialized = true;
}
return mappings;
}
void ConvertExpressionEntryFunctionCall(std::vector<expressionEntry>& entries, const CommonExpressionFunctionCall* functionCall, const CommonMenuDef* menu,
const CommonItemDef* item) const
{
const auto& functionMappings = GetFunctionMap();
const auto foundMapping = functionMappings.find(functionCall->m_function_name);
if (foundMapping == functionMappings.end())
throw MenuConversionException("Could not find function \"" + functionCall->m_function_name + "\"", menu, item);
expressionEntry functionEntry{};
functionEntry.type = EET_OPERATOR;
functionEntry.data.op = foundMapping->second;
functionEntry.data.op = static_cast<int>(functionCall->m_function_index);
entries.emplace_back(functionEntry);
auto firstArg = true;
for(const auto& arg : functionCall->m_args)
for (const auto& arg : functionCall->m_args)
{
if (!firstArg)
{
@ -134,7 +116,7 @@ namespace IW4
else
firstArg = false;
ConvertExpressionEntry(entries, arg.get(), menu, item);
ConvertExpressionEntry(gameStatement, entries, arg.get(), menu, item);
}
expressionEntry parenRight{};
@ -143,6 +125,33 @@ namespace IW4
entries.emplace_back(parenRight);
}
void ConvertExpressionEntryCustomFunctionCall(Statement_s* gameStatement, std::vector<expressionEntry>& entries, const CommonExpressionCustomFunctionCall* functionCall, const CommonMenuDef* menu,
const CommonItemDef* item) const
{
Statement_s* functionStatement = m_conversion_zone_state->FindFunction(functionCall->m_function_name);
if (functionStatement == nullptr)
{
// Function was not converted yet: Convert it now
const auto foundCommonFunction = m_parsing_zone_state->m_functions_by_name.find(functionCall->m_function_name);
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_OPERATOR;
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)]
{
OP_NOT,
@ -150,7 +159,7 @@ namespace IW4
OP_SUBTRACT
};
void ConvertExpressionEntryUnaryOperation(std::vector<expressionEntry>& entries, const SimpleExpressionUnaryOperation* unaryOperation, const CommonMenuDef* menu,
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));
@ -166,7 +175,7 @@ namespace IW4
parenLeft.data.op = OP_LEFTPAREN;
entries.emplace_back(parenLeft);
ConvertExpressionEntry(entries, unaryOperation->m_operand.get(), menu, item);
ConvertExpressionEntry(gameStatement, entries, unaryOperation->m_operand.get(), menu, item);
expressionEntry parenRight{};
parenRight.type = EET_OPERATOR;
@ -174,7 +183,7 @@ namespace IW4
entries.emplace_back(parenRight);
}
else
ConvertExpressionEntry(entries, unaryOperation->m_operand.get(), menu, item);
ConvertExpressionEntry(gameStatement, entries, unaryOperation->m_operand.get(), menu, item);
}
constexpr static expressionOperatorType_e BINARY_OPERATION_MAPPING[static_cast<unsigned>(SimpleBinaryOperationId::COUNT)]
@ -198,7 +207,7 @@ namespace IW4
OP_OR
};
void ConvertExpressionEntryBinaryOperation(std::vector<expressionEntry>& entries, const SimpleExpressionBinaryOperation* binaryOperation, const CommonMenuDef* menu,
void ConvertExpressionEntryBinaryOperation(Statement_s* gameStatement, std::vector<expressionEntry>& entries, const SimpleExpressionBinaryOperation* binaryOperation, const CommonMenuDef* menu,
const CommonItemDef* item) const
{
if (binaryOperation->Operand1NeedsParenthesis())
@ -208,7 +217,7 @@ namespace IW4
parenLeft.data.op = OP_LEFTPAREN;
entries.emplace_back(parenLeft);
ConvertExpressionEntry(entries, binaryOperation->m_operand1.get(), menu, item);
ConvertExpressionEntry(gameStatement, entries, binaryOperation->m_operand1.get(), menu, item);
expressionEntry parenRight{};
parenRight.type = EET_OPERATOR;
@ -216,7 +225,7 @@ namespace IW4
entries.emplace_back(parenRight);
}
else
ConvertExpressionEntry(entries, binaryOperation->m_operand1.get(), menu, item);
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{};
@ -231,7 +240,7 @@ namespace IW4
parenLeft.data.op = OP_LEFTPAREN;
entries.emplace_back(parenLeft);
ConvertExpressionEntry(entries, binaryOperation->m_operand2.get(), menu, item);
ConvertExpressionEntry(gameStatement, entries, binaryOperation->m_operand2.get(), menu, item);
expressionEntry parenRight{};
parenRight.type = EET_OPERATOR;
@ -239,7 +248,7 @@ namespace IW4
entries.emplace_back(parenRight);
}
else
ConvertExpressionEntry(entries, binaryOperation->m_operand2.get(), menu, item);
ConvertExpressionEntry(gameStatement, entries, binaryOperation->m_operand2.get(), menu, item);
}
void ConvertExpressionEntryExpressionValue(std::vector<expressionEntry>& entries, const SimpleExpressionValue* expressionValue) const
@ -266,7 +275,7 @@ namespace IW4
entries.emplace_back(entry);
}
void ConvertExpressionEntry(std::vector<expressionEntry>& entries, const ISimpleExpression* expression, const CommonMenuDef* menu, const CommonItemDef* item) const
void ConvertExpressionEntry(Statement_s* gameStatement, std::vector<expressionEntry>& entries, const ISimpleExpression* expression, const CommonMenuDef* menu, const CommonItemDef* item) const
{
if (!m_disable_optimizations && expression->IsStatic())
{
@ -279,15 +288,19 @@ namespace IW4
}
else if (const auto* binaryOperation = dynamic_cast<const SimpleExpressionBinaryOperation*>(expression))
{
ConvertExpressionEntryBinaryOperation(entries, binaryOperation, menu, item);
ConvertExpressionEntryBinaryOperation(gameStatement, entries, binaryOperation, menu, item);
}
else if (const auto* unaryOperation = dynamic_cast<const SimpleExpressionUnaryOperation*>(expression))
{
ConvertExpressionEntryUnaryOperation(entries, unaryOperation, menu, item);
ConvertExpressionEntryUnaryOperation(gameStatement, entries, unaryOperation, menu, item);
}
else if (const auto* functionCall = dynamic_cast<const CommonExpressionFunctionCall*>(expression))
else if (const auto* baseFunctionCall = dynamic_cast<const CommonExpressionBaseFunctionCall*>(expression))
{
ConvertExpressionEntryFunctionCall(entries, functionCall, menu, item);
ConvertExpressionEntryBaseFunctionCall(gameStatement, entries, baseFunctionCall, menu, item);
}
else if (const auto* customFunctionCall = dynamic_cast<const CommonExpressionCustomFunctionCall*>(expression))
{
ConvertExpressionEntryCustomFunctionCall(gameStatement, entries, customFunctionCall, menu, item);
}
else if (dynamic_cast<const SimpleExpressionConditionalOperator*>(expression))
{
@ -308,10 +321,11 @@ namespace IW4
auto* statement = m_memory->Create<Statement_s>();
statement->lastResult = Operand{};
statement->lastExecuteTime = 0;
statement->supportingData = nullptr; // Supporting data is set upon using it
std::vector<expressionEntry> expressionEntries;
ConvertExpressionEntry(expressionEntries, expression, menu, item);
ConvertExpressionEntry(statement, expressionEntries, expression, menu, item);
auto* outputExpressionEntries = static_cast<expressionEntry*>(m_memory->Alloc(sizeof(expressionEntry) * expressionEntries.size()));
memcpy(outputExpressionEntries, expressionEntries.data(), sizeof(expressionEntry) * expressionEntries.size());
@ -319,9 +333,6 @@ namespace IW4
statement->entries = outputExpressionEntries;
statement->numEntries = static_cast<int>(expressionEntries.size());
// TODO: Add supporting data
statement->supportingData = nullptr;
return statement;
}
@ -646,8 +657,12 @@ namespace IW4
public:
MenuConverterImpl(const bool disableOptimizations, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager)
: AbstractMenuConverter(disableOptimizations, searchPath, memory, manager)
: AbstractMenuConverter(disableOptimizations, searchPath, memory, manager),
m_conversion_zone_state(manager->GetAssetLoadingContext()->GetZoneAssetLoaderState<MenuConversionZoneState>()),
m_parsing_zone_state(manager->GetAssetLoadingContext()->GetZoneAssetLoaderState<MenuAssetZoneState>())
{
assert(m_conversion_zone_state);
assert(m_parsing_zone_state);
}
_NODISCARD menuDef_t* ConvertMenu(const CommonMenuDef& commonMenu) const
@ -697,6 +712,7 @@ namespace IW4
menu->onESC = ConvertEventHandlerSet(commonMenu.m_on_esc.get(), &commonMenu);
menu->onKey = ConvertKeyHandler(commonMenu.m_key_handlers, &commonMenu);
menu->items = ConvertMenuItems(commonMenu);
menu->expressionData = m_conversion_zone_state->m_supporting_data;
return menu;
}

View File

@ -0,0 +1,43 @@
#include "CommonExpressionBaseFunctionCall.h"
using namespace menu;
CommonExpressionBaseFunctionCall::CommonExpressionBaseFunctionCall(std::string functionName, size_t functionIndex)
: m_function_name(std::move(functionName)),
m_function_index(functionIndex)
{
}
bool CommonExpressionBaseFunctionCall::Equals(const ISimpleExpression* other) const
{
const auto otherFunctionCall = dynamic_cast<const CommonExpressionBaseFunctionCall*>(other);
if (!otherFunctionCall
|| m_function_name != otherFunctionCall->m_function_name
|| m_function_index != otherFunctionCall->m_function_index
|| m_args.size() != otherFunctionCall->m_args.size())
{
return false;
}
for (auto i = 0u; i < m_args.size(); i++)
{
const auto* arg = m_args[i].get();
const auto* otherArg = otherFunctionCall->m_args[i].get();
if (!arg->Equals(otherArg))
return false;
}
return true;
}
bool CommonExpressionBaseFunctionCall::IsStatic() const
{
return false;
}
SimpleExpressionValue CommonExpressionBaseFunctionCall::Evaluate() const
{
return SimpleExpressionValue(0);
}

View File

@ -5,13 +5,14 @@
namespace menu
{
class CommonExpressionFunctionCall final : public ISimpleExpression
class CommonExpressionBaseFunctionCall final : public ISimpleExpression
{
public:
std::string m_function_name;
size_t m_function_index;
std::vector<std::unique_ptr<ISimpleExpression>> m_args;
explicit CommonExpressionFunctionCall(std::string functionName);
CommonExpressionBaseFunctionCall(std::string functionName, size_t functionIndex);
_NODISCARD bool Equals(const ISimpleExpression* other) const override;
_NODISCARD bool IsStatic() const override;

View File

@ -0,0 +1,24 @@
#include "CommonExpressionCustomFunctionCall.h"
using namespace menu;
CommonExpressionCustomFunctionCall::CommonExpressionCustomFunctionCall(std::string functionName)
: m_function_name(std::move(functionName))
{
}
bool CommonExpressionCustomFunctionCall::Equals(const ISimpleExpression* other) const
{
const auto otherFunctionCall = dynamic_cast<const CommonExpressionCustomFunctionCall*>(other);
return otherFunctionCall && m_function_name == otherFunctionCall->m_function_name;
}
bool CommonExpressionCustomFunctionCall::IsStatic() const
{
return false;
}
SimpleExpressionValue CommonExpressionCustomFunctionCall::Evaluate() const
{
return SimpleExpressionValue(0);
}

View File

@ -0,0 +1,18 @@
#pragma once
#include "Parsing/Simple/Expression/ISimpleExpression.h"
namespace menu
{
class CommonExpressionCustomFunctionCall final : public ISimpleExpression
{
public:
std::string m_function_name;
explicit CommonExpressionCustomFunctionCall(std::string functionName);
_NODISCARD bool Equals(const ISimpleExpression* other) const override;
_NODISCARD bool IsStatic() const override;
_NODISCARD SimpleExpressionValue Evaluate() const override;
};
}

View File

@ -1,41 +0,0 @@
#include "CommonExpressionFunctionCall.h"
using namespace menu;
CommonExpressionFunctionCall::CommonExpressionFunctionCall(std::string functionName)
: m_function_name(std::move(functionName))
{
}
bool CommonExpressionFunctionCall::Equals(const ISimpleExpression* other) const
{
const auto otherFunctionCall = dynamic_cast<const CommonExpressionFunctionCall*>(other);
if (!otherFunctionCall
|| m_function_name != otherFunctionCall->m_function_name
|| m_args.size() != otherFunctionCall->m_args.size())
{
return false;
}
for(auto i = 0u; i < m_args.size(); i++)
{
const auto* arg = m_args[i].get();
const auto* otherArg = otherFunctionCall->m_args[i].get();
if (!arg->Equals(otherArg))
return false;
}
return true;
}
bool CommonExpressionFunctionCall::IsStatic() const
{
return false;
}
SimpleExpressionValue CommonExpressionFunctionCall::Evaluate() const
{
return SimpleExpressionValue(0);
}

View File

@ -1,7 +1,12 @@
#include "MenuExpressionMatchers.h"
#include "MenuMatcherFactory.h"
#include "Parsing/Menu/Domain/Expression/CommonExpressionFunctionCall.h"
#include "Game/IW4/IW4.h"
#include "Game/IW5/IW5.h"
#include "Game/IW4/MenuConstantsIW4.h"
#include "Game/IW5/MenuConstantsIW5.h"
#include "Parsing/Menu/Domain/Expression/CommonExpressionBaseFunctionCall.h"
#include "Parsing/Menu/Domain/Expression/CommonExpressionCustomFunctionCall.h"
using namespace menu;
@ -10,9 +15,14 @@ static constexpr int TAG_EXPRESSION_FUNCTION_CALL_END = SimpleExpressionMatchers
static constexpr int CAPTURE_FUNCTION_NAME = SimpleExpressionMatchers::CAPTURE_OFFSET_EXPRESSION_EXT + 1;
MenuExpressionMatchers::MenuExpressionMatchers(const MenuFileParserState* state)
: SimpleExpressionMatchers(true, true, true, true, true),
m_state(state)
{
}
MenuExpressionMatchers::MenuExpressionMatchers()
: SimpleExpressionMatchers(true, true, true, true, true)
: MenuExpressionMatchers(nullptr)
{
}
@ -36,17 +46,73 @@ std::unique_ptr<SimpleExpressionMatchers::matcher_t> MenuExpressionMatchers::Par
});
}
const std::map<std::string, size_t>& MenuExpressionMatchers::GetBaseFunctionMapForFeatureLevel(const FeatureLevel featureLevel)
{
if(featureLevel == FeatureLevel::IW4)
{
static std::map<std::string, size_t> iw4FunctionMap;
static bool iw4FunctionMapInitialized = false;
if(!iw4FunctionMapInitialized)
{
for(size_t i = IW4::expressionFunction_e::EXP_FUNC_DYN_START; i < std::extent_v<decltype(IW4::g_expFunctionNames)>; i++)
iw4FunctionMap.emplace(std::make_pair(IW4::g_expFunctionNames[i], i));
}
return iw4FunctionMap;
}
if(featureLevel == FeatureLevel::IW5)
{
static std::map<std::string, size_t> iw5FunctionMap;
static bool iw5FunctionMapInitialized = false;
if(!iw5FunctionMapInitialized)
{
for(size_t i = IW5::expressionFunction_e::EXP_FUNC_DYN_START; i < std::extent_v<decltype(IW5::g_expFunctionNames)>; i++)
iw5FunctionMap.emplace(std::make_pair(IW5::g_expFunctionNames[i], i));
}
return iw5FunctionMap;
}
assert(false);
throw ParsingException(TokenPos(), "Feature level has no functions registered!!");
}
std::unique_ptr<ISimpleExpression> MenuExpressionMatchers::ProcessOperandExtension(SequenceResult<SimpleParserValue>& result) const
{
assert(m_state);
if(m_state == nullptr)
throw ParsingException(TokenPos(), "No state when processing menu operand extension!!");
if (result.PeekAndRemoveIfTag(TAG_EXPRESSION_FUNCTION_CALL) != TAG_EXPRESSION_FUNCTION_CALL)
throw ParsingException(TokenPos(), "Menu Operand Extension must be function call");
auto functionCall = std::make_unique<CommonExpressionFunctionCall>(result.NextCapture(CAPTURE_FUNCTION_NAME).IdentifierValue());
const auto& functionCallToken = result.NextCapture(CAPTURE_FUNCTION_NAME);
auto functionCallName = functionCallToken.IdentifierValue();
while (result.PeekAndRemoveIfTag(TAG_EXPRESSION_FUNCTION_CALL_END) != TAG_EXPRESSION_FUNCTION_CALL_END)
const auto& baseFunctionMap = GetBaseFunctionMapForFeatureLevel(m_state->m_feature_level);
const auto foundBaseFunction = baseFunctionMap.find(functionCallName);
if(foundBaseFunction != baseFunctionMap.end())
{
functionCall->m_args.emplace_back(ProcessExpression(result));
auto functionCall = std::make_unique<CommonExpressionBaseFunctionCall>(std::move(functionCallName), foundBaseFunction->second);
while (result.PeekAndRemoveIfTag(TAG_EXPRESSION_FUNCTION_CALL_END) != TAG_EXPRESSION_FUNCTION_CALL_END)
{
functionCall->m_args.emplace_back(ProcessExpression(result));
}
return std::move(functionCall);
}
return std::move(functionCall);
}
const auto foundCustomFunction = m_state->m_functions_by_name.find(functionCallName);
if(foundCustomFunction != m_state->m_functions_by_name.end())
{
auto functionCall = std::make_unique<CommonExpressionCustomFunctionCall>(std::move(functionCallName));
if(result.PeekAndRemoveIfTag(TAG_EXPRESSION_FUNCTION_CALL_END) != TAG_EXPRESSION_FUNCTION_CALL_END)
throw ParsingException(functionCallToken.GetPos(), "Custom functions cannot be called with arguments");
return std::move(functionCall);
}
throw ParsingException(functionCallToken.GetPos(), "Unknown function");
}

View File

@ -2,14 +2,20 @@
#include <memory>
#include "Parsing/Menu/MenuFileParserState.h"
#include "Parsing/Simple/Expression/SimpleExpressionMatchers.h"
namespace menu
{
class MenuExpressionMatchers final : public SimpleExpressionMatchers
{
const MenuFileParserState* m_state;
static const std::map<std::string, size_t>& GetBaseFunctionMapForFeatureLevel(FeatureLevel featureLevel);
public:
MenuExpressionMatchers();
explicit MenuExpressionMatchers(const MenuFileParserState* state);
protected:
std::unique_ptr<matcher_t> ParseOperandExtension(const supplier_t* labelSupplier) const override;

View File

@ -101,7 +101,7 @@ std::string& MenuMatcherFactory::TokenTextValue(const SimpleParserValue& value)
return value.StringValue();
}
int MenuMatcherFactory::TokenIntExpressionValue(SequenceResult<SimpleParserValue>& result)
int MenuMatcherFactory::TokenIntExpressionValue(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result)
{
const auto nextTag = result.PeekTag();
@ -115,7 +115,7 @@ int MenuMatcherFactory::TokenIntExpressionValue(SequenceResult<SimpleParserValue
if (nextTag == TAG_EXPRESSION)
{
result.NextTag();
const auto expression = MenuExpressionMatchers().ProcessExpression(result);
const auto expression = MenuExpressionMatchers(state).ProcessExpression(result);
if (!expression || !expression->IsStatic())
throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), "Not a valid static expression");
@ -131,7 +131,7 @@ int MenuMatcherFactory::TokenIntExpressionValue(SequenceResult<SimpleParserValue
throw ParsingException(TokenPos(), "TokenIntExpressionValue must be expression or int");
}
double MenuMatcherFactory::TokenNumericExpressionValue(SequenceResult<SimpleParserValue>& result)
double MenuMatcherFactory::TokenNumericExpressionValue(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result)
{
const auto nextTag = result.PeekTag();
@ -145,7 +145,7 @@ double MenuMatcherFactory::TokenNumericExpressionValue(SequenceResult<SimplePars
if (nextTag == TAG_EXPRESSION)
{
result.NextTag();
const auto expression = MenuExpressionMatchers().ProcessExpression(result);
const auto expression = MenuExpressionMatchers(state).ProcessExpression(result);
if (!expression || !expression->IsStatic())
throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), "Not a valid static expression");

View File

@ -2,6 +2,7 @@
#include "Parsing/Sequence/SequenceResult.h"
#include "Parsing/Simple/Matcher/SimpleMatcherFactory.h"
#include "Parsing/Menu/MenuFileParserState.h"
namespace menu
{
@ -30,7 +31,7 @@ namespace menu
_NODISCARD static double TokenNumericFloatingPointValue(const SimpleParserValue& value);
_NODISCARD static std::string& TokenTextValue(const SimpleParserValue& value);
_NODISCARD static int TokenIntExpressionValue(SequenceResult<SimpleParserValue>& result);
_NODISCARD static double TokenNumericExpressionValue(SequenceResult<SimpleParserValue>& result);
_NODISCARD static int TokenIntExpressionValue(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result);
_NODISCARD static double TokenNumericExpressionValue(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result);
};
}

View File

@ -0,0 +1,19 @@
#include "MenuAssetZoneState.h"
using namespace menu;
void MenuAssetZoneState::AddLoadedFile(std::string loadedFileName)
{
m_loaded_files.emplace(std::move(loadedFileName));
}
void MenuAssetZoneState::AddFunction(std::unique_ptr<CommonFunctionDef> function)
{
m_functions_by_name.emplace(std::make_pair(function->m_name, function.get()));
m_functions.emplace_back(std::move(function));
}
void MenuAssetZoneState::AddMenu(std::unique_ptr<CommonMenuDef> menu)
{
m_menus.emplace_back(std::move(menu));
}

View File

@ -16,6 +16,12 @@ namespace menu
std::vector<std::unique_ptr<CommonFunctionDef>> m_functions;
std::vector<std::unique_ptr<CommonMenuDef>> m_menus;
std::map<std::string, CommonFunctionDef*> m_functions_by_name;
MenuAssetZoneState() = default;
void AddLoadedFile(std::string loadedFileName);
void AddFunction(std::unique_ptr<CommonFunctionDef> function);
void AddMenu(std::unique_ptr<CommonMenuDef> menu);
};
}

View File

@ -582,7 +582,7 @@ namespace menu::event_handler_set_scope_sequences
protected:
void ProcessMatch(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result) const override
{
const MenuExpressionMatchers expressionMatchers;
const MenuExpressionMatchers expressionMatchers(state);
const auto typeTag = static_cast<SetLocalVarType>(result.NextTag());
const auto& varNameToken = result.NextCapture(CAPTURE_VAR_NAME);
@ -623,7 +623,7 @@ namespace menu::event_handler_set_scope_sequences
protected:
void ProcessMatch(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result) const override
{
const MenuExpressionMatchers expressionMatchers;
const MenuExpressionMatchers expressionMatchers(state);
auto expression = expressionMatchers.ProcessExpression(result);
if (!expression)
@ -668,7 +668,7 @@ namespace menu::event_handler_set_scope_sequences
protected:
void ProcessMatch(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result) const override
{
const MenuExpressionMatchers expressionMatchers;
const MenuExpressionMatchers expressionMatchers(state);
auto expression = expressionMatchers.ProcessExpression(result);
if (!expression)
@ -708,9 +708,7 @@ namespace menu::event_handler_set_scope_sequences
{
const ScriptMatcherFactory create(this);
const MenuExpressionMatchers expressionMatchers;
AddLabeledMatchers(expressionMatchers.Expression(this), MenuExpressionMatchers::LABEL_EXPRESSION);
AddMatchers({
create.Char('}'),
create.Keyword("else").Capture(CAPTURE_KEYWORD),

View File

@ -22,10 +22,10 @@ GenericColorPropertySequence::GenericColorPropertySequence(std::string keywordNa
});
}
double GenericColorPropertySequence::ReadColorValue(SequenceResult<SimpleParserValue>& result)
double GenericColorPropertySequence::ReadColorValue(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result)
{
if (result.PeekAndRemoveIfTag(TAG_COLOR) == TAG_COLOR)
return MenuMatcherFactory::TokenNumericExpressionValue(result);
return MenuMatcherFactory::TokenNumericExpressionValue(state, result);
return 0.0;
}
@ -35,10 +35,10 @@ void GenericColorPropertySequence::ProcessMatch(MenuFileParserState* state, Sequ
if (m_set_callback)
{
CommonColor color{};
color.r = ReadColorValue(result);
color.g = ReadColorValue(result);
color.b = ReadColorValue(result);
color.a = ReadColorValue(result);
color.r = ReadColorValue(state, result);
color.g = ReadColorValue(state, result);
color.b = ReadColorValue(state, result);
color.a = ReadColorValue(state, result);
m_set_callback(state, result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), color);
}

View File

@ -20,7 +20,7 @@ namespace menu
const callback_t m_set_callback;
static double ReadColorValue(SequenceResult<SimpleParserValue>& result);
static double ReadColorValue(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result);
protected:
void ProcessMatch(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result) const override;

View File

@ -65,7 +65,7 @@ void GenericExpressionPropertySequence::ProcessMatch(MenuFileParserState* state,
{
if (m_set_callback)
{
const MenuExpressionMatchers expressionMatchers;
const MenuExpressionMatchers expressionMatchers(state);
auto expression = expressionMatchers.ProcessExpression(result);
m_set_callback(state, result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), std::move(expression));
}

View File

@ -23,7 +23,7 @@ void GenericFloatingPointPropertySequence::ProcessMatch(MenuFileParserState* sta
{
if (m_set_callback)
{
const auto value = MenuMatcherFactory::TokenNumericExpressionValue(result);
const auto value = MenuMatcherFactory::TokenNumericExpressionValue(state, result);
m_set_callback(state, result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), value);
}
}

View File

@ -23,7 +23,7 @@ void GenericIntPropertySequence::ProcessMatch(MenuFileParserState* state, Sequen
{
if (m_set_callback)
{
const auto value = MenuMatcherFactory::TokenIntExpressionValue(result);
const auto value = MenuMatcherFactory::TokenIntExpressionValue(state, result);
m_set_callback(state, result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), value);
}
}

View File

@ -188,10 +188,10 @@ namespace menu::item_scope_sequences
{
assert(state->m_current_item);
const auto x = MenuMatcherFactory::TokenNumericExpressionValue(result);
const auto y = MenuMatcherFactory::TokenNumericExpressionValue(result);
const auto w = MenuMatcherFactory::TokenNumericExpressionValue(result);
const auto h = MenuMatcherFactory::TokenNumericExpressionValue(result);
const auto x = MenuMatcherFactory::TokenNumericExpressionValue(state, result);
const auto y = MenuMatcherFactory::TokenNumericExpressionValue(state, result);
const auto w = MenuMatcherFactory::TokenNumericExpressionValue(state, result);
const auto h = MenuMatcherFactory::TokenNumericExpressionValue(state, result);
CommonRect rect
{
x,
@ -231,8 +231,8 @@ namespace menu::item_scope_sequences
{
assert(state->m_current_item);
state->m_current_item->m_rect.x = MenuMatcherFactory::TokenNumericExpressionValue(result);
state->m_current_item->m_rect.y = MenuMatcherFactory::TokenNumericExpressionValue(result);
state->m_current_item->m_rect.x = MenuMatcherFactory::TokenNumericExpressionValue(state, result);
state->m_current_item->m_rect.y = MenuMatcherFactory::TokenNumericExpressionValue(state, result);
}
};
@ -261,9 +261,9 @@ namespace menu::item_scope_sequences
{
assert(state->m_current_item);
state->m_current_item->m_fx_letter_time = MenuMatcherFactory::TokenIntExpressionValue(result);
state->m_current_item->m_fx_decay_start_time = MenuMatcherFactory::TokenIntExpressionValue(result);
state->m_current_item->m_fx_decay_duration = MenuMatcherFactory::TokenIntExpressionValue(result);
state->m_current_item->m_fx_letter_time = MenuMatcherFactory::TokenIntExpressionValue(state, result);
state->m_current_item->m_fx_decay_start_time = MenuMatcherFactory::TokenIntExpressionValue(state, result);
state->m_current_item->m_fx_decay_duration = MenuMatcherFactory::TokenIntExpressionValue(state, result);
}
};
@ -341,9 +341,9 @@ namespace menu::item_scope_sequences
ItemScopeOperations::EnsureHasEditFieldFeatures(*state->m_current_item, result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos());
state->m_current_item->m_dvar = MenuMatcherFactory::TokenTextValue(result.NextCapture(CAPTURE_DVAR_NAME));
state->m_current_item->m_edit_field_features->m_def_val = MenuMatcherFactory::TokenNumericExpressionValue(result);
state->m_current_item->m_edit_field_features->m_min_val = MenuMatcherFactory::TokenNumericExpressionValue(result);
state->m_current_item->m_edit_field_features->m_max_val = MenuMatcherFactory::TokenNumericExpressionValue(result);
state->m_current_item->m_edit_field_features->m_def_val = MenuMatcherFactory::TokenNumericExpressionValue(state, result);
state->m_current_item->m_edit_field_features->m_min_val = MenuMatcherFactory::TokenNumericExpressionValue(state, result);
state->m_current_item->m_edit_field_features->m_max_val = MenuMatcherFactory::TokenNumericExpressionValue(state, result);
}
};
@ -422,7 +422,7 @@ namespace menu::item_scope_sequences
while (result.HasNextCapture(CAPTURE_STEP_NAME))
{
multiValueFeatures->m_step_names.emplace_back(MenuMatcherFactory::TokenTextValue(result.NextCapture(CAPTURE_STEP_NAME)));
multiValueFeatures->m_double_values.emplace_back(MenuMatcherFactory::TokenNumericExpressionValue(result));
multiValueFeatures->m_double_values.emplace_back(MenuMatcherFactory::TokenNumericExpressionValue(state, result));
}
}
};

View File

@ -124,10 +124,10 @@ namespace menu::menu_scope_sequences
{
assert(state->m_current_menu);
const auto x = MenuMatcherFactory::TokenNumericExpressionValue(result);
const auto y = MenuMatcherFactory::TokenNumericExpressionValue(result);
const auto w = MenuMatcherFactory::TokenNumericExpressionValue(result);
const auto h = MenuMatcherFactory::TokenNumericExpressionValue(result);
const auto x = MenuMatcherFactory::TokenNumericExpressionValue(state, result);
const auto y = MenuMatcherFactory::TokenNumericExpressionValue(state, result);
const auto w = MenuMatcherFactory::TokenNumericExpressionValue(state, result);
const auto h = MenuMatcherFactory::TokenNumericExpressionValue(state, result);
CommonRect rect
{
x,