From 1657c8dc00f3d5f03955fa1a419b012ca02ef633 Mon Sep 17 00:00:00 2001 From: dayfine Date: Sat, 31 Oct 2026 08:45:21 -0700 Subject: [PATCH] CommonTools: hold async session commands and detector callbacks in MoveOnlyFunction AsyncCommandSession, SuperControlSession, DetectionDebouncer and LetsGoKillWatcher each own their callback and never copy it. LetsGoKillWatcher now moves its callback in instead of copying it. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E --- .../Source/CommonTools/Async/InterruptableCommands.h | 4 ++-- .../Source/CommonTools/Async/InterruptableCommands.tpp | 8 ++++---- .../Source/CommonTools/Async/SuperControlSession.h | 6 +++--- .../Source/CommonTools/Async/SuperControlSession.tpp | 2 +- SerialPrograms/Source/CommonTools/DetectionDebouncer.h | 6 +++--- .../PokemonLA/Programs/PokemonLA_EscapeFromAttack.h | 2 +- .../PokemonLA/Programs/PokemonLA_FlagNavigationAir.h | 2 +- .../Inference/Overworld/PokemonSV_LetsGoKillDetector.cpp | 4 ++-- .../Inference/Overworld/PokemonSV_LetsGoKillDetector.h | 6 +++--- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/SerialPrograms/Source/CommonTools/Async/InterruptableCommands.h b/SerialPrograms/Source/CommonTools/Async/InterruptableCommands.h index f0cab8171e..86d360c23e 100644 --- a/SerialPrograms/Source/CommonTools/Async/InterruptableCommands.h +++ b/SerialPrograms/Source/CommonTools/Async/InterruptableCommands.h @@ -7,7 +7,7 @@ #ifndef PokemonAutomation_CommonTools_InterruptableCommands_H #define PokemonAutomation_CommonTools_InterruptableCommands_H -#include +#include "Common/Cpp/MoveOnlyFunction.h" #include "Common/Cpp/Concurrency/Mutex.h" #include "Common/Cpp/Concurrency/ConditionVariable.h" #include "Common/Cpp/Concurrency/AsyncTask.h" @@ -44,7 +44,7 @@ class AsyncCommandSession final : private Cancellable{ // previous `dispatch()` while a new `dispatch()` presses button A and button B // at the same time, button A is not released during the transition. // You can use it to adjust button state continuously without interruption. - void dispatch(std::function&& lambda); + void dispatch(MoveOnlyFunction&& lambda); // Wait for currently running command to finish. void wait(); diff --git a/SerialPrograms/Source/CommonTools/Async/InterruptableCommands.tpp b/SerialPrograms/Source/CommonTools/Async/InterruptableCommands.tpp index 193dad2d9b..bc96bbc675 100644 --- a/SerialPrograms/Source/CommonTools/Async/InterruptableCommands.tpp +++ b/SerialPrograms/Source/CommonTools/Async/InterruptableCommands.tpp @@ -21,11 +21,11 @@ template struct AsyncCommandSession::CommandSet{ CommandSet( CancellableScope& parent, ControllerType& controller, - std::function&& lambda + MoveOnlyFunction&& lambda ); CancellableHolder scope; ControllerContextType context; - std::function commands; + MoveOnlyFunction commands; }; @@ -33,7 +33,7 @@ struct AsyncCommandSession::CommandSet{ template AsyncCommandSession::CommandSet::CommandSet( CancellableScope& parent, ControllerType& controller, - std::function&& lambda + MoveOnlyFunction&& lambda ) : scope(parent) , context(scope, controller) @@ -97,7 +97,7 @@ void AsyncCommandSession::stop_command(){ } } template -void AsyncCommandSession::dispatch(std::function&& lambda){ +void AsyncCommandSession::dispatch(MoveOnlyFunction&& lambda){ auto scope_check = m_sanitizer.check_scope(); // Construct the CommandSet outside the lock. diff --git a/SerialPrograms/Source/CommonTools/Async/SuperControlSession.h b/SerialPrograms/Source/CommonTools/Async/SuperControlSession.h index 62d5ec99e3..b13532bf23 100644 --- a/SerialPrograms/Source/CommonTools/Async/SuperControlSession.h +++ b/SerialPrograms/Source/CommonTools/Async/SuperControlSession.h @@ -11,7 +11,7 @@ #include #include #include -#include +#include "Common/Cpp/MoveOnlyFunction.h" #include "Common/Cpp/Time.h" namespace PokemonAutomation{ @@ -58,7 +58,7 @@ class SuperControlSession{ void operator+=(VisualInferenceCallback& callback); void operator+=(AudioInferenceCallback& callback); - void register_state_command(size_t state, std::function&& action); + void register_state_command(size_t state, MoveOnlyFunction&& action); protected: @@ -91,7 +91,7 @@ class SuperControlSession{ std::vector m_audio_callbacks; // These are actions - std::map> m_state_actions; + std::map> m_state_actions; private: // Run-time state. diff --git a/SerialPrograms/Source/CommonTools/Async/SuperControlSession.tpp b/SerialPrograms/Source/CommonTools/Async/SuperControlSession.tpp index c8343ecf0e..a5fae0b94e 100644 --- a/SerialPrograms/Source/CommonTools/Async/SuperControlSession.tpp +++ b/SerialPrograms/Source/CommonTools/Async/SuperControlSession.tpp @@ -49,7 +49,7 @@ void SuperControlSession::operator+=(AudioInferenceCallback& cal m_audio_callbacks.emplace_back(&callback); } template -void SuperControlSession::register_state_command(size_t state, std::function&& action){ +void SuperControlSession::register_state_command(size_t state, MoveOnlyFunction&& action){ auto iter = m_state_actions.find(state); if (iter != m_state_actions.end()){ throw InternalProgramError(&m_stream.logger(), PA_CURRENT_FUNCTION, "Duplicate State Enum: " + std::to_string(state)); diff --git a/SerialPrograms/Source/CommonTools/DetectionDebouncer.h b/SerialPrograms/Source/CommonTools/DetectionDebouncer.h index ee4f41cf24..6b071efe88 100644 --- a/SerialPrograms/Source/CommonTools/DetectionDebouncer.h +++ b/SerialPrograms/Source/CommonTools/DetectionDebouncer.h @@ -7,8 +7,8 @@ #ifndef PokemonAutomation_CommonTools_DetectionDebouncer_H #define PokemonAutomation_CommonTools_DetectionDebouncer_H -#include #include +#include "Common/Cpp/MoveOnlyFunction.h" #include "Common/Cpp/Time.h" namespace PokemonAutomation{ @@ -20,7 +20,7 @@ class DetectionDebouncer{ DetectionDebouncer( Type initial_state, std::chrono::milliseconds min_streak, - std::function&& state_reporter + MoveOnlyFunction&& state_reporter ) : m_min_streak(min_streak) , m_state_reporter(std::move(state_reporter)) @@ -57,7 +57,7 @@ class DetectionDebouncer{ private: std::chrono::milliseconds m_min_streak; - std::function m_state_reporter; + MoveOnlyFunction m_state_reporter; std::atomic m_current_reported; WallClock m_last_match; diff --git a/SerialPrograms/Source/VideoGames/PokemonLA/Programs/PokemonLA_EscapeFromAttack.h b/SerialPrograms/Source/VideoGames/PokemonLA/Programs/PokemonLA_EscapeFromAttack.h index 370b76c572..d3fe64694e 100644 --- a/SerialPrograms/Source/VideoGames/PokemonLA/Programs/PokemonLA_EscapeFromAttack.h +++ b/SerialPrograms/Source/VideoGames/PokemonLA/Programs/PokemonLA_EscapeFromAttack.h @@ -46,7 +46,7 @@ class EscapeFromAttack : public SuperControlSession{ GET_ON_SNEASLER, CLIMBING, }; - void register_state_command(State state, std::function&& action){ + void register_state_command(State state, MoveOnlyFunction&& action){ SuperControlSession::register_state_command((size_t)state, std::move(action)); } bool run_state_action(State state){ diff --git a/SerialPrograms/Source/VideoGames/PokemonLA/Programs/PokemonLA_FlagNavigationAir.h b/SerialPrograms/Source/VideoGames/PokemonLA/Programs/PokemonLA_FlagNavigationAir.h index 3a5c1ddd8e..8c2d10cd60 100644 --- a/SerialPrograms/Source/VideoGames/PokemonLA/Programs/PokemonLA_FlagNavigationAir.h +++ b/SerialPrograms/Source/VideoGames/PokemonLA/Programs/PokemonLA_FlagNavigationAir.h @@ -62,7 +62,7 @@ class FlagNavigationAir : public SuperControlSession{ TURN_RIGHT, FIND_FLAG, }; - void register_state_command(State state, std::function&& action){ + void register_state_command(State state, MoveOnlyFunction&& action){ SuperControlSession::register_state_command((size_t)state, std::move(action)); } bool run_state_action(State state){ diff --git a/SerialPrograms/Source/VideoGames/PokemonSV/Inference/Overworld/PokemonSV_LetsGoKillDetector.cpp b/SerialPrograms/Source/VideoGames/PokemonSV/Inference/Overworld/PokemonSV_LetsGoKillDetector.cpp index 2ca84ccb49..adabbccbf2 100644 --- a/SerialPrograms/Source/VideoGames/PokemonSV/Inference/Overworld/PokemonSV_LetsGoKillDetector.cpp +++ b/SerialPrograms/Source/VideoGames/PokemonSV/Inference/Overworld/PokemonSV_LetsGoKillDetector.cpp @@ -181,13 +181,13 @@ LetsGoKillWatcher::LetsGoKillWatcher( Logger& logger, Color color, bool trigger_if_detected, const ImageFloatBox& box, - std::function on_kill_callback, + MoveOnlyFunction on_kill_callback, std::chrono::milliseconds duration ) : DetectorToFinder("LetsGoKillWatcher", duration, color, box) , m_logger(logger) , m_trigger_if_detected(trigger_if_detected) - , m_on_kill_callback(on_kill_callback) + , m_on_kill_callback(std::move(on_kill_callback)) , m_last_detection(false) , m_last_detected(WallClock::min()) {} diff --git a/SerialPrograms/Source/VideoGames/PokemonSV/Inference/Overworld/PokemonSV_LetsGoKillDetector.h b/SerialPrograms/Source/VideoGames/PokemonSV/Inference/Overworld/PokemonSV_LetsGoKillDetector.h index dde7152198..985e0f4359 100644 --- a/SerialPrograms/Source/VideoGames/PokemonSV/Inference/Overworld/PokemonSV_LetsGoKillDetector.h +++ b/SerialPrograms/Source/VideoGames/PokemonSV/Inference/Overworld/PokemonSV_LetsGoKillDetector.h @@ -7,9 +7,9 @@ #ifndef PokemonAutomation_PokemonSV_LetsGoKillDetector_H #define PokemonAutomation_PokemonSV_LetsGoKillDetector_H -#include #include #include "Common/Cpp/Color.h" +#include "Common/Cpp/MoveOnlyFunction.h" #include "Common/Cpp/TestRunners/UnitTestDatabase.h" #include "CommonFramework/ImageTools/ImageBoxes.h" #include "CommonTools/Audio/AudioPerSpectrumDetectorBase.h" @@ -39,7 +39,7 @@ class LetsGoKillWatcher : public DetectorToFinder{ Logger& logger, Color color, bool trigger_if_detected = true, const ImageFloatBox& box = {0.71, 0.15, 0.04, 0.08}, - std::function on_kill_callback = nullptr, + MoveOnlyFunction on_kill_callback = nullptr, std::chrono::milliseconds duration = std::chrono::milliseconds(250) ); @@ -52,7 +52,7 @@ class LetsGoKillWatcher : public DetectorToFinder{ private: Logger& m_logger; bool m_trigger_if_detected; - std::function m_on_kill_callback; + MoveOnlyFunction m_on_kill_callback; bool m_last_detection; std::atomic m_last_detected;