diff --git a/src/ObjLoading/Parsing/Menu/Sequence/Generic/GenericMenuEventHandlerSetPropertySequence.cpp b/src/ObjLoading/Parsing/Menu/Sequence/Generic/GenericMenuEventHandlerSetPropertySequence.cpp index 2a7eac99..fafcfcc9 100644 --- a/src/ObjLoading/Parsing/Menu/Sequence/Generic/GenericMenuEventHandlerSetPropertySequence.cpp +++ b/src/ObjLoading/Parsing/Menu/Sequence/Generic/GenericMenuEventHandlerSetPropertySequence.cpp @@ -21,9 +21,11 @@ void GenericMenuEventHandlerSetPropertySequence::ProcessMatch(MenuFileParserStat { if (m_set_callback) { - auto newEventHandlerSet = std::make_unique(); - state->m_current_event_handler_set = newEventHandlerSet.get(); - state->m_current_nested_event_handler_set = newEventHandlerSet.get(); - m_set_callback(state, result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), std::move(newEventHandlerSet)); + auto& eventHandlerPtr = m_set_callback(state, result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos()); + if(!eventHandlerPtr) + eventHandlerPtr = std::make_unique(); + + state->m_current_event_handler_set = eventHandlerPtr.get(); + state->m_current_nested_event_handler_set = eventHandlerPtr.get(); } } diff --git a/src/ObjLoading/Parsing/Menu/Sequence/Generic/GenericMenuEventHandlerSetPropertySequence.h b/src/ObjLoading/Parsing/Menu/Sequence/Generic/GenericMenuEventHandlerSetPropertySequence.h index 81479be8..217c753f 100644 --- a/src/ObjLoading/Parsing/Menu/Sequence/Generic/GenericMenuEventHandlerSetPropertySequence.h +++ b/src/ObjLoading/Parsing/Menu/Sequence/Generic/GenericMenuEventHandlerSetPropertySequence.h @@ -11,7 +11,7 @@ namespace menu class GenericMenuEventHandlerSetPropertySequence final : public MenuFileParser::sequence_t { public: - using callback_t = std::function value)>; + using callback_t = std::function& (MenuFileParserState* state, const TokenPos& pos)>; private: static constexpr auto CAPTURE_FIRST_TOKEN = 1; diff --git a/src/ObjLoading/Parsing/Menu/Sequence/ItemScopeSequences.cpp b/src/ObjLoading/Parsing/Menu/Sequence/ItemScopeSequences.cpp index 7411fb0d..693cc025 100644 --- a/src/ObjLoading/Parsing/Menu/Sequence/ItemScopeSequences.cpp +++ b/src/ObjLoading/Parsing/Menu/Sequence/ItemScopeSequences.cpp @@ -681,37 +681,37 @@ void ItemScopeSequences::AddSequences(FeatureLevel featureLevel, bool permissive { state->m_current_item->m_background = value; })); - AddSequence(std::make_unique("onFocus", [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr value) + AddSequence(std::make_unique("onFocus", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { - state->m_current_item->m_on_focus = std::move(value); + return state->m_current_item->m_on_focus; })); - AddSequence(std::make_unique("leaveFocus", [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr value) + AddSequence(std::make_unique("leaveFocus", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { - state->m_current_item->m_on_leave_focus = std::move(value); + return state->m_current_item->m_on_leave_focus; })); - AddSequence(std::make_unique("mouseEnter", [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr value) + AddSequence(std::make_unique("mouseEnter", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { - state->m_current_item->m_on_mouse_enter = std::move(value); + return state->m_current_item->m_on_mouse_enter; })); - AddSequence(std::make_unique("mouseExit", [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr value) + AddSequence(std::make_unique("mouseExit", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { - state->m_current_item->m_on_mouse_exit = std::move(value); + return state->m_current_item->m_on_mouse_exit; })); - AddSequence(std::make_unique("mouseEnterText", [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr value) + AddSequence(std::make_unique("mouseEnterText", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { - state->m_current_item->m_on_mouse_enter_text = std::move(value); + return state->m_current_item->m_on_mouse_enter_text; })); - AddSequence(std::make_unique("mouseExitText", [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr value) + AddSequence(std::make_unique("mouseExitText", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { - state->m_current_item->m_on_mouse_exit_text = std::move(value); + return state->m_current_item->m_on_mouse_exit_text; })); - AddSequence(std::make_unique("action", [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr value) + AddSequence(std::make_unique("action", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { - state->m_current_item->m_on_action = std::move(value); + return state->m_current_item->m_on_action; })); - AddSequence(std::make_unique("accept", [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr value) + AddSequence(std::make_unique("accept", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { - state->m_current_item->m_on_accept = std::move(value); + return state->m_current_item->m_on_accept; })); // special AddSequence(std::make_unique("dvar", [](const MenuFileParserState* state, const TokenPos&, const std::string& value) @@ -891,10 +891,10 @@ void ItemScopeSequences::AddSequences(FeatureLevel featureLevel, bool permissive ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos); state->m_current_item->m_list_box_features->m_element_style = value; })); - AddSequence(std::make_unique("doubleclick", [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr value) + AddSequence(std::make_unique("doubleclick", [](const MenuFileParserState* state, const TokenPos& pos) -> std::unique_ptr& { ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos); - state->m_current_item->m_list_box_features->m_on_double_click = std::move(value); + return state->m_current_item->m_list_box_features->m_on_double_click; })); AddSequence(std::make_unique("selectBorder", [](const MenuFileParserState* state, const TokenPos& pos, const CommonColor value) { diff --git a/src/ObjLoading/Parsing/Menu/Sequence/MenuScopeSequences.cpp b/src/ObjLoading/Parsing/Menu/Sequence/MenuScopeSequences.cpp index 6dcb8d73..3405d097 100644 --- a/src/ObjLoading/Parsing/Menu/Sequence/MenuScopeSequences.cpp +++ b/src/ObjLoading/Parsing/Menu/Sequence/MenuScopeSequences.cpp @@ -258,21 +258,21 @@ void MenuScopeSequences::AddSequences(FeatureLevel featureLevel, bool permissive { state->m_current_menu->m_visible_expression = std::move(value); })); - AddSequence(std::make_unique("onOpen", [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr value) + AddSequence(std::make_unique("onOpen", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { - state->m_current_menu->m_on_open = std::move(value); + return state->m_current_menu->m_on_open; })); - AddSequence(std::make_unique("onClose", [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr value) + AddSequence(std::make_unique("onClose", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { - state->m_current_menu->m_on_close = std::move(value); + return state->m_current_menu->m_on_close; })); - AddSequence(std::make_unique("onRequestClose", [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr value) + AddSequence(std::make_unique("onRequestClose", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { - state->m_current_menu->m_on_request_close = std::move(value); + return state->m_current_menu->m_on_request_close; })); - AddSequence(std::make_unique("onESC", [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr value) + AddSequence(std::make_unique("onESC", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { - state->m_current_menu->m_on_esc = std::move(value); + return state->m_current_menu->m_on_esc; })); AddSequence(std::make_unique("border", [](const MenuFileParserState* state, const TokenPos&, const int value) { diff --git a/test/ObjLoadingTests/Game/IW4/Menu/MenuParsingIW4IT.cpp b/test/ObjLoadingTests/Game/IW4/Menu/MenuParsingIW4IT.cpp index 703e2dba..c5103f8b 100644 --- a/test/ObjLoadingTests/Game/IW4/Menu/MenuParsingIW4IT.cpp +++ b/test/ObjLoadingTests/Game/IW4/Menu/MenuParsingIW4IT.cpp @@ -271,7 +271,7 @@ namespace test::game::iw4::menu::parsing::it ItemKeyHandler* qKeyHandler; ItemKeyHandler* leetKeyHandler; - if(keyHandler1->key == 'q') + if (keyHandler1->key == 'q') { qKeyHandler = keyHandler1; leetKeyHandler = keyHandler2; @@ -299,4 +299,83 @@ namespace test::game::iw4::menu::parsing::it REQUIRE(menu->itemCount == 0); REQUIRE(menu->items == nullptr); } + + TEST_CASE("MenuParsingIW4IT: Can specify event handler multiple times", "[parsing][converting][menu][it]") + { + MenuParsingItHelper helper; + + helper.AddFile(R"testmenu( +{ + menuDef + { + name "Blab" + onOpen + { + focusFirst; + } + onOpen + { + play "fart_sound"; + } + onOpen + { + exec "wait 1; set r_fullbright 1"; + } + + itemDef + { + action + { + play "lmfao"; + } + action + { + play "lol"; + } + } + } +} + )testmenu"); + + const auto result = helper.RunIntegrationTest(); + REQUIRE(result); + + const auto* menuList = helper.GetMenuListAsset(); + const auto* menu = helper.GetMenuAsset("Blab"); + + REQUIRE(menuList->menuCount == 1); + REQUIRE(menuList->menus); + + REQUIRE(menuList->menus[0] == menu); + + REQUIRE(menu->window.name == "Blab"s); + + REQUIRE(menu->onOpen != nullptr); + REQUIRE(menu->onOpen->eventHandlerCount == 3); + REQUIRE(menu->onOpen->eventHandlers[0]->eventType == EventType::EVENT_UNCONDITIONAL); + REQUIRE(menu->onOpen->eventHandlers[0]->eventData.unconditionalScript != nullptr); + REQUIRE(menu->onOpen->eventHandlers[0]->eventData.unconditionalScript == R"("focusFirst" ; )"s); + REQUIRE(menu->onOpen->eventHandlers[1]->eventType == EventType::EVENT_UNCONDITIONAL); + REQUIRE(menu->onOpen->eventHandlers[1]->eventData.unconditionalScript != nullptr); + REQUIRE(menu->onOpen->eventHandlers[1]->eventData.unconditionalScript == R"("play" "fart_sound" ; )"s); + REQUIRE(menu->onOpen->eventHandlers[2]->eventType == EventType::EVENT_UNCONDITIONAL); + REQUIRE(menu->onOpen->eventHandlers[2]->eventData.unconditionalScript != nullptr); + REQUIRE(menu->onOpen->eventHandlers[2]->eventData.unconditionalScript == R"("exec" "wait 1; set r_fullbright 1" ; )"s); + + + REQUIRE(menu->itemCount == 1); + REQUIRE(menu->items != nullptr); + + const auto* item = menu->items[0]; + REQUIRE(item != nullptr); + + REQUIRE(item->action != nullptr); + REQUIRE(item->action->eventHandlerCount == 2); + REQUIRE(item->action->eventHandlers[0]->eventType == EventType::EVENT_UNCONDITIONAL); + REQUIRE(item->action->eventHandlers[0]->eventData.unconditionalScript != nullptr); + REQUIRE(item->action->eventHandlers[0]->eventData.unconditionalScript == R"("play" "lmfao" ; )"s); + REQUIRE(item->action->eventHandlers[1]->eventType == EventType::EVENT_UNCONDITIONAL); + REQUIRE(item->action->eventHandlers[1]->eventData.unconditionalScript != nullptr); + REQUIRE(item->action->eventHandlers[1]->eventData.unconditionalScript == R"("play" "lol" ; )"s); + } }