diff --git a/Common/Cpp/ListenerSet.h b/Common/Cpp/ListenerSet.h index b7aa254f18..5eefadde1b 100644 --- a/Common/Cpp/ListenerSet.h +++ b/Common/Cpp/ListenerSet.h @@ -8,6 +8,7 @@ #define PokemonAutomation_ListenerSet_H #include +#include #include #include //#include "Common/Cpp/PrettyPrint.h" @@ -97,8 +98,6 @@ class ListenerSet{ struct Node{ SpinLock lock; ListenerType& listener; - Node* next = nullptr; - Node** prevs_next = nullptr; #ifdef PA_DEBUG_ListenerSet LifetimeSanitizer sanitizer; @@ -106,14 +105,13 @@ class ListenerSet{ Node(ListenerSet& parent, ListenerType& p_listener) : listener(p_listener) - , prevs_next(&parent.m_list) #ifdef PA_DEBUG_ListenerSet , sanitizer("Node") #endif {} }; - Node* m_list = nullptr; - std::map m_listeners; + std::list m_list; + std::map::iterator> m_listeners; #ifdef PA_DEBUG_ListenerSet LifetimeSanitizer m_sanitizer; @@ -140,23 +138,22 @@ void ListenerSet::add(ListenerType& listener){ auto scope = m_sanitizer.check_scope(); #endif WriteSpinLock lg(m_lock, m_suppress_lock_prints ? nullptr : "ListenerSet::add()"); - auto ret = m_listeners.emplace( - std::piecewise_construct, - std::forward_as_tuple(&listener), - std::forward_as_tuple(*this, listener) - ); - if (!ret.second){ - return; - } - Node& node = ret.first->second; -#ifdef PA_DEBUG_ListenerSet - node.sanitizer.check_usage(); -#endif - if (m_list != nullptr){ - m_list->prevs_next = &node.next; + + auto iter = m_list.emplace(m_list.end(), *this, listener); + try{ + auto ret = m_listeners.emplace( + std::piecewise_construct, + std::forward_as_tuple(&listener), + std::forward_as_tuple(iter) + ); + if (!ret.second){ + m_list.erase(iter); + return; + } + }catch (...){ + m_list.erase(iter); + throw; } - node.next = m_list; - m_list = &node; m_count.store(m_listeners.size(), std::memory_order_release); } template @@ -174,13 +171,13 @@ void ListenerSet::remove(ListenerType& listener) noexcept{ return; } - Node& node = iter->second; + typename std::list::iterator node = iter->second; #ifdef PA_DEBUG_ListenerSet - node.sanitizer.check_usage(); + node->sanitizer.check_usage(); #endif - if (!node.lock.try_acquire_write()){ + if (!node->lock.try_acquire_write()){ #if 0 if (!printed){ try{ @@ -194,18 +191,7 @@ void ListenerSet::remove(ListenerType& listener) noexcept{ // std::cout << "node = " << &node.sanitizer << " : " << &node.prev->sanitizer << " : " << &node.next->sanitizer << std::endl; - *node.prevs_next = node.next; - if (node.next){ -#ifdef PA_DEBUG_ListenerSet - node.next->sanitizer.check_usage(); -#endif - node.next->prevs_next = node.prevs_next; - } - -#ifdef PA_DEBUG_ListenerSet - node.sanitizer.check_usage(); -#endif - + m_list.erase(node); m_listeners.erase(iter); m_count.store(m_listeners.size(), std::memory_order_release); return; @@ -228,8 +214,8 @@ bool ListenerSet::try_remove(ListenerType& listener) noexcept{ return true; } - Node& node = iter->second; - if (!node.lock.try_acquire_write()){ + typename std::list::iterator node = iter->second; + if (!node->lock.try_acquire_write()){ try{ std::cout << "ListenerSet::try_remove(): Fail inner." << std::endl; }catch (...){} @@ -237,21 +223,10 @@ bool ListenerSet::try_remove(ListenerType& listener) noexcept{ } #ifdef PA_DEBUG_ListenerSet - node.sanitizer.check_usage(); -#endif - - *node.prevs_next = node.next; - if (node.next){ -#ifdef PA_DEBUG_ListenerSet - node.next->sanitizer.check_usage(); -#endif - node.next->prevs_next = node.prevs_next; - } - -#ifdef PA_DEBUG_ListenerSet - node.sanitizer.check_usage(); + node->sanitizer.check_usage(); #endif + m_list.erase(node); m_listeners.erase(iter); m_count.store(m_listeners.size(), std::memory_order_release); m_lock.unlock_write(); @@ -273,17 +248,16 @@ void ListenerSet::run_method(Function function, Args&&... args){ m_lock.acquire_read(); - Node* node = m_list; - while (node){ + for (Node& node : m_list){ { - ReadSpinLock lg(node->lock, m_suppress_lock_prints ? nullptr : "ListenerSet::run_method()"); + ReadSpinLock lg(node.lock, m_suppress_lock_prints ? nullptr : "ListenerSet::run_method()"); #ifdef PA_DEBUG_ListenerSet - node->sanitizer.check_usage(); + node.sanitizer.check_usage(); #endif m_lock.unlock_read(); try{ - (node->listener.*function)(std::forward(args)...); + (node.listener.*function)(std::forward(args)...); }catch (...){ if (!err){ err = std::current_exception(); @@ -291,10 +265,6 @@ void ListenerSet::run_method(Function function, Args&&... args){ } m_lock.acquire_read(); } -#ifdef PA_DEBUG_ListenerSet - node->sanitizer.check_usage(); -#endif - node = node->next; } m_lock.unlock_read(); @@ -317,18 +287,17 @@ void ListenerSet::run_on_all(Lambda&& lambda){ m_lock.acquire_read(); - Node* node = m_list; - while (node){ + for (Node& node : m_list){ bool return_now = false; { - ReadSpinLock lg(node->lock, m_suppress_lock_prints ? nullptr : "ListenerSet::run_on_all()"); + ReadSpinLock lg(node.lock, m_suppress_lock_prints ? nullptr : "ListenerSet::run_on_all()"); #ifdef PA_DEBUG_ListenerSet - node->sanitizer.check_usage(); + node.sanitizer.check_usage(); #endif m_lock.unlock_read(); try{ - return_now = lambda(node->listener); + return_now = lambda(node.listener); }catch (...){ if (!err){ err = std::current_exception(); @@ -340,9 +309,8 @@ void ListenerSet::run_on_all(Lambda&& lambda){ break; } #ifdef PA_DEBUG_ListenerSet - node->sanitizer.check_usage(); + node.sanitizer.check_usage(); #endif - node = node->next; } m_lock.unlock_read(); diff --git a/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoOverlaySession.cpp b/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoOverlaySession.cpp index 9f46a2b7c3..784829b765 100644 --- a/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoOverlaySession.cpp +++ b/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoOverlaySession.cpp @@ -74,15 +74,16 @@ void VideoOverlaySession::set(const VideoOverlayOption& option){ void VideoOverlaySession::stats_thread(){ std::unique_lock lg(m_stats_lock); while (!m_stopping){ + std::vector lines; + m_stats.run_on_all([&](OverlayStat& stat){ + OverlayStatSnapshot snapshot = stat.get_current(); + if (!snapshot.text.empty()){ + lines.emplace_back(std::move(snapshot)); + } + return false; + }); { - std::vector lines; WriteSpinLock lg0(m_lock, PA_CURRENT_FUNCTION); - for (const auto& stat : m_stats_order){ - OverlayStatSnapshot snapshot = stat->get_current(); - if (!snapshot.text.empty()){ - lines.emplace_back(std::move(snapshot)); - } - } m_stat_lines = std::move(lines); } m_stats_cv.wait_for(lg, std::chrono::milliseconds(100)); @@ -117,31 +118,10 @@ void VideoOverlaySession::set_enabled_log(bool enabled){ // void VideoOverlaySession::add_stat(OverlayStat& stat){ - WriteSpinLock lg(m_lock, PA_CURRENT_FUNCTION); - auto map_iter = m_stats.find(&stat); - if (map_iter != m_stats.end()){ - return; - } - - m_stats_order.emplace_back(&stat); - auto list_iter = m_stats_order.end(); - --list_iter; - try{ - m_stats.emplace(&stat, list_iter); - }catch (...){ - m_stats_order.pop_back(); - throw; - } + m_stats.add(stat); } void VideoOverlaySession::remove_stat(OverlayStat& stat){ - WriteSpinLock lg(m_lock, PA_CURRENT_FUNCTION); - auto iter = m_stats.find(&stat); - if (iter == m_stats.end()){ - return; - } - - m_stats_order.erase(iter->second); - m_stats.erase(iter); + m_stats.remove(stat); } std::vector VideoOverlaySession::stats() const{ diff --git a/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoOverlaySession.h b/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoOverlaySession.h index 62d4215d1b..e3c9861484 100644 --- a/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoOverlaySession.h +++ b/SerialPrograms/Source/CommonFramework/VideoPipeline/VideoOverlaySession.h @@ -26,7 +26,6 @@ #include "Common/Cpp/Concurrency/Mutex.h" #include "Common/Cpp/Concurrency/ConditionVariable.h" #include "Common/Cpp/Concurrency/AsyncTask.h" -#include "Common/Cpp/Concurrency/Thread.h" #include "VideoOverlay.h" #include "VideoOverlayOption.h" @@ -146,8 +145,7 @@ class VideoOverlaySession : public VideoOverlay{ std::set m_images; std::deque m_log_texts; - std::list m_stats_order; - std::map::iterator> m_stats; + ListenerSet m_stats; ListenerSet m_listeners; diff --git a/SerialPrograms/Source/PokemonSwSh/Inference/Battles/PokemonSwSh_BattleDialogDetector.cpp b/SerialPrograms/Source/PokemonSwSh/Inference/Battles/PokemonSwSh_BattleDialogDetector.cpp index b04d225807..25bcb3e5cb 100644 --- a/SerialPrograms/Source/PokemonSwSh/Inference/Battles/PokemonSwSh_BattleDialogDetector.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Inference/Battles/PokemonSwSh_BattleDialogDetector.cpp @@ -33,17 +33,17 @@ void BattleDialogDetector::make_overlays(VideoOverlaySet& items) const{ bool BattleDialogDetector::detect(const ImageViewRGB32& screen){ ImageStats bottom = image_stats(extract_box_reference(screen, m_bottom)); // cout << "bottom: " << bottom.average << bottom.stddev << endl; - if (!is_grey(bottom, 0, 200, 10)){ + if (!is_grey(bottom, 0, 200, 5)){ return false; } ImageStats left = image_stats(extract_box_reference(screen, m_left)); // cout << "left: " << left.average << left.stddev << endl; - if (!is_grey(left, 0, 200, 5)){ + if (!is_grey(left, 0, 200, 3)){ return false; } ImageStats right = image_stats(extract_box_reference(screen, m_right)); // cout << "right: " << right.average << right.stddev << endl; - if (!is_grey(right, 0, 200, 5)){ + if (!is_grey(right, 0, 200, 3)){ return false; }