From c4150279d013a9a881225901005ac243315be549 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 6 Jan 2024 19:39:07 +0100 Subject: [PATCH] Add naive expression dumping for menus for debugging purposes --- .../Game/IW4/Menu/MenuDumperIW4.cpp | 102 +++++++++++++++++- src/ObjWriting/Game/IW4/Menu/MenuDumperIW4.h | 2 + .../Game/IW5/Menu/MenuDumperIW5.cpp | 92 +++++++++++++++- src/ObjWriting/Game/IW5/Menu/MenuDumperIW5.h | 2 + 4 files changed, 191 insertions(+), 7 deletions(-) diff --git a/src/ObjWriting/Game/IW4/Menu/MenuDumperIW4.cpp b/src/ObjWriting/Game/IW4/Menu/MenuDumperIW4.cpp index 46ac1b65..63da316b 100644 --- a/src/ObjWriting/Game/IW4/Menu/MenuDumperIW4.cpp +++ b/src/ObjWriting/Game/IW4/Menu/MenuDumperIW4.cpp @@ -9,7 +9,16 @@ using namespace IW4; -size_t MenuDumper::FindStatementClosingParenthesis(const Statement_s* statement, size_t openingParenthesisPosition) +// Uncomment this macro to skip interpretative expression dumping +// #define DUMP_NAIVE + +#ifdef DUMP_NAIVE +#define DUMP_FUNC WriteStatementNaive +#else +#define DUMP_FUNC WriteStatementSkipInitialUnnecessaryParenthesis +#endif + +size_t MenuDumper::FindStatementClosingParenthesis(const Statement_s* statement, const size_t openingParenthesisPosition) { assert(statement->numEntries >= 0); assert(openingParenthesisPosition < static_cast(statement->numEntries)); @@ -206,7 +215,7 @@ void MenuDumper::WriteStatementOperand(const Statement_s* statement, size_t& cur spaceNext = true; } -void MenuDumper::WriteStatementEntryRange(const Statement_s* statement, size_t startOffset, size_t endOffset) const +void MenuDumper::WriteStatementEntryRange(const Statement_s* statement, const size_t startOffset, const size_t endOffset) const { assert(startOffset <= endOffset); assert(endOffset <= static_cast(statement->numEntries)); @@ -260,6 +269,91 @@ void MenuDumper::WriteStatementSkipInitialUnnecessaryParenthesis(const Statement } } +void MenuDumper::WriteStatementNaive(const Statement_s* statement) const +{ + const auto entryCount = static_cast(statement->numEntries); + + const auto missingClosingParenthesis = statement->numEntries > 0 && statement->entries[0].type == EET_OPERATOR + && statement->entries[0].data.op == OP_LEFTPAREN + && FindStatementClosingParenthesis(statement, 0) >= static_cast(statement->numEntries); + + for (auto i = 0u; i < entryCount; i++) + { + const auto& entry = statement->entries[i]; + if (entry.type == EET_OPERAND) + { + size_t pos = i; + bool discard = false; + WriteStatementOperand(statement, pos, discard); + } + else if (entry.data.op >= EXP_FUNC_STATIC_DVAR_INT && entry.data.op <= EXP_FUNC_STATIC_DVAR_STRING) + { + switch (entry.data.op) + { + case EXP_FUNC_STATIC_DVAR_INT: + m_stream << "dvarint"; + break; + + case EXP_FUNC_STATIC_DVAR_BOOL: + m_stream << "dvarbool"; + break; + + case EXP_FUNC_STATIC_DVAR_FLOAT: + m_stream << "dvarfloat"; + break; + + case EXP_FUNC_STATIC_DVAR_STRING: + m_stream << "dvarstring"; + break; + + default: + break; + } + + // Functions do not have opening parenthesis in the entries. We can just pretend they do though + const auto closingParenPos = FindStatementClosingParenthesis(statement, i); + m_stream << "("; + + if (closingParenPos - i + 1 >= 1) + { + const auto& staticDvarEntry = statement->entries[i + 1]; + if (staticDvarEntry.type == EET_OPERAND && staticDvarEntry.data.operand.dataType == VAL_INT) + { + if (statement->supportingData && statement->supportingData->staticDvarList.staticDvars && staticDvarEntry.data.operand.internals.intVal >= 0 + && staticDvarEntry.data.operand.internals.intVal < statement->supportingData->staticDvarList.numStaticDvars) + { + const auto* staticDvar = statement->supportingData->staticDvarList.staticDvars[staticDvarEntry.data.operand.internals.intVal]; + if (staticDvar && staticDvar->dvarName) + m_stream << staticDvar->dvarName; + } + else + { + m_stream << "#INVALID_DVAR_INDEX"; + } + } + else + { + m_stream << "#INVALID_DVAR_OPERAND"; + } + } + + m_stream << ")"; + i = closingParenPos; + } + else + { + assert(entry.data.op >= 0 && static_cast(entry.data.op) < std::extent_v); + if (entry.data.op >= 0 && static_cast(entry.data.op) < std::extent_v) + m_stream << g_expFunctionNames[entry.data.op]; + if (entry.data.op >= OP_COUNT) + m_stream << "("; + } + } + + if (missingClosingParenthesis) + m_stream << ")"; +} + void MenuDumper::WriteStatementProperty(const std::string& propertyKey, const Statement_s* statementValue, bool isBooleanStatement) const { if (statementValue == nullptr || statementValue->numEntries < 0) @@ -271,12 +365,12 @@ void MenuDumper::WriteStatementProperty(const std::string& propertyKey, const St if (isBooleanStatement) { m_stream << "when("; - WriteStatementSkipInitialUnnecessaryParenthesis(statementValue); + DUMP_FUNC(statementValue); m_stream << ");\n"; } else { - WriteStatementSkipInitialUnnecessaryParenthesis(statementValue); + DUMP_FUNC(statementValue); m_stream << ";\n"; } } diff --git a/src/ObjWriting/Game/IW4/Menu/MenuDumperIW4.h b/src/ObjWriting/Game/IW4/Menu/MenuDumperIW4.h index 89a84349..9baff905 100644 --- a/src/ObjWriting/Game/IW4/Menu/MenuDumperIW4.h +++ b/src/ObjWriting/Game/IW4/Menu/MenuDumperIW4.h @@ -11,6 +11,8 @@ namespace IW4 { static size_t FindStatementClosingParenthesis(const Statement_s* statement, size_t openingParenthesisPosition); + void WriteStatementNaive(const Statement_s* statement) const; + void WriteStatementOperator(const Statement_s* statement, size_t& currentPos, bool& spaceNext) const; void WriteStatementOperandFunction(const Statement_s* statement, size_t currentPos) const; void WriteStatementOperand(const Statement_s* statement, size_t& currentPos, bool& spaceNext) const; diff --git a/src/ObjWriting/Game/IW5/Menu/MenuDumperIW5.cpp b/src/ObjWriting/Game/IW5/Menu/MenuDumperIW5.cpp index 8eb879f2..e1f8ff55 100644 --- a/src/ObjWriting/Game/IW5/Menu/MenuDumperIW5.cpp +++ b/src/ObjWriting/Game/IW5/Menu/MenuDumperIW5.cpp @@ -9,6 +9,15 @@ using namespace IW5; +// Uncomment this macro to skip interpretative expression dumping +// #define DUMP_NAIVE + +#ifdef DUMP_NAIVE +#define DUMP_FUNC WriteStatementNaive +#else +#define DUMP_FUNC WriteStatementSkipInitialUnnecessaryParenthesis +#endif + size_t MenuDumper::FindStatementClosingParenthesis(const Statement_s* statement, size_t openingParenthesisPosition) { assert(statement->numEntries >= 0); @@ -23,7 +32,7 @@ size_t MenuDumper::FindStatementClosingParenthesis(const Statement_s* statement, { const auto& expEntry = statement->entries[currentSearchPosition]; if (expEntry.type != EET_OPERATOR) - continue; + continue; // Any function means a "left out" left paren if (expEntry.data.op == OP_LEFTPAREN || expEntry.data.op >= OP_COUNT) @@ -228,6 +237,83 @@ void MenuDumper::WriteStatementEntryRange(const Statement_s* statement, size_t s } } +void MenuDumper::WriteStatementNaive(const Statement_s* statement) const +{ + const auto entryCount = static_cast(statement->numEntries); + for (auto i = 0u; i < entryCount; i++) + { + const auto& entry = statement->entries[i]; + if (entry.type == EET_OPERAND) + { + size_t pos = i; + bool discard = false; + WriteStatementOperand(statement, pos, discard); + } + else if (entry.data.op >= EXP_FUNC_STATIC_DVAR_INT && entry.data.op <= EXP_FUNC_STATIC_DVAR_STRING) + { + switch (entry.data.op) + { + case EXP_FUNC_STATIC_DVAR_INT: + m_stream << "dvarint"; + break; + + case EXP_FUNC_STATIC_DVAR_BOOL: + m_stream << "dvarbool"; + break; + + case EXP_FUNC_STATIC_DVAR_FLOAT: + m_stream << "dvarfloat"; + break; + + case EXP_FUNC_STATIC_DVAR_STRING: + m_stream << "dvarstring"; + break; + + default: + break; + } + + // Functions do not have opening parenthesis in the entries. We can just pretend they do though + const auto closingParenPos = FindStatementClosingParenthesis(statement, i); + m_stream << "("; + + if (closingParenPos - i + 1 >= 1) + { + const auto& staticDvarEntry = statement->entries[i + 1]; + if (staticDvarEntry.type == EET_OPERAND && staticDvarEntry.data.operand.dataType == VAL_INT) + { + if (statement->supportingData && statement->supportingData->staticDvarList.staticDvars && staticDvarEntry.data.operand.internals.intVal >= 0 + && staticDvarEntry.data.operand.internals.intVal < statement->supportingData->staticDvarList.numStaticDvars) + { + const auto* staticDvar = statement->supportingData->staticDvarList.staticDvars[staticDvarEntry.data.operand.internals.intVal]; + if (staticDvar && staticDvar->dvarName) + m_stream << staticDvar->dvarName; + } + else + { + m_stream << "#INVALID_DVAR_INDEX"; + } + } + else + { + m_stream << "#INVALID_DVAR_OPERAND"; + } + } + + m_stream << ")"; + i = closingParenPos; + } + else + { + assert(entry.data.op >= 0 && static_cast(entry.data.op) < std::extent_v); + if (entry.data.op >= 0 && static_cast(entry.data.op) < std::extent_v) + m_stream << g_expFunctionNames[entry.data.op]; + if (entry.data.op >= OP_COUNT) + m_stream << "("; + } + } +} + void MenuDumper::WriteStatement(const Statement_s* statement) const { if (statement == nullptr || statement->numEntries < 0) @@ -271,12 +357,12 @@ void MenuDumper::WriteStatementProperty(const std::string& propertyKey, const St if (isBooleanStatement) { m_stream << "when("; - WriteStatementSkipInitialUnnecessaryParenthesis(statementValue); + DUMP_FUNC(statementValue); m_stream << ");\n"; } else { - WriteStatementSkipInitialUnnecessaryParenthesis(statementValue); + DUMP_FUNC(statementValue); m_stream << ";\n"; } } diff --git a/src/ObjWriting/Game/IW5/Menu/MenuDumperIW5.h b/src/ObjWriting/Game/IW5/Menu/MenuDumperIW5.h index 4879eb6d..9e3e3000 100644 --- a/src/ObjWriting/Game/IW5/Menu/MenuDumperIW5.h +++ b/src/ObjWriting/Game/IW5/Menu/MenuDumperIW5.h @@ -11,6 +11,8 @@ namespace IW5 { static size_t FindStatementClosingParenthesis(const Statement_s* statement, size_t openingParenthesisPosition); + void WriteStatementNaive(const Statement_s* statement) const; + void WriteStatementOperator(const Statement_s* statement, size_t& currentPos, bool& spaceNext) const; void WriteStatementOperandFunction(const Statement_s* statement, size_t currentPos) const; void WriteStatementOperand(const Statement_s* statement, size_t& currentPos, bool& spaceNext) const;