From 71b467f0d5773b38ba70055b30a0b6eea5eb60a2 Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Sat, 9 Aug 2025 02:28:59 -0700 Subject: [PATCH 1/6] Fix re-entrant call to VideoSession::reset(). --- SerialPrograms/Source/CommonFramework/Globals.cpp | 2 +- .../Source/CommonFramework/VideoPipeline/VideoSession.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/SerialPrograms/Source/CommonFramework/Globals.cpp b/SerialPrograms/Source/CommonFramework/Globals.cpp index de00f88319..06afe9c498 100644 --- a/SerialPrograms/Source/CommonFramework/Globals.cpp +++ b/SerialPrograms/Source/CommonFramework/Globals.cpp @@ -26,7 +26,7 @@ namespace PokemonAutomation{ const bool IS_BETA_VERSION = true; const int PROGRAM_VERSION_MAJOR = 0; const int PROGRAM_VERSION_MINOR = 55; -const int PROGRAM_VERSION_PATCH = 1; +const int PROGRAM_VERSION_PATCH = 2; const std::string PROGRAM_VERSION_BASE = "v" + std::to_string(PROGRAM_VERSION_MAJOR) + diff --git a/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoSession.cpp b/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoSession.cpp index 79f5aaaba5..eb8aaf153d 100644 --- a/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoSession.cpp +++ b/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoSession.cpp @@ -91,7 +91,7 @@ void VideoSession::set(const VideoSourceOption& option){ void VideoSession::reset(){ m_logger.log("Resetting the video...", COLOR_GREEN); - dispatch_to_main_thread([this]{ + queue_on_main_thread([this]{ std::lock_guard lg0(m_reset_lock); m_state_listeners.run_method_unique(&StateListener::pre_shutdown); @@ -124,7 +124,7 @@ void VideoSession::set_source( Resolution resolution ){ m_logger.log("Changing video...", COLOR_GREEN); - dispatch_to_main_thread([this, device, resolution]{ + queue_on_main_thread([this, device, resolution]{ std::lock_guard lg0(m_reset_lock); if (*m_descriptor == *device && !m_descriptor->should_reload()){ return; @@ -163,7 +163,7 @@ void VideoSession::set_source( } void VideoSession::set_resolution(Resolution resolution){ m_logger.log("Changing resolution...", COLOR_GREEN); - dispatch_to_main_thread([this, resolution]{ + queue_on_main_thread([this, resolution]{ std::lock_guard lg0(m_reset_lock); if (m_option.m_resolution == resolution){ return; From 973a4edf3b919ab5cc164ecbca5f47c50b2928fa Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Sat, 9 Aug 2025 12:36:11 -0700 Subject: [PATCH 2/6] Increase tolerance of the black dialog box detector. --- .../DevPrograms/TestProgramSwitch.cpp | 17 ++++++++++++++++- .../Boxes/PokemonSV_BoxShinyDetector.h | 2 +- .../Inference/PokemonSwSh_DialogBoxDetector.cpp | 4 ++-- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp b/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp index 2bf87afa1e..e05f679cf6 100644 --- a/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp +++ b/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp @@ -139,6 +139,8 @@ #include "PokemonSwSh/MaxLair/Inference/PokemonSwSh_MaxLair_Detect_PathSide.h" #include "PokemonSwSh/MaxLair/Inference/PokemonSwSh_MaxLair_Detect_PathMap.h" #include "NintendoSwitch/Inference/NintendoSwitch_SelectedSettingDetector.h" +#include "PokemonSV/Inference/Boxes/PokemonSV_BoxShinyDetector.h" +#include "PokemonSwSh/Inference/PokemonSwSh_DialogBoxDetector.h" #include #include @@ -260,10 +262,23 @@ void TestProgram::program(MultiSwitchProgramEnvironment& env, CancellableScope& auto screenshot = feed.snapshot(); - YCommIconDetector detector(true); + PokemonSwSh::BlackDialogBoxDetector detector(true); + detector.make_overlays(overlays); cout << detector.process_frame(screenshot, current_time()) << endl; + +// PokemonSV::BoxShinyDetector detector; +// cout << detector.detect(screenshot) << endl; + + + + +#if 0 + YCommIconDetector detector(true); + cout << detector.process_frame(screenshot, current_time()) << endl; +#endif + #if 0 bool switch2 = true; ImageFloatBox key1_box; diff --git a/SerialPrograms/Source/PokemonSV/Inference/Boxes/PokemonSV_BoxShinyDetector.h b/SerialPrograms/Source/PokemonSV/Inference/Boxes/PokemonSV_BoxShinyDetector.h index 91520f1b1c..95b1c6ea1a 100644 --- a/SerialPrograms/Source/PokemonSV/Inference/Boxes/PokemonSV_BoxShinyDetector.h +++ b/SerialPrograms/Source/PokemonSV/Inference/Boxes/PokemonSV_BoxShinyDetector.h @@ -11,7 +11,7 @@ #include "CommonFramework/ImageTools/ImageBoxes.h" #include "CommonTools/InferenceCallbacks/VisualInferenceCallback.h" #include "CommonTools/VisualDetector.h" -#include "PokemonSV/Inference/Boxes/PokemonSV_BoxDetection.h" +//#include "PokemonSV/Inference/Boxes/PokemonSV_BoxDetection.h" namespace PokemonAutomation{ namespace NintendoSwitch{ diff --git a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_DialogBoxDetector.cpp b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_DialogBoxDetector.cpp index 00ce853b5c..12cf72497c 100644 --- a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_DialogBoxDetector.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_DialogBoxDetector.cpp @@ -50,8 +50,8 @@ void BlackDialogBoxDetector::make_overlays(VideoOverlaySet& items) const{ bool BlackDialogBoxDetector::process_frame(const ImageViewRGB32& frame, WallClock timestamp){ bool detected = true; - for(const auto& box : BLACK_BOXES){ - if (is_black(extract_box_reference(frame, box), 180, 35) == false){ + for (const auto& box : BLACK_BOXES){ + if (is_black(extract_box_reference(frame, box), 200, 35) == false){ detected = false; break; } From 2e90005304c23601f7ceeffcddc3943032bbc835 Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Sat, 9 Aug 2025 12:37:33 -0700 Subject: [PATCH 3/6] Increase detection duration for shiny symbol. --- .../PokemonSV/Programs/Eggs/PokemonSV_EggRoutines.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/SerialPrograms/Source/PokemonSV/Programs/Eggs/PokemonSV_EggRoutines.cpp b/SerialPrograms/Source/PokemonSV/Programs/Eggs/PokemonSV_EggRoutines.cpp index 6c9dd8d0db..248c78b469 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/Eggs/PokemonSV_EggRoutines.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/Eggs/PokemonSV_EggRoutines.cpp @@ -757,7 +757,11 @@ bool check_baby_info( gender_detector.make_overlays(overlay_set); BoxNatureDetector nature_detector(stream.overlay(), LANGUAGE); - const int shiny_ret = wait_until(stream, context, std::chrono::milliseconds(200), {shiny_detector}); + const int shiny_ret = wait_until( + stream, context, + std::chrono::milliseconds(500), + {shiny_detector} + ); const bool shiny = (shiny_ret == 0); VideoSnapshot screen = stream.video().snapshot(); From 4f5382c02c4211d5ce0efa62a0a2ca8eb9964202 Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Sat, 9 Aug 2025 14:10:08 -0700 Subject: [PATCH 4/6] Improve reliability of sbb2 for SwSh datespam programs. --- .../DateSpamFarmers/PokemonSwSh_DateSpam-BerryFarmer.cpp | 6 +++++- .../PokemonSwSh_DateSpam-DailyHighlightFarmer.cpp | 6 +++++- .../DateSpamFarmers/PokemonSwSh_DateSpam-LotoFarmer.cpp | 6 +++++- .../PokemonSwSh_DateSpam-StowOnSideFarmer.cpp | 6 +++++- .../DateSpamFarmers/PokemonSwSh_DateSpam-WattFarmer.cpp | 6 +++++- 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-BerryFarmer.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-BerryFarmer.cpp index 0563932ff8..81c6d00e7a 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-BerryFarmer.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-BerryFarmer.cpp @@ -69,7 +69,11 @@ void BerryFarmer::program(SingleSwitchProgramEnvironment& env, ProControllerCont env.log("Fetch Attempts: " + tostr_u_commas(c)); home_roll_date_enter_game_autorollback(env.console, context, year); - pbf_mash_button(context, BUTTON_B, 90); + if (context->performance_class() == ControllerPerformanceClass::SysbotBase){ + pbf_wait(context, 90); + }else{ + pbf_mash_button(context, BUTTON_B, 90); + } pbf_press_button(context, BUTTON_A, 10, 10); pbf_mash_button(context, BUTTON_ZL, 385); diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-DailyHighlightFarmer.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-DailyHighlightFarmer.cpp index 844881a893..45aa245eb8 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-DailyHighlightFarmer.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-DailyHighlightFarmer.cpp @@ -68,7 +68,11 @@ void DailyHighlightFarmer::program(SingleSwitchProgramEnvironment& env, ProContr for (uint32_t c = 0; c < SKIPS; c++){ env.log("Fetch Attempts: " + tostr_u_commas(c)); home_roll_date_enter_game_autorollback(env.console, context, year); - pbf_mash_button(context, BUTTON_B, 90); + if (context->performance_class() == ControllerPerformanceClass::SysbotBase){ + pbf_wait(context, 90); + }else{ + pbf_mash_button(context, BUTTON_B, 90); + } pbf_press_button(context, BUTTON_A, 10, 110); pbf_press_button(context, BUTTON_ZL, 10, 40); diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-LotoFarmer.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-LotoFarmer.cpp index 99ab147be0..3780eb8ce5 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-LotoFarmer.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-LotoFarmer.cpp @@ -68,7 +68,11 @@ void LotoFarmer::program(SingleSwitchProgramEnvironment& env, ProControllerConte for (uint32_t c = 0; c < SKIPS; c++){ env.log("Fetch Attempts: " + tostr_u_commas(c)); home_roll_date_enter_game_autorollback(env.console, context, year); - pbf_mash_button(context, BUTTON_B, 90); + if (context->performance_class() == ControllerPerformanceClass::SysbotBase){ + pbf_wait(context, 90); + }else{ + pbf_mash_button(context, BUTTON_B, 90); + } pbf_press_button(context, BUTTON_A, 10, 90); pbf_press_button(context, BUTTON_B, 10, 70); diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-StowOnSideFarmer.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-StowOnSideFarmer.cpp index 4251e6c50c..94200d8a53 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-StowOnSideFarmer.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-StowOnSideFarmer.cpp @@ -68,7 +68,11 @@ void StowOnSideFarmer::program(SingleSwitchProgramEnvironment& env, ProControlle for (uint32_t c = 0; c < SKIPS; c++){ env.log("Fetch Attempts: " + tostr_u_commas(c)); home_roll_date_enter_game_autorollback(env.console, context, year); - pbf_mash_button(context, BUTTON_B, 90); + if (context->performance_class() == ControllerPerformanceClass::SysbotBase){ + pbf_wait(context, 90); + }else{ + pbf_mash_button(context, BUTTON_B, 90); + } ssf_press_button_ptv(context, BUTTON_A, 160ms); pbf_mash_button(context, BUTTON_ZL, 385); diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-WattFarmer.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-WattFarmer.cpp index 48ede4f866..b58b758f88 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-WattFarmer.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-WattFarmer.cpp @@ -85,7 +85,11 @@ void WattFarmer::program(SingleSwitchProgramEnvironment& env, ProControllerConte env.log("Fetch Attempts: " + tostr_u_commas(c)); home_roll_date_enter_game_autorollback(env.console, context, year); - pbf_mash_button(context, BUTTON_B, 90); + if (context->performance_class() == ControllerPerformanceClass::SysbotBase){ + pbf_wait(context, 90); + }else{ + pbf_mash_button(context, BUTTON_B, 90); + } ssf_press_button_ptv(context, BUTTON_A, 40ms); pbf_mash_button(context, BUTTON_B, EXIT_DEN_WAIT); From f27e69248af3787bc90dcff2e8a36791d07f332b Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Sat, 9 Aug 2025 17:43:22 -0700 Subject: [PATCH 5/6] Try again to fix reentrancy issue. --- .../VideoPipeline/VideoSession.cpp | 257 ++++++++++++------ .../VideoPipeline/VideoSession.h | 30 +- 2 files changed, 207 insertions(+), 80 deletions(-) diff --git a/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoSession.cpp b/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoSession.cpp index eb8aaf153d..c00b906473 100644 --- a/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoSession.cpp +++ b/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoSession.cpp @@ -90,109 +90,208 @@ void VideoSession::set(const VideoSourceOption& option){ } void VideoSession::reset(){ - m_logger.log("Resetting the video...", COLOR_GREEN); - queue_on_main_thread([this]{ - std::lock_guard lg0(m_reset_lock); + { + WriteSpinLock lg(m_queue_lock); +// cout << "VideoSession::reset(): " << m_queued_commands.size() << endl; + m_queued_commands.emplace_back( + Command{ + CommandType::RESET, + nullptr, + Resolution{} + } + ); + } + dispatch_to_main_thread([this]{ run_commands(); }); +} +void VideoSession::set_source( + const std::shared_ptr& device, + Resolution resolution +){ + { + WriteSpinLock lg(m_queue_lock); +// cout << "VideoSession::set_source(): " << m_queued_commands.size() << endl; + m_queued_commands.emplace_back( + Command{ + CommandType::SET_SOURCE, + device, + resolution + } + ); + } + dispatch_to_main_thread([this]{ run_commands(); }); +} +void VideoSession::set_resolution(Resolution resolution){ + { + WriteSpinLock lg(m_queue_lock); +// cout << "VideoSession::set_resolution(): " << m_queued_commands.size() << endl; + m_queued_commands.emplace_back( + Command{ + CommandType::SET_RESOLUTION, + nullptr, + resolution + } + ); + } + dispatch_to_main_thread([this]{ run_commands(); }); +} - m_state_listeners.run_method_unique(&StateListener::pre_shutdown); +void VideoSession::internal_reset(){ + m_logger.log("Resetting the video...", COLOR_GREEN); + m_state_listeners.run_method_unique(&StateListener::pre_shutdown); - { - WriteSpinLock lg(m_state_lock); - if (m_video_source){ - m_video_source->remove_source_frame_listener(*this); - m_video_source->remove_rendered_frame_listener(*this); - m_video_source.reset(); - } + Resolution resolution = m_option.m_resolution; + std::unique_ptr source; + { + WriteSpinLock lg(m_state_lock); + source = std::move(m_video_source); + } + if (source){ + source->remove_source_frame_listener(*this); + source->remove_rendered_frame_listener(*this); + source.reset(); + } - m_video_source = m_descriptor->make_VideoSource(m_logger, m_option.m_resolution); + source = m_descriptor->make_VideoSource(m_logger, resolution); + if (source){ + resolution = source->current_resolution(); + source->add_source_frame_listener(*this); + source->add_rendered_frame_listener(*this); + } - if (m_video_source){ - m_option.m_resolution = m_video_source->current_resolution(); - m_video_source->add_source_frame_listener(*this); - m_video_source->add_rendered_frame_listener(*this); - } - } + { + WriteSpinLock lg(m_state_lock); + m_option.m_resolution = resolution; + m_video_source = std::move(source); + } - m_state_listeners.run_method_unique( - &StateListener::post_startup, - m_video_source.get() - ); - }); + m_state_listeners.run_method_unique( + &StateListener::post_startup, + m_video_source.get() + ); } -void VideoSession::set_source( +void VideoSession::internal_set_source( const std::shared_ptr& device, Resolution resolution ){ m_logger.log("Changing video...", COLOR_GREEN); - queue_on_main_thread([this, device, resolution]{ - std::lock_guard lg0(m_reset_lock); - if (*m_descriptor == *device && !m_descriptor->should_reload()){ - return; - } - - m_state_listeners.run_method_unique(&StateListener::pre_shutdown); - - { - WriteSpinLock lg(m_state_lock); - if (m_video_source){ - m_video_source->remove_source_frame_listener(*this); - m_video_source->remove_rendered_frame_listener(*this); - m_video_source.reset(); - } + if (*m_descriptor == *device && !m_descriptor->should_reload()){ + return; + } - m_option.set_descriptor(device); - m_descriptor = device; + m_state_listeners.run_method_unique(&StateListener::pre_shutdown); - Resolution desired_resolution = resolution ? resolution : m_option.m_resolution; -// cout << "VideoSession::set_source(): " << &m_option << " - " << desired_resolution.width << " x " << desired_resolution.height << endl; + std::unique_ptr source; + { + WriteSpinLock lg(m_state_lock); + source = std::move(m_video_source); + } + if (source){ + source->remove_source_frame_listener(*this); + source->remove_rendered_frame_listener(*this); + source.reset(); + } + { + WriteSpinLock lg(m_state_lock); + m_option.set_descriptor(device); + m_descriptor = device; + } - m_video_source = device->make_VideoSource(m_logger, desired_resolution); + Resolution desired_resolution = resolution ? resolution : m_option.m_resolution; + source = device->make_VideoSource(m_logger, desired_resolution); + if (source){ + resolution = source->current_resolution(); + source->add_source_frame_listener(*this); + source->add_rendered_frame_listener(*this); + } - if (m_video_source){ - m_option.m_resolution = m_video_source->current_resolution(); - m_video_source->add_source_frame_listener(*this); - m_video_source->add_rendered_frame_listener(*this); - } - } + { + WriteSpinLock lg(m_state_lock); + m_option.m_resolution = resolution; + m_video_source = std::move(source); + } - m_state_listeners.run_method_unique( - &StateListener::post_startup, - m_video_source.get() - ); - }); + m_state_listeners.run_method_unique( + &StateListener::post_startup, + m_video_source.get() + ); } -void VideoSession::set_resolution(Resolution resolution){ +void VideoSession::internal_set_resolution(Resolution resolution){ m_logger.log("Changing resolution...", COLOR_GREEN); - queue_on_main_thread([this, resolution]{ - std::lock_guard lg0(m_reset_lock); - if (m_option.m_resolution == resolution){ - return; - } + if (m_option.m_resolution == resolution){ + return; + } + + m_state_listeners.run_method_unique(&StateListener::pre_shutdown); + + std::unique_ptr source; + { + WriteSpinLock lg(m_state_lock); + source = std::move(m_video_source); + } + if (source){ + source->remove_source_frame_listener(*this); + source->remove_rendered_frame_listener(*this); + source.reset(); + } + + source = m_descriptor->make_VideoSource(m_logger, resolution); + if (source){ + resolution = source->current_resolution(); + source->add_source_frame_listener(*this); + source->add_rendered_frame_listener(*this); + } + + { + WriteSpinLock lg(m_state_lock); + m_option.m_resolution = resolution; + m_video_source = std::move(source); + } - { - WriteSpinLock lg(m_state_lock); - m_state_listeners.run_method_unique(&StateListener::pre_shutdown); + m_state_listeners.run_method_unique( + &StateListener::post_startup, + m_video_source.get() + ); +} - if (m_video_source){ - m_video_source->remove_source_frame_listener(*this); - m_video_source->remove_rendered_frame_listener(*this); - m_video_source.reset(); +void VideoSession::run_commands(){ + std::lock_guard lg0(m_reset_lock); + if (m_recursion_depth != 0){ + m_logger.log("Suppressing re-entrant command...", COLOR_RED); + return; + } + m_recursion_depth++; + try{ + while (true){ + Command command; + { + WriteSpinLock lg(m_queue_lock); +// cout << "VideoSession::run_commands(): " << m_queued_commands.size() << endl; + if (m_queued_commands.empty()){ + break; + } + command = std::move(m_queued_commands.front()); + m_queued_commands.pop_front(); } - m_video_source = m_descriptor->make_VideoSource(m_logger, resolution); + switch (command.command_type){ + case CommandType::RESET: + internal_reset(); + break; - if (m_video_source){ - m_option.m_resolution = m_video_source->current_resolution(); - m_video_source->add_source_frame_listener(*this); - m_video_source->add_rendered_frame_listener(*this); + case CommandType::SET_SOURCE: + internal_set_source(command.device, command.resolution); + break; + + case CommandType::SET_RESOLUTION: + internal_set_resolution(command.resolution); + break; } } - - m_state_listeners.run_method_unique( - &StateListener::post_startup, - m_video_source.get() - ); - }); + m_recursion_depth--; + }catch (...){ + m_recursion_depth--; + throw; + } } diff --git a/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoSession.h b/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoSession.h index 3886847050..2c58d1a1f9 100644 --- a/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoSession.h +++ b/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoSession.h @@ -8,6 +8,7 @@ #define PokemonAutomation_VideoPipeline_VideoSession_H #include +#include #include #include "Common/Cpp/EventRateTracker.h" #include "Common/Cpp/Concurrency/SpinLock.h" @@ -176,7 +177,28 @@ class VideoSession private: - mutable std::mutex m_reset_lock; + enum CommandType{ + RESET, + SET_SOURCE, + SET_RESOLUTION + }; + struct Command{ + CommandType command_type; + std::shared_ptr device; + Resolution resolution; + }; + void run_commands(); + + void internal_reset(); + void internal_set_source( + const std::shared_ptr& device, + Resolution resolution = {} + ); + void internal_set_resolution(Resolution resolution); + + +private: + mutable std::recursive_mutex m_reset_lock; mutable SpinLock m_state_lock; Logger& m_logger; @@ -189,6 +211,12 @@ class VideoSession std::shared_ptr m_descriptor; std::unique_ptr m_video_source; + // We need to queue up all reset commands and run them on the main thread. + // This is needed to prevent re-entrant calls from event processing. + SpinLock m_queue_lock; + size_t m_recursion_depth = 0; + std::deque m_queued_commands; + ListenerSet m_state_listeners; ListenerSet m_frame_listeners; }; From 3d3588c8e6493800593207bda99f75ccd996d258 Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Sun, 10 Aug 2025 13:30:00 -0700 Subject: [PATCH 6/6] Always show the wireless controller table. --- .../Source/NintendoSwitch/NintendoSwitch_Settings.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/SerialPrograms/Source/NintendoSwitch/NintendoSwitch_Settings.cpp b/SerialPrograms/Source/NintendoSwitch/NintendoSwitch_Settings.cpp index 2959565bdb..64db99a9d3 100644 --- a/SerialPrograms/Source/NintendoSwitch/NintendoSwitch_Settings.cpp +++ b/SerialPrograms/Source/NintendoSwitch/NintendoSwitch_Settings.cpp @@ -165,12 +165,6 @@ ConsoleSettingsPanel::ConsoleSettingsPanel(const ConsoleSettings_Descriptor& des , settings(ConsoleSettings::instance()) { PA_ADD_OPTION(settings); - - settings.CONTROLLER_SETTINGS.set_visibility( - settings.CONTROLLER_SETTINGS.current_rows() > 0 - ? ConfigOptionState::ENABLED - : ConfigOptionState::HIDDEN - ); }