diff --git a/src/ObjLoading/Parsing/Menu/Domain/EventHandler/CommonEventHandlerSetLocalVar.cpp b/src/ObjLoading/Parsing/Menu/Domain/EventHandler/CommonEventHandlerSetLocalVar.cpp index 68e38f12..a21253f7 100644 --- a/src/ObjLoading/Parsing/Menu/Domain/EventHandler/CommonEventHandlerSetLocalVar.cpp +++ b/src/ObjLoading/Parsing/Menu/Domain/EventHandler/CommonEventHandlerSetLocalVar.cpp @@ -3,10 +3,13 @@ using namespace menu; CommonEventHandlerSetLocalVar::CommonEventHandlerSetLocalVar() -= default; + : m_type(SetLocalVarType::UNKNOWN) +{ +} -CommonEventHandlerSetLocalVar::CommonEventHandlerSetLocalVar(std::string varName, std::unique_ptr value) - : m_var_name(std::move(varName)), +CommonEventHandlerSetLocalVar::CommonEventHandlerSetLocalVar(SetLocalVarType type, std::string varName, std::unique_ptr value) + : m_type(type), + m_var_name(std::move(varName)), m_value(std::move(value)) { } diff --git a/src/ObjLoading/Parsing/Menu/Domain/EventHandler/CommonEventHandlerSetLocalVar.h b/src/ObjLoading/Parsing/Menu/Domain/EventHandler/CommonEventHandlerSetLocalVar.h index 3385b24b..af0fc768 100644 --- a/src/ObjLoading/Parsing/Menu/Domain/EventHandler/CommonEventHandlerSetLocalVar.h +++ b/src/ObjLoading/Parsing/Menu/Domain/EventHandler/CommonEventHandlerSetLocalVar.h @@ -7,14 +7,24 @@ namespace menu { + enum class SetLocalVarType + { + UNKNOWN, + BOOL, + INT, + FLOAT, + STRING + }; + class CommonEventHandlerSetLocalVar final : public ICommonEventHandlerElement { public: + SetLocalVarType m_type; std::string m_var_name; std::unique_ptr m_value; CommonEventHandlerSetLocalVar(); - CommonEventHandlerSetLocalVar(std::string varName, std::unique_ptr value); + CommonEventHandlerSetLocalVar(SetLocalVarType type, std::string varName, std::unique_ptr value); CommonEventHandlerElementType GetType() override; }; diff --git a/src/ObjLoading/Parsing/Menu/Sequence/EventHandlerSetScopeSequences.cpp b/src/ObjLoading/Parsing/Menu/Sequence/EventHandlerSetScopeSequences.cpp index 9cc64303..1a9452d5 100644 --- a/src/ObjLoading/Parsing/Menu/Sequence/EventHandlerSetScopeSequences.cpp +++ b/src/ObjLoading/Parsing/Menu/Sequence/EventHandlerSetScopeSequences.cpp @@ -1,13 +1,111 @@ #include "EventHandlerSetScopeSequences.h" #include +#include +#include #include "Generic/GenericStringPropertySequence.h" #include "Parsing/Menu/Domain/EventHandler/CommonEventHandlerScript.h" +#include "Parsing/Menu/Domain/EventHandler/CommonEventHandlerSetLocalVar.h" +#include "Parsing/Menu/Matcher/MenuCommonMatchers.h" #include "Parsing/Menu/Matcher/MenuMatcherFactory.h" using namespace menu; +namespace menu +{ + enum class ExpectedScriptToken + { + NUMERIC, + INT, + TEXT + }; + + class ScriptMatcherFactory final : public MenuMatcherFactory + { + public: + explicit ScriptMatcherFactory(const IMatcherForLabelSupplier* labelSupplier) + : MenuMatcherFactory(labelSupplier) + { + } + + _NODISCARD MatcherFactoryWrapper ScriptNumeric() const + { + return Or({ + Type(SimpleParserValueType::INTEGER).Transform([](const token_list_t& tokens)-> SimpleParserValue + { + const auto& firstToken = tokens[0].get(); + return SimpleParserValue::String(firstToken.GetPos(), new std::string(std::to_string(firstToken.IntegerValue()))); + }), + Type(SimpleParserValueType::FLOATING_POINT).Transform([](const token_list_t& tokens)-> SimpleParserValue + { + const auto& firstToken = tokens[0].get(); + return SimpleParserValue::String(firstToken.GetPos(), new std::string(std::to_string(firstToken.FloatingPointValue()))); + }), + Or({ + Type(SimpleParserValueType::CHARACTER), + Type(SimpleParserValueType::STRING), + Type(SimpleParserValueType::IDENTIFIER), + }).Transform([](const token_list_t& tokens) -> SimpleParserValue + { + return SimpleParserValue::Integer(tokens[0].get().GetPos(), static_cast(ExpectedScriptToken::INT)); + }) + }); + } + + _NODISCARD MatcherFactoryWrapper ScriptInt() const + { + return Or({ + Type(SimpleParserValueType::INTEGER).Transform([](const token_list_t& tokens)-> SimpleParserValue + { + const auto& firstToken = tokens[0].get(); + return SimpleParserValue::String(firstToken.GetPos(), new std::string(std::to_string(firstToken.IntegerValue()))); + }), + Or({ + Type(SimpleParserValueType::CHARACTER), + Type(SimpleParserValueType::FLOATING_POINT), + Type(SimpleParserValueType::STRING), + Type(SimpleParserValueType::IDENTIFIER), + }).Transform([](const token_list_t& tokens) -> SimpleParserValue + { + return SimpleParserValue::Integer(tokens[0].get().GetPos(), static_cast(ExpectedScriptToken::INT)); + }) + }); + } + + _NODISCARD MatcherFactoryWrapper ScriptText() const + { + return Or({ + Type(SimpleParserValueType::STRING), + Type(SimpleParserValueType::IDENTIFIER), + Or({ + Type(SimpleParserValueType::CHARACTER), + Type(SimpleParserValueType::FLOATING_POINT), + Type(SimpleParserValueType::INTEGER), + }).Transform([](const token_list_t& tokens) -> SimpleParserValue + { + return SimpleParserValue::Integer(tokens[0].get().GetPos(), static_cast(ExpectedScriptToken::TEXT)); + }) + }); + } + + _NODISCARD MatcherFactoryWrapper ScriptKeyword(std::string keyword) const + { + return KeywordIgnoreCase(std::move(keyword)); + } + + _NODISCARD MatcherFactoryWrapper ScriptColor() const + { + return And({ + Optional(ScriptNumeric()), + Optional(ScriptNumeric()), + Optional(ScriptNumeric()), + Optional(ScriptNumeric()) + }); + } + }; +} + namespace menu::event_handler_set_scope_sequences { class SequenceCloseBlock final : public MenuFileParser::sequence_t @@ -36,7 +134,7 @@ namespace menu::event_handler_set_scope_sequences { state->m_condition_stack.pop(); - if(!state->m_condition_stack.empty()) + if (!state->m_condition_stack.empty()) { const auto& newConditionState = state->m_condition_stack.top(); if (newConditionState.m_in_condition_elements) @@ -54,6 +152,233 @@ namespace menu::event_handler_set_scope_sequences } } }; + + class SequenceSkipEmptyStatements final : public MenuFileParser::sequence_t + { + public: + SequenceSkipEmptyStatements() + { + const MenuMatcherFactory create(this); + + AddMatchers({ + create.Char(';') + }); + } + + protected: + void ProcessMatch(MenuFileParserState* state, SequenceResult& result) const override + { + } + }; + + class SequenceGenericScriptStatement : public MenuFileParser::sequence_t + { + protected: + static constexpr auto CAPTURE_SCRIPT_TOKEN = 1; + + SequenceGenericScriptStatement() = default; + + public: + explicit SequenceGenericScriptStatement(std::initializer_list>>> matchers) + { + const MenuMatcherFactory create(this); + + AddMatchers({ + create.And(matchers).Capture(CAPTURE_SCRIPT_TOKEN), + create.Optional(create.Char(';')) + }); + } + + static std::unique_ptr Create(std::initializer_list>>> matchers) + { + return std::make_unique(matchers); + } + + private: + static std::string ScriptTokenTypeToString(int tokenType) + { + switch (static_cast(tokenType)) + { + case ExpectedScriptToken::INT: + return "INT"; + + case ExpectedScriptToken::NUMERIC: + return "NUMERIC"; + + case ExpectedScriptToken::TEXT: + return "TEXT"; + + default: + return "UNKNOWN"; + } + } + + protected: + void ProcessMatch(MenuFileParserState* state, SequenceResult& result) const override + { + while (result.HasNextCapture(CAPTURE_SCRIPT_TOKEN)) + { + const auto& capture = result.NextCapture(CAPTURE_SCRIPT_TOKEN); + + if (capture.m_type == SimpleParserValueType::IDENTIFIER) + { + state->m_current_script << "\"" << capture.IdentifierValue() << "\" "; + } + else if (capture.m_type == SimpleParserValueType::STRING) + { + state->m_current_script << "\"" << capture.StringValue() << "\" "; + } + else if (capture.m_type == SimpleParserValueType::INTEGER) + { + std::ostringstream ss; + ss << "Invalid script token. Expected " << ScriptTokenTypeToString(capture.IntegerValue()) << "."; + + throw ParsingException(capture.GetPos(), ss.str()); + } + else + throw ParsingException(capture.GetPos(), "Invalid script capture"); + } + + state->m_current_script << "; "; + } + }; + + class SequenceSetPlayerData final : public SequenceGenericScriptStatement + { + public: + explicit SequenceSetPlayerData() + { + const MenuMatcherFactory create(this); + + AddMatchers({ + create.And({ + }).Capture(CAPTURE_SCRIPT_TOKEN), + create.Optional(create.Char(';')) + }); + } + }; + + class SequenceSetLocalVar final : public MenuFileParser::sequence_t + { + static constexpr auto TAG_BOOL = static_cast(SetLocalVarType::BOOL); + static constexpr auto TAG_INT = static_cast(SetLocalVarType::INT); + static constexpr auto TAG_FLOAT = static_cast(SetLocalVarType::FLOAT); + static constexpr auto TAG_STRING = static_cast(SetLocalVarType::STRING); + + static constexpr auto CAPTURE_VAR_NAME = 1; + + public: + SequenceSetLocalVar() + { + const ScriptMatcherFactory create(this); + + AddLabeledMatchers(MenuCommonMatchers::Expression(this), MenuCommonMatchers::LABEL_EXPRESSION); + + AddMatchers({ + create.Or({ + create.ScriptKeyword("setLocalVarBool").Tag(TAG_BOOL), + create.ScriptKeyword("setLocalVarInt").Tag(TAG_INT), + create.ScriptKeyword("setLocalVarFloat").Tag(TAG_FLOAT), + create.ScriptKeyword("setLocalVarString").Tag(TAG_STRING) + }), + create.ScriptText().Capture(CAPTURE_VAR_NAME), + create.Label(MenuCommonMatchers::LABEL_EXPRESSION), + create.Optional(create.Char(';')) + }); + } + + private: + static std::string ScriptKeywordForType(const SetLocalVarType type) + { + switch (type) + { + case SetLocalVarType::BOOL: + return "setLocalVarBool"; + case SetLocalVarType::INT: + return "setLocalVarInt"; + case SetLocalVarType::FLOAT: + return "setLocalVarFloat"; + case SetLocalVarType::STRING: + return "setLocalVarString"; + default: + return "unknown"; + } + } + + static void EmitStaticValue(MenuFileParserState* state, const CommonExpressionValue& value) + { + switch (value.m_type) + { + case CommonExpressionValue::Type::DOUBLE: + state->m_current_script << value.m_double_value; + break; + + case CommonExpressionValue::Type::INT: + state->m_current_script << value.m_int_value; + break; + + case CommonExpressionValue::Type::STRING: + state->m_current_script << *value.m_string_value; + break; + } + } + + static void CheckStaticValueType(const TokenPos& pos, const SetLocalVarType type, const CommonExpressionValue& staticValue) + { + switch (type) + { + case SetLocalVarType::BOOL: + if (staticValue.m_type != CommonExpressionValue::Type::INT) + throw ParsingException(pos, "Static value must be BOOL"); + break; + + case SetLocalVarType::INT: + if (staticValue.m_type != CommonExpressionValue::Type::INT) + throw ParsingException(pos, "Static value must be INT"); + break; + + case SetLocalVarType::FLOAT: + if (staticValue.m_type != CommonExpressionValue::Type::DOUBLE && staticValue.m_type != CommonExpressionValue::Type::INT) + throw ParsingException(pos, "Static value must be FLOAT"); + break; + + case SetLocalVarType::STRING: + default: + break; + } + } + + static void EmitStaticSetLocalVar(MenuFileParserState* state, const TokenPos& pos, const SetLocalVarType type, const std::string& varName, std::unique_ptr expression) + { + state->m_current_script << "\"" << ScriptKeywordForType(type) << "\" \"" << varName << "\" \""; + const auto staticValue = expression->Evaluate(); + CheckStaticValueType(pos, type, staticValue); + EmitStaticValue(state, staticValue); + state->m_current_script << "\" ; "; + } + + static void EmitDynamicSetLocalVar(const MenuFileParserState* state, const SetLocalVarType type, const std::string& varName, std::unique_ptr expression) + { + state->m_current_nested_event_handler_set->m_elements.emplace_back(std::make_unique(type, varName, std::move(expression))); + } + + protected: + void ProcessMatch(MenuFileParserState* state, SequenceResult& result) const override + { + const auto typeTag = static_cast(result.NextTag()); + const auto& varNameToken = result.NextCapture(CAPTURE_VAR_NAME); + const auto& varName = MenuMatcherFactory::TokenTextValue(varNameToken); + auto expression = MenuCommonMatchers::ProcessExpression(state, result); + + if (!expression) + throw ParsingException(varNameToken.GetPos(), "No expression"); + + if (expression && expression->IsStatic()) + EmitStaticSetLocalVar(state, varNameToken.GetPos(), typeTag, varName, std::move(expression)); + else + EmitDynamicSetLocalVar(state, typeTag, varName, std::move(expression)); + } + }; } using namespace event_handler_set_scope_sequences; @@ -66,4 +391,66 @@ EventHandlerSetScopeSequences::EventHandlerSetScopeSequences(std::vector()); + AddSequence(std::make_unique()); + // If else and stuff + + // Creating factory with no label supplier. Cannot use labels with it. + const ScriptMatcherFactory create(nullptr); + + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("fadeIn"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("fadeOut"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("show"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("hide"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("showMenu"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("hideMenu"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("setColor"), create.ScriptColor()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("open"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("close"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("escape"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("closeForAllPlayers"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("ingameOpen"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("ingameClose"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("setBackground"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("setItemColor"), create.ScriptText(), create.ScriptText(), create.ScriptColor()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("focusFirst")})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("setFocus"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("setFocusByDvar"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("setDvar"), create.ScriptText(), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("exec"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("execNow"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("execOnDvarStringValue"), create.ScriptText(), create.ScriptText(), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("execOnDvarIntValue"), create.ScriptText(), create.ScriptInt(), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("execOnDvarFloatValue"), create.ScriptText(), create.ScriptNumeric(), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("execNowOnDvarStringValue"), create.ScriptText(), create.ScriptText(), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("execNowOnDvarIntValue"), create.ScriptText(), create.ScriptInt(), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("execNowOnDvarFloatValue"), create.ScriptText(), create.ScriptNumeric(), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("play"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("scriptMenuResponse"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("respondOnDvarStringValue"), create.ScriptText(), create.ScriptText(), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("respondOnDvarIntValue"), create.ScriptText(), create.ScriptInt(), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("respondOnDvarFloatValue"), create.ScriptText(), create.ScriptNumeric(), create.ScriptText()})); + AddSequence(std::make_unique()); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("setPlayerDataSp")})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("updateMail")})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("openMail")})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("deleteMail")})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("doMailLottery")})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("resetStatsConfirm")})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("resetStatsCancel")})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("setGameMode"), create.ScriptText()})); + AddSequence(std::make_unique()); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("feederTop")})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("feederBottom")})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("showGamerCard")})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("openForGameType"), create.ScriptText()})); + AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("closeForGameType"), create.ScriptText()})); + // statClearPerkNew + // statSetUsingTable + // statClearBitMask + AddSequence(SequenceGenericScriptStatement::Create({ create.ScriptKeyword("kickPlayer") })); + AddSequence(SequenceGenericScriptStatement::Create({ create.ScriptKeyword("getKickPlayerQuestion") })); + AddSequence(SequenceGenericScriptStatement::Create({ create.ScriptKeyword("partyUpdateMissingMapPackDvar") })); + AddSequence(SequenceGenericScriptStatement::Create({ create.ScriptKeyword("togglePlayerMute") })); + AddSequence(SequenceGenericScriptStatement::Create({ create.ScriptKeyword("resolveError") })); + // lerp }