diff --git a/Cleanup.cmd b/Cleanup.cmd index 69a8c2eab6..61d45f2e79 100644 --- a/Cleanup.cmd +++ b/Cleanup.cmd @@ -3,7 +3,7 @@ cd %~dp0\ClientProject @call Cleanup.cmd cd %~dp0\NativePrograms -@call !Cleanup.cmd +@call Cleanup.cmd cd %~dp0\GeneratorSource @call Cleanup.cmd diff --git a/ClientProject/PokemonAutomationClient/PokemonAutomationClient.vcxproj b/ClientProject/PokemonAutomationClient/PokemonAutomationClient.vcxproj index 87c5852f34..90ba8951d9 100644 --- a/ClientProject/PokemonAutomationClient/PokemonAutomationClient.vcxproj +++ b/ClientProject/PokemonAutomationClient/PokemonAutomationClient.vcxproj @@ -156,14 +156,17 @@ - - - - - + + + + + + + + @@ -193,9 +196,11 @@ - - - + + + + + true true diff --git a/ClientProject/PokemonAutomationClient/PokemonAutomationClient.vcxproj.filters b/ClientProject/PokemonAutomationClient/PokemonAutomationClient.vcxproj.filters index b4513e3867..db7fa29eb3 100644 --- a/ClientProject/PokemonAutomationClient/PokemonAutomationClient.vcxproj.filters +++ b/ClientProject/PokemonAutomationClient/PokemonAutomationClient.vcxproj.filters @@ -27,9 +27,6 @@ {227cd5ac-1fca-4f18-a5c4-e517dd526f05} - - {8d23dd57-0446-4723-8b44-05293f49c650} - {ca670832-1439-443e-a6b2-6bf5b48ad8d3} @@ -39,6 +36,9 @@ {10ade231-7f71-4505-a596-091dfe263106} + + {8d23dd57-0446-4723-8b44-05293f49c650} + @@ -65,27 +65,12 @@ Source Files\ClientSource\Libraries - - Source Files\ClientSource\Libraries - Source Files\ClientSource\Libraries - - Source Files\Common\Clientside - - - Source Files\Common\Clientside - Source Files\ClientSource\Connection - - Source Files\Common\Clientside - - - Source Files\Common\Clientside - Source Files\Common\PokemonSwSh @@ -128,6 +113,30 @@ Source Files\Common\SwitchFramework + + Source Files\Common\Cpp + + + Source Files\Common\Cpp + + + Source Files\Common\Cpp + + + Source Files\Common\Cpp + + + Source Files\Common\Cpp + + + Source Files\Common\Cpp + + + Source Files\Common\Cpp + + + Source Files\Common + @@ -169,15 +178,6 @@ Source Files\ClientSource\Programs - - Source Files\Common\Clientside - - - Source Files\Common\Clientside - - - Source Files\Common\Clientside - Source Files\Common\PokemonSwSh @@ -220,5 +220,20 @@ Source Files\Common\SwitchFramework + + Source Files\Common\Cpp + + + Source Files\Common\Cpp + + + Source Files\Common\Cpp + + + Source Files\Common\Cpp + + + Source Files\Common\Cpp + \ No newline at end of file diff --git a/ClientSource/Connection/BotBase.h b/ClientSource/Connection/BotBase.h index 83dcae8e76..1ddeb61697 100644 --- a/ClientSource/Connection/BotBase.h +++ b/ClientSource/Connection/BotBase.h @@ -9,6 +9,7 @@ #include #include +#include #include "Common/MessageProtocol.h" namespace PokemonAutomation{ @@ -44,34 +45,48 @@ class BotBase{ virtual ~BotBase() = default; virtual State state() const = 0; virtual void wait_for_all_requests() = 0; + virtual void stop_all_commands() = 0; public: // Request Dispatch // Return if request cannot be dispatched immediately. template - bool try_issue_request(SendParams& send_params); + bool try_issue_request( + const std::atomic* cancelled, + SendParams& send_params + ); // Block the thread until the request is sent. template - void issue_request(SendParams& send_params); + void issue_request( + const std::atomic* cancelled, + SendParams& send_params + ); - // Block the thread until the request is send and the response is received. + // Block the thread until the request is sent and the response is received. template < uint8_t SendType, uint8_t RecvType, typename SendParams, typename RecvParams > - void issue_request_and_wait(SendParams& send_params, RecvParams& recv_params); + void issue_request_and_wait( + const std::atomic* cancelled, + SendParams& send_params, + RecvParams& recv_params + ); protected: virtual bool try_issue_request( + const std::atomic* cancelled, uint8_t send_type, char* send_params, size_t send_bytes ) = 0; virtual void issue_request( + const std::atomic* cancelled, uint8_t send_type, char* send_params, size_t send_bytes ) = 0; virtual void issue_request_and_wait( + const std::atomic* cancelled, uint8_t send_type, char* send_params, size_t send_bytes, uint8_t recv_type, char* recv_params, size_t recv_bytes ) = 0; @@ -79,28 +94,78 @@ class BotBase{ +// A wrapper for BotBase that allows for asynchronous cancelling. +class BotBaseContext{ +public: + BotBaseContext(BotBase& botbase) + : m_botbase(&botbase) + , m_cancelled(false) + {} + + BotBase& botbase() const{ return *m_botbase; } +// operator BotBase&() const{ +// return *m_botbase; +// } + BotBase* operator->() const{ + check_cancelled(); + return m_botbase; + } + void check_cancelled() const{ + if (m_cancelled.load(std::memory_order_acquire)){ + throw CancelledException(); + } + } + void cancel(){ + m_cancelled.store(true, std::memory_order_release); + m_botbase->stop_all_commands(); + } + + const std::atomic& cancelled_bool() const{ + return m_cancelled; + } + +private: + BotBase* m_botbase; + std::atomic m_cancelled; +}; + + + + + // Implementations template -bool BotBase::try_issue_request(SendParams& send_params){ +bool BotBase::try_issue_request( + const std::atomic* cancelled, + SendParams& send_params +){ static_assert(sizeof(SendParams) <= PABB_MAX_MESSAGE_SIZE, "Message is too large."); - return try_issue_request(SendType, (char*)&send_params, sizeof(SendParams)); + return try_issue_request(cancelled, SendType, (char*)&send_params, sizeof(SendParams)); } template -void BotBase::issue_request(SendParams& send_params){ +void BotBase::issue_request( + const std::atomic* cancelled, + SendParams& send_params +){ static_assert(sizeof(SendParams) <= PABB_MAX_MESSAGE_SIZE, "Message is too large."); - issue_request(SendType, (char*)&send_params, sizeof(SendParams)); + issue_request(cancelled, SendType, (char*)&send_params, sizeof(SendParams)); } template < uint8_t SendType, uint8_t RecvType, typename SendParams, typename RecvParams > -void BotBase::issue_request_and_wait(SendParams& send_params, RecvParams& recv_params){ +void BotBase::issue_request_and_wait( + const std::atomic* cancelled, + SendParams& send_params, + RecvParams& recv_params +){ static_assert(sizeof(SendParams) <= PABB_MAX_MESSAGE_SIZE, "Message is too large."); static_assert(sizeof(RecvParams) <= PABB_MAX_MESSAGE_SIZE, "Message is too large."); static_assert(PABB_MSG_IS_REQUEST(SendType), "Message must be a request."); issue_request_and_wait( + cancelled, SendType, (char*)&send_params, sizeof(SendParams), RecvType, (char*)&recv_params, sizeof(RecvParams) ); diff --git a/ClientSource/Connection/PABotBase.cpp b/ClientSource/Connection/PABotBase.cpp index 36d79c0312..1fb795b97b 100644 --- a/ClientSource/Connection/PABotBase.cpp +++ b/ClientSource/Connection/PABotBase.cpp @@ -8,6 +8,8 @@ #include #include #include "Common/MessageProtocol.h" +#include "Common/Cpp/Exception.h" +#include "Common/Cpp/PanicDump.h" #include "PABotBase.h" namespace PokemonAutomation{ @@ -24,7 +26,7 @@ PABotBase::PABotBase( , m_retransmit_delay(retransmit_delay) , m_last_ack(std::chrono::system_clock::now()) , m_state(State::RUNNING) - , m_retransmit_thread(&PABotBase::retransmit_thread, this) + , m_retransmit_thread(run_with_catch, "PABotBase::retransmit_thread()", [=]{ retransmit_thread(); }) { set_sniffer(logger); } @@ -38,7 +40,7 @@ void PABotBase::connect(){ // Send seqnum reset. pabb_MsgInfoSeqnumReset params; pabb_MsgAckRequest response; - issue_request_and_wait(params, response); + issue_request_and_wait(nullptr, params, response); } void PABotBase::stop(){ // cout << "stop" << endl; @@ -95,6 +97,26 @@ void PABotBase::wait_for_all_requests(){ throw CancelledException(); } } +void PABotBase::stop_all_commands(){ + pabb_MsgRequestProtocolVersion params; + pabb_MsgAckRequest response; + issue_request_and_wait(nullptr, params, response); + { + std::lock_guard lg0(m_sleep_lock); + SpinLockGuard lg1(m_state_lock, "PABotBase::stop_all_commands()"); + + // Remove all commands that are before the stop seqnum. + uint64_t seqnum = infer_full_seqnum(m_pending_commands, response.seqnum); + while (true){ + auto iter = m_pending_commands.begin(); + if (iter == m_pending_commands.end() || iter->first > seqnum){ + break; + } + m_pending_commands.erase(iter); + } + m_cv.notify_all(); + } +} void PABotBase::remove_request(std::map::iterator iter){ // Must be called under both sleep and state locks. m_pending_requests.erase(iter); @@ -374,14 +396,18 @@ void PABotBase::retransmit_thread(){ bool PABotBase::try_issue_request( std::map::iterator& iter, + const std::atomic* cancelled, uint8_t send_type, char* send_params, size_t send_bytes, bool silent_remove, size_t queue_limit ){ if (send_bytes > PABB_MAX_MESSAGE_SIZE){ - throw "Message is too long."; + PA_THROW_StringException("Message is too long."); } SpinLockGuard lg(m_state_lock, "PABotBase::try_issue_request()"); + if (cancelled != nullptr && cancelled->load(std::memory_order_acquire)){ + throw CancelledException(); + } State state = m_state.load(std::memory_order_acquire); if (state != State::RUNNING){ @@ -403,7 +429,7 @@ bool PABotBase::try_issue_request( std::forward_as_tuple() ); if (!ret.second){ - throw "Duplicate sequence number: " + std::to_string(seqnum); + PA_THROW_StringException("Duplicate sequence number: " + std::to_string(seqnum)); } m_send_seq = seqnum + 1; @@ -422,14 +448,18 @@ bool PABotBase::try_issue_request( } bool PABotBase::try_issue_command( std::map::iterator& iter, + const std::atomic* cancelled, uint8_t send_type, char* send_params, size_t send_bytes, bool silent_remove, size_t queue_limit ){ if (send_bytes > PABB_MAX_MESSAGE_SIZE){ - throw "Message is too long."; + PA_THROW_StringException("Message is too long."); } SpinLockGuard lg(m_state_lock, "PABotBase::try_issue_command()"); + if (cancelled != nullptr && cancelled->load(std::memory_order_acquire)){ + throw CancelledException(); + } State state = m_state.load(std::memory_order_acquire); if (state != State::RUNNING){ @@ -457,7 +487,7 @@ bool PABotBase::try_issue_command( std::forward_as_tuple() ); if (!ret.second){ - throw "Duplicate sequence number: " + std::to_string(seqnum); + PA_THROW_StringException("Duplicate sequence number: " + std::to_string(seqnum)); } m_send_seq = seqnum + 1; @@ -476,6 +506,7 @@ bool PABotBase::try_issue_command( } bool PABotBase::issue_request( std::map::iterator& iter, + const std::atomic* cancelled, uint8_t send_type, char* send_params, size_t send_bytes, bool silent_remove ){ @@ -500,12 +531,16 @@ bool PABotBase::issue_request( while (true){ if (try_issue_request( iter, + cancelled, send_type, send_params, send_bytes, silent_remove, MAX_PENDING_REQUESTS )){ return true; } std::unique_lock lg(m_sleep_lock); + if (cancelled != nullptr && cancelled->load(std::memory_order_acquire)){ + throw CancelledException(); + } if (m_state.load(std::memory_order_acquire) != State::RUNNING){ throw CancelledException(); } @@ -514,6 +549,7 @@ bool PABotBase::issue_request( } bool PABotBase::issue_command( std::map::iterator& iter, + const std::atomic* cancelled, uint8_t send_type, char* send_params, size_t send_bytes, bool silent_remove ){ @@ -538,12 +574,16 @@ bool PABotBase::issue_command( while (true){ if (try_issue_command( iter, + cancelled, send_type, send_params, send_bytes, silent_remove, MAX_PENDING_REQUESTS )){ return true; } std::unique_lock lg(m_sleep_lock); + if (cancelled != nullptr && cancelled->load(std::memory_order_acquire)){ + throw CancelledException(); + } if (m_state.load(std::memory_order_acquire) != State::RUNNING){ throw CancelledException(); } @@ -553,37 +593,40 @@ bool PABotBase::issue_command( bool PABotBase::try_issue_request( + const std::atomic* cancelled, uint8_t send_type, char* send_params, size_t send_bytes ){ if (!PABB_MSG_IS_COMMAND(send_type)){ std::map::iterator iter; - return try_issue_request(iter, send_type, send_params, send_bytes, true, MAX_PENDING_REQUESTS); + return try_issue_request(iter, cancelled, send_type, send_params, send_bytes, true, MAX_PENDING_REQUESTS); }else{ std::map::iterator iter; - return try_issue_command(iter, send_type, send_params, send_bytes, true, MAX_PENDING_REQUESTS); + return try_issue_command(iter, cancelled, send_type, send_params, send_bytes, true, MAX_PENDING_REQUESTS); } } void PABotBase::issue_request( + const std::atomic* cancelled, uint8_t send_type, char* send_params, size_t send_bytes ){ if (!PABB_MSG_IS_COMMAND(send_type)){ std::map::iterator iter; - issue_request(iter, send_type, send_params, send_bytes, true); + issue_request(iter, cancelled, send_type, send_params, send_bytes, true); }else{ std::map::iterator iter; - issue_command(iter, send_type, send_params, send_bytes, true); + issue_command(iter, cancelled, send_type, send_params, send_bytes, true); } } void PABotBase::issue_request_and_wait( + const std::atomic* cancelled, uint8_t send_type, char* send_params, size_t send_bytes, uint8_t recv_type, char* recv_params, size_t recv_bytes ){ if (!PABB_MSG_IS_REQUEST(send_type)){ - throw "This function only supports requests."; + PA_THROW_StringException("This function only supports requests."); } std::map::iterator iter; - issue_request(iter, send_type, send_params, send_bytes, false); + issue_request(iter, cancelled, send_type, send_params, send_bytes, false); // Wait for ack. while (true){ @@ -609,13 +652,13 @@ void PABotBase::issue_request_and_wait( if (type != recv_type){ SpinLockGuard slg(m_state_lock, "PABotBase::issue_request_and_wait() - 1"); remove_request(iter); - throw "Received incorrect response type: " + std::to_string(type); + PA_THROW_StringException("Received incorrect response type: " + std::to_string(type)); } const std::string& body = iter->second.ack.body; if (body.size() != recv_bytes){ SpinLockGuard slg(m_state_lock, "PABotBase::issue_request_and_wait() - 2"); remove_request(iter); - throw "Received incorrect response size: " + std::to_string(body.size()); + PA_THROW_StringException("Received incorrect response size: " + std::to_string(body.size())); } memcpy(recv_params, body.c_str(), body.size()); @@ -629,19 +672,19 @@ void PABotBase::issue_request_and_wait( uint32_t PABotBase::protocol_version(){ pabb_MsgRequestProtocolVersion params; pabb_MsgAckRequestI32 response; - issue_request_and_wait(params, response); + issue_request_and_wait(nullptr, params, response); return response.data; } uint32_t PABotBase::program_version(){ pabb_MsgRequestProgramVersion params; pabb_MsgAckRequestI32 response; - issue_request_and_wait(params, response); + issue_request_and_wait(nullptr, params, response); return response.data; } uint8_t PABotBase::program_id(){ pabb_MsgRequestProgramID params; pabb_MsgAckRequestI8 response; - issue_request_and_wait(params, response); + issue_request_and_wait(nullptr, params, response); return response.data; } diff --git a/ClientSource/Connection/PABotBase.h b/ClientSource/Connection/PABotBase.h index a44382089e..3da01e6dee 100644 --- a/ClientSource/Connection/PABotBase.h +++ b/ClientSource/Connection/PABotBase.h @@ -29,7 +29,7 @@ #include #include #include -#include "Common/Clientside/SpinLock.h" +#include "Common/Cpp/SpinLock.h" #include "ClientSource/Connection/PABotBaseConnection.h" #include "ClientSource/Libraries/Logging.h" #include "BotBase.h" @@ -76,6 +76,10 @@ class PABotBase : public BotBase, private PABotBaseConnection{ // Waits for all pending requests to finish. virtual void wait_for_all_requests() override; + // Stop all pending commands. This wipes the command queue on both sides + // and stops any currently executing command. + virtual void stop_all_commands() override; + public: // For Command Implementations @@ -125,32 +129,39 @@ class PABotBase : public BotBase, private PABotBaseConnection{ private: bool try_issue_request( std::map::iterator& iter, + const std::atomic* cancelled, uint8_t send_type, char* send_params, size_t send_bytes, bool silent_remove, size_t queue_limit ); bool try_issue_command( std::map::iterator& iter, + const std::atomic* cancelled, uint8_t send_type, char* send_params, size_t send_bytes, bool silent_remove, size_t queue_limit ); bool issue_request( std::map::iterator& iter, + const std::atomic* cancelled, uint8_t send_type, char* send_params, size_t send_bytes, bool silent_remove ); bool issue_command( std::map::iterator& iter, + const std::atomic* cancelled, uint8_t send_type, char* send_params, size_t send_bytes, bool silent_remove ); virtual bool try_issue_request( + const std::atomic* cancelled, uint8_t send_type, char* send_params, size_t send_bytes ) override; virtual void issue_request( + const std::atomic* cancelled, uint8_t send_type, char* send_params, size_t send_bytes ) override; virtual void issue_request_and_wait( + const std::atomic* cancelled, uint8_t send_type, char* send_params, size_t send_bytes, uint8_t recv_type, char* recv_params, size_t recv_bytes ) override; diff --git a/ClientSource/Connection/PABotBaseConnection.cpp b/ClientSource/Connection/PABotBaseConnection.cpp index 3d67aa64d6..94422f9964 100644 --- a/ClientSource/Connection/PABotBaseConnection.cpp +++ b/ClientSource/Connection/PABotBaseConnection.cpp @@ -7,6 +7,7 @@ #include #include "Common/CRC32.h" #include "Common/MessageProtocol.h" +#include "Common/Cpp/Exception.h" #include "ClientSource/Libraries/Logging.h" #include "ClientSource/Libraries/MessageConverter.h" #include "PABotBaseConnection.h" @@ -53,7 +54,7 @@ void PABotBaseConnection::send_message(const BotBaseMessage& message, bool is_re size_t total_bytes = PABB_PROTOCOL_OVERHEAD + message.body.size(); if (total_bytes > PABB_MAX_PACKET_SIZE){ - throw "Message is too long."; + PA_THROW_StringException("Message is too long."); } std::string buffer; diff --git a/ClientSource/Connection/PABotBaseConnection.h b/ClientSource/Connection/PABotBaseConnection.h index c11c29c282..8d195726e6 100644 --- a/ClientSource/Connection/PABotBaseConnection.h +++ b/ClientSource/Connection/PABotBaseConnection.h @@ -19,7 +19,6 @@ #include #include "Common/Compiler.h" #include "Common/MessageProtocol.h" -#include "ClientSource/Libraries/Compiler.h" #include "BotBase.h" #include "StreamInterface.h" diff --git a/ClientSource/Connection/SerialConnectionPOSIX.h b/ClientSource/Connection/SerialConnectionPOSIX.h index ac759c5205..450fd8f7e5 100644 --- a/ClientSource/Connection/SerialConnectionPOSIX.h +++ b/ClientSource/Connection/SerialConnectionPOSIX.h @@ -13,7 +13,9 @@ #include #include #include -#include "Common/Clientside/SpinLock.h" +#include "Common/Cpp/Exception.h" +#include "Common/Cpp/SpinLock.h" +#include "Common/Cpp/PanicDump.h" #include "StreamInterface.h" //#include @@ -34,7 +36,7 @@ class SerialConnection : public StreamConnection{ case 57600: baud = B57600; break; case 115200: baud = B115200;break; default: - throw "Unsupported Baud Rate: " + std::to_string(baud_rate); + PA_THROW_StringException("Unsupported Baud Rate: " + std::to_string(baud_rate)); } // std::cout << "desired baud = " << baud << std::endl; @@ -45,13 +47,13 @@ class SerialConnection : public StreamConnection{ if (error == EACCES){ str += " (permission denied)\nPlease run as sudo."; } - throw str; + PA_THROW_StringException(std::move(str)); } struct termios options; if (tcgetattr(m_fd, &options) == -1){ int error = errno; - throw "tcgetattr() failed. Error = " + std::to_string(error); + PA_THROW_StringException("tcgetattr() failed. Error = " + std::to_string(error)); } // std::cout << "read baud = " << cfgetispeed(&options) << std::endl; // std::cout << "write baud = " << cfgetospeed(&options) << std::endl; @@ -59,11 +61,11 @@ class SerialConnection : public StreamConnection{ // Baud Rate if (cfsetispeed(&options, baud) == -1){ int error = errno; - throw "cfsetispeed() failed. Error = " + std::to_string(error); + PA_THROW_StringException("cfsetispeed() failed. Error = " + std::to_string(error)); } if (cfsetospeed(&options, baud) == -1){ int error = errno; - throw "cfsetospeed() failed. Error = " + std::to_string(error); + PA_THROW_StringException("cfsetospeed() failed. Error = " + std::to_string(error)); } // std::cout << "write baud = " << cfgetispeed(&options) << std::endl; // std::cout << "write baud = " << cfgetospeed(&options) << std::endl; @@ -102,27 +104,28 @@ class SerialConnection : public StreamConnection{ if (tcsetattr(m_fd, TCSANOW, &options) == -1){ int error = errno; - throw "tcsetattr() failed. Error = " + std::to_string(error); + PA_THROW_StringException("tcsetattr() failed. Error = " + std::to_string(error)); } if (tcgetattr(m_fd, &options) == -1){ int error = errno; - throw "tcgetattr() failed. Error = " + std::to_string(error); + PA_THROW_StringException("tcgetattr() failed. Error = " + std::to_string(error)); } if (cfgetispeed(&options) != baud){ // std::cout << "actual baud = " << cfgetispeed(&options) << std::endl; - throw "Unable to set input baud rate."; + PA_THROW_StringException("Unable to set input baud rate."); } if (cfgetospeed(&options) != baud){ // std::cout << "actual baud = " << cfgetospeed(&options) << std::endl; - throw "Unable to set output baud rate."; + PA_THROW_StringException("Unable to set output baud rate."); } // Start receiver thread. try{ - m_listener = std::thread(&SerialConnection::recv_loop, this); + m_listener = std::thread(run_with_catch, "SerialConnection::SerialConnection()", [=]{ recv_loop(); }); }catch (...){ close(m_fd); + throw; } } diff --git a/ClientSource/Connection/SerialConnectionWinAPI.h b/ClientSource/Connection/SerialConnectionWinAPI.h index 4e2bb6540f..15e7146784 100644 --- a/ClientSource/Connection/SerialConnectionWinAPI.h +++ b/ClientSource/Connection/SerialConnectionWinAPI.h @@ -12,8 +12,10 @@ #include #include #include "Common/Compiler.h" -#include "Common/Clientside/Unicode.h" -#include "Common/Clientside/SpinLock.h" +#include "Common/Cpp/Exception.h" +#include "Common/Cpp/Unicode.h" +#include "Common/Cpp/SpinLock.h" +#include "Common/Cpp/PanicDump.h" #include "ClientSource/Libraries/Logging.h" #include "StreamInterface.h" @@ -42,7 +44,7 @@ class SerialConnection : public StreamConnection{ ); if (m_handle == INVALID_HANDLE_VALUE){ DWORD error = GetLastError(); - throw "Unable to open serial connection. Error = " + std::to_string(error); + PA_THROW_StringException("Unable to open serial connection. Error = " + std::to_string(error)); } DCB serial_params{0}; @@ -51,7 +53,7 @@ class SerialConnection : public StreamConnection{ if (!GetCommState(m_handle, &serial_params)){ DWORD error = GetLastError(); CloseHandle(m_handle); - throw "GetCommState() failed. Error = " + std::to_string(error); + PA_THROW_StringException("GetCommState() failed. Error = " + std::to_string(error)); } // cout << "BaudRate = " << (int)serial_params.BaudRate << endl; // cout << "ByteSize = " << (int)serial_params.ByteSize << endl; @@ -64,7 +66,7 @@ class SerialConnection : public StreamConnection{ if (!SetCommState(m_handle, &serial_params)){ DWORD error = GetLastError(); CloseHandle(m_handle); - throw "SetCommState() failed. Error = " + std::to_string(error); + PA_THROW_StringException("SetCommState() failed. Error = " + std::to_string(error)); } #if 1 @@ -72,7 +74,7 @@ class SerialConnection : public StreamConnection{ if (!GetCommTimeouts(m_handle, &timeouts)){ DWORD error = GetLastError(); CloseHandle(m_handle); - throw "GetCommTimeouts() failed. Error = " + std::to_string(error); + PA_THROW_StringException("GetCommTimeouts() failed. Error = " + std::to_string(error)); } //std::cout << "ReadIntervalTimeout = " << timeouts.ReadIntervalTimeout << std::endl; @@ -94,15 +96,16 @@ class SerialConnection : public StreamConnection{ if (!SetCommTimeouts(m_handle, &timeouts)){ DWORD error = GetLastError(); CloseHandle(m_handle); - throw "SetCommTimeouts() failed. Error = " + std::to_string(error); + PA_THROW_StringException("SetCommTimeouts() failed. Error = " + std::to_string(error)); } #endif // Start receiver thread. try{ - m_listener = std::thread(&SerialConnection::recv_loop, this); + m_listener = std::thread(run_with_catch, "SerialConnection::SerialConnection()", [=]{ recv_loop(); }); }catch (...){ CloseHandle(m_handle); + throw; } } virtual ~SerialConnection(){ diff --git a/ClientSource/Libraries/Compiler.h b/ClientSource/Libraries/Compiler.h deleted file mode 100644 index 2243a0cbd0..0000000000 --- a/ClientSource/Libraries/Compiler.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Pokemon Automation Push Button Framework - * - * From: https://github.com/PokemonAutomation/Arduino-Source - * - */ - - -// Disable specific warnings. - -#if _MSC_VER - -#pragma warning(disable:4100) // Unreferenced Formal Parameter -#pragma warning(disable:4127) // Conditional expresstion is constant -#pragma warning(disable:4996) // Unsafe function - -#else - - - -#endif diff --git a/ClientSource/Libraries/Logging.cpp b/ClientSource/Libraries/Logging.cpp index a8b0219d02..052f2b40b0 100644 --- a/ClientSource/Libraries/Logging.cpp +++ b/ClientSource/Libraries/Logging.cpp @@ -10,6 +10,7 @@ #include #include #include "Common/MessageProtocol.h" +#include "Common/Cpp/Exception.h" #include "Common/PokemonSwSh/PokemonSwShMisc.h" #include "MessageConverter.h" #include "Logging.h" @@ -19,7 +20,7 @@ namespace PokemonAutomation{ std::string to_string_padded(size_t digits, uint64_t x){ std::string str = std::to_string(x); if (digits < str.size()){ - throw "Number is too big to convert to fixed length string."; + PA_THROW_StringException("Number is too big to convert to fixed length string."); } return std::string(digits - str.size(), '0') + str; } diff --git a/ClientSource/Libraries/Logging.h b/ClientSource/Libraries/Logging.h index 52b13cf347..ba3eb5b77d 100644 --- a/ClientSource/Libraries/Logging.h +++ b/ClientSource/Libraries/Logging.h @@ -24,7 +24,7 @@ std::string current_time(); class MessageLogger : public MessageSniffer{ public: MessageLogger(bool log_everything = false) - : m_low_everything_owner(false) + : m_low_everything_owner(log_everything) , m_log_everything(m_low_everything_owner) {} MessageLogger(std::atomic& log_everything) diff --git a/ClientSource/Libraries/MessageConverter.cpp b/ClientSource/Libraries/MessageConverter.cpp index 41edc6276a..f3c12832a8 100644 --- a/ClientSource/Libraries/MessageConverter.cpp +++ b/ClientSource/Libraries/MessageConverter.cpp @@ -8,7 +8,7 @@ #include #include #include "Common/MessageProtocol.h" -#include "ClientSource/Libraries/Compiler.h" +#include "Common/Cpp/Exception.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonProgramIDs.h" #include "MessageConverter.h" @@ -24,7 +24,7 @@ void register_message_converter(uint8_t type, MessageConverter converter){ std::map& converters = converter_map(); auto iter = converters.find(type); if (iter != converters.end()){ - throw "Duplicate message type."; + PA_THROW_StringException("Duplicate message type."); } converters[type] = converter; } diff --git a/ClientSource/Libraries/Utilities.cpp b/ClientSource/Libraries/Utilities.cpp index 8cb1f9ff39..b135e4d4c7 100644 --- a/ClientSource/Libraries/Utilities.cpp +++ b/ClientSource/Libraries/Utilities.cpp @@ -5,7 +5,8 @@ */ #include -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/Exception.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonProgramIDs.h" #include "ClientSource/Connection/SerialConnection.h" @@ -58,7 +59,9 @@ std::unique_ptr start_connection( uint32_t version_hi = version / 100; uint32_t version_lo = version % 100; if (version_hi != PABB_PROTOCOL_VERSION / 100 || version_lo < PABB_PROTOCOL_VERSION % 100){ - throw "Incompatible version. Client: " + std::to_string(PABB_PROTOCOL_VERSION) + ", Device: " + std::to_string(version); + PA_THROW_StringException( + "Incompatible version. Client: " + std::to_string(PABB_PROTOCOL_VERSION) + ", Device: " + std::to_string(version) + ); } std::cout << std::endl; @@ -77,7 +80,7 @@ std::unique_ptr start_connection( // If we're running an actual program, the device needs to be running PABotBase to work. if (require_pabotbase && (int)program_id_to_botbase_level(program_id) >= (int)PABB_PID_PABOTBASE_12KB){ - throw "The device must be running PABotBase for this program to work."; + PA_THROW_StringException("The device must be running PABotBase for this program to work."); } // std::cout << "Begin Message Logging..." << std::endl; diff --git a/ClientSource/Programs/BallThrower.cpp b/ClientSource/Programs/BallThrower.cpp index 287339ae1a..68c34baa80 100644 --- a/ClientSource/Programs/BallThrower.cpp +++ b/ClientSource/Programs/BallThrower.cpp @@ -20,7 +20,7 @@ void program_BallThrower(const std::string& device_name){ std::cout << "Starting PABotBase - Ballthrower..." << std::endl; std::cout << std::endl; std::unique_ptr pabotbase = start_connection(true, device_name); - global_connection = pabotbase.get(); +// global_connection = pabotbase.get(); std::cout << "Begin Message Logging..." << std::endl; MessageLogger logger; @@ -29,19 +29,19 @@ void program_BallThrower(const std::string& device_name){ // Start Program - start_program_flash(CONNECT_CONTROLLER_DELAY); - grip_menu_connect_go_home(); - pbf_press_button(BUTTON_HOME, 10, HOME_TO_GAME_DELAY); + start_program_flash(*pabotbase, CONNECT_CONTROLLER_DELAY); + grip_menu_connect_go_home(*pabotbase); + pbf_press_button(*pabotbase, BUTTON_HOME, 10, HOME_TO_GAME_DELAY); while (true){ - pbf_press_button(BUTTON_X, 50, 50); - pbf_press_button(BUTTON_A, 50, 50); - pbf_mash_button(BUTTON_B, 100); + pbf_press_button(*pabotbase, BUTTON_X, 50, 50); + pbf_press_button(*pabotbase, BUTTON_A, 50, 50); + pbf_mash_button(*pabotbase, BUTTON_B, 100); } -// pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); -// end_program_callback(); -// end_program_loop(); +// pbf_press_button(*pabotbase, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); +// end_program_callback(*pabotbase); +// end_program_loop(*pabotbase); } diff --git a/ClientSource/Programs/BeamReset.cpp b/ClientSource/Programs/BeamReset.cpp index 91de28232c..d1e5d74621 100644 --- a/ClientSource/Programs/BeamReset.cpp +++ b/ClientSource/Programs/BeamReset.cpp @@ -32,7 +32,7 @@ void program_BeamReset(const std::string& device_name){ std::cout << "Starting PABotBase - BeamReset..." << std::endl; std::cout << std::endl; std::unique_ptr pabotbase = start_connection(true, device_name); - global_connection = pabotbase.get(); +// global_connection = pabotbase.get(); std::cout << "Begin Message Logging..." << std::endl; MessageLogger logger; @@ -40,35 +40,35 @@ void program_BeamReset(const std::string& device_name){ // Start Program - start_program_flash(CONNECT_CONTROLLER_DELAY); - grip_menu_connect_go_home(); + start_program_flash(*pabotbase, CONNECT_CONTROLLER_DELAY); + grip_menu_connect_go_home(*pabotbase); - resume_game_front_of_den_nowatts(TOLERATE_SYSTEM_UPDATE_MENU_SLOW); - pbf_mash_button(BUTTON_B, 100); + resume_game_front_of_den_nowatts(*pabotbase, TOLERATE_SYSTEM_UPDATE_MENU_SLOW); + pbf_mash_button(*pabotbase, BUTTON_B, 100); while (true){ // Talk to den. - pbf_press_button(BUTTON_A, 10, 450); + pbf_press_button(*pabotbase, BUTTON_A, 10, 450); if (EXTRA_LINE){ - pbf_press_button(BUTTON_A, 10, 300); + pbf_press_button(*pabotbase, BUTTON_A, 10, 300); } - pbf_press_button(BUTTON_A, 10, 300); + pbf_press_button(*pabotbase, BUTTON_A, 10, 300); // Drop wishing piece. - pbf_press_button(BUTTON_A, 10, 70); - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_FAST); + pbf_press_button(*pabotbase, BUTTON_A, 10, 70); + pbf_press_button(*pabotbase, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_FAST); for (uint16_t c = 0; c < 4; c++){ - pbf_press_button(BUTTON_HOME, 10, 10); - pbf_press_button(BUTTON_HOME, 10, 220); + pbf_press_button(*pabotbase, BUTTON_HOME, 10, 10); + pbf_press_button(*pabotbase, BUTTON_HOME, 10, 220); } - pbf_wait(DELAY_BEFORE_RESET); + pbf_wait(*pabotbase, DELAY_BEFORE_RESET); - reset_game_from_home(TOLERATE_SYSTEM_UPDATE_MENU_SLOW); + reset_game_from_home(*pabotbase, TOLERATE_SYSTEM_UPDATE_MENU_SLOW); } - end_program_callback(); - end_program_loop(); + end_program_callback(*pabotbase); + end_program_loop(*pabotbase); } diff --git a/ClientSource/Programs/ClothingBuyer.cpp b/ClientSource/Programs/ClothingBuyer.cpp index c86ab326d5..eef44e82b9 100644 --- a/ClientSource/Programs/ClothingBuyer.cpp +++ b/ClientSource/Programs/ClothingBuyer.cpp @@ -29,7 +29,7 @@ void program_ClothingBuyer(const std::string& device_name){ std::cout << "Starting PABotBase - ClothingBuyer..." << std::endl; std::cout << std::endl; std::unique_ptr pabotbase = start_connection(true, device_name); - global_connection = pabotbase.get(); +// global_connection = pabotbase.get(); std::cout << "Begin Message Logging..." << std::endl; MessageLogger logger; @@ -37,18 +37,18 @@ void program_ClothingBuyer(const std::string& device_name){ // Start Program - start_program_flash(CONNECT_CONTROLLER_DELAY); - grip_menu_connect_go_home(); - resume_game_no_interact(TOLERATE_SYSTEM_UPDATE_MENU_FAST); + start_program_flash(*pabotbase, CONNECT_CONTROLLER_DELAY); + grip_menu_connect_go_home(*pabotbase); + resume_game_no_interact(*pabotbase, TOLERATE_SYSTEM_UPDATE_MENU_FAST); while (true){ - pbf_press_button(BUTTON_A, 10, 90); + pbf_press_button(*pabotbase, BUTTON_A, 10, 90); if (CATEGORY_ROTATION){ - pbf_press_dpad(DPAD_RIGHT, 10, 40); + pbf_press_dpad(*pabotbase, DPAD_RIGHT, 10, 40); } - pbf_press_button(BUTTON_A, 10, 90); - pbf_press_button(BUTTON_A, 10, 90); - pbf_press_dpad(DPAD_DOWN, 10, 40); + pbf_press_button(*pabotbase, BUTTON_A, 10, 90); + pbf_press_button(*pabotbase, BUTTON_A, 10, 90); + pbf_press_dpad(*pabotbase, DPAD_DOWN, 10, 40); } } diff --git a/ClientSource/Programs/DateSpam-WattFarmer.cpp b/ClientSource/Programs/DateSpam-WattFarmer.cpp index 8f711f730d..03345d2e00 100644 --- a/ClientSource/Programs/DateSpam-WattFarmer.cpp +++ b/ClientSource/Programs/DateSpam-WattFarmer.cpp @@ -35,7 +35,7 @@ void program_DateSpam_WattFarmer(const std::string& device_name){ std::cout << "Starting PABotBase - DateSpam-WattFarmer..." << std::endl; std::cout << std::endl; std::unique_ptr pabotbase = start_connection(true, device_name); - global_connection = pabotbase.get(); +// global_connection = pabotbase.get(); std::cout << "Begin Message Logging..." << std::endl; MessageLogger logger; @@ -43,39 +43,39 @@ void program_DateSpam_WattFarmer(const std::string& device_name){ - start_program_flash(CONNECT_CONTROLLER_DELAY); - grip_menu_connect_go_home(); + start_program_flash(*pabotbase, CONNECT_CONTROLLER_DELAY); + grip_menu_connect_go_home(*pabotbase); uint8_t year = MAX_YEAR; uint16_t save_count = 0; for (uint32_t c = 0; c < SKIPS; c++){ // pabb_send_info_i32(c); log("Frames Skipped: " + std::to_string(c)); - home_roll_date_enter_game_autorollback(&year); - pbf_mash_button(BUTTON_B, 90); + home_roll_date_enter_game_autorollback(*pabotbase, &year); + pbf_mash_button(*pabotbase, BUTTON_B, 90); - pbf_press_button(BUTTON_A, 5, 5); - pbf_mash_button(BUTTON_B, 215); + pbf_press_button(*pabotbase, BUTTON_A, 5, 5); + pbf_mash_button(*pabotbase, BUTTON_B, 215); if (SAVE_ITERATIONS != 0){ save_count++; if (save_count >= SAVE_ITERATIONS){ save_count = 0; - pbf_mash_button(BUTTON_B, 2 * TICKS_PER_SECOND); - pbf_press_button(BUTTON_X, 20, OVERWORLD_TO_MENU_DELAY); - pbf_press_button(BUTTON_R, 20, 2 * TICKS_PER_SECOND); - pbf_press_button(BUTTON_ZL, 20, 3 * TICKS_PER_SECOND); + pbf_mash_button(*pabotbase, BUTTON_B, 2 * TICKS_PER_SECOND); + pbf_press_button(*pabotbase, BUTTON_X, 20, OVERWORLD_TO_MENU_DELAY); + pbf_press_button(*pabotbase, BUTTON_R, 20, 2 * TICKS_PER_SECOND); + pbf_press_button(*pabotbase, BUTTON_ZL, 20, 3 * TICKS_PER_SECOND); } } // Tap HOME and quickly spam B. The B spamming ensures that we don't // accidentally update the system if the system update window pops up. - pbf_press_button(BUTTON_HOME, 10, 5); - pbf_mash_button(BUTTON_B, GAME_TO_HOME_DELAY_FAST - 15); + pbf_press_button(*pabotbase, BUTTON_HOME, 10, 5); + pbf_mash_button(*pabotbase, BUTTON_B, GAME_TO_HOME_DELAY_FAST - 15); } - end_program_callback(); - end_program_loop(); + end_program_callback(*pabotbase); + end_program_loop(*pabotbase); } diff --git a/ClientSource/Programs/DeviceLogger.cpp b/ClientSource/Programs/DeviceLogger.cpp index 81447fd719..a2cb753c87 100644 --- a/ClientSource/Programs/DeviceLogger.cpp +++ b/ClientSource/Programs/DeviceLogger.cpp @@ -18,7 +18,7 @@ void device_logger(const std::string& device_name){ std::cout << "Starting Device Logger..." << std::endl; std::cout << std::endl; std::unique_ptr pabotbase = start_connection(false, device_name); - global_connection = pabotbase.get(); +// global_connection = pabotbase.get(); std::cout << "Begin Message Logging..." << std::endl; MessageLogger logger; diff --git a/ClientSource/Programs/FriendDelete.cpp b/ClientSource/Programs/FriendDelete.cpp index d4213ee2a3..d933bf8a56 100644 --- a/ClientSource/Programs/FriendDelete.cpp +++ b/ClientSource/Programs/FriendDelete.cpp @@ -34,7 +34,7 @@ void program_FriendDelete(const std::string& device_name){ std::cout << "Starting PABotBase - FriendDelete..." << std::endl; std::cout << std::endl; std::unique_ptr pabotbase = start_connection(true, device_name); - global_connection = pabotbase.get(); +// global_connection = pabotbase.get(); std::cout << "Begin Message Logging..." << std::endl; MessageLogger logger; @@ -42,26 +42,26 @@ void program_FriendDelete(const std::string& device_name){ // Start Program - start_program_flash(CONNECT_CONTROLLER_DELAY); - pbf_press_button(BUTTON_A, 5, 5); + start_program_flash(*pabotbase, CONNECT_CONTROLLER_DELAY); + pbf_press_button(*pabotbase, BUTTON_A, 5, 5); for (uint16_t c = 0; c < FRIENDS_TO_DELETE; c++){ - pbf_press_button(BUTTON_A, 5, VIEW_FRIEND_DELAY); // View friend - pbf_press_dpad(DPAD_DOWN, 5, 5); - pbf_press_button(BUTTON_A, 10, 90); // Click on Options + pbf_press_button(*pabotbase, BUTTON_A, 5, VIEW_FRIEND_DELAY); // View friend + pbf_press_dpad(*pabotbase, DPAD_DOWN, 5, 5); + pbf_press_button(*pabotbase, BUTTON_A, 10, 90); // Click on Options if (BLOCK_FRIENDS){ - pbf_press_dpad(DPAD_DOWN, 5, 5); + pbf_press_dpad(*pabotbase, DPAD_DOWN, 5, 5); } - pbf_press_button(BUTTON_A, 10, 90); // Click on Remove/Block Friend + pbf_press_button(*pabotbase, BUTTON_A, 10, 90); // Click on Remove/Block Friend if (BLOCK_FRIENDS){ - pbf_press_button(BUTTON_A, 5, VIEW_FRIEND_DELAY); // Confirm + pbf_press_button(*pabotbase, BUTTON_A, 5, VIEW_FRIEND_DELAY); // Confirm } - pbf_press_button(BUTTON_A, 5, DELETE_FRIEND_DELAY); // Confirm - pbf_press_button(BUTTON_A, 5, FINISH_DELETE_DELAY); // Finish delete friend. + pbf_press_button(*pabotbase, BUTTON_A, 5, DELETE_FRIEND_DELAY); // Confirm + pbf_press_button(*pabotbase, BUTTON_A, 5, FINISH_DELETE_DELAY); // Finish delete friend. } - end_program_callback(); - end_program_loop(); + end_program_callback(*pabotbase); + end_program_loop(*pabotbase); } diff --git a/ClientSource/Programs/TurboA.cpp b/ClientSource/Programs/TurboA.cpp index 8e67f73f50..2d943c6c45 100644 --- a/ClientSource/Programs/TurboA.cpp +++ b/ClientSource/Programs/TurboA.cpp @@ -21,7 +21,7 @@ void program_TurboA(const std::string& device_name){ std::cout << "Starting PABotBase - TurboA..." << std::endl; std::cout << std::endl; std::unique_ptr pabotbase = start_connection(true, device_name); - global_connection = pabotbase.get(); +// global_connection = pabotbase.get(); std::cout << "Begin Message Logging..." << std::endl; MessageLogger logger; @@ -29,12 +29,12 @@ void program_TurboA(const std::string& device_name){ // Start Program - start_program_flash(CONNECT_CONTROLLER_DELAY); - grip_menu_connect_go_home(); - resume_game_no_interact(TOLERATE_SYSTEM_UPDATE_MENU_FAST); + start_program_flash(*pabotbase, CONNECT_CONTROLLER_DELAY); + grip_menu_connect_go_home(*pabotbase); + resume_game_no_interact(*pabotbase, TOLERATE_SYSTEM_UPDATE_MENU_FAST); while (true){ - pbf_press_button(BUTTON_A, 5, 5); + pbf_press_button(*pabotbase, BUTTON_A, 5, 5); } } diff --git a/Common/Compiler.h b/Common/Compiler.h index 7a253a56f5..1c52bc0855 100644 --- a/Common/Compiler.h +++ b/Common/Compiler.h @@ -19,8 +19,12 @@ namespace PokemonAutomation{ using ssize_t = ptrdiff_t; #pragma warning(disable:4100) // Unreferenced Formal Parameter +#pragma warning(disable:4127) // Conditional expresstion is constant +#pragma warning(disable:4996) // Unsafe function +#define __PRETTY_FUNCTION__ __FUNCSIG__ + #elif __GNUC__ diff --git a/Common/Clientside/AsyncDispatcher.cpp b/Common/Cpp/AsyncDispatcher.cpp similarity index 81% rename from Common/Clientside/AsyncDispatcher.cpp rename to Common/Cpp/AsyncDispatcher.cpp index 5dddcc65ee..f577ddea0e 100644 --- a/Common/Clientside/AsyncDispatcher.cpp +++ b/Common/Cpp/AsyncDispatcher.cpp @@ -4,8 +4,12 @@ * */ +#include "PanicDump.h" #include "AsyncDispatcher.h" +#include +using std::cout; +using std::endl; namespace PokemonAutomation{ @@ -33,7 +37,7 @@ AsyncDispatcher::AsyncDispatcher(size_t starting_threads) , m_busy_count(0) { for (size_t c = 0; c < starting_threads; c++){ - m_threads.emplace_back(&AsyncDispatcher::thread_loop, this); + m_threads.emplace_back(run_with_catch, "AsyncDispatcher::thread_loop()", [=]{ thread_loop(); }); } } AsyncDispatcher::~AsyncDispatcher(){ @@ -57,7 +61,7 @@ void AsyncDispatcher::dispatch_task(AsyncTask& task){ // Make sure a thread is ready for it. if (m_queue.size() > m_threads.size() - m_busy_count){ - m_threads.emplace_back(&AsyncDispatcher::thread_loop, this); + m_threads.emplace_back(run_with_catch, "AsyncDispatcher::thread_loop()", [=]{ thread_loop(); }); } m_cv.notify_one(); @@ -95,7 +99,7 @@ void AsyncDispatcher::run_in_parallel( // Make sure there are enough threads. while (m_queue.size() > m_threads.size() - m_busy_count){ - m_threads.emplace_back(&AsyncDispatcher::thread_loop, this); + m_threads.emplace_back(run_with_catch, "AsyncDispatcher::thread_loop()", [=]{ thread_loop(); }); } for (size_t c = 0; c < tasks.size(); c++){ @@ -143,10 +147,11 @@ void AsyncDispatcher::thread_loop(){ task->m_task(); }catch (...){ task->m_exception = std::current_exception(); - std::lock_guard lg(m_lock); - for (AsyncTask* t : m_queue){ - t->signal(); - } + cout << "Task threw an exception." << endl; +// std::lock_guard lg(m_lock); +// for (AsyncTask* t : m_queue){ +// t->signal(); +// } } task->signal(); } diff --git a/Common/Clientside/AsyncDispatcher.h b/Common/Cpp/AsyncDispatcher.h similarity index 84% rename from Common/Clientside/AsyncDispatcher.h rename to Common/Cpp/AsyncDispatcher.h index f1f5066576..cbe5b96d2c 100644 --- a/Common/Clientside/AsyncDispatcher.h +++ b/Common/Cpp/AsyncDispatcher.h @@ -2,6 +2,11 @@ * * From: https://github.com/PokemonAutomation/Arduino-Source * + * This class is meant for asynchronous tasks, not for parallel computation. + * This class will always spawn enough threads run all tasks in parallel. + * + * If you need to spam a bunch of compute tasks in parallel, use ParallelTaskRunner. + * */ #ifndef PokemonAutomation_AsyncDispatcher_H @@ -30,17 +35,19 @@ class AsyncTask{ // Wait for the task to finish. Will rethrow any exceptions. void wait(); + private: template AsyncTask(Args&&... args) : m_task(std::forward(args)...) , m_finished(false) {} - void signal(); private: friend class AsyncDispatcher; + friend class ParallelTaskRunner; + std::function m_task; bool m_finished; std::exception_ptr m_exception; diff --git a/Common/Cpp/Exception.cpp b/Common/Cpp/Exception.cpp new file mode 100644 index 0000000000..fcba47c287 --- /dev/null +++ b/Common/Cpp/Exception.cpp @@ -0,0 +1,35 @@ +/* Exception + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "Exception.h" + +namespace PokemonAutomation{ + + +StringException::StringException(const char* type, const char* location, std::string message) + : m_message(std::move(message)) +{ + m_full_body = type; + m_full_body += ":\r\n\r\n"; + m_full_body += "Location: "; + m_full_body += location; + m_full_body += "\r\n\r\n"; + m_full_body += m_message; + m_full_body += "\r\n\r\n"; +} + + + +FileException::FileException(const char* location, std::string message, const std::string& file) + : StringException("FileException", location, std::move(message)) +{ + m_full_body += file; + m_full_body += "\r\n\r\n"; +} + + +} + diff --git a/Common/Cpp/Exception.h b/Common/Cpp/Exception.h new file mode 100644 index 0000000000..396729213d --- /dev/null +++ b/Common/Cpp/Exception.h @@ -0,0 +1,99 @@ +/* Exception + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_Exception_H +#define PokemonAutomation_Exception_H + +#include +#include + +#ifdef QT_VERSION +#include +#endif + +#include "Common/Compiler.h" + +namespace PokemonAutomation{ + + +class StringException : public std::exception{ +public: + StringException(const char* location, const char* message) + : StringException("StringException", location, std::string(message)) + {} + StringException(const char* location, const std::string& message) + : StringException("StringException", location, message) + {} +#ifdef QT_VERSION + StringException(const char* location, const QString& message) + : StringException("StringException", location, message.toUtf8().data()) + {} +#endif + + virtual const char* type() const{ + return "StringException"; + } + virtual const char* what() const noexcept{ + return m_full_body.c_str(); + } + const std::string& message() const{ + return m_message; + } +#ifdef QT_VERSION + QString message_qt() const{ + return QString::fromUtf8(m_message.c_str()); + } +#endif + + +protected: + StringException(const char* type, const char* location, std::string message); + + +protected: + std::string m_full_body; + std::string m_message; +}; +#define PA_THROW_StringException(message) \ + throw StringException(__PRETTY_FUNCTION__, message) + + + +class ParseException : public StringException{ +public: + using StringException::StringException; + + virtual const char* type() const{ + return "ParseException"; + } +}; +#define PA_THROW_ParseException(message) \ + throw ParseException(__PRETTY_FUNCTION__, message) + + + +class FileException : public StringException{ +public: + FileException(const char* location, std::string message, const std::string& file); +#ifdef QT_VERSION + FileException(const char* location, std::string message, const QString& file) + : FileException(location, std::move(message), std::string(file.toUtf8().data())) + {} +#endif + + virtual const char* type() const{ + return "FileException"; + } + +private: +}; +#define PA_THROW_FileException(message, file) \ + throw FileException(__PRETTY_FUNCTION__, message, file) + + +} +#endif + diff --git a/Common/Cpp/FixedLimitVector.h b/Common/Cpp/FixedLimitVector.h new file mode 100644 index 0000000000..89b9d1b62e --- /dev/null +++ b/Common/Cpp/FixedLimitVector.h @@ -0,0 +1,120 @@ +/* Fixed Limit Vector + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + * A non-copyable, non-movable vector whose buffer cannot be resized. + * It supports emplace_back() and pop_back(). All elements are unchanged + * through either operation unless it's the one being popped by pop_back(). + * + * There are no requirements of the elements. They need not be copyable nor + * movable since they will stay in place. + * + */ + +#ifndef PokemonAutomation_FixedLimitVector_H +#define PokemonAutomation_FixedLimitVector_H + +#include +#include + +namespace PokemonAutomation{ + + +template +class FixedLimitVector{ +public: + ~FixedLimitVector(){ + while (m_size > 0){ + pop_back(); + } + delete[] reinterpret_cast(m_data); + } + FixedLimitVector(const FixedLimitVector&) = delete; + void operator=(const FixedLimitVector&) = delete; + FixedLimitVector(FixedLimitVector&& x) + : m_data(x.m_data) + , m_size(x.m_size) + , m_capacity(x.m_capacity) + { + x.m_data = nullptr; + x.m_size = 0; + x.m_capacity = 0; + } + +public: + FixedLimitVector() + : m_data(nullptr) + , m_size(0) + , m_capacity(0) + {} + FixedLimitVector(size_t capacity) + : m_size(0) + , m_capacity(capacity) + { + m_data = reinterpret_cast(new char[capacity * sizeof(Object)]); + } + + void reset(){ + while (m_size > 0){ + pop_back(); + } + delete[] reinterpret_cast(m_data); + m_data = nullptr; + m_capacity = 0; + } + void reset(size_t capacity){ + Object* data = reinterpret_cast(new char[capacity * sizeof(Object)]); + while (m_size > 0){ + pop_back(); + } + delete[] reinterpret_cast(m_data); + m_data = data; + m_capacity = capacity; + } + +public: + size_t size() const{ return m_size; } + size_t capacity() const{ return m_capacity; } + + Object& operator[](size_t index) { return m_data[index]; } + const Object& operator[](size_t index) const{ return m_data[index]; } + Object& back() { return m_data[m_size - 1]; } + const Object& back() const{ return m_data[m_size - 1]; } + + template + bool emplace_back(Args&&... args){ + if (m_size < m_capacity){ + new (m_data + m_size) Object(std::forward(args)...); + m_size++; + return true; + }else{ + return false; + } + } + void pop_back(){ + m_data[--m_size].~Object(); + } + + Object* begin(){ + return m_data; + } + const Object* begin() const{ + return m_data; + } + Object* end(){ + return m_data + m_size; + } + const Object* end() const{ + return m_data + m_size; + } + +private: + Object* m_data; + size_t m_size; + size_t m_capacity; +}; + + + +} +#endif diff --git a/Common/Cpp/PanicDump.cpp b/Common/Cpp/PanicDump.cpp new file mode 100644 index 0000000000..9b470744ff --- /dev/null +++ b/Common/Cpp/PanicDump.cpp @@ -0,0 +1,57 @@ +/* Panic Dumping + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "ClientSource/Libraries/Logging.h" +#include "PrettyPrint.h" +#include "PanicDump.h" + +namespace PokemonAutomation{ + + + +void panic_dump(const char* location, const char* message){ + std::string body; + body += "\xef\xbb\xbf"; // UTF-8 BOM +// body += "Panic Dump:\r\n"; + + body += "Caught Location: "; + body += location; + body += "\r\n\r\n"; + +// body += "Exception: "; + body += message; + body += "\r\n"; + + FILE* file = fopen(("PanicDump-" + now_to_filestring() + ".log").c_str(), "wb"); + fwrite(body.c_str(), sizeof(char), body.size() * sizeof(char), file); + fclose(file); +} + + +void run_with_catch(const char* location, std::function&& lambda){ + try{ + lambda(); + }catch (CancelledException&){ + panic_dump(location, "CancelledException"); + throw; + }catch (const char* e){ + panic_dump(location, e); + throw; + }catch (const std::string& e){ + panic_dump(location, e.c_str()); + throw; + }catch (const std::exception& e){ + panic_dump(location, e.what()); + throw; + }catch (...){ + panic_dump(location, "Unknown Exception"); + throw; + } +} + + + +} diff --git a/Common/Cpp/PanicDump.h b/Common/Cpp/PanicDump.h new file mode 100644 index 0000000000..26a5f05ad5 --- /dev/null +++ b/Common/Cpp/PanicDump.h @@ -0,0 +1,24 @@ +/* Panic Dumping + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PanicDumping_H +#define PokemonAutomation_PanicDumping_H + +#include +#include +#include "ClientSource/Connection/BotBase.h" + +namespace PokemonAutomation{ + + +void panic_dump(const char* location, const char* message); + +void run_with_catch(const char* location, std::function&& lambda); + + +} +#endif + diff --git a/Common/Cpp/ParallelTaskRunner.cpp b/Common/Cpp/ParallelTaskRunner.cpp new file mode 100644 index 0000000000..027b877e43 --- /dev/null +++ b/Common/Cpp/ParallelTaskRunner.cpp @@ -0,0 +1,116 @@ +/* Parallel Task Runner + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#if _WIN32 +#include +#endif +#include "PanicDump.h" +#include "ParallelTaskRunner.h" + +namespace PokemonAutomation{ + + + +ParallelTaskRunner::ParallelTaskRunner(size_t starting_threads, size_t max_threads) + : m_max_threads(max_threads == 0 ? std::thread::hardware_concurrency() : max_threads) + , m_stopping(false) + , m_busy_count(0) +{ + for (size_t c = 0; c < starting_threads; c++){ + m_threads.emplace_back(run_with_catch, "ParallelTaskRunner::thread_loop()", [=]{ thread_loop(); }); + } +} +ParallelTaskRunner::~ParallelTaskRunner(){ + { + std::lock_guard lg(m_lock); + m_stopping = true; + m_thread_cv.notify_all(); +// m_dispatch_cv.notify_all(); + } + for (std::thread& thread : m_threads){ + thread.join(); + } + for (auto& task : m_queue){ + task->signal(); + } +} + +void ParallelTaskRunner::wait_for_everything(){ + std::unique_lock lg(m_lock); + m_dispatch_cv.wait(lg, [=]{ + return m_queue.size() + m_busy_count == 0; + }); +} + +std::shared_ptr ParallelTaskRunner::dispatch(std::function&& func){ + std::shared_ptr task(new AsyncTask(std::move(func))); + + std::unique_lock lg(m_lock); + + m_dispatch_cv.wait(lg, [=]{ + return m_queue.size() + m_busy_count < m_max_threads; + }); + + // Enqueue task. + m_queue.emplace_back(task); + + if (m_queue.size() + m_busy_count > m_threads.size()){ + m_threads.emplace_back(run_with_catch, "ParallelTaskRunner::thread_loop()", [=]{ thread_loop(); }); + } + + m_thread_cv.notify_one(); + + return task; +} + + +void ParallelTaskRunner::thread_loop(){ +#if _WIN32 + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE); +#endif + + bool busy = false; + while (true){ + std::shared_ptr task; + { + std::unique_lock lg(m_lock); + if (busy){ + m_busy_count--; + busy = false; + m_dispatch_cv.notify_all(); + } + + if (m_stopping){ + return; + } + if (m_queue.empty()){ + m_thread_cv.wait(lg); + continue; + } + + task = m_queue.front(); + m_queue.pop_front(); + + busy = true; + m_busy_count++; + } + + try{ + task->m_task(); + }catch (...){ + task->m_exception = std::current_exception(); +// std::lock_guard lg(m_lock); +// for (std::shared_ptr& t : m_queue){ +// t->signal(); +// } + } + task->signal(); + } +} + + + +} diff --git a/Common/Cpp/ParallelTaskRunner.h b/Common/Cpp/ParallelTaskRunner.h new file mode 100644 index 0000000000..b576f6872b --- /dev/null +++ b/Common/Cpp/ParallelTaskRunner.h @@ -0,0 +1,46 @@ +/* Parallel Task Runner + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_ParallelTaskRunner_H +#define PokemonAutomation_ParallelTaskRunner_H + +#include "AsyncDispatcher.h" + +namespace PokemonAutomation{ + + +class ParallelTaskRunner{ +public: + ParallelTaskRunner(size_t starting_threads = 0, size_t max_threads = 0); + ~ParallelTaskRunner(); + + void wait_for_everything(); + + std::shared_ptr dispatch(std::function&& func); + + +private: +// void dispatch_task(AsyncTask& task); + void thread_loop(); + + +private: + size_t m_max_threads; + std::deque> m_queue; + std::vector m_threads; + bool m_stopping; + size_t m_busy_count; + std::mutex m_lock; + std::condition_variable m_thread_cv; + std::condition_variable m_dispatch_cv; +}; + + + + + +} +#endif diff --git a/Common/Clientside/PrettyPrint.cpp b/Common/Cpp/PrettyPrint.cpp similarity index 68% rename from Common/Clientside/PrettyPrint.cpp rename to Common/Cpp/PrettyPrint.cpp index a0629f80f5..e24b9accf8 100644 --- a/Common/Clientside/PrettyPrint.cpp +++ b/Common/Cpp/PrettyPrint.cpp @@ -4,6 +4,7 @@ * */ +#include #include #include #include "Common/SwitchFramework/SwitchControllerDefs.h" @@ -76,6 +77,27 @@ std::string ticks_to_time(uint64_t ticks){ } +std::string now_to_filestring(){ +#if _WIN32 && _MSC_VER +#pragma warning(disable:4996) +#endif + + time_t t = time(0); + struct tm* now = localtime(&t); + + std::string str; + str += std::to_string(now->tm_year + 1900); + str += std::string(now->tm_mon + 1 < 10 ? "0" : "") + std::to_string(now->tm_mon + 1); + str += std::string(now->tm_mday < 10 ? "0" : "") + std::to_string(now->tm_mday); + str += "-"; + str += std::string(now->tm_hour < 10 ? "0" : "") + std::to_string(now->tm_hour); + str += std::string(now->tm_min < 10 ? "0" : "") + std::to_string(now->tm_min); + str += std::string(now->tm_sec < 10 ? "0" : "") + std::to_string(now->tm_sec); + return str; +} + + + } diff --git a/Common/Clientside/PrettyPrint.h b/Common/Cpp/PrettyPrint.h similarity index 86% rename from Common/Clientside/PrettyPrint.h rename to Common/Cpp/PrettyPrint.h index f9e33bff79..f35dea4950 100644 --- a/Common/Clientside/PrettyPrint.h +++ b/Common/Cpp/PrettyPrint.h @@ -15,6 +15,8 @@ std::string tostr_u_commas(uint64_t x); std::string tostr_fixed(double x, int precision); std::string ticks_to_time(uint64_t ticks); +std::string now_to_filestring(); + } #endif diff --git a/Common/Clientside/SpinLock.h b/Common/Cpp/SpinLock.h similarity index 100% rename from Common/Clientside/SpinLock.h rename to Common/Cpp/SpinLock.h diff --git a/Common/Clientside/Unicode.cpp b/Common/Cpp/Unicode.cpp similarity index 100% rename from Common/Clientside/Unicode.cpp rename to Common/Cpp/Unicode.cpp diff --git a/Common/Clientside/Unicode.h b/Common/Cpp/Unicode.h similarity index 100% rename from Common/Clientside/Unicode.h rename to Common/Cpp/Unicode.h diff --git a/Common/MessageProtocol.h b/Common/MessageProtocol.h index fc2eb2b24d..797666aa43 100644 --- a/Common/MessageProtocol.h +++ b/Common/MessageProtocol.h @@ -153,10 +153,10 @@ // (version / 100) must be the same on both server and client. // (version % 100) can be higher on server than client. // -#define PABB_PROTOCOL_VERSION 2021032200 +#define PABB_PROTOCOL_VERSION 2021052600 // Program versioning doesn't matter. It's just for informational purposes. -#define PABB_PROGRAM_VERSION 2021032200 +#define PABB_PROGRAM_VERSION 2021052600 #define PABB_BAUD_RATE 115200 #define PABB_RETRANSMIT_DELAY_MILLIS 80 diff --git a/Common/PokemonSwSh/PokemonSettings.c b/Common/PokemonSwSh/PokemonSettings.c index 863249aa70..cdba13332e 100644 --- a/Common/PokemonSwSh/PokemonSettings.c +++ b/Common/PokemonSwSh/PokemonSettings.c @@ -92,9 +92,6 @@ uint16_t ENTER_PROFILE_DELAY = 2 * TICKS_PER_SECOND; //////////////////////////////////////////////////////////////////////////////// // Start Game Timings -// If starting the game requires checking the internet, wait this long for it. -uint16_t START_GAME_INTERNET_CHECK_DELAY = 3 * TICKS_PER_SECOND; - // Delays to start and enter the game when it isn't running. uint16_t START_GAME_MASH = 2 * TICKS_PER_SECOND; // 1. Mash A for this long to start the game. uint16_t START_GAME_WAIT = 20 * TICKS_PER_SECOND; // 2. Wait this long for the game to load. diff --git a/Common/PokemonSwSh/PokemonSettings.h b/Common/PokemonSwSh/PokemonSettings.h index 8bba28a244..122a8bb60f 100644 --- a/Common/PokemonSwSh/PokemonSettings.h +++ b/Common/PokemonSwSh/PokemonSettings.h @@ -91,9 +91,6 @@ extern uint16_t ENTER_PROFILE_DELAY; //////////////////////////////////////////////////////////////////////////////// // Start Game Timings -// If starting the game requires checking the internet, wait this long for it. -extern uint16_t START_GAME_INTERNET_CHECK_DELAY; - // Delays to start and enter the game when it isn't running. extern uint16_t START_GAME_MASH; // 1. Mash A for this long to start the game. extern uint16_t START_GAME_WAIT; // 2. Wait this long for the game to load. diff --git a/Common/PokemonSwSh/PokemonSwShAutoHosts.cpp b/Common/PokemonSwSh/PokemonSwShAutoHosts.cpp index b24f91329b..bd6738d17a 100644 --- a/Common/PokemonSwSh/PokemonSwShAutoHosts.cpp +++ b/Common/PokemonSwSh/PokemonSwShAutoHosts.cpp @@ -6,34 +6,19 @@ #include #include "Common/SwitchFramework/Switch_PushButtons.h" +#include "Common/PokemonSwSh/PokemonSettings.h" +#include "Common/PokemonSwSh/PokemonSwShGameEntry.h" #include "ClientSource/Connection/BotBase.h" #include "ClientSource/Libraries/MessageConverter.h" #include "PokemonSwShAutoHosts.h" -using namespace PokemonAutomation; +#if 0 void connect_to_internet(uint16_t open_ycomm_delay, uint16_t connect_to_internet_delay){ - connect_to_internet(*global_connection, open_ycomm_delay, connect_to_internet_delay); -} -void connect_to_internet( - BotBase& device, - uint16_t open_ycomm_delay, - uint16_t connect_to_internet_delay -){ - pabb_connect_to_internet params; - params.open_ycomm_delay = open_ycomm_delay; - params.connect_to_internet_delay = connect_to_internet_delay; - device.issue_request(params); + connect_to_internet(*PokemonAutomation::global_connection, open_ycomm_delay, connect_to_internet_delay); } void home_to_add_friends(uint8_t user_slot, uint8_t scroll_down, bool fix_cursor){ - home_to_add_friends(*global_connection, user_slot, scroll_down, fix_cursor); -} -void home_to_add_friends(BotBase& device, uint8_t user_slot, uint8_t scroll_down, bool fix_cursor){ - pabb_home_to_add_friends params; - params.user_slot = user_slot; - params.scroll_down = scroll_down; - params.fix_cursor = fix_cursor; - device.issue_request(params); + home_to_add_friends(*PokemonAutomation::global_connection, user_slot, scroll_down, fix_cursor); } uint16_t accept_FRs( uint8_t slot, bool fix_cursor, @@ -42,7 +27,7 @@ uint16_t accept_FRs( bool tolerate_system_update_window_slow ){ accept_FRs( - *global_connection, + *PokemonAutomation::global_connection, slot, fix_cursor, game_to_home_delay_safe, auto_fr_duration, @@ -50,22 +35,6 @@ uint16_t accept_FRs( ); return 0; } -uint16_t accept_FRs( - BotBase& device, - uint8_t slot, bool fix_cursor, - uint16_t game_to_home_delay_safe, - uint16_t auto_fr_duration, - bool tolerate_system_update_window_slow -){ - pabb_accept_FRs params; - params.slot = slot; - params.fix_cursor = fix_cursor; - params.game_to_home_delay_safe = game_to_home_delay_safe; - params.auto_fr_duration = auto_fr_duration; - params.tolerate_system_update_window_slow = tolerate_system_update_window_slow; - device.issue_request(params); - return 0; -} void accept_FRs_while_waiting( uint8_t slot, uint16_t wait_time, uint16_t game_to_home_delay_safe, @@ -73,27 +42,70 @@ void accept_FRs_while_waiting( bool tolerate_system_update_window_slow ){ accept_FRs_while_waiting( - *global_connection, + *PokemonAutomation::global_connection, slot, wait_time, game_to_home_delay_safe, auto_fr_duration, tolerate_system_update_window_slow ); } -void accept_FRs_while_waiting( - BotBase& device, - uint8_t slot, uint16_t wait_time, +#endif + + + +namespace PokemonAutomation{ + + + + +void connect_to_internet( + const BotBaseContext& context, + uint16_t open_ycomm_delay, + uint16_t connect_to_internet_delay +){ + pabb_connect_to_internet params; + params.open_ycomm_delay = open_ycomm_delay; + params.connect_to_internet_delay = connect_to_internet_delay; + context->issue_request(&context.cancelled_bool(), params); +} +void home_to_add_friends( + const BotBaseContext& context, + uint8_t user_slot, + uint8_t scroll_down, + bool fix_cursor +){ + pabb_home_to_add_friends params; + params.user_slot = user_slot; + params.scroll_down = scroll_down; + params.fix_cursor = fix_cursor; + context->issue_request(&context.cancelled_bool(), params); +} +void accept_FRs( + const BotBaseContext& context, + uint8_t slot, bool fix_cursor, uint16_t game_to_home_delay_safe, uint16_t auto_fr_duration, bool tolerate_system_update_window_slow ){ - pabb_accept_FRs_while_waiting params; - params.slot = slot; - params.wait_time = wait_time; - params.game_to_home_delay_safe = game_to_home_delay_safe; - params.auto_fr_duration = auto_fr_duration; - params.tolerate_system_update_window_slow = tolerate_system_update_window_slow; - device.issue_request(params); + if (slot > 7){ + slot = 7; + } + + // Go to Switch Home menu. + pbf_press_button(context, BUTTON_HOME, 10, game_to_home_delay_safe); + + home_to_add_friends(context, slot, 0, fix_cursor); + + // Mash A. + pbf_mash_button(context, BUTTON_A, auto_fr_duration); + + // Return to Switch Home menu. (or game) + settings_to_enter_game_den_lobby( + context, + tolerate_system_update_window_slow, false, + ENTER_SWITCH_POKEMON, EXIT_SWITCH_POKEMON + ); + pbf_wait(context, 300); } @@ -125,39 +137,11 @@ int register_message_converters_pokemon_autohosting(){ return ss.str(); } ); - register_message_converter( - PABB_MSG_COMMAND_ACCEPT_FRS, - [](const std::string& body){ - std::stringstream ss; - ss << "accept_FRs() - "; - if (body.size() != sizeof(pabb_accept_FRs)){ ss << "(invalid size)" << std::endl; return ss.str(); } - const auto* params = (const pabb_accept_FRs*)body.c_str(); - ss << "seqnum = " << (uint64_t)params->seqnum; - ss << ", slot = " << (unsigned)params->slot; - ss << ", fix_cursor = " << params->fix_cursor; - ss << ", game_to_home_delay_safe = " << params->game_to_home_delay_safe; - ss << ", auto_fr_duration = " << params->auto_fr_duration; - ss << ", tolerate_system_update_window_slow = " << params->tolerate_system_update_window_slow; - return ss.str(); - } - ); - register_message_converter( - PABB_MSG_COMMAND_ACCEPT_FRS_WHILE_WAITING, - [](const std::string& body){ - std::stringstream ss; - ss << "accept_FRs_while_waiting() - "; - if (body.size() != sizeof(pabb_accept_FRs_while_waiting)){ ss << "(invalid size)" << std::endl; return ss.str(); } - const auto* params = (const pabb_accept_FRs_while_waiting*)body.c_str(); - ss << "seqnum = " << (uint64_t)params->seqnum; - ss << ", slot = " << (unsigned)params->slot; - ss << ", wait_time = " << params->wait_time; - ss << ", game_to_home_delay_safe = " << params->game_to_home_delay_safe; - ss << ", auto_fr_duration = " << params->auto_fr_duration; - ss << ", tolerate_system_update_window_slow = " << params->tolerate_system_update_window_slow; - return ss.str(); - } - ); return 0; } int init_PokemonSwShAutoHosts = register_message_converters_pokemon_autohosting(); + +} + + diff --git a/Common/PokemonSwSh/PokemonSwShAutoHosts.h b/Common/PokemonSwSh/PokemonSwShAutoHosts.h index 2ef7e7d71d..f6de5f857c 100644 --- a/Common/PokemonSwSh/PokemonSwShAutoHosts.h +++ b/Common/PokemonSwSh/PokemonSwShAutoHosts.h @@ -18,7 +18,7 @@ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // Universal -#ifdef __cplusplus +#if 0 void connect_to_internet( uint16_t open_ycomm_delay, uint16_t connect_to_internet_delay @@ -28,18 +28,6 @@ void home_to_add_friends( uint8_t scroll_down, bool fix_cursor ); -uint16_t accept_FRs( - uint8_t slot, bool fix_cursor, - uint16_t game_to_home_delay_safe, - uint16_t auto_fr_duration, - bool tolerate_system_update_window_slow -); -void accept_FRs_while_waiting( - uint8_t slot, uint16_t wait_time, - uint16_t game_to_home_delay_safe, - uint16_t auto_fr_duration, - bool tolerate_system_update_window_slow -); #endif //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -48,33 +36,27 @@ void accept_FRs_while_waiting( // Client Side #ifdef __cplusplus namespace PokemonAutomation{ - class BotBase; + class BotBaseContext; + + void connect_to_internet( + const BotBaseContext& context, + uint16_t open_ycomm_delay, + uint16_t connect_to_internet_delay + ); + void home_to_add_friends( + const BotBaseContext& context, + uint8_t user_slot, + uint8_t scroll_down, + bool fix_cursor + ); + void accept_FRs( + const BotBaseContext& context, + uint8_t slot, bool fix_cursor, + uint16_t game_to_home_delay_safe, + uint16_t auto_fr_duration, + bool tolerate_system_update_window_slow + ); } -void connect_to_internet( - PokemonAutomation::BotBase& device, - uint16_t open_ycomm_delay, - uint16_t connect_to_internet_delay -); -void home_to_add_friends( - PokemonAutomation::BotBase& device, - uint8_t user_slot, - uint8_t scroll_down, - bool fix_cursor -); -uint16_t accept_FRs( - PokemonAutomation::BotBase& device, - uint8_t slot, bool fix_cursor, - uint16_t game_to_home_delay_safe, - uint16_t auto_fr_duration, - bool tolerate_system_update_window_slow -); -void accept_FRs_while_waiting( - PokemonAutomation::BotBase& device, - uint8_t slot, uint16_t wait_time, - uint16_t game_to_home_delay_safe, - uint16_t auto_fr_duration, - bool tolerate_system_update_window_slow -); #endif //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -89,14 +71,14 @@ void accept_FRs_while_waiting( #endif //////////////////////////////////////////////////////////////////////////////// -#define PABB_MSG_COMMAND_CONNECT_TO_INTERNET 0xba +#define PABB_MSG_COMMAND_CONNECT_TO_INTERNET 0xbb typedef struct{ seqnum_t seqnum; uint16_t open_ycomm_delay; uint16_t connect_to_internet_delay; } PABB_PACK pabb_connect_to_internet; -#define PABB_MSG_COMMAND_HOME_TO_ADD_FRIENDS 0xbb +#define PABB_MSG_COMMAND_HOME_TO_ADD_FRIENDS 0xbc typedef struct{ seqnum_t seqnum; uint8_t user_slot; @@ -104,26 +86,6 @@ typedef struct{ bool fix_cursor; } PABB_PACK pabb_home_to_add_friends; -#define PABB_MSG_COMMAND_ACCEPT_FRS 0xbc -typedef struct{ - seqnum_t seqnum; - uint8_t slot; - bool fix_cursor; - uint16_t game_to_home_delay_safe; - uint16_t auto_fr_duration; - bool tolerate_system_update_window_slow; -} PABB_PACK pabb_accept_FRs; - -#define PABB_MSG_COMMAND_ACCEPT_FRS_WHILE_WAITING 0xbd -typedef struct{ - seqnum_t seqnum; - uint8_t slot; - uint16_t wait_time; - uint16_t game_to_home_delay_safe; - uint16_t auto_fr_duration; - bool tolerate_system_update_window_slow; -} PABB_PACK pabb_accept_FRs_while_waiting; - //////////////////////////////////////////////////////////////////////////////// #if _WIN32 #pragma pack(pop) diff --git a/Common/PokemonSwSh/PokemonSwShDateSpam.cpp b/Common/PokemonSwSh/PokemonSwShDateSpam.cpp index 60785d0cfc..499b85a7dd 100644 --- a/Common/PokemonSwSh/PokemonSwShDateSpam.cpp +++ b/Common/PokemonSwSh/PokemonSwShDateSpam.cpp @@ -10,81 +10,89 @@ #include "ClientSource/Libraries/MessageConverter.h" #include "PokemonSwShDateSpam.h" -using namespace PokemonAutomation; +#if 0 void home_to_date_time(bool to_date_change, bool fast){ - home_to_date_time(*global_connection, to_date_change, fast); + home_to_date_time(*PokemonAutomation::global_connection, to_date_change, fast); } -void home_to_date_time(BotBase& device, bool to_date_change, bool fast){ +void roll_date_forward_1(bool fast){ + roll_date_forward_1(*PokemonAutomation::global_connection, fast); +} +void roll_date_backward_N(uint8_t skips, bool fast){ + roll_date_backward_N(*PokemonAutomation::global_connection, skips, fast); +} +void home_roll_date_enter_game_autorollback(uint8_t* year){ + home_roll_date_enter_game_autorollback(*PokemonAutomation::global_connection, year); +} +void home_roll_date_enter_game(bool rollback_year){ + home_roll_date_enter_game(*PokemonAutomation::global_connection, rollback_year); +} +void touch_date_from_home(uint16_t settings_to_home_delay){ + touch_date_from_home(*PokemonAutomation::global_connection, settings_to_home_delay); +} +void rollback_hours_from_home(uint8_t hours, uint16_t settings_to_home_delay){ + rollback_hours_from_home(*PokemonAutomation::global_connection, hours, settings_to_home_delay); +} +#endif + + + +namespace PokemonAutomation{ + + + +void home_to_date_time(const BotBaseContext& context, bool to_date_change, bool fast){ pabb_home_to_date_time params; params.to_date_change = to_date_change; params.fast = fast; - device.issue_request(params); + context->issue_request(&context.cancelled_bool(), params); } - -void roll_date_forward_1(bool fast){ - roll_date_forward_1(*global_connection, fast); +void neutral_date_skip(const BotBaseContext& context){ + pabb_neutral_date_skip params; + context->issue_request(&context.cancelled_bool(), params); } -void roll_date_forward_1(BotBase& device, bool fast){ +void roll_date_forward_1(const BotBaseContext& context, bool fast){ pabb_roll_date_forward_1 params; params.fast = fast; - device.issue_request(params); -} - -void roll_date_backward_N(uint8_t skips, bool fast){ - roll_date_backward_N(*global_connection, skips, fast); + context->issue_request(&context.cancelled_bool(), params); } -void roll_date_backward_N(BotBase& device, uint8_t skips, bool fast){ +void roll_date_backward_N(const BotBaseContext& context, uint8_t skips, bool fast){ pabb_roll_date_backward_N params; params.skips = skips; params.fast = fast; - device.issue_request(params); + context->issue_request(&context.cancelled_bool(), params); } - -void home_roll_date_enter_game_autorollback(uint8_t* year){ - home_roll_date_enter_game_autorollback(*global_connection, year); -} -void home_roll_date_enter_game_autorollback(BotBase& device, uint8_t* year){ +void home_roll_date_enter_game_autorollback(const BotBaseContext& context, uint8_t* year){ // This version automatically handles the 2060 roll-back. if (*year >= MAX_YEAR){ - home_roll_date_enter_game(device, true); + home_roll_date_enter_game(context, true); *year = 0; }else{ - home_roll_date_enter_game(device, false); + home_roll_date_enter_game(context, false); } (*year)++; } - -void home_roll_date_enter_game(bool rollback_year){ - home_roll_date_enter_game(*global_connection, rollback_year); -} -void home_roll_date_enter_game(BotBase& device, bool rollback_year){ +void home_roll_date_enter_game(const BotBaseContext& context, bool rollback_year){ pabb_home_roll_date_enter_game params; params.rollback_year = rollback_year; - device.issue_request(params); -} - -void touch_date_from_home(uint16_t settings_to_home_delay){ - touch_date_from_home(*global_connection, settings_to_home_delay); + context->issue_request(&context.cancelled_bool(), params); } -void touch_date_from_home(BotBase& device, uint16_t settings_to_home_delay){ +void touch_date_from_home(const BotBaseContext& context, uint16_t settings_to_home_delay){ pabb_touch_date_from_home params; params.settings_to_home_delay = settings_to_home_delay; - device.issue_request(params); -} - -void rollback_hours_from_home(uint8_t hours, uint16_t settings_to_home_delay){ - rollback_hours_from_home(*global_connection, hours, settings_to_home_delay); + context->issue_request(&context.cancelled_bool(), params); } -void rollback_hours_from_home(BotBase& device, uint8_t hours, uint16_t settings_to_home_delay){ +void rollback_hours_from_home(const BotBaseContext& context, uint8_t hours, uint16_t settings_to_home_delay){ pabb_rollback_hours_from_home params; params.hours = hours; params.settings_to_home_delay = settings_to_home_delay; - device.issue_request(params); + context->issue_request(&context.cancelled_bool(), params); } + + int register_message_converters_pokemon_date_spam(){ register_message_converter( PABB_MSG_COMMAND_HOME_TO_DATE_TIME, @@ -99,6 +107,17 @@ int register_message_converters_pokemon_date_spam(){ return ss.str(); } ); + register_message_converter( + PABB_MSG_COMMAND_NEUTRAL_DATE_SKIP, + [](const std::string& body){ + std::stringstream ss; + ss << "neutral_date_skip() - "; + if (body.size() != sizeof(pabb_neutral_date_skip)){ ss << "(invalid size)" << std::endl; return ss.str(); } + const auto* params = (const pabb_neutral_date_skip*)body.c_str(); + ss << "seqnum = " << (uint64_t)params->seqnum; + return ss.str(); + } + ); register_message_converter( PABB_MSG_COMMAND_ROLL_DATE_FORWARD_1, [](const std::string& body){ @@ -165,3 +184,6 @@ int register_message_converters_pokemon_date_spam(){ int init_PokemonSwShDateSpam = register_message_converters_pokemon_date_spam(); + +} + diff --git a/Common/PokemonSwSh/PokemonSwShDateSpam.h b/Common/PokemonSwSh/PokemonSwShDateSpam.h index 70af1baf3f..b1ff891508 100644 --- a/Common/PokemonSwSh/PokemonSwShDateSpam.h +++ b/Common/PokemonSwSh/PokemonSwShDateSpam.h @@ -20,7 +20,7 @@ // Universal #define MAX_YEAR 60 -#ifdef __cplusplus +#if 0 // From the Switch Home (cursor over 1st game), navigate all the way to the // date change button. @@ -28,6 +28,12 @@ // not making all way in. Do this only if the program is able to self-recover. void home_to_date_time(bool to_date_change, bool fast); +// Perform date skip and leave the current date unchanged. You are expected to +// press HOME immediately after this function returns. +// +// This function is slower than the other methods of date-spam. +void neutral_date_skip(void); + // Call this immediately after calling "home_to_date_time()". // This function will roll the 1st and 3rd slots forward by one. void roll_date_forward_1(bool fast); @@ -77,15 +83,17 @@ void rollback_hours_from_home(uint8_t hours, uint16_t settings_to_home_delay); // Client Side #ifdef __cplusplus namespace PokemonAutomation{ - class BotBase; + class BotBaseContext; + + void home_to_date_time (const BotBaseContext& context, bool to_date_change, bool fast); + void neutral_date_skip (const BotBaseContext& context); + void roll_date_forward_1 (const BotBaseContext& context, bool fast); + void roll_date_backward_N (const BotBaseContext& context, uint8_t skips, bool fast); + void home_roll_date_enter_game (const BotBaseContext& context, bool rollback_year); + void home_roll_date_enter_game_autorollback (const BotBaseContext& context, uint8_t* year); + void touch_date_from_home (const BotBaseContext& context, uint16_t settings_to_home_delay); + void rollback_hours_from_home (const BotBaseContext& context, uint8_t hours, uint16_t settings_to_home_delay); } -void home_to_date_time (PokemonAutomation::BotBase& device, bool to_date_change, bool fast); -void roll_date_forward_1 (PokemonAutomation::BotBase& device, bool fast); -void roll_date_backward_N (PokemonAutomation::BotBase& device, uint8_t skips, bool fast); -void home_roll_date_enter_game (PokemonAutomation::BotBase& device, bool rollback_year); -void home_roll_date_enter_game_autorollback (PokemonAutomation::BotBase& device, uint8_t* year); -void touch_date_from_home (PokemonAutomation::BotBase& device, uint16_t settings_to_home_delay); -void rollback_hours_from_home (PokemonAutomation::BotBase& device, uint8_t hours, uint16_t settings_to_home_delay); #endif //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -107,32 +115,37 @@ typedef struct{ bool fast; } PABB_PACK pabb_home_to_date_time; -#define PABB_MSG_COMMAND_ROLL_DATE_FORWARD_1 0xb5 +#define PABB_MSG_COMMAND_NEUTRAL_DATE_SKIP 0xb5 +typedef struct{ + seqnum_t seqnum; +} PABB_PACK pabb_neutral_date_skip; + +#define PABB_MSG_COMMAND_ROLL_DATE_FORWARD_1 0xb6 typedef struct{ seqnum_t seqnum; bool fast; } PABB_PACK pabb_roll_date_forward_1; -#define PABB_MSG_COMMAND_ROLL_DATE_BACKWARD_N 0xb6 +#define PABB_MSG_COMMAND_ROLL_DATE_BACKWARD_N 0xb7 typedef struct{ seqnum_t seqnum; uint8_t skips; bool fast; } PABB_PACK pabb_roll_date_backward_N; -#define PABB_MSG_COMMAND_HOME_ROLL_DATE_ENTER_GAME 0xb7 +#define PABB_MSG_COMMAND_HOME_ROLL_DATE_ENTER_GAME 0xb8 typedef struct{ seqnum_t seqnum; bool rollback_year; } PABB_PACK pabb_home_roll_date_enter_game; -#define PABB_MSG_COMMAND_TOUCH_DATE_FROM_HOME 0xb8 +#define PABB_MSG_COMMAND_TOUCH_DATE_FROM_HOME 0xb9 typedef struct{ seqnum_t seqnum; uint16_t settings_to_home_delay; } PABB_PACK pabb_touch_date_from_home; -#define PABB_MSG_COMMAND_ROLLBACK_HOURS_FROM_HOME 0xb9 +#define PABB_MSG_COMMAND_ROLLBACK_HOURS_FROM_HOME 0xba typedef struct{ seqnum_t seqnum; uint8_t hours; diff --git a/Common/PokemonSwSh/PokemonSwShDaySkippers.cpp b/Common/PokemonSwSh/PokemonSwShDaySkippers.cpp index b377a7e3c7..06ef9a292f 100644 --- a/Common/PokemonSwSh/PokemonSwShDaySkippers.cpp +++ b/Common/PokemonSwSh/PokemonSwShDaySkippers.cpp @@ -10,66 +10,74 @@ #include "ClientSource/Libraries/MessageConverter.h" #include "PokemonSwShDaySkippers.h" -using namespace PokemonAutomation; +#if 0 void skipper_init_view(void){ - skipper_init_view(*global_connection); -} -void skipper_init_view(BotBase& device){ - pabb_skipper_init_view params; - device.issue_request(params); + skipper_init_view(*PokemonAutomation::global_connection); } void skipper_auto_recovery(void){ - skipper_auto_recovery(*global_connection); -} -void skipper_auto_recovery(BotBase& device){ - pabb_skipper_auto_recovery params; - device.issue_request(params); + skipper_auto_recovery(*PokemonAutomation::global_connection); } void skipper_rollback_year_full(bool date_us){ - skipper_rollback_year_full(*global_connection, date_us); + skipper_rollback_year_full(*PokemonAutomation::global_connection, date_us); +} +void skipper_rollback_year_sync(void){ + skipper_rollback_year_sync(*PokemonAutomation::global_connection); +} +void skipper_increment_day(bool date_us){ + skipper_increment_day(*PokemonAutomation::global_connection, date_us); +} +void skipper_increment_month(uint8_t days){ + skipper_increment_month(*PokemonAutomation::global_connection, days); +} +void skipper_increment_all(void){ + skipper_increment_all(*PokemonAutomation::global_connection); +} +void skipper_increment_all_rollback(void){ + skipper_increment_all_rollback(*PokemonAutomation::global_connection); +} +#endif + + + +namespace PokemonAutomation{ + + + +void skipper_init_view(const BotBaseContext& context){ + pabb_skipper_init_view params; + context->issue_request(&context.cancelled_bool(), params); } -void skipper_rollback_year_full(BotBase& device, bool date_us){ +void skipper_auto_recovery(const BotBaseContext& context){ + pabb_skipper_auto_recovery params; + context->issue_request(&context.cancelled_bool(), params); +} +void skipper_rollback_year_full(const BotBaseContext& context, bool date_us){ pabb_skipper_rollback_year_full params; params.date_us = date_us; - device.issue_request(params); -} -void skipper_rollback_year_sync(void){ - skipper_rollback_year_sync(*global_connection); + context->issue_request(&context.cancelled_bool(), params); } -void skipper_rollback_year_sync(BotBase& device){ +void skipper_rollback_year_sync(const BotBaseContext& context){ pabb_skipper_rollback_year_sync params; - device.issue_request(params); -} -void skipper_increment_day(bool date_us){ - skipper_increment_day(*global_connection, date_us); + context->issue_request(&context.cancelled_bool(), params); } -void skipper_increment_day(BotBase& device, bool date_us){ +void skipper_increment_day(const BotBaseContext& context, bool date_us){ pabb_skipper_increment_day params; params.date_us = date_us; - device.issue_request(params); -} -void skipper_increment_month(uint8_t days){ - skipper_increment_month(*global_connection, days); + context->issue_request(&context.cancelled_bool(), params); } -void skipper_increment_month(BotBase& device, uint8_t days){ +void skipper_increment_month(const BotBaseContext& context, uint8_t days){ pabb_skipper_increment_month params; params.days = days; - device.issue_request(params); + context->issue_request(&context.cancelled_bool(), params); } -void skipper_increment_all(void){ - skipper_increment_all(*global_connection); -} -void skipper_increment_all(BotBase& device){ +void skipper_increment_all(const BotBaseContext& context){ pabb_skipper_increment_all params; - device.issue_request(params); + context->issue_request(&context.cancelled_bool(), params); } -void skipper_increment_all_rollback(void){ - skipper_increment_all_rollback(*global_connection); -} -void skipper_increment_all_rollback(BotBase& device){ +void skipper_increment_all_rollback(const BotBaseContext& context){ pabb_skipper_increment_all_rollback params; - device.issue_request(params); + context->issue_request(&context.cancelled_bool(), params); } @@ -169,3 +177,9 @@ int register_message_converters_pokemon_skippers(){ return 0; } int init_PokemonSwShDaySkippers = register_message_converters_pokemon_skippers(); + + + + +} + diff --git a/Common/PokemonSwSh/PokemonSwShDaySkippers.h b/Common/PokemonSwSh/PokemonSwShDaySkippers.h index 899de90585..37e4133767 100644 --- a/Common/PokemonSwSh/PokemonSwShDaySkippers.h +++ b/Common/PokemonSwSh/PokemonSwShDaySkippers.h @@ -20,7 +20,7 @@ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // Universal -#ifdef __cplusplus +#if 0 void skipper_init_view (void); void skipper_auto_recovery (void); void skipper_rollback_year_full (bool date_us); @@ -37,16 +37,17 @@ void skipper_increment_all_rollback (void); // Client Side #ifdef __cplusplus namespace PokemonAutomation{ - class BotBase; + class BotBaseContext; + + void skipper_init_view (const BotBaseContext& context); + void skipper_auto_recovery (const BotBaseContext& context); + void skipper_rollback_year_full (const BotBaseContext& context, bool date_us); + void skipper_rollback_year_sync (const BotBaseContext& context); + void skipper_increment_day (const BotBaseContext& context, bool date_us); + void skipper_increment_month (const BotBaseContext& context, uint8_t days); + void skipper_increment_all (const BotBaseContext& context); + void skipper_increment_all_rollback (const BotBaseContext& context); } -void skipper_init_view (PokemonAutomation::BotBase& device); -void skipper_auto_recovery (PokemonAutomation::BotBase& device); -void skipper_rollback_year_full (PokemonAutomation::BotBase& device, bool date_us); -void skipper_rollback_year_sync (PokemonAutomation::BotBase& device); -void skipper_increment_day (PokemonAutomation::BotBase& device, bool date_us); -void skipper_increment_month (PokemonAutomation::BotBase& device, uint8_t days); -void skipper_increment_all (PokemonAutomation::BotBase& device); -void skipper_increment_all_rollback (PokemonAutomation::BotBase& device); #endif //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -61,45 +62,45 @@ void skipper_increment_all_rollback (PokemonAutomation::BotBase& device); #endif //////////////////////////////////////////////////////////////////////////////// -#define PABB_MSG_COMMAND_SKIPPER_INIT_VIEW 0xbe +#define PABB_MSG_COMMAND_SKIPPER_INIT_VIEW 0xbd typedef struct{ seqnum_t seqnum; } PABB_PACK pabb_skipper_init_view; -#define PABB_MSG_COMMAND_SKIPPER_AUTO_RECOVERY 0xbf +#define PABB_MSG_COMMAND_SKIPPER_AUTO_RECOVERY 0xbe typedef struct{ seqnum_t seqnum; } PABB_PACK pabb_skipper_auto_recovery; -#define PABB_MSG_COMMAND_SKIPPER_ROLLBACK_YEAR_FULL 0xc0 +#define PABB_MSG_COMMAND_SKIPPER_ROLLBACK_YEAR_FULL 0xbf typedef struct{ seqnum_t seqnum; bool date_us; } PABB_PACK pabb_skipper_rollback_year_full; -#define PABB_MSG_COMMAND_SKIPPER_ROLLBACK_YEAR_SYNC 0xc1 +#define PABB_MSG_COMMAND_SKIPPER_ROLLBACK_YEAR_SYNC 0xc0 typedef struct{ seqnum_t seqnum; } PABB_PACK pabb_skipper_rollback_year_sync; -#define PABB_MSG_COMMAND_SKIPPER_INCREMENT_DAY 0xc2 +#define PABB_MSG_COMMAND_SKIPPER_INCREMENT_DAY 0xc1 typedef struct{ seqnum_t seqnum; bool date_us; } PABB_PACK pabb_skipper_increment_day; -#define PABB_MSG_COMMAND_SKIPPER_INCREMENT_MONTH 0xc3 +#define PABB_MSG_COMMAND_SKIPPER_INCREMENT_MONTH 0xc2 typedef struct{ seqnum_t seqnum; uint8_t days; } PABB_PACK pabb_skipper_increment_month; -#define PABB_MSG_COMMAND_SKIPPER_INCREMENT_ALL 0xc4 +#define PABB_MSG_COMMAND_SKIPPER_INCREMENT_ALL 0xc3 typedef struct{ seqnum_t seqnum; } PABB_PACK pabb_skipper_increment_all; -#define PABB_MSG_COMMAND_SKIPPER_INCREMENT_ALL_ROLLBACK 0xc5 +#define PABB_MSG_COMMAND_SKIPPER_INCREMENT_ALL_ROLLBACK 0xc4 typedef struct{ seqnum_t seqnum; } PABB_PACK pabb_skipper_increment_all_rollback; diff --git a/Common/PokemonSwSh/PokemonSwShEggRoutines.cpp b/Common/PokemonSwSh/PokemonSwShEggRoutines.cpp index cef92a8c50..b3a5649294 100644 --- a/Common/PokemonSwSh/PokemonSwShEggRoutines.cpp +++ b/Common/PokemonSwSh/PokemonSwShEggRoutines.cpp @@ -10,44 +10,52 @@ #include "ClientSource/Libraries/MessageConverter.h" #include "PokemonSwShEggRoutines.h" -using namespace PokemonAutomation; +#if 0 void eggfetcher_loop(void){ - eggfetcher_loop(*global_connection); -} -void eggfetcher_loop(BotBase& device){ - pabb_eggfetcher_loop params; - device.issue_request(params); + eggfetcher_loop(*PokemonAutomation::global_connection); } void move_while_mashing_B(uint16_t duration){ - move_while_mashing_B(*global_connection, duration); + move_while_mashing_B(*PokemonAutomation::global_connection, duration); +} +void spin_and_mash_A(uint16_t duration){ + spin_and_mash_A(*PokemonAutomation::global_connection, duration); +} +void travel_to_spin_location(void){ + travel_to_spin_location(*PokemonAutomation::global_connection); +} +void travel_back_to_lady(void){ + travel_back_to_lady(*PokemonAutomation::global_connection); +} +#endif + + + +namespace PokemonAutomation{ + + + +void eggfetcher_loop(const BotBaseContext& context){ + pabb_eggfetcher_loop params; + context->issue_request(&context.cancelled_bool(), params); } -void move_while_mashing_B(BotBase& device, uint16_t duration){ +void move_while_mashing_B(const BotBaseContext& context, uint16_t duration){ pabb_move_while_mashing_B params; params.duration = duration; - device.issue_request(params); + context->issue_request(&context.cancelled_bool(), params); } -void spin_and_mash_A(uint16_t duration){ - spin_and_mash_A(*global_connection, duration); -} -void spin_and_mash_A(BotBase& device, uint16_t duration){ +void spin_and_mash_A(const BotBaseContext& context, uint16_t duration){ pabb_spin_and_mash_A params; params.duration = duration; - device.issue_request(params); -} -void travel_to_spin_location(void){ - travel_to_spin_location(*global_connection); + context->issue_request(&context.cancelled_bool(), params); } -void travel_to_spin_location(BotBase& device){ +void travel_to_spin_location(const BotBaseContext& context){ pabb_travel_to_spin_location params; - device.issue_request(params); + context->issue_request(&context.cancelled_bool(), params); } -void travel_back_to_lady(void){ - travel_back_to_lady(*global_connection); -} -void travel_back_to_lady(BotBase& device){ +void travel_back_to_lady(const BotBaseContext& context){ pabb_travel_back_to_lady params; - device.issue_request(params); + context->issue_request(&context.cancelled_bool(), params); } @@ -113,3 +121,7 @@ int register_message_converters_eggs(){ return 0; } int init_PokemonSwShEggRoutines = register_message_converters_eggs(); + + +} + diff --git a/Common/PokemonSwSh/PokemonSwShEggRoutines.h b/Common/PokemonSwSh/PokemonSwShEggRoutines.h index 97ce397132..43cc95a6f5 100644 --- a/Common/PokemonSwSh/PokemonSwShEggRoutines.h +++ b/Common/PokemonSwSh/PokemonSwShEggRoutines.h @@ -22,7 +22,7 @@ // Universal #define TRAVEL_TO_SPIN_SPOT_DURATION (300) #define TRAVEL_BACK_TO_LADY_DURATION (30 + 260 + (620) + 120 + 120 * 0) -#ifdef __cplusplus +#if 0 void eggfetcher_loop (void); void move_while_mashing_B (uint16_t duration); void spin_and_mash_A (uint16_t duration); @@ -36,13 +36,14 @@ void travel_back_to_lady (void); // Client Side #ifdef __cplusplus namespace PokemonAutomation{ - class BotBase; + class BotBaseContext; + + void eggfetcher_loop (const BotBaseContext& context); + void move_while_mashing_B (const BotBaseContext& context, uint16_t duration); + void spin_and_mash_A (const BotBaseContext& context, uint16_t duration); + void travel_to_spin_location(const BotBaseContext& context); + void travel_back_to_lady (const BotBaseContext& context); } -void eggfetcher_loop (PokemonAutomation::BotBase& device); -void move_while_mashing_B (PokemonAutomation::BotBase& device, uint16_t duration); -void spin_and_mash_A (PokemonAutomation::BotBase& device, uint16_t duration); -void travel_to_spin_location(PokemonAutomation::BotBase& device); -void travel_back_to_lady (PokemonAutomation::BotBase& device); #endif //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -57,29 +58,29 @@ void travel_back_to_lady (PokemonAutomation::BotBase& device); #endif //////////////////////////////////////////////////////////////////////////////// -#define PABB_MSG_COMMAND_EGG_FETCHER_LOOP 0xc6 +#define PABB_MSG_COMMAND_EGG_FETCHER_LOOP 0xc5 typedef struct{ seqnum_t seqnum; } PABB_PACK pabb_eggfetcher_loop; -#define PABB_MSG_COMMAND_MOVE_WHILE_MASHING_B 0xc7 +#define PABB_MSG_COMMAND_MOVE_WHILE_MASHING_B 0xc6 typedef struct{ seqnum_t seqnum; uint16_t duration; } PABB_PACK pabb_move_while_mashing_B; -#define PABB_MSG_COMMAND_SPIN_AND_MASH_A 0xc8 +#define PABB_MSG_COMMAND_SPIN_AND_MASH_A 0xc7 typedef struct{ seqnum_t seqnum; uint16_t duration; } PABB_PACK pabb_spin_and_mash_A; -#define PABB_MSG_COMMAND_TRAVEL_TO_SPIN_LOCATION 0xc9 +#define PABB_MSG_COMMAND_TRAVEL_TO_SPIN_LOCATION 0xc8 typedef struct{ seqnum_t seqnum; } PABB_PACK pabb_travel_to_spin_location; -#define PABB_MSG_COMMAND_TRAVEL_BACK_TO_LADY 0xca +#define PABB_MSG_COMMAND_TRAVEL_BACK_TO_LADY 0xc9 typedef struct{ seqnum_t seqnum; } PABB_PACK pabb_travel_back_to_lady; diff --git a/Common/PokemonSwSh/PokemonSwShGameEntry.cpp b/Common/PokemonSwSh/PokemonSwShGameEntry.cpp index 663e790f5c..9a8c183c8f 100644 --- a/Common/PokemonSwSh/PokemonSwShGameEntry.cpp +++ b/Common/PokemonSwSh/PokemonSwShGameEntry.cpp @@ -12,56 +12,79 @@ #include "ClientSource/Libraries/MessageConverter.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" -using namespace PokemonAutomation; +#if 0 void resume_game_no_interact(bool tolerate_update_menu){ - resume_game_no_interact(*global_connection, tolerate_update_menu); + resume_game_no_interact(*PokemonAutomation::global_connection, tolerate_update_menu); } -void resume_game_no_interact(BotBase& device, bool tolerate_update_menu){ - if (tolerate_update_menu){ - pbf_press_button(device, BUTTON_HOME, 10, HOME_TO_GAME_DELAY); - pbf_press_dpad(device, DPAD_DOWN, 10, 10); - pbf_press_dpad(device, DPAD_UP, 10, 10); - pbf_press_button(device, BUTTON_A, 10, HOME_TO_GAME_DELAY); - }else{ - pbf_press_button(device, BUTTON_HOME, 10, HOME_TO_GAME_DELAY); - } -} - void resume_game_back_out(bool tolerate_update_menu, uint16_t mash_B_time){ - resume_game_back_out(*global_connection, tolerate_update_menu, mash_B_time); -} -void resume_game_back_out(BotBase& device, bool tolerate_update_menu, uint16_t mash_B_time){ - if (tolerate_update_menu){ - pbf_press_button(device, BUTTON_HOME, 10, HOME_TO_GAME_DELAY); - pbf_press_dpad(device, DPAD_DOWN, 10, 10); - pbf_press_dpad(device, DPAD_UP, 10, 10); - pbf_press_button(device, BUTTON_A, 10, HOME_TO_GAME_DELAY); - pbf_mash_button(device, BUTTON_B, mash_B_time); - }else{ - pbf_press_button(device, BUTTON_HOME, 10, HOME_TO_GAME_DELAY); - } + resume_game_back_out(*PokemonAutomation::global_connection, tolerate_update_menu, mash_B_time); } - void resume_game_front_of_den_nowatts(bool tolerate_update_menu){ - resume_game_front_of_den_nowatts(*global_connection, tolerate_update_menu); + resume_game_front_of_den_nowatts(*PokemonAutomation::global_connection, tolerate_update_menu); } -void resume_game_front_of_den_nowatts(BotBase& device, bool tolerate_update_menu){ - resume_game_back_out(device, tolerate_update_menu, 400); -} - void fast_reset_game( uint16_t start_game_mash, uint16_t start_game_wait, uint16_t enter_game_mash, uint16_t enter_game_wait ){ fast_reset_game( - *global_connection, + *PokemonAutomation::global_connection, start_game_mash, start_game_wait, enter_game_mash, enter_game_wait ); } +void reset_game_from_home(bool tolerate_update_menu){ + reset_game_from_home(*PokemonAutomation::global_connection, tolerate_update_menu); +} +void settings_to_enter_game(bool fast){ + settings_to_enter_game(*PokemonAutomation::global_connection, fast); +} +void settings_to_enter_game_den_lobby(bool tolerate_update_menu, bool fast){ + settings_to_enter_game_den_lobby(*PokemonAutomation::global_connection, tolerate_update_menu, fast); +} +void start_game_from_home(bool tolerate_update_menu, uint8_t game_slot, uint8_t user_slot, bool backup_save){ + start_game_from_home(*PokemonAutomation::global_connection, tolerate_update_menu, game_slot, user_slot, backup_save); +} +void enter_game(bool backup_save, uint16_t enter_game_mash, uint16_t enter_game_wait){ + enter_game(*PokemonAutomation::global_connection, backup_save, enter_game_mash, enter_game_wait); +} +void close_game(void){ + close_game(*PokemonAutomation::global_connection); +} +#endif + + + +namespace PokemonAutomation{ + + + +void resume_game_no_interact(const BotBaseContext& context, bool tolerate_update_menu){ + if (tolerate_update_menu){ + pbf_press_button(context, BUTTON_HOME, 10, HOME_TO_GAME_DELAY); + pbf_press_dpad(context, DPAD_DOWN, 10, 10); + pbf_press_dpad(context, DPAD_UP, 10, 10); + pbf_press_button(context, BUTTON_A, 10, HOME_TO_GAME_DELAY); + }else{ + pbf_press_button(context, BUTTON_HOME, 10, HOME_TO_GAME_DELAY); + } +} +void resume_game_back_out(const BotBaseContext& context, bool tolerate_update_menu, uint16_t mash_B_time){ + if (tolerate_update_menu){ + pbf_press_button(context, BUTTON_HOME, 10, HOME_TO_GAME_DELAY); + pbf_press_dpad(context, DPAD_DOWN, 10, 10); + pbf_press_dpad(context, DPAD_UP, 10, 10); + pbf_press_button(context, BUTTON_A, 10, HOME_TO_GAME_DELAY); + pbf_mash_button(context, BUTTON_B, mash_B_time); + }else{ + pbf_press_button(context, BUTTON_HOME, 10, HOME_TO_GAME_DELAY); + } +} +void resume_game_front_of_den_nowatts(const BotBaseContext& context, bool tolerate_update_menu){ + resume_game_back_out(context, tolerate_update_menu, 400); +} void fast_reset_game( - BotBase& device, + const BotBaseContext& context, uint16_t start_game_mash, uint16_t start_game_wait, uint16_t enter_game_mash, uint16_t enter_game_wait ){ @@ -70,90 +93,81 @@ void fast_reset_game( params.start_game_wait = start_game_wait; params.enter_game_mash = enter_game_mash; params.enter_game_wait = enter_game_wait; - device.issue_request(params); + context->issue_request(&context.cancelled_bool(), params); } - -void reset_game_from_home(bool tolerate_update_menu){ - reset_game_from_home(*global_connection, tolerate_update_menu); -} -void reset_game_from_home(BotBase& device, bool tolerate_update_menu){ +void reset_game_from_home(const BotBaseContext& context, bool tolerate_update_menu){ if (!START_GAME_REQUIRES_INTERNET && !tolerate_update_menu){ fast_reset_game( - device, + context, START_GAME_MASH, START_GAME_WAIT, ENTER_GAME_MASH, ENTER_GAME_WAIT ); return; } - close_game(device); - start_game_from_home(device, tolerate_update_menu, 0, 0, false); -} - -void settings_to_enter_game(bool fast){ - settings_to_enter_game(*global_connection, fast); + close_game(context); + start_game_from_home(context, tolerate_update_menu, 0, 0, false); } -void settings_to_enter_game(BotBase& device, bool fast){ +void settings_to_enter_game(const BotBaseContext& context, bool fast){ if (fast){ // 100 ticks for the first press isn't enough to finish the animation. // But since the HOME button has delayed effect, we start pressing the 2nd // press before the animation finishes. - pbf_press_button(device, BUTTON_HOME, 10, 90); - pbf_press_button(device, BUTTON_HOME, 10, 0); + pbf_press_button(context, BUTTON_HOME, 10, 90); + pbf_press_button(context, BUTTON_HOME, 10, 0); }else{ - pbf_press_button(device, BUTTON_HOME, 10, 190); - pbf_press_button(device, BUTTON_HOME, 10, 0); + pbf_press_button(context, BUTTON_HOME, 10, 190); + pbf_press_button(context, BUTTON_HOME, 10, 0); } } - -void settings_to_enter_game_den_lobby(bool tolerate_update_menu, bool fast){ - settings_to_enter_game_den_lobby(*global_connection, tolerate_update_menu, fast); -} -void settings_to_enter_game_den_lobby(BotBase& device, bool tolerate_update_menu, bool fast){ +void settings_to_enter_game_den_lobby( + const BotBaseContext& context, + bool tolerate_update_menu, bool fast, + uint16_t enter_switch_pokemon_delay, + uint16_t exit_switch_pokemon_delay +){ pabb_settings_to_enter_game_den_lobby params; params.tolerate_update_menu = tolerate_update_menu; params.fast = fast; - device.issue_request(params); -} - -void start_game_from_home(bool tolerate_update_menu, uint8_t game_slot, uint8_t user_slot, bool backup_save){ - start_game_from_home(*global_connection, tolerate_update_menu, game_slot, user_slot, backup_save); + params.enter_switch_pokemon_delay = enter_switch_pokemon_delay; + params.exit_switch_pokemon_delay = exit_switch_pokemon_delay; + context->issue_request(&context.cancelled_bool(), params); } -void start_game_from_home(BotBase& device, bool tolerate_update_menu, uint8_t game_slot, uint8_t user_slot, bool backup_save){ +void start_game_from_home(const BotBaseContext& context, bool tolerate_update_menu, uint8_t game_slot, uint8_t user_slot, bool backup_save){ // Start the game with the specified "game_slot" and "user_slot". // If "game_slot" is zero, it uses whatever the cursor is on. // If "user_slot" is zero, it uses whatever the cursor is on. if (game_slot != 0){ - pbf_press_button(device, BUTTON_HOME, 10, SETTINGS_TO_HOME_DELAY - 10); + pbf_press_button(context, BUTTON_HOME, 10, SETTINGS_TO_HOME_DELAY - 10); for (uint8_t c = 1; c < game_slot; c++){ - pbf_press_dpad(device, DPAD_RIGHT, 5, 5); + pbf_press_dpad(context, DPAD_RIGHT, 5, 5); } } if (tolerate_update_menu){ // If the update menu isn't there, these will get swallowed by the opening // animation for the select user menu. - pbf_press_button(device, BUTTON_A, 5, 35); // Choose game - pbf_press_dpad(device, DPAD_UP, 5, 0); // Skip the update window. + pbf_press_button(context, BUTTON_A, 5, 35); // Choose game + pbf_press_dpad(context, DPAD_UP, 5, 0); // Skip the update window. } if (!START_GAME_REQUIRES_INTERNET && user_slot == 0){ // Mash your way into the game. - pbf_mash_button(device, BUTTON_A, START_GAME_MASH); + pbf_mash_button(context, BUTTON_A, START_GAME_MASH); }else{ - pbf_press_button(device, BUTTON_A, 5, 175); // Enter select user menu. + pbf_press_button(context, BUTTON_A, 5, 175); // Enter select user menu. if (user_slot != 0){ // Move to correct user. for (uint8_t c = 0; c < 8; c++){ - pbf_press_dpad(device, DPAD_LEFT, 7, 7); + pbf_press_dpad(context, DPAD_LEFT, 7, 7); } // pbf_wait(50); for (uint8_t c = 1; c < user_slot; c++){ - pbf_press_dpad(device, DPAD_RIGHT, 7, 7); + pbf_press_dpad(context, DPAD_RIGHT, 7, 7); } } - pbf_press_button(device, BUTTON_A, 5, 5); // Enter game + pbf_press_button(context, BUTTON_A, 5, 5); // Enter game // Switch to mashing ZR instead of A to get into the game. // Mash your way into the game. @@ -162,30 +176,22 @@ void start_game_from_home(BotBase& device, bool tolerate_update_menu, uint8_t ga // Need to wait a bit longer for the internet check. duration += START_GAME_INTERNET_CHECK_DELAY; } - pbf_mash_button(device, BUTTON_ZR, duration); + pbf_mash_button(context, BUTTON_ZR, duration); } - pbf_wait(device, START_GAME_WAIT); - enter_game(device, backup_save, ENTER_GAME_MASH, ENTER_GAME_WAIT); -} - -void enter_game(bool backup_save, uint16_t enter_game_mash, uint16_t enter_game_wait){ - enter_game(*global_connection, backup_save, enter_game_mash, enter_game_wait); + pbf_wait(context, START_GAME_WAIT); + enter_game(context, backup_save, ENTER_GAME_MASH, ENTER_GAME_WAIT); } -void enter_game(BotBase& device, bool backup_save, uint16_t enter_game_mash, uint16_t enter_game_wait){ +void enter_game(const BotBaseContext& context, bool backup_save, uint16_t enter_game_mash, uint16_t enter_game_wait){ pabb_enter_game params; params.backup_save = backup_save; params.enter_game_mash = enter_game_mash; params.enter_game_wait = enter_game_wait; - device.issue_request(params); + context->issue_request(&context.cancelled_bool(), params); } - -void close_game(void){ - close_game(*global_connection); -} -void close_game(BotBase& device){ +void close_game(const BotBaseContext& context){ pabb_close_game params; - device.issue_request(params); + context->issue_request(&context.cancelled_bool(), params); } @@ -216,6 +222,8 @@ int register_message_converters_pokemon_game_entry(){ ss << "seqnum = " << (uint64_t)params->seqnum; ss << ", tolerate_update_menu = " << params->tolerate_update_menu; ss << ", fast = " << params->fast; + ss << ", enter_switch_pokemon_delay = " << params->enter_switch_pokemon_delay; + ss << ", exit_switch_pokemon_delay = " << params->exit_switch_pokemon_delay; return ss.str(); } ); @@ -247,3 +255,7 @@ int register_message_converters_pokemon_game_entry(){ return 0; } int init_PokemonSwShGameEntry = register_message_converters_pokemon_game_entry(); + + +} + diff --git a/Common/PokemonSwSh/PokemonSwShGameEntry.h b/Common/PokemonSwSh/PokemonSwShGameEntry.h index f085d4d02c..f24adf2f6e 100644 --- a/Common/PokemonSwSh/PokemonSwShGameEntry.h +++ b/Common/PokemonSwSh/PokemonSwShGameEntry.h @@ -18,7 +18,7 @@ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // Universal -#ifdef __cplusplus +#if 0 // From the Switch home menu, resume the game. // Nothing in front of you should be interactable. @@ -44,7 +44,11 @@ void settings_to_enter_game(bool fast); // From anywhere in the Switch settings except the home menu, return to the game. // Return to the game where you are inside an open den lobby with the cursor over // "Switch Pokemon". -void settings_to_enter_game_den_lobby(bool tolerate_update_menu, bool fast); +void settings_to_enter_game_den_lobby( + bool tolerate_update_menu, bool fast, + uint16_t enter_switch_pokemon_delay, + uint16_t exit_switch_pokemon_delay +); // Enter the game when you're sitting in the game intro. void enter_game(bool backup_save, uint16_t enter_game_mash, uint16_t enter_game_wait); @@ -83,22 +87,28 @@ void reset_game_from_home(bool tolerate_update_menu); // Client Side #ifdef __cplusplus namespace PokemonAutomation{ - class BotBase; + class BotBaseContext; + + void resume_game_no_interact (const BotBaseContext& device, bool tolerate_update_menu); + void resume_game_back_out (const BotBaseContext& device, bool tolerate_update_menu, uint16_t mash_B_time); + void resume_game_front_of_den_nowatts (const BotBaseContext& device, bool tolerate_update_menu); + void settings_to_enter_game (const BotBaseContext& device, bool fast); + void settings_to_enter_game_den_lobby ( + const BotBaseContext& device, + bool tolerate_update_menu, bool fast, + uint16_t enter_switch_pokemon_delay, + uint16_t exit_switch_pokemon_delay + ); + void enter_game (const BotBaseContext& device, bool backup_save, uint16_t enter_game_mash, uint16_t enter_game_wait); + void close_game (const BotBaseContext& device); + void start_game_from_home (const BotBaseContext& device, bool tolerate_update_menu, uint8_t game_slot, uint8_t user_slot, bool backup_save); + void fast_reset_game( + const BotBaseContext& device, + uint16_t start_game_mash, uint16_t start_game_wait, + uint16_t enter_game_mash, uint16_t enter_game_wait + ); + void reset_game_from_home (const BotBaseContext& device, bool tolerate_update_menu); } -void resume_game_no_interact (PokemonAutomation::BotBase& device, bool tolerate_update_menu); -void resume_game_back_out (PokemonAutomation::BotBase& device, bool tolerate_update_menu, uint16_t mash_B_time); -void resume_game_front_of_den_nowatts (PokemonAutomation::BotBase& device, bool tolerate_update_menu); -void settings_to_enter_game (PokemonAutomation::BotBase& device, bool fast); -void settings_to_enter_game_den_lobby (PokemonAutomation::BotBase& device, bool tolerate_update_menu, bool fast); -void enter_game (PokemonAutomation::BotBase& device, bool backup_save, uint16_t enter_game_mash, uint16_t enter_game_wait); -void close_game (PokemonAutomation::BotBase& device); -void start_game_from_home (PokemonAutomation::BotBase& device, bool tolerate_update_menu, uint8_t game_slot, uint8_t user_slot, bool backup_save); -void fast_reset_game( - PokemonAutomation::BotBase& device, - uint16_t start_game_mash, uint16_t start_game_wait, - uint16_t enter_game_mash, uint16_t enter_game_wait -); -void reset_game_from_home (PokemonAutomation::BotBase& device, bool tolerate_update_menu); #endif //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -118,6 +128,8 @@ typedef struct{ seqnum_t seqnum; bool tolerate_update_menu; bool fast; + uint16_t enter_switch_pokemon_delay; + uint16_t exit_switch_pokemon_delay; } PABB_PACK pabb_settings_to_enter_game_den_lobby; #define PABB_MSG_COMMAND_ENTER_GAME 0xb1 diff --git a/Common/PokemonSwSh/PokemonSwShMisc.cpp b/Common/PokemonSwSh/PokemonSwShMisc.cpp index cea4f9cd13..acf1147466 100644 --- a/Common/PokemonSwSh/PokemonSwShMisc.cpp +++ b/Common/PokemonSwSh/PokemonSwShMisc.cpp @@ -12,24 +12,29 @@ #include "ClientSource/Libraries/MessageConverter.h" #include "Common/PokemonSwSh/PokemonSwShMisc.h" -using namespace PokemonAutomation; +#if 0 void mash_A(uint16_t ticks){ - mash_A(*global_connection, ticks); + mash_A(*PokemonAutomation::global_connection, ticks); } -void mash_A(BotBase& device, uint16_t ticks){ - pabb_mashA params; - params.ticks = ticks; - device.issue_request(params); +void IoA_backout(uint16_t pokemon_to_menu_delay){ + IoA_backout(*PokemonAutomation::global_connection, pokemon_to_menu_delay); } +#endif -void IoA_backout(uint16_t pokemon_to_menu_delay){ - IoA_backout(*global_connection, pokemon_to_menu_delay); + +namespace PokemonAutomation{ + + +void mash_A(const BotBaseContext& context, uint16_t ticks){ + pabb_mashA params; + params.ticks = ticks; + context->issue_request(&context.cancelled_bool(), params); } -void IoA_backout(BotBase& device, uint16_t pokemon_to_menu_delay){ +void IoA_backout(const BotBaseContext& context, uint16_t pokemon_to_menu_delay){ pabb_IoA_backout params; params.pokemon_to_menu_delay = pokemon_to_menu_delay; - device.issue_request(params); + context->issue_request(&context.cancelled_bool(), params); } int register_message_converters_pokemon_misc(){ @@ -76,3 +81,10 @@ int register_message_converters_pokemon_misc(){ return 0; } int init_PokemonSwShMisc = register_message_converters_pokemon_misc(); + + + + +} + + diff --git a/Common/PokemonSwSh/PokemonSwShMisc.h b/Common/PokemonSwSh/PokemonSwShMisc.h index bbbb85c191..691ebacd72 100644 --- a/Common/PokemonSwSh/PokemonSwShMisc.h +++ b/Common/PokemonSwSh/PokemonSwShMisc.h @@ -18,7 +18,7 @@ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // Universal -#ifdef __cplusplus +#if 0 void mash_A (uint16_t ticks); void IoA_backout (uint16_t pokemon_to_menu_delay); @@ -31,10 +31,11 @@ void IoA_backout (uint16_t pokemon_to_menu_delay); // Client Side #ifdef __cplusplus namespace PokemonAutomation{ - class BotBase; + class BotBaseContext; + + void mash_A (const BotBaseContext& context, uint16_t ticks); + void IoA_backout (const BotBaseContext& context, uint16_t pokemon_to_menu_delay); } -void mash_A (PokemonAutomation::BotBase& device, uint16_t ticks); -void IoA_backout (PokemonAutomation::BotBase& device, uint16_t pokemon_to_menu_delay); #endif //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// diff --git a/Common/Qt/CodeValidator.cpp b/Common/Qt/CodeValidator.cpp index b6428005c0..3e6ce0b057 100644 --- a/Common/Qt/CodeValidator.cpp +++ b/Common/Qt/CodeValidator.cpp @@ -4,7 +4,7 @@ * */ -#include "StringException.h" +#include "Common/Cpp/Exception.h" #include "CodeValidator.h" namespace PokemonAutomation{ @@ -41,16 +41,16 @@ QString sanitize_code(size_t digits, const QString& code){ continue; } if (ch < '0' || ch > '9'){ - throw StringException("Invalid code digit."); + PA_THROW_ParseException(std::string("Invalid code digit: ") + QString(ch).toUtf8().data()); } c++; if (c > digits){ - throw StringException("Code is too long."); + PA_THROW_ParseException(std::string("Code is too long: ") + code.toUtf8().data()); } ret += ch; } if (c < digits){ - throw StringException("Code is too short."); + PA_THROW_ParseException(std::string("Code is too short: ") + code.toUtf8().data()); } return ret; } diff --git a/Common/Qt/ExpressionEvaluator.cpp b/Common/Qt/ExpressionEvaluator.cpp index 664d588f41..75b121ffef 100644 --- a/Common/Qt/ExpressionEvaluator.cpp +++ b/Common/Qt/ExpressionEvaluator.cpp @@ -7,7 +7,7 @@ #include #include #include -#include "StringException.h" +#include "Common/Cpp/Exception.h" #include "ExpressionEvaluator.h" namespace PokemonAutomation{ @@ -51,6 +51,8 @@ bool skip_whitespace(const char*& str){ } } uint32_t parse_integer(const char*& str){ + const char* ptr = str; + uint64_t x = 0; while (true){ char ch = *str; @@ -61,7 +63,7 @@ uint32_t parse_integer(const char*& str){ x *= 10; x += ch - '0'; if ((uint32_t)x != x){ - throw StringException("Number is too large."); + PA_THROW_ParseException(std::string("Number is too large: ") + ptr); } str++; continue; @@ -73,10 +75,12 @@ uint32_t parse_integer(const char*& str){ case ')': return (uint32_t)x; } - throw StringException("Invalid integer."); + PA_THROW_ParseException(std::string("Invalid integer: ") + ptr); } } std::string parse_symbol(const char*& str){ + const char* ptr = str; + std::string ret; ret += *str++; while (true){ @@ -101,7 +105,7 @@ std::string parse_symbol(const char*& str){ case ')': return ret; } - throw StringException("Invalid symbol."); + PA_THROW_ParseException(std::string("Invalid symbol: ") + ptr); } } @@ -113,7 +117,7 @@ uint8_t precedence(char ch){ case '*': return 1; } - throw StringException("Invalid operator."); + PA_THROW_ParseException(std::string("Invalid operator: ") + ch); } int32_t parse_expression( @@ -139,7 +143,7 @@ int32_t parse_expression( std::string symbol = parse_symbol(str); auto iter = variables.find(symbol); if (iter == variables.end()){ - throw StringException("Undefined symbol."); + PA_THROW_ParseException("Undefined symbol: " + symbol); } num.emplace_back(0, iter->second); continue; @@ -171,7 +175,7 @@ int32_t parse_expression( // if (ch == ')'){ // // } - throw StringException("Invalid expression."); + PA_THROW_ParseException("Invalid expression: " + expression); } while (!op.empty()){ @@ -206,7 +210,7 @@ int32_t parse_expression( switch (item.first){ case '+':{ if (stack.size() < 2){ - throw StringException("Invalid expression: unexpected +"); + PA_THROW_ParseException("Invalid expression: unexpected +"); } int64_t x = stack[stack.size() - 2]; int64_t y = stack[stack.size() - 1]; @@ -214,14 +218,14 @@ int32_t parse_expression( stack.pop_back(); x += y; if ((int32_t)x != x){ - throw StringException("Overflow"); + PA_THROW_ParseException("Overflow"); } stack.push_back(x); continue; } case '-':{ if (stack.size() < 2){ - throw StringException("Invalid expression: unexpected -"); + PA_THROW_ParseException("Invalid expression: unexpected -"); } int64_t x = stack[stack.size() - 2]; int64_t y = stack[stack.size() - 1]; @@ -229,14 +233,14 @@ int32_t parse_expression( stack.pop_back(); x -= y; if ((int32_t)x != x){ - throw StringException("Overflow"); + PA_THROW_ParseException("Overflow"); } stack.push_back(x); continue; } case '*':{ if (stack.size() < 2){ - throw StringException("Invalid expression: unexpected *"); + PA_THROW_ParseException("Invalid expression: unexpected *"); } int64_t x = stack[stack.size() - 2]; int64_t y = stack[stack.size() - 1]; @@ -244,16 +248,16 @@ int32_t parse_expression( stack.pop_back(); x *= y; if ((int32_t)x != x){ - throw StringException("Overflow"); + PA_THROW_ParseException("Overflow"); } stack.push_back(x); continue; } } - throw StringException("Invalid operator."); + PA_THROW_ParseException("Invalid operator."); } if (stack.size() != 1){ - throw StringException("Invalid expression."); + PA_THROW_ParseException("Invalid expression."); } return (int32_t)stack[0]; @@ -270,7 +274,7 @@ const std::map& SYMBOLS(){ uint32_t parse_ticks_i32(const QString& expression){ int32_t x = parse_expression(SYMBOLS(), expression.toUtf8().toStdString()); if (x < 0){ - throw StringException("Value cannot be negative."); + PA_THROW_ParseException("Value cannot be negative."); } return x; } diff --git a/Common/Qt/NoWheelComboBox.h b/Common/Qt/NoWheelComboBox.h new file mode 100644 index 0000000000..e02f43f71a --- /dev/null +++ b/Common/Qt/NoWheelComboBox.h @@ -0,0 +1,24 @@ +/* ComboBox without mouse wheel scrolling. + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_NoWheelComboBox_H +#define PokemonAutomation_NoWheelComboBox_H + +#include + +namespace PokemonAutomation{ + + +class NoWheelComboBox : public QComboBox{ +public: + using QComboBox::QComboBox; + virtual void wheelEvent(QWheelEvent* e) override{} +}; + + + +} +#endif diff --git a/Common/Qt/Options/BooleanCheckBoxOption.cpp b/Common/Qt/Options/BooleanCheckBoxOption.cpp index 6d731bf12b..5eba89fcdb 100644 --- a/Common/Qt/Options/BooleanCheckBoxOption.cpp +++ b/Common/Qt/Options/BooleanCheckBoxOption.cpp @@ -8,6 +8,10 @@ #include #include "BooleanCheckBoxOption.h" +#include +using std::cout; +using std::endl; + namespace PokemonAutomation{ @@ -19,7 +23,10 @@ BooleanCheckBoxOption::BooleanCheckBoxOption( : m_label(std::move(label)) , m_default(default_value) , m_current(backing) -{} +{ +// cout << "Backing: " << m_label.toUtf8().data() << endl; +// cout << "&m_current = " << &m_current << endl; +} BooleanCheckBoxOption::BooleanCheckBoxOption( QString label, bool default_value @@ -67,7 +74,11 @@ BooleanCheckBoxOptionUI::BooleanCheckBoxOptionUI(QWidget& parent, BooleanCheckBo layout->addWidget(m_box, 1); connect( m_box, &QCheckBox::stateChanged, - this, [=](int){ m_value.m_current = m_box->isChecked(); } + this, [=](int){ + m_value.m_current = m_box->isChecked(); +// cout << "m_value.m_current = " << m_value.m_current << endl; +// cout << "&m_value.m_current = " << &m_value.m_current << endl; + } ); } void BooleanCheckBoxOptionUI::restore_defaults(){ diff --git a/Common/Qt/Options/FossilTableOption.cpp b/Common/Qt/Options/FossilTableOption.cpp index c71382bfb8..4db562a4d2 100644 --- a/Common/Qt/Options/FossilTableOption.cpp +++ b/Common/Qt/Options/FossilTableOption.cpp @@ -10,7 +10,6 @@ #include #include #include -#include "Common/Qt/StringException.h" #include "Common/Qt/QtJsonTools.h" #include "FossilTableOption.h" diff --git a/Common/Qt/Options/MultiHostTableOption.cpp b/Common/Qt/Options/MultiHostTableOption.cpp index 05b559fa01..27bfcdd51c 100644 --- a/Common/Qt/Options/MultiHostTableOption.cpp +++ b/Common/Qt/Options/MultiHostTableOption.cpp @@ -11,7 +11,7 @@ #include #include #include -#include "Common/Qt/StringException.h" +#include "Common/Cpp/Exception.h" #include "Common/Qt/QtJsonTools.h" #include "Common/Qt/ExpressionEvaluator.h" #include "MultiHostTableOption.h" @@ -37,7 +37,7 @@ std::vector parse_game_slot(const QJsonValue& js json_get_int(slot.game_slot, line, MultiHostTableOption::JSON_GAME_SLOT, 1, 2); json_get_int(slot.user_slot, line, MultiHostTableOption::JSON_USER_SLOT, 1, 8); - json_get_int(slot.skips, line, MultiHostTableOption::JSON_SKIPS, 1, 7); + json_get_int(slot.skips, line, MultiHostTableOption::JSON_SKIPS, 0, 7); json_get_bool(slot.backup_save, line, MultiHostTableOption::JSON_BACKUP_SAVE); json_get_bool(slot.always_catchable, line, MultiHostTableOption::JSON_ALWAYS_CATCHABLE); @@ -128,7 +128,7 @@ bool MultiHostTableOption::is_valid() const{ int ticks; try{ ticks = parse_ticks_i32(item.post_raid_delay); - }catch (...){ + }catch (const ParseException&){ return false; } if (ticks < 0 || ticks > 65535){ diff --git a/Common/Qt/Options/SimpleIntegerOption.cpp b/Common/Qt/Options/SimpleIntegerOption.cpp index e631a24988..03e31bc3b6 100644 --- a/Common/Qt/Options/SimpleIntegerOption.cpp +++ b/Common/Qt/Options/SimpleIntegerOption.cpp @@ -125,9 +125,11 @@ void SimpleIntegerOptionUI::restore_defaults(){ template class SimpleIntegerOption; template class SimpleIntegerOption; template class SimpleIntegerOption; +template class SimpleIntegerOption; template class SimpleIntegerOptionUI; template class SimpleIntegerOptionUI; template class SimpleIntegerOptionUI; +template class SimpleIntegerOptionUI; } diff --git a/Common/Qt/Options/StringOption.cpp b/Common/Qt/Options/StringOption.cpp new file mode 100644 index 0000000000..ff9bd4992f --- /dev/null +++ b/Common/Qt/Options/StringOption.cpp @@ -0,0 +1,82 @@ +/* String Option + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "StringOption.h" + +#include +#include + +namespace PokemonAutomation{ + + +StringOption::StringOption( + QString& backing, + QString label, + QString default_value +) + : m_label(std::move(label)) + , m_default(default_value) + , m_current(backing) +{} +StringOption::StringOption( + QString label, + QString default_value +) + : m_label(std::move(label)) + , m_default(default_value) + , m_current(m_backing) + , m_backing(default_value) +{} +void StringOption::load_default(const QJsonValue& json){ + if (!json.isString()) { + return; + } + m_default = json.toString(); +} +void StringOption::load_current(const QJsonValue& json){ + if (!json.isString()) { + return; + } + m_current = json.toString(); +} +QJsonValue StringOption::write_default() const{ + return QJsonValue(m_default); +} +QJsonValue StringOption::write_current() const{ + return QJsonValue(m_current); +} + +void StringOption::restore_defaults(){ + m_current = m_default; +} + +StringOptionUI::StringOptionUI(QWidget& parent, StringOption& value) + : QWidget(&parent) + , m_value(value) +{ + QHBoxLayout* layout = new QHBoxLayout(this); + QLabel* text = new QLabel(value.m_label, this); + layout->addWidget(text, 1); + text->setWordWrap(true); + + m_line_edit = new QLineEdit(m_value.m_current); + layout->addWidget(m_line_edit, 1); + + connect( + m_line_edit, &QLineEdit::textChanged, + this, [=](const QString& line){ + m_value.m_current = line; + } + ); +} +void StringOptionUI::restore_defaults(){ + m_value.restore_defaults(); + m_line_edit->setText(m_value.m_current); +} + + +} + diff --git a/Common/Qt/Options/StringOption.h b/Common/Qt/Options/StringOption.h new file mode 100644 index 0000000000..4baf87c085 --- /dev/null +++ b/Common/Qt/Options/StringOption.h @@ -0,0 +1,60 @@ +/* String Option + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_StringOption_H +#define PokemonAutomation_StringOption_H + +#include +#include +#include +#include + +namespace PokemonAutomation{ + + +class StringOption{ +public: + StringOption( + QString& backing, + QString label, + QString default_value + ); + StringOption( + QString label, + QString default_value + ); + + void load_default(const QJsonValue& json); + void load_current(const QJsonValue& json); + QJsonValue write_default() const; + QJsonValue write_current() const; + + operator QString() const{ return m_current; } + QString value() const{ return m_current; } + + void restore_defaults(); + +private: + friend class StringOptionUI; + const QString m_label; + QString m_default; + QString& m_current; + QString m_backing; +}; + + +class StringOptionUI : public QWidget{ +public: + StringOptionUI(QWidget& parent, StringOption& value); + void restore_defaults(); + +private: + StringOption& m_value; + QLineEdit * m_line_edit; +}; + +} +#endif diff --git a/Common/Qt/Options/TimeExpressionOption.cpp b/Common/Qt/Options/TimeExpressionOption.cpp index 61c016226c..7a8f7fa30d 100644 --- a/Common/Qt/Options/TimeExpressionOption.cpp +++ b/Common/Qt/Options/TimeExpressionOption.cpp @@ -6,11 +6,15 @@ #include #include -#include "Common/Clientside/PrettyPrint.h" -#include "Common/Qt/StringException.h" +#include "Common/Cpp/Exception.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/Qt/ExpressionEvaluator.h" #include "TimeExpressionOption.h" +#include +using std::cout; +using std::endl; + namespace PokemonAutomation{ @@ -105,8 +109,8 @@ bool TimeExpressionOption::update(){ uint32_t value; try{ value = parse_ticks_i32(m_current); - }catch (const StringException& str){ - m_error = str.message(); + }catch (const ParseException& str){ + m_error = str.message_qt(); return false; }catch (...){ m_error = "Unknown Error"; diff --git a/Common/Qt/QtJsonTools.cpp b/Common/Qt/QtJsonTools.cpp index e52429a328..4b0e598603 100644 --- a/Common/Qt/QtJsonTools.cpp +++ b/Common/Qt/QtJsonTools.cpp @@ -7,7 +7,7 @@ #include #include #include -#include "StringException.h" +#include "Common/Cpp/Exception.h" #include "QtJsonTools.h" namespace PokemonAutomation{ @@ -16,7 +16,7 @@ namespace PokemonAutomation{ QJsonDocument read_json_file(const QString& path){ QFile file(path); if (!file.open(QFile::ReadOnly)){ - throw StringException("Unable to open file: " + path); + PA_THROW_FileException("Unable to open file.", path); } // auto data = file.readAll(); // return QJsonDocument::fromJson(data); @@ -37,10 +37,10 @@ void write_json_file(const QString& path, const QJsonDocument& json){ QFile file(path); if (!file.open(QFile::WriteOnly)){ - throw StringException("Unable to create settings file.\r\n" + path); + PA_THROW_FileException("Unable to create file.", path); } if (file.write(json_out.c_str(), json_out.size()) != (int)json_out.size()){ - throw StringException("Unable to write settings file.\r\n" + path); + PA_THROW_FileException("Unable to write file.", path); } file.close(); } @@ -50,67 +50,67 @@ void write_json_file(const QString& path, const QJsonDocument& json){ QJsonValue json_get_value_throw(const QJsonObject& obj, const QString& key){ auto iter = obj.find(key); if (iter == obj.end()){ - throw StringException("Config Error - Key not found: " + key); + PA_THROW_ParseException("Config Error - Key not found: " + key); } return *iter; } bool json_get_bool_throw(const QJsonObject& obj, const QString& key){ auto iter = obj.find(key); if (iter == obj.end()){ - throw StringException("Config Error - Key not found: " + key); + PA_THROW_ParseException("Config Error - Key not found: " + key); } if (!iter->isBool()){ - throw StringException("Config Error - Expected a boolean: " + key); + PA_THROW_ParseException("Config Error - Expected a boolean: " + key); } return iter->toBool(); } int json_get_int_throw(const QJsonObject& obj, const QString& key){ auto iter = obj.find(key); if (iter == obj.end()){ - throw StringException("Config Error - Key not found: " + key); + PA_THROW_ParseException("Config Error - Key not found: " + key); } if (!iter->isDouble()){ - throw StringException("Config Error - Expected a number: " + key); + PA_THROW_ParseException("Config Error - Expected a number: " + key); } return iter->toInt(); } double json_get_double_throw(const QJsonObject& obj, const QString& key){ auto iter = obj.find(key); if (iter == obj.end()){ - throw StringException("Config Error - Key not found: " + key); + PA_THROW_ParseException("Config Error - Key not found: " + key); } if (!iter->isDouble()){ - throw StringException("Config Error - Expected a number: " + key); + PA_THROW_ParseException("Config Error - Expected a number: " + key); } return iter->toDouble(); } QString json_get_string_throw(const QJsonObject& obj, const QString& key){ auto iter = obj.find(key); if (iter == obj.end()){ - throw StringException("Config Error - Key not found: " + key); + PA_THROW_ParseException("Config Error - Key not found: " + key); } if (!iter->isString()){ - throw StringException("Config Error - Expected a string: " + key); + PA_THROW_ParseException("Config Error - Expected a string: " + key); } return iter->toString(); } QJsonArray json_get_array_throw(const QJsonObject& obj, const QString& key){ auto iter = obj.find(key); if (iter == obj.end()){ - throw StringException("Config Error - Key not found: " + key); + PA_THROW_ParseException("Config Error - Key not found: " + key); } if (!iter->isArray()){ - throw StringException("Config Error - Expected an array: " + key); + PA_THROW_ParseException("Config Error - Expected an array: " + key); } return iter->toArray(); } QJsonObject json_get_object_throw(const QJsonObject& obj, const QString& key){ auto iter = obj.find(key); if (iter == obj.end()){ - throw StringException("Config Error - Key not found: " + key); + PA_THROW_ParseException("Config Error - Key not found: " + key); } if (!iter->isObject()){ - throw StringException("Config Error - Expected an array: " + key); + PA_THROW_ParseException("Config Error - Expected an array: " + key); } return iter->toObject(); } diff --git a/Common/Qt/StringException.h b/Common/Qt/StringException.h deleted file mode 100644 index b12a823606..0000000000 --- a/Common/Qt/StringException.h +++ /dev/null @@ -1,48 +0,0 @@ -/* Simple (and incomplete) Expression Evaluator - * - * From: https://github.com/PokemonAutomation/Arduino-Source - * - */ - -#ifndef PokemonAutomation_StringException_H -#define PokemonAutomation_StringException_H - -#include -#include - -//#include -//using std::cout; -//using std::endl; - -namespace PokemonAutomation{ - - -class StringException{ -public: - StringException(const char* str) - : m_message(QString::fromUtf8(str)) - { -// cout << str << endl; - } - StringException(const std::string& str) - : m_message(QString::fromUtf8(str.c_str())) - { -// cout << str << endl; - } - StringException(QString str) - : m_message(std::move(str)) - { -// cout << str.toUtf8().data() << endl; - } - - const QString& message() const{ return m_message; } -// QString message() const{ return ""; } - -private: - QString m_message; -}; - - -} - -#endif diff --git a/Common/SwitchFramework/FrameworkSettings.c b/Common/SwitchFramework/FrameworkSettings.c index 695f02576d..e1ad85379d 100644 --- a/Common/SwitchFramework/FrameworkSettings.c +++ b/Common/SwitchFramework/FrameworkSettings.c @@ -13,10 +13,10 @@ // The initial wait period before the program does anything. This gives you // time to switch the Arduino from computer to Switch if connected over a KVM. -uint16_t CONNECT_CONTROLLER_DELAY = 5 * TICKS_PER_SECOND; +uint16_t CONNECT_CONTROLLER_DELAY = 5 * TICKS_PER_SECOND; // Delay from pressing home anywhere in the settings to return to the home menu. -uint16_t SETTINGS_TO_HOME_DELAY = 120; +uint16_t SETTINGS_TO_HOME_DELAY = 120; // Set this to true if starting the game requires checking the internet. // Otherwise, programs that require soft-resetting may not work properly. @@ -26,13 +26,36 @@ uint16_t SETTINGS_TO_HOME_DELAY = 120; // can be played. If this is the case, set this to true. // // Setting this option to true will slow down soft-resetting by about 3 seconds. -bool START_GAME_REQUIRES_INTERNET = false; +bool START_GAME_REQUIRES_INTERNET = false; + +// If starting the game requires checking the internet, wait this long for it. +uint16_t START_GAME_INTERNET_CHECK_DELAY = 3 * TICKS_PER_SECOND; // Some programs can bypass the system update menu at little performance cost. // Setting this to true enables this. -bool TOLERATE_SYSTEM_UPDATE_MENU_FAST = true; +bool TOLERATE_SYSTEM_UPDATE_MENU_FAST = true; // Some programs can bypass the system update menu, but will take a noticeable // performance hit. Setting this to true enables this. -bool TOLERATE_SYSTEM_UPDATE_MENU_SLOW = false; +bool TOLERATE_SYSTEM_UPDATE_MENU_SLOW = false; + + +#ifdef __cplusplus + +// Some programs can send discord messages in your own private server. Set this +// to your discord webhook ID. +std::string DISCORD_WEBHOOK_ID = ""; + +// Some programs can send discord messages in your own private server. Set this +// to your discord webhook token. +std::string DISCORD_WEBHOOK_TOKEN = ""; + +// Some programs can send discord messages in your own private server. Set this +// to your discord user ID. +std::string DISCORD_USER_ID = ""; + +// Some programs can send discord messages in your own private server. Set this +// to your discord user short name. +std::string DISCORD_USER_SHORT_NAME = ""; +#endif diff --git a/Common/SwitchFramework/FrameworkSettings.h b/Common/SwitchFramework/FrameworkSettings.h index b5c739937f..b447c65da3 100644 --- a/Common/SwitchFramework/FrameworkSettings.h +++ b/Common/SwitchFramework/FrameworkSettings.h @@ -10,6 +10,10 @@ #include #include +#ifdef __cplusplus +#include +#endif + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // General Options @@ -31,6 +35,9 @@ extern uint16_t SETTINGS_TO_HOME_DELAY; // Setting this option to true will slow down soft-resetting by about 3 seconds. extern bool START_GAME_REQUIRES_INTERNET; +// If starting the game requires checking the internet, wait this long for it. +extern uint16_t START_GAME_INTERNET_CHECK_DELAY; + // Some programs can bypass the system update menu at little performance cost. // Setting this to true enables this. extern bool TOLERATE_SYSTEM_UPDATE_MENU_FAST; @@ -39,6 +46,26 @@ extern bool TOLERATE_SYSTEM_UPDATE_MENU_FAST; // cost of speed/performance. Setting this to true enables this. extern bool TOLERATE_SYSTEM_UPDATE_MENU_SLOW; +#ifdef __cplusplus + +// Some programs can send discord messages in your own private server. Set this +// to your discord webhook ID. +extern std::string DISCORD_WEBHOOK_ID; + +// Some programs can send discord messages in your own private server. Set this +// to your discord webhook token. +extern std::string DISCORD_WEBHOOK_TOKEN; + +// Some programs can send discord messages in your own private server. Set this +// to your discord user ID. +extern std::string DISCORD_USER_ID; + +// Some programs can send discord messages in your own private server. Set this +// to your discord user short name. +extern std::string DISCORD_USER_SHORT_NAME; + +#endif + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// #endif diff --git a/Common/SwitchFramework/Switch_PushButtons.cpp b/Common/SwitchFramework/Switch_PushButtons.cpp index 446edb1616..666ad36762 100644 --- a/Common/SwitchFramework/Switch_PushButtons.cpp +++ b/Common/SwitchFramework/Switch_PushButtons.cpp @@ -8,7 +8,6 @@ #include "Common/MessageProtocol.h" #include "Common/SwitchFramework/FrameworkSettings.h" #include "Common/SwitchFramework/Switch_PushButtons.h" -#include "ClientSource/Libraries/Compiler.h" #include "ClientSource/Connection/BotBase.h" //#include @@ -16,129 +15,128 @@ //using std::endl; -namespace PokemonAutomation{ - BotBase* global_connection = nullptr; +#if 0 +void end_program_callback(){ + end_program_callback(*PokemonAutomation::global_connection); } -using namespace PokemonAutomation; - void initialize_framework(uint8_t program_id){} - -void end_program_callback(){ - end_program_callback(*global_connection); +void set_leds(bool on){ + set_leds(*PokemonAutomation::global_connection, on); } -void end_program_callback(BotBase& device){ - pabb_end_program_callback params; - device.issue_request(params); +uint32_t system_clock(void){ + return system_clock(*PokemonAutomation::global_connection); +} +void pbf_wait(uint16_t ticks){ + pbf_wait(*PokemonAutomation::global_connection, ticks); +} +void pbf_press_button(Button button, uint16_t hold_ticks, uint16_t release_ticks){ + pbf_press_button(*PokemonAutomation::global_connection, button, hold_ticks, release_ticks); +} +void pbf_press_dpad(DpadPosition position, uint16_t hold_ticks, uint16_t release_ticks){ + pbf_press_dpad(*PokemonAutomation::global_connection, position, hold_ticks, release_ticks); +} +void pbf_move_left_joystick(uint8_t x, uint8_t y, uint16_t hold_ticks, uint16_t release_ticks){ + pbf_move_left_joystick(*PokemonAutomation::global_connection, x, y, hold_ticks, release_ticks); +} +void pbf_move_right_joystick(uint8_t x, uint8_t y, uint16_t hold_ticks, uint16_t release_ticks){ + pbf_move_right_joystick(*PokemonAutomation::global_connection, x, y, hold_ticks, release_ticks); +} +void pbf_mash_button(Button button, uint16_t ticks){ + pbf_mash_button(*PokemonAutomation::global_connection, button, ticks); +} +void start_program_flash(uint16_t ticks){ + start_program_flash(*PokemonAutomation::global_connection, ticks); +} +void grip_menu_connect_go_home(void){ + grip_menu_connect_go_home(*PokemonAutomation::global_connection); +} +void end_program_loop(void){ + end_program_loop(*PokemonAutomation::global_connection); } +#endif -void set_leds(bool on){ - set_leds(*global_connection, on); + + + + + +namespace PokemonAutomation{ + BotBaseContext* global_connection = nullptr; + + + +void end_program_callback(const BotBaseContext& context){ + pabb_end_program_callback params; + context->issue_request(&context.cancelled_bool(), params); } -void set_leds(BotBase& device, bool on){ + +void set_leds(const BotBaseContext& context, bool on){ pabb_MsgCommandSetLeds params; params.on = on; - device.issue_request(params); + context->issue_request(&context.cancelled_bool(), params); } -uint32_t system_clock(void){ - return system_clock(*global_connection); -} -uint32_t system_clock(BotBase& device){ +uint32_t system_clock(const BotBaseContext& context){ pabb_system_clock params; pabb_MsgAckRequestI32 response; - device.issue_request_and_wait(params, response); + context->issue_request_and_wait(&context.cancelled_bool(), params, response); return response.data; } - -void pbf_wait(uint16_t ticks){ - pbf_wait(*global_connection, ticks); -} -void pbf_wait(BotBase& device, uint16_t ticks){ +void pbf_wait(const BotBaseContext& context, uint16_t ticks){ pabb_pbf_wait params; params.ticks = ticks; - device.issue_request(params); + context->issue_request(&context.cancelled_bool(), params); } - -void pbf_press_button(Button button, uint16_t hold_ticks, uint16_t release_ticks){ - pbf_press_button(*global_connection, button, hold_ticks, release_ticks); -} -void pbf_press_button(BotBase& device, Button button, uint16_t hold_ticks, uint16_t release_ticks){ +void pbf_press_button(const BotBaseContext& context, Button button, uint16_t hold_ticks, uint16_t release_ticks){ pabb_pbf_press_button params; params.button = button; params.hold_ticks = hold_ticks; params.release_ticks = release_ticks; - device.issue_request(params); + context->issue_request(&context.cancelled_bool(), params); } - -void pbf_press_dpad(DpadPosition position, uint16_t hold_ticks, uint16_t release_ticks){ - pbf_press_dpad(*global_connection, position, hold_ticks, release_ticks); -} -void pbf_press_dpad(BotBase& device, DpadPosition position, uint16_t hold_ticks, uint16_t release_ticks){ +void pbf_press_dpad(const BotBaseContext& context, DpadPosition position, uint16_t hold_ticks, uint16_t release_ticks){ pabb_pbf_press_dpad params; params.dpad = position; params.hold_ticks = hold_ticks; params.release_ticks = release_ticks; - device.issue_request(params); -} - -void pbf_move_left_joystick(uint8_t x, uint8_t y, uint16_t hold_ticks, uint16_t release_ticks){ - pbf_move_left_joystick(*global_connection, x, y, hold_ticks, release_ticks); + context->issue_request(&context.cancelled_bool(), params); } -void pbf_move_left_joystick(BotBase& device, uint8_t x, uint8_t y, uint16_t hold_ticks, uint16_t release_ticks){ +void pbf_move_left_joystick(const BotBaseContext& context, uint8_t x, uint8_t y, uint16_t hold_ticks, uint16_t release_ticks){ pabb_pbf_move_joystick params; params.x = x; params.y = y; params.hold_ticks = hold_ticks; params.release_ticks = release_ticks; - device.issue_request(params); + context->issue_request(&context.cancelled_bool(), params); } -void pbf_move_right_joystick(uint8_t x, uint8_t y, uint16_t hold_ticks, uint16_t release_ticks){ - pbf_move_right_joystick(*global_connection, x, y, hold_ticks, release_ticks); -} -void pbf_move_right_joystick(BotBase& device, uint8_t x, uint8_t y, uint16_t hold_ticks, uint16_t release_ticks){ +void pbf_move_right_joystick(const BotBaseContext& context, uint8_t x, uint8_t y, uint16_t hold_ticks, uint16_t release_ticks){ pabb_pbf_move_joystick params; params.x = x; params.y = y; params.hold_ticks = hold_ticks; params.release_ticks = release_ticks; - device.issue_request(params); -} - -void pbf_mash_button(Button button, uint16_t ticks){ - pbf_mash_button(*global_connection, button, ticks); + context->issue_request(&context.cancelled_bool(), params); } -void pbf_mash_button(BotBase& device, Button button, uint16_t ticks){ +void pbf_mash_button(const BotBaseContext& context, Button button, uint16_t ticks){ pabb_pbf_mash_button params; params.button = button; params.ticks = ticks; - device.issue_request(params); + context->issue_request(&context.cancelled_bool(), params); } - -void start_program_flash(uint16_t ticks){ - start_program_flash(*global_connection, ticks); -} -void start_program_flash(BotBase& device, uint16_t ticks){ +void start_program_flash(const BotBaseContext& context, uint16_t ticks){ for (uint16_t c = 0; c < ticks; c += 50){ - set_leds(device, true); - pbf_wait(device, 25); - set_leds(device, false); - pbf_wait(device, 25); + set_leds(context, true); + pbf_wait(context, 25); + set_leds(context, false); + pbf_wait(context, 25); } } - -void grip_menu_connect_go_home(void){ - grip_menu_connect_go_home(*global_connection); -} -void grip_menu_connect_go_home(BotBase& device){ - pbf_press_button(device, BUTTON_L | BUTTON_R, 10, 40); - pbf_press_button(device, BUTTON_A, 10, 140); - pbf_press_button(device, BUTTON_HOME, 10, SETTINGS_TO_HOME_DELAY); -} - -void end_program_loop(void){ - end_program_loop(*global_connection); +void grip_menu_connect_go_home(const BotBaseContext& context){ + pbf_press_button(context, BUTTON_L | BUTTON_R, 10, 40); + pbf_press_button(context, BUTTON_A, 10, 140); + pbf_press_button(context, BUTTON_HOME, 10, SETTINGS_TO_HOME_DELAY); } -void end_program_loop(BotBase& device){ +void end_program_loop(const BotBaseContext& context){ #if 0 pbf_wait(device, 15 * TICKS_PER_SECOND); while (true){ @@ -149,3 +147,7 @@ void end_program_loop(BotBase& device){ + +} + + diff --git a/Common/SwitchFramework/Switch_PushButtons.h b/Common/SwitchFramework/Switch_PushButtons.h index 3fb148e661..e9ae7453de 100644 --- a/Common/SwitchFramework/Switch_PushButtons.h +++ b/Common/SwitchFramework/Switch_PushButtons.h @@ -20,9 +20,7 @@ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // Shared API -#ifdef __cplusplus -extern "C" { -#endif +#ifndef __cplusplus //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // System Functions @@ -37,6 +35,8 @@ void set_leds(bool on); // the program. uint32_t system_clock(void); +void end_program_callback(void); + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // Basic Framework Operations @@ -81,8 +81,6 @@ void end_program_loop(void); //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -#ifdef __cplusplus -} #endif //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -91,28 +89,26 @@ void end_program_loop(void); // Client Side Extensions #ifdef __cplusplus namespace PokemonAutomation{ - class BotBase; - - // Global instance - extern BotBase* global_connection; -} + class BotBaseContext; -void end_program_callback (); +// // Global instance +// extern BotBaseContext* global_connection; -void set_leds (PokemonAutomation::BotBase& device, bool on); -void end_program_callback (PokemonAutomation::BotBase& device); + void set_leds (const BotBaseContext& context, bool on); + void end_program_callback (const BotBaseContext& context); -uint32_t system_clock (PokemonAutomation::BotBase& device); -void pbf_wait (PokemonAutomation::BotBase& device, uint16_t ticks); -void pbf_press_button (PokemonAutomation::BotBase& device, Button button, uint16_t hold_ticks, uint16_t release_ticks); -void pbf_press_dpad (PokemonAutomation::BotBase& device, DpadPosition position, uint16_t hold_ticks, uint16_t release_ticks); -void pbf_move_left_joystick (PokemonAutomation::BotBase& device, uint8_t x, uint8_t y, uint16_t hold_ticks, uint16_t release_ticks); -void pbf_move_right_joystick (PokemonAutomation::BotBase& device, uint8_t x, uint8_t y, uint16_t hold_ticks, uint16_t release_ticks); -void pbf_mash_button (PokemonAutomation::BotBase& device, Button button, uint16_t ticks); + uint32_t system_clock (const BotBaseContext& context); + void pbf_wait (const BotBaseContext& context, uint16_t ticks); + void pbf_press_button (const BotBaseContext& context, Button button, uint16_t hold_ticks, uint16_t release_ticks); + void pbf_press_dpad (const BotBaseContext& context, DpadPosition position, uint16_t hold_ticks, uint16_t release_ticks); + void pbf_move_left_joystick (const BotBaseContext& context, uint8_t x, uint8_t y, uint16_t hold_ticks, uint16_t release_ticks); + void pbf_move_right_joystick (const BotBaseContext& context, uint8_t x, uint8_t y, uint16_t hold_ticks, uint16_t release_ticks); + void pbf_mash_button (const BotBaseContext& context, Button button, uint16_t ticks); -void start_program_flash (PokemonAutomation::BotBase& device, uint16_t ticks); -void grip_menu_connect_go_home (PokemonAutomation::BotBase& device); -void end_program_loop (PokemonAutomation::BotBase& device); + void start_program_flash (const BotBaseContext& context, uint16_t ticks); + void grip_menu_connect_go_home (const BotBaseContext& context); + void end_program_loop (const BotBaseContext& context); +} #endif //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// diff --git a/Common/SwitchRoutines/SwitchDigitEntry.cpp b/Common/SwitchRoutines/SwitchDigitEntry.cpp index fd29a924cf..a53f97623f 100644 --- a/Common/SwitchRoutines/SwitchDigitEntry.cpp +++ b/Common/SwitchRoutines/SwitchDigitEntry.cpp @@ -14,16 +14,23 @@ #include "ClientSource/Connection/BotBase.h" #include "ClientSource/Libraries/MessageConverter.h" -using namespace PokemonAutomation; +#if 0 void enter_digits_str(uint8_t count, const char* digits){ enter_digits(count, (const uint8_t*)digits); } -void enter_digits_str(BotBase& device, uint8_t count, const char* digits){ - enter_digits(device, count, (const uint8_t*)digits); -} void enter_digits(uint8_t count, const uint8_t* digits){ - enter_digits(*global_connection, count, digits); + enter_digits(*PokemonAutomation::global_connection, count, digits); +} +#endif + + +namespace PokemonAutomation{ + + + +void enter_digits_str(const BotBaseContext& context, uint8_t count, const char* digits){ + enter_digits(context, count, (const uint8_t*)digits); } uint8_t convert_digit(uint8_t digit){ if (digit >= '0'){ @@ -34,14 +41,14 @@ uint8_t convert_digit(uint8_t digit){ } return digit; } -void enter_digits(BotBase& device, uint8_t count, const uint8_t* digits){ +void enter_digits(const BotBaseContext& context, uint8_t count, const uint8_t* digits){ pabb_enter_digits params; params.count = count; memset(params.digit_pairs, 0, sizeof(params.digit_pairs)); for (uint8_t c = 0; c < count; c++){ params.digit_pairs[c/2] |= convert_digit(digits[c]) << 4 * (c & 1); } - device.issue_request(params); + context->issue_request(&context.cancelled_bool(), params); } @@ -66,3 +73,6 @@ int register_message_converters_switch_digit_entry(){ return 0; } int init_SwitchDigitEntry = register_message_converters_switch_digit_entry(); + + +} diff --git a/Common/SwitchRoutines/SwitchDigitEntry.h b/Common/SwitchRoutines/SwitchDigitEntry.h index c154bfacd8..a7249883ce 100644 --- a/Common/SwitchRoutines/SwitchDigitEntry.h +++ b/Common/SwitchRoutines/SwitchDigitEntry.h @@ -32,10 +32,11 @@ void enter_digits (uint8_t count, const uint8_t* digits); // Client Side #ifdef __cplusplus namespace PokemonAutomation{ - class BotBase; + class BotBaseContext; + + void enter_digits_str (const BotBaseContext& context, uint8_t count, const char* digits); + void enter_digits (const BotBaseContext& context, uint8_t count, const uint8_t* digits); } -void enter_digits_str (PokemonAutomation::BotBase& device, uint8_t count, const char* digits); -void enter_digits (PokemonAutomation::BotBase& device, uint8_t count, const uint8_t* digits); #endif //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// diff --git a/GeneratorConfig/BuildWindows.cmd b/GeneratorConfig/BuildWindows.cmd index 8757caf5c9..b1b41da83e 100644 --- a/GeneratorConfig/BuildWindows.cmd +++ b/GeneratorConfig/BuildWindows.cmd @@ -1,10 +1,11 @@ ::@echo off set board=%1 -set program=%2 +set category=%2 +set program=%3 cd /D "%~dp0" -cd "../NativePrograms" +cd "../NativePrograms/%category%" if [%board%] == [ArduinoUnoR3] ( @@ -65,6 +66,6 @@ del "%program%.lss" del "%program%.sym" del "%program%.tmp" -move "%program%.hex" "../%program%-%board%.hex" +move "%program%.hex" "../../%program%-%board%.hex" ::pause \ No newline at end of file diff --git a/GeneratorConfig/Categories.json b/GeneratorConfig/Categories.json new file mode 100644 index 0000000000..b694b111d5 --- /dev/null +++ b/GeneratorConfig/Categories.json @@ -0,0 +1,14 @@ +[ + { + "Name": "NintendoSwitch", + "Display": "General", + "Settings": [ "FrameworkSettings" ] + }, + { + "Name": "PokemonSwSh", + "Display": "Sword/Shield", + "Settings": [ "PokemonSettings" ] + } +] + + diff --git a/GeneratorConfig/FrameworkSettings.json b/GeneratorConfig/NintendoSwitch/FrameworkSettings.json similarity index 100% rename from GeneratorConfig/FrameworkSettings.json rename to GeneratorConfig/NintendoSwitch/FrameworkSettings.json diff --git a/GeneratorConfig/FriendDelete.json b/GeneratorConfig/NintendoSwitch/FriendDelete.json similarity index 100% rename from GeneratorConfig/FriendDelete.json rename to GeneratorConfig/NintendoSwitch/FriendDelete.json diff --git a/GeneratorConfig/PABotBase.json b/GeneratorConfig/NintendoSwitch/PABotBase.json similarity index 100% rename from GeneratorConfig/PABotBase.json rename to GeneratorConfig/NintendoSwitch/PABotBase.json diff --git a/GeneratorConfig/AutoHost-MultiGame.json b/GeneratorConfig/PokemonSwSh/AutoHost-MultiGame.json similarity index 100% rename from GeneratorConfig/AutoHost-MultiGame.json rename to GeneratorConfig/PokemonSwSh/AutoHost-MultiGame.json diff --git a/GeneratorConfig/AutoHost-Rolling.json b/GeneratorConfig/PokemonSwSh/AutoHost-Rolling.json similarity index 100% rename from GeneratorConfig/AutoHost-Rolling.json rename to GeneratorConfig/PokemonSwSh/AutoHost-Rolling.json diff --git a/GeneratorConfig/BallThrower.json b/GeneratorConfig/PokemonSwSh/BallThrower.json similarity index 100% rename from GeneratorConfig/BallThrower.json rename to GeneratorConfig/PokemonSwSh/BallThrower.json diff --git a/GeneratorConfig/BeamReset.json b/GeneratorConfig/PokemonSwSh/BeamReset.json similarity index 100% rename from GeneratorConfig/BeamReset.json rename to GeneratorConfig/PokemonSwSh/BeamReset.json diff --git a/GeneratorConfig/ClothingBuyer.json b/GeneratorConfig/PokemonSwSh/ClothingBuyer.json similarity index 100% rename from GeneratorConfig/ClothingBuyer.json rename to GeneratorConfig/PokemonSwSh/ClothingBuyer.json diff --git a/GeneratorConfig/CustomProgram.json b/GeneratorConfig/PokemonSwSh/CustomProgram.json similarity index 100% rename from GeneratorConfig/CustomProgram.json rename to GeneratorConfig/PokemonSwSh/CustomProgram.json diff --git a/GeneratorConfig/DateSpam-BerryFarmer.json b/GeneratorConfig/PokemonSwSh/DateSpam-BerryFarmer.json similarity index 100% rename from GeneratorConfig/DateSpam-BerryFarmer.json rename to GeneratorConfig/PokemonSwSh/DateSpam-BerryFarmer.json diff --git a/GeneratorConfig/DateSpam-DailyHighlightFarmer.json b/GeneratorConfig/PokemonSwSh/DateSpam-DailyHighlightFarmer.json similarity index 100% rename from GeneratorConfig/DateSpam-DailyHighlightFarmer.json rename to GeneratorConfig/PokemonSwSh/DateSpam-DailyHighlightFarmer.json diff --git a/GeneratorConfig/DateSpam-LotoFarmer.json b/GeneratorConfig/PokemonSwSh/DateSpam-LotoFarmer.json similarity index 85% rename from GeneratorConfig/DateSpam-LotoFarmer.json rename to GeneratorConfig/PokemonSwSh/DateSpam-LotoFarmer.json index 6667681f3f..7b69bc35a2 100644 --- a/GeneratorConfig/DateSpam-LotoFarmer.json +++ b/GeneratorConfig/PokemonSwSh/DateSpam-LotoFarmer.json @@ -17,8 +17,8 @@ "02-Declaration": "const uint16_t MASH_B_DURATION", "03-MinValue": 0, "04-MaxValue": 65535, - "98-Default": "8 * TICKS_PER_SECOND", - "99-Current": "8 * TICKS_PER_SECOND" + "98-Default": "9 * TICKS_PER_SECOND", + "99-Current": "9 * TICKS_PER_SECOND" } ] } diff --git a/GeneratorConfig/DateSpam-StowOnSideFarmer.json b/GeneratorConfig/PokemonSwSh/DateSpam-StowOnSideFarmer.json similarity index 100% rename from GeneratorConfig/DateSpam-StowOnSideFarmer.json rename to GeneratorConfig/PokemonSwSh/DateSpam-StowOnSideFarmer.json diff --git a/GeneratorConfig/DateSpam-WattFarmer.json b/GeneratorConfig/PokemonSwSh/DateSpam-WattFarmer.json similarity index 100% rename from GeneratorConfig/DateSpam-WattFarmer.json rename to GeneratorConfig/PokemonSwSh/DateSpam-WattFarmer.json diff --git a/GeneratorConfig/DaySkipperEU.json b/GeneratorConfig/PokemonSwSh/DaySkipperEU.json similarity index 100% rename from GeneratorConfig/DaySkipperEU.json rename to GeneratorConfig/PokemonSwSh/DaySkipperEU.json diff --git a/GeneratorConfig/DaySkipperJPN-7.8k.json b/GeneratorConfig/PokemonSwSh/DaySkipperJPN-7.8k.json similarity index 100% rename from GeneratorConfig/DaySkipperJPN-7.8k.json rename to GeneratorConfig/PokemonSwSh/DaySkipperJPN-7.8k.json diff --git a/GeneratorConfig/DaySkipperJPN.json b/GeneratorConfig/PokemonSwSh/DaySkipperJPN.json similarity index 100% rename from GeneratorConfig/DaySkipperJPN.json rename to GeneratorConfig/PokemonSwSh/DaySkipperJPN.json diff --git a/GeneratorConfig/DaySkipperUS.json b/GeneratorConfig/PokemonSwSh/DaySkipperUS.json similarity index 100% rename from GeneratorConfig/DaySkipperUS.json rename to GeneratorConfig/PokemonSwSh/DaySkipperUS.json diff --git a/GeneratorConfig/DenRoller.json b/GeneratorConfig/PokemonSwSh/DenRoller.json similarity index 100% rename from GeneratorConfig/DenRoller.json rename to GeneratorConfig/PokemonSwSh/DenRoller.json diff --git a/GeneratorConfig/EggCombined2.json b/GeneratorConfig/PokemonSwSh/EggCombined2.json similarity index 100% rename from GeneratorConfig/EggCombined2.json rename to GeneratorConfig/PokemonSwSh/EggCombined2.json diff --git a/GeneratorConfig/EggFetcher2.json b/GeneratorConfig/PokemonSwSh/EggFetcher2.json similarity index 100% rename from GeneratorConfig/EggFetcher2.json rename to GeneratorConfig/PokemonSwSh/EggFetcher2.json diff --git a/GeneratorConfig/EggHatcher.json b/GeneratorConfig/PokemonSwSh/EggHatcher.json similarity index 100% rename from GeneratorConfig/EggHatcher.json rename to GeneratorConfig/PokemonSwSh/EggHatcher.json diff --git a/GeneratorConfig/EggSuperCombined2.json b/GeneratorConfig/PokemonSwSh/EggSuperCombined2.json similarity index 100% rename from GeneratorConfig/EggSuperCombined2.json rename to GeneratorConfig/PokemonSwSh/EggSuperCombined2.json diff --git a/GeneratorConfig/EventBeamFinder.json b/GeneratorConfig/PokemonSwSh/EventBeamFinder.json similarity index 100% rename from GeneratorConfig/EventBeamFinder.json rename to GeneratorConfig/PokemonSwSh/EventBeamFinder.json diff --git a/GeneratorConfig/FastCodeEntry.json b/GeneratorConfig/PokemonSwSh/FastCodeEntry.json similarity index 100% rename from GeneratorConfig/FastCodeEntry.json rename to GeneratorConfig/PokemonSwSh/FastCodeEntry.json diff --git a/GeneratorConfig/GodEggDuplication.json b/GeneratorConfig/PokemonSwSh/GodEggDuplication.json similarity index 100% rename from GeneratorConfig/GodEggDuplication.json rename to GeneratorConfig/PokemonSwSh/GodEggDuplication.json diff --git a/GeneratorConfig/GodEggItemDupe.json b/GeneratorConfig/PokemonSwSh/GodEggItemDupe.json similarity index 100% rename from GeneratorConfig/GodEggItemDupe.json rename to GeneratorConfig/PokemonSwSh/GodEggItemDupe.json diff --git a/GeneratorConfig/MassRelease.json b/GeneratorConfig/PokemonSwSh/MassRelease.json similarity index 100% rename from GeneratorConfig/MassRelease.json rename to GeneratorConfig/PokemonSwSh/MassRelease.json diff --git a/GeneratorConfig/MultiGameFossil.json b/GeneratorConfig/PokemonSwSh/MultiGameFossil.json similarity index 100% rename from GeneratorConfig/MultiGameFossil.json rename to GeneratorConfig/PokemonSwSh/MultiGameFossil.json diff --git a/GeneratorConfig/PokemonSettings.json b/GeneratorConfig/PokemonSwSh/PokemonSettings.json similarity index 100% rename from GeneratorConfig/PokemonSettings.json rename to GeneratorConfig/PokemonSwSh/PokemonSettings.json diff --git a/GeneratorConfig/ShinyHunt-Regi.json b/GeneratorConfig/PokemonSwSh/ShinyHunt-Regi.json similarity index 100% rename from GeneratorConfig/ShinyHunt-Regi.json rename to GeneratorConfig/PokemonSwSh/ShinyHunt-Regi.json diff --git a/GeneratorConfig/ShinyHunt-SwordsOfJustice.json b/GeneratorConfig/PokemonSwSh/ShinyHunt-SwordsOfJustice.json similarity index 100% rename from GeneratorConfig/ShinyHunt-SwordsOfJustice.json rename to GeneratorConfig/PokemonSwSh/ShinyHunt-SwordsOfJustice.json diff --git a/GeneratorConfig/ShinyHuntUnattended-IoATrade.json b/GeneratorConfig/PokemonSwSh/ShinyHuntUnattended-IoATrade.json similarity index 100% rename from GeneratorConfig/ShinyHuntUnattended-IoATrade.json rename to GeneratorConfig/PokemonSwSh/ShinyHuntUnattended-IoATrade.json diff --git a/GeneratorConfig/ShinyHuntUnattended-Regi.json b/GeneratorConfig/PokemonSwSh/ShinyHuntUnattended-Regi.json similarity index 100% rename from GeneratorConfig/ShinyHuntUnattended-Regi.json rename to GeneratorConfig/PokemonSwSh/ShinyHuntUnattended-Regi.json diff --git a/GeneratorConfig/ShinyHuntUnattended-Regigigas.json b/GeneratorConfig/PokemonSwSh/ShinyHuntUnattended-Regigigas.json similarity index 100% rename from GeneratorConfig/ShinyHuntUnattended-Regigigas.json rename to GeneratorConfig/PokemonSwSh/ShinyHuntUnattended-Regigigas.json diff --git a/GeneratorConfig/ShinyHuntUnattended-Regigigas2.json b/GeneratorConfig/PokemonSwSh/ShinyHuntUnattended-Regigigas2.json similarity index 100% rename from GeneratorConfig/ShinyHuntUnattended-Regigigas2.json rename to GeneratorConfig/PokemonSwSh/ShinyHuntUnattended-Regigigas2.json diff --git a/GeneratorConfig/ShinyHuntUnattended-StrongSpawn.json b/GeneratorConfig/PokemonSwSh/ShinyHuntUnattended-StrongSpawn.json similarity index 100% rename from GeneratorConfig/ShinyHuntUnattended-StrongSpawn.json rename to GeneratorConfig/PokemonSwSh/ShinyHuntUnattended-StrongSpawn.json diff --git a/GeneratorConfig/ShinyHuntUnattended-SwordsOfJustice.json b/GeneratorConfig/PokemonSwSh/ShinyHuntUnattended-SwordsOfJustice.json similarity index 100% rename from GeneratorConfig/ShinyHuntUnattended-SwordsOfJustice.json rename to GeneratorConfig/PokemonSwSh/ShinyHuntUnattended-SwordsOfJustice.json diff --git a/GeneratorConfig/SurpriseTrade.json b/GeneratorConfig/PokemonSwSh/SurpriseTrade.json similarity index 100% rename from GeneratorConfig/SurpriseTrade.json rename to GeneratorConfig/PokemonSwSh/SurpriseTrade.json diff --git a/GeneratorConfig/TradeBot.json b/GeneratorConfig/PokemonSwSh/TradeBot.json similarity index 100% rename from GeneratorConfig/TradeBot.json rename to GeneratorConfig/PokemonSwSh/TradeBot.json diff --git a/GeneratorConfig/TurboA.json b/GeneratorConfig/PokemonSwSh/TurboA.json similarity index 100% rename from GeneratorConfig/TurboA.json rename to GeneratorConfig/PokemonSwSh/TurboA.json diff --git a/GeneratorConfig/SettingsList.txt b/GeneratorConfig/SettingsList.txt deleted file mode 100644 index d30a339284..0000000000 --- a/GeneratorConfig/SettingsList.txt +++ /dev/null @@ -1,2 +0,0 @@ -FrameworkSettings -PokemonSettings \ No newline at end of file diff --git a/GeneratorSource/HexGenerator.pro b/GeneratorSource/HexGenerator.pro index c668719398..6c394ae2e9 100644 --- a/GeneratorSource/HexGenerator.pro +++ b/GeneratorSource/HexGenerator.pro @@ -21,8 +21,9 @@ win32-msvc{ } SOURCES += \ - ../Common/Clientside/PrettyPrint.cpp \ - ../Common/Clientside/Unicode.cpp \ + ../Common/Cpp/Exception.cpp \ + ../Common/Cpp/PrettyPrint.cpp \ + ../Common/Cpp/Unicode.cpp \ ../Common/Qt/CodeValidator.cpp \ ../Common/Qt/ExpressionEvaluator.cpp \ ../Common/Qt/Options/BooleanCheckBoxOption.cpp \ @@ -30,6 +31,7 @@ SOURCES += \ ../Common/Qt/Options/FossilTableOption.cpp \ ../Common/Qt/Options/MultiHostTableOption.cpp \ ../Common/Qt/Options/SimpleIntegerOption.cpp \ + ../Common/Qt/Options/StringOption.cpp \ ../Common/Qt/Options/SwitchDateOption.cpp \ ../Common/Qt/Options/TimeExpressionOption.cpp \ ../Common/Qt/QtJsonTools.cpp \ @@ -50,19 +52,19 @@ SOURCES += \ Source/Panels/ConfigSet.cpp \ Source/Panels/JsonProgram.cpp \ Source/Panels/JsonSettings.cpp \ - Source/Panels/PanelList.cpp \ Source/Panels/Program.cpp \ + Source/Panels/ProgramTab.cpp \ + Source/Panels/ProgramTabs.cpp \ Source/Tools/CommandRunner.cpp \ Source/Tools/MiscTools.cpp \ Source/Tools/PersistentSettings.cpp \ Source/UI/BoardList.cpp \ - Source/UI/MainWindow.cpp \ - Source/UI/ProgramListUI.cpp \ - Source/UI/SettingListUI.cpp + Source/UI/MainWindow.cpp HEADERS += \ - ../Common/Clientside/PrettyPrint.h \ - ../Common/Clientside/Unicode.h \ + ../Common/Cpp/Exception.h \ + ../Common/Cpp/PrettyPrint.h \ + ../Common/Cpp/Unicode.h \ ../Common/Qt/CodeValidator.h \ ../Common/Qt/ExpressionEvaluator.h \ ../Common/Qt/Options/BooleanCheckBoxOption.h \ @@ -70,10 +72,10 @@ HEADERS += \ ../Common/Qt/Options/FossilTableOption.h \ ../Common/Qt/Options/MultiHostTableOption.h \ ../Common/Qt/Options/SimpleIntegerOption.h \ + ../Common/Qt/Options/StringOption.h \ ../Common/Qt/Options/SwitchDateOption.h \ ../Common/Qt/Options/TimeExpressionOption.h \ ../Common/Qt/QtJsonTools.h \ - ../Common/Qt/StringException.h \ Source/Options/BooleanCheckBox.h \ Source/Options/ConfigItem.h \ Source/Options/Divider.h \ @@ -90,15 +92,14 @@ HEADERS += \ Source/Panels/ConfigSet.h \ Source/Panels/JsonProgram.h \ Source/Panels/JsonSettings.h \ - Source/Panels/PanelList.h \ Source/Panels/Program.h \ + Source/Panels/ProgramTab.h \ + Source/Panels/ProgramTabs.h \ Source/Panels/RightPanel.h \ Source/Tools/PersistentSettings.h \ Source/Tools/Tools.h \ Source/UI/BoardList.h \ - Source/UI/MainWindow.h \ - Source/UI/ProgramListUI.h \ - Source/UI/SettingListUI.h + Source/UI/MainWindow.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin diff --git a/GeneratorSource/Source/Options/ConfigItem.cpp b/GeneratorSource/Source/Options/ConfigItem.cpp index 93ce134682..677815d53e 100644 --- a/GeneratorSource/Source/Options/ConfigItem.cpp +++ b/GeneratorSource/Source/Options/ConfigItem.cpp @@ -4,7 +4,8 @@ * */ -#include "Common/Qt/StringException.h" +#include +#include "Common/Cpp/Exception.h" #include "Common/Qt/QtJsonTools.h" #include "Tools/Tools.h" #include "ConfigItem.h" @@ -37,14 +38,14 @@ std::unique_ptr parse_option(const QJsonObject& obj){ std::map& map = OPTION_FACTORIES(); auto iter = map.find(type); if (iter == map.end()){ - throw StringException("Unknown option type: " + type); + PA_THROW_ParseException("Unknown option type: " + type); } return iter->second(obj); } int register_option(const QString& name, OptionMaker fp){ std::map& map = OPTION_FACTORIES(); if (!map.emplace(name, fp).second){ - throw StringException("Duplicate option name."); + PA_THROW_ParseException("Duplicate option name."); } return 0; } diff --git a/GeneratorSource/Source/Options/EnumDropdown.cpp b/GeneratorSource/Source/Options/EnumDropdown.cpp index 67dd54289b..ec584c2c86 100644 --- a/GeneratorSource/Source/Options/EnumDropdown.cpp +++ b/GeneratorSource/Source/Options/EnumDropdown.cpp @@ -10,7 +10,7 @@ #include #include #include -#include "Common/Qt/StringException.h" +#include "Common/Cpp/Exception.h" #include "Common/Qt/QtJsonTools.h" #include "Tools/Tools.h" #include "EnumDropdown.h" @@ -38,14 +38,14 @@ EnumDropdown::EnumDropdown(const QJsonObject& obj) QJsonArray options = json_get_array_throw(obj, JSON_OPTIONS); for (const auto option : options){ if (!option.isArray()){ - throw StringException("Config Error - Expected Array: " + JSON_OPTIONS); + PA_THROW_ParseException("Config Error - Expected Array: " + JSON_OPTIONS); } QJsonArray pair = option.toArray(); if (pair.size() != 2){ - throw StringException("Config Error - Enum pairs should be 2 elements: " + JSON_OPTIONS); + PA_THROW_ParseException("Config Error - Enum pairs should be 2 elements: " + JSON_OPTIONS); } if (!pair[0].isString() || !pair[1].isString()){ - throw StringException("Config Error - Enum pairs should be strings: " + JSON_OPTIONS); + PA_THROW_ParseException("Config Error - Enum pairs should be strings: " + JSON_OPTIONS); } m_options.emplace_back( pair[0].toString(), @@ -54,20 +54,20 @@ EnumDropdown::EnumDropdown(const QJsonObject& obj) } for (size_t c = 0; c < m_options.size(); c++){ if (!m_map.emplace(m_options[c].first, c).second){ - throw StringException("Config Error - Duplicate option token."); + PA_THROW_ParseException("Config Error - Duplicate option token."); } } { auto iter = m_map.find(json_get_string_throw(obj, JSON_DEFAULT)); if (iter == m_map.end()){ - throw StringException("Config Error - Unrecognized token."); + PA_THROW_ParseException("Config Error - Unrecognized token."); } m_default = iter->second; } { auto iter = m_map.find(json_get_string_throw(obj, JSON_CURRENT)); if (iter == m_map.end()){ - throw StringException("Config Error - Unrecognized token."); + PA_THROW_ParseException("Config Error - Unrecognized token."); } m_current = iter->second; } diff --git a/GeneratorSource/Source/Options/FixedCode.cpp b/GeneratorSource/Source/Options/FixedCode.cpp index 1ebe0a8121..b4e4d83114 100644 --- a/GeneratorSource/Source/Options/FixedCode.cpp +++ b/GeneratorSource/Source/Options/FixedCode.cpp @@ -8,7 +8,7 @@ #include #include #include -#include "Common/Qt/StringException.h" +#include "Common/Cpp/Exception.h" #include "Common/Qt/QtJsonTools.h" #include "Common/Qt/CodeValidator.h" #include "FixedCode.h" @@ -36,10 +36,10 @@ FixedCode::FixedCode(const QJsonObject& obj) , m_current(json_get_string_throw(obj, JSON_CURRENT)) { if (!validate_code(m_digits, m_default)){ - throw StringException("Invalid code."); + PA_THROW_ParseException("Invalid code."); } if (!validate_code(m_digits, m_current)){ - throw StringException("Invalid code."); + PA_THROW_ParseException("Invalid code."); } } void FixedCode::restore_defaults(){ @@ -73,8 +73,8 @@ QString FixedCodeUI::sanitized_code(const QString& text){ QString message; try{ message = "Code: " + sanitize_code(m_value.m_digits, text); - }catch (const StringException& str){ - message = "" + str.message() + ""; + }catch (const ParseException& e){ + message = "" + e.message_qt() + ""; } return message; } diff --git a/GeneratorSource/Source/Options/FossilTable.cpp b/GeneratorSource/Source/Options/FossilTable.cpp index e693c49599..2f873b78ef 100644 --- a/GeneratorSource/Source/Options/FossilTable.cpp +++ b/GeneratorSource/Source/Options/FossilTable.cpp @@ -10,7 +10,6 @@ #include #include #include -#include "Common/Qt/StringException.h" #include "Common/Qt/QtJsonTools.h" #include "Tools/Tools.h" #include "FossilTable.h" diff --git a/GeneratorSource/Source/Options/MultiHostTable.cpp b/GeneratorSource/Source/Options/MultiHostTable.cpp index 46e5191cea..78c40d2138 100644 --- a/GeneratorSource/Source/Options/MultiHostTable.cpp +++ b/GeneratorSource/Source/Options/MultiHostTable.cpp @@ -12,7 +12,6 @@ #include #include #include -#include "Common/Qt/StringException.h" #include "Common/Qt/QtJsonTools.h" #include "Common/Qt/ExpressionEvaluator.h" #include "Tools/Tools.h" diff --git a/GeneratorSource/Source/Options/RandomCode.cpp b/GeneratorSource/Source/Options/RandomCode.cpp index 24ff012d3d..604d43f6ab 100644 --- a/GeneratorSource/Source/Options/RandomCode.cpp +++ b/GeneratorSource/Source/Options/RandomCode.cpp @@ -8,7 +8,7 @@ #include #include #include -#include "Common/Qt/StringException.h" +#include "Common/Cpp/Exception.h" #include "Common/Qt/QtJsonTools.h" #include "Common/Qt/CodeValidator.h" #include "RandomCode.h" @@ -52,10 +52,10 @@ RandomCode::RandomCode(const QJsonObject& obj) m_current_random = m_digits; } if (!validate_code(m_digits, m_default_code)){ - throw StringException("Invalid code."); + PA_THROW_ParseException("Invalid code."); } if (!validate_code(m_digits, m_current_code)){ - throw StringException("Invalid code."); + PA_THROW_ParseException("Invalid code."); } } void RandomCode::restore_defaults(){ @@ -106,8 +106,8 @@ QString RandomCodeUI::sanitized_code(const QString& text) const{ QString message; try{ message = "Fixed Raid Code: " + sanitize_code(m_value.m_digits, text); - }catch (const StringException& str){ - message = "" + str.message() + ""; + }catch (const ParseException& e){ + message = "" + e.message_qt() + ""; } return message; } diff --git a/GeneratorSource/Source/Options/TimeExpression.cpp b/GeneratorSource/Source/Options/TimeExpression.cpp index 380644711c..5dfc03a740 100644 --- a/GeneratorSource/Source/Options/TimeExpression.cpp +++ b/GeneratorSource/Source/Options/TimeExpression.cpp @@ -8,8 +8,7 @@ #include #include #include -#include "Common/Clientside/PrettyPrint.h" -#include "Common/Qt/StringException.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/Qt/QtJsonTools.h" #include "Common/Qt/ExpressionEvaluator.h" #include "Tools/Tools.h" diff --git a/GeneratorSource/Source/Panels/ConfigSet.cpp b/GeneratorSource/Source/Panels/ConfigSet.cpp index 9becce2902..1161daaf83 100644 --- a/GeneratorSource/Source/Panels/ConfigSet.cpp +++ b/GeneratorSource/Source/Panels/ConfigSet.cpp @@ -10,7 +10,7 @@ #include #include #include -#include "Common/Qt/StringException.h" +#include "Common/Cpp/Exception.h" #include "Common/Qt/QtJsonTools.h" #include "Tools/Tools.h" #include "Tools/PersistentSettings.h" @@ -25,8 +25,8 @@ const QString ConfigSet::JSON_CONFIG_PATH = "1-ConfigPath"; const QString ConfigSet::JSON_DESCRIPTION = "2-Description"; const QString ConfigSet::JSON_OPTIONS = "3-Options"; -ConfigSet::ConfigSet(const QJsonObject& obj) - : RightPanel(json_get_string_throw(obj, JSON_CONFIG_NAME)) +ConfigSet::ConfigSet(QString category, const QJsonObject& obj) + : RightPanel(std::move(category), json_get_string_throw(obj, JSON_CONFIG_NAME)) , m_path(json_get_string_throw(obj, JSON_CONFIG_PATH)) , m_description(json_get_string_throw(obj, JSON_DESCRIPTION)) {} @@ -49,7 +49,7 @@ std::string ConfigSet::to_cfile() const{ return body; } QString ConfigSet::save_json() const{ - QString name = settings.path + CONFIG_FOLDER_NAME + "/" + m_name + ".json"; + QString name = settings.path + CONFIG_FOLDER_NAME + "/" + m_category + "/" + m_name + ".json"; write_json_file(name, to_json()); return name; } @@ -58,10 +58,10 @@ QString ConfigSet::save_cfile() const{ std::string cpp = to_cfile(); QFile file(name); if (!file.open(QFile::WriteOnly)){ - throw StringException("Unable to create source file: " + name); + PA_THROW_FileException("Unable to create source file.", name); } if (file.write(cpp.c_str(), cpp.size()) != cpp.size()){ - throw StringException("Unable to write source file: " + name); + PA_THROW_FileException("Unable to write source file.", name); } file.close(); return name; @@ -91,9 +91,9 @@ QWidget* ConfigSet::make_ui(MainWindow& parent){ QString cfile = save_cfile(); QMessageBox box; box.information(nullptr, "Success!", "Settings saved to:\n" + json + "\n" + cfile); - }catch (const StringException& str){ + }catch (const StringException& e){ QMessageBox box; - box.critical(nullptr, "Error", str.message()); + box.critical(nullptr, "Error", e.message_qt()); return; } } diff --git a/GeneratorSource/Source/Panels/ConfigSet.h b/GeneratorSource/Source/Panels/ConfigSet.h index fecc0bf3bb..d5434972a7 100644 --- a/GeneratorSource/Source/Panels/ConfigSet.h +++ b/GeneratorSource/Source/Panels/ConfigSet.h @@ -22,7 +22,7 @@ class ConfigSet : public RightPanel{ static const QString JSON_OPTIONS; public: - ConfigSet(const QJsonObject& obj); + ConfigSet(QString category, const QJsonObject& obj); const QString& description() const{ return m_description; } diff --git a/GeneratorSource/Source/Panels/JsonProgram.cpp b/GeneratorSource/Source/Panels/JsonProgram.cpp index bb977f944a..c38323b13b 100644 --- a/GeneratorSource/Source/Panels/JsonProgram.cpp +++ b/GeneratorSource/Source/Panels/JsonProgram.cpp @@ -7,7 +7,7 @@ #include #include #include -#include "Common/Qt/StringException.h" +#include "Common/Cpp/Exception.h" #include "Common/Qt/QtJsonTools.h" #include "Tools/Tools.h" #include "JsonProgram.h" @@ -15,15 +15,15 @@ namespace PokemonAutomation{ -Program_JsonFile::Program_JsonFile(const QString& filepath) - : Program_JsonFile(read_json_file(filepath).object()) +Program_JsonFile::Program_JsonFile(QString category, const QString& filepath) + : Program_JsonFile(std::move(category), read_json_file(filepath).object()) {} -Program_JsonFile::Program_JsonFile(const QJsonObject& obj) - : Program(obj) +Program_JsonFile::Program_JsonFile(QString category, const QJsonObject& obj) + : Program(std::move(category), obj) { for (const auto item : json_get_array_throw(obj, JSON_PARAMETERS)){ if (!item.isObject()){ - throw StringException("Config Error - Expected and object."); + PA_THROW_ParseException("Config Error - Expected and object."); } m_options.emplace_back(parse_option(item.toObject())); } diff --git a/GeneratorSource/Source/Panels/JsonProgram.h b/GeneratorSource/Source/Panels/JsonProgram.h index 7742bad93f..66813e5079 100644 --- a/GeneratorSource/Source/Panels/JsonProgram.h +++ b/GeneratorSource/Source/Panels/JsonProgram.h @@ -14,8 +14,8 @@ namespace PokemonAutomation{ class Program_JsonFile : public Program{ public: - Program_JsonFile(const QString& filepath); - Program_JsonFile(const QJsonObject& obj); + Program_JsonFile(QString category, const QString& filepath); + Program_JsonFile(QString category, const QJsonObject& obj); virtual bool is_valid() const override; virtual void restore_defaults() override; diff --git a/GeneratorSource/Source/Panels/JsonSettings.cpp b/GeneratorSource/Source/Panels/JsonSettings.cpp index 89d037521a..9300ac1753 100644 --- a/GeneratorSource/Source/Panels/JsonSettings.cpp +++ b/GeneratorSource/Source/Panels/JsonSettings.cpp @@ -7,7 +7,7 @@ #include #include #include -#include "Common/Qt/StringException.h" +#include "Common/Cpp/Exception.h" #include "Common/Qt/QtJsonTools.h" #include "Tools/Tools.h" #include "JsonSettings.h" @@ -15,15 +15,15 @@ namespace PokemonAutomation{ -Settings_JsonFile::Settings_JsonFile(const QString& filepath) - : Settings_JsonFile(read_json_file(filepath).object()) +Settings_JsonFile::Settings_JsonFile(QString category, const QString& filepath) + : Settings_JsonFile(std::move(category), read_json_file(filepath).object()) {} -Settings_JsonFile::Settings_JsonFile(const QJsonObject& obj) - : ConfigSet(obj) +Settings_JsonFile::Settings_JsonFile(QString category, const QJsonObject& obj) + : ConfigSet(std::move(category), obj) { for (const auto item : json_get_array_throw(obj, JSON_OPTIONS)){ if (!item.isObject()){ - throw StringException("Config Error - Expected and object."); + PA_THROW_ParseException("Config Error - Expected and object."); } m_options.emplace_back(parse_option(item.toObject())); } diff --git a/GeneratorSource/Source/Panels/JsonSettings.h b/GeneratorSource/Source/Panels/JsonSettings.h index 6c50f52d68..cfb8562eb3 100644 --- a/GeneratorSource/Source/Panels/JsonSettings.h +++ b/GeneratorSource/Source/Panels/JsonSettings.h @@ -14,8 +14,8 @@ namespace PokemonAutomation{ class Settings_JsonFile : public ConfigSet{ public: - Settings_JsonFile(const QString& filepath); - Settings_JsonFile(const QJsonObject& obj); + Settings_JsonFile(QString category, const QString& filepath); + Settings_JsonFile(QString category, const QJsonObject& obj); virtual bool is_valid() const override; virtual void restore_defaults() override; diff --git a/GeneratorSource/Source/Panels/PanelList.cpp b/GeneratorSource/Source/Panels/PanelList.cpp deleted file mode 100644 index db58527125..0000000000 --- a/GeneratorSource/Source/Panels/PanelList.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* List of all Panels - * - * From: https://github.com/PokemonAutomation/Arduino-Source - * - */ - -#include -#include -#include -#include "Common/Qt/StringException.h" -#include "Common/Qt/QtJsonTools.h" -#include "JsonSettings.h" -#include "JsonProgram.h" -#include "Tools/PersistentSettings.h" -#include "PanelList.h" - -#include -using std::cout; -using std::endl; - -namespace PokemonAutomation{ - - - -const std::vector>& SETTINGS_LIST(){ - static std::vector> list; - if (!list.empty()){ - return list; - } - - QString path = settings.path + CONFIG_FOLDER_NAME + "/SettingsList.txt"; - QFile file(path); - if (!file.open(QFile::ReadOnly)){ -// QMessageBox box; -// box.critical(nullptr, "Error", "Unable to open settings list: " + settings_path); - return list; - } - cout << "File = " << path.toUtf8().data() << endl; - - QTextStream stream(&file); - while (!stream.atEnd()){ - QString line = stream.readLine(); - if (line.isEmpty()){ - continue; - } - cout << "Open: " << line.toUtf8().data() << endl; - try{ - QString path = settings.path + CONFIG_FOLDER_NAME + "/" + line + ".json"; - list.emplace_back(new Settings_JsonFile(path)); - }catch (const StringException& str){ - cout << "Error: " << str.message().toUtf8().data() << endl; - } - } - file.close(); - - return list; -} -const std::map& SETTINGS_MAP(){ - static std::map map; - if (!map.empty()){ - return map; - } - for (const auto& program : SETTINGS_LIST()){ - auto ret = map.emplace(program->name(), program.get()); - if (!ret.second){ - throw StringException("Duplicate program name: " + program->name()); - } - } - return map; -} - - -const std::vector>& PROGRAM_LIST(){ - static std::vector> list; - if (!list.empty()){ - return list; - } - - QString path = settings.path + CONFIG_FOLDER_NAME + "/ProgramList.txt"; - QFile file(path); - if (!file.open(QFile::ReadOnly)){ -// QMessageBox box; -// box.critical(nullptr, "Error", "Unable to open programs list: " + settings_path); - return list; - } - cout << "File = " << path.toUtf8().data() << endl; - - QTextStream stream(&file); - while (!stream.atEnd()){ - QString line = stream.readLine(); - if (line.isEmpty()){ - continue; - } - cout << "Open: " << line.toUtf8().data() << endl; - try{ - QString path = settings.path + CONFIG_FOLDER_NAME + "/" + line + ".json"; - list.emplace_back(new Program_JsonFile(path)); - }catch (const StringException& str){ - cout << "Error: " << str.message().toUtf8().data() << endl; - } - } - file.close(); - - return list; -} -const std::map& PROGRAM_MAP(){ - static std::map map; - if (map.empty()){ - for (const auto& program : PROGRAM_LIST()){ - auto ret = map.emplace(program->name(), program.get()); - if (!ret.second){ - throw StringException("Duplicate program name: " + program->name()); - } - } - } - return map; -} - - - -} - - diff --git a/GeneratorSource/Source/Panels/PanelList.h b/GeneratorSource/Source/Panels/PanelList.h deleted file mode 100644 index f43f9a4c87..0000000000 --- a/GeneratorSource/Source/Panels/PanelList.h +++ /dev/null @@ -1,25 +0,0 @@ -/* List of all Panels - * - * From: https://github.com/PokemonAutomation/Arduino-Source - * - */ - -#ifndef PokemonAutomation_PanelList_H -#define PokemonAutomation_PanelList_H - -#include -#include -#include -#include "ConfigSet.h" -#include "Program.h" - -namespace PokemonAutomation{ - -const std::vector>& SETTINGS_LIST(); -const std::map& SETTINGS_MAP(); - -const std::vector>& PROGRAM_LIST(); -const std::map& PROGRAM_MAP(); - -} -#endif diff --git a/GeneratorSource/Source/Panels/Program.cpp b/GeneratorSource/Source/Panels/Program.cpp index 63027c4cb9..e88f1cd590 100644 --- a/GeneratorSource/Source/Panels/Program.cpp +++ b/GeneratorSource/Source/Panels/Program.cpp @@ -16,7 +16,7 @@ using std::endl; #include #include #include -#include "Common/Qt/StringException.h" +#include "Common/Cpp/Exception.h" #include "Common/Qt/QtJsonTools.h" #include "Tools/Tools.h" #include "Tools/PersistentSettings.h" @@ -34,12 +34,12 @@ const QString Program::JSON_PARAMETERS = "2-Parameters"; const QString Program::BUILD_BUTTON_NORMAL = "Save and generate .hex file!"; const QString Program::BUILD_BUTTON_BUSY = "Build in progress... Please Wait."; -Program::Program(const QString& name, const QString& description) - : RightPanel(name) - , m_description(description) +Program::Program(QString category, QString name, QString description) + : RightPanel(std::move(category), std::move(name)) + , m_description(std::move(description)) {} -Program::Program(const QJsonObject& obj) - : RightPanel(json_get_string_throw(obj, JSON_PROGRAM_NAME)) +Program::Program(QString category, const QJsonObject& obj) + : RightPanel(std::move(category), json_get_string_throw(obj, JSON_PROGRAM_NAME)) , m_description(json_get_string_throw(obj, JSON_DESCRIPTION)) {} Program::~Program(){ @@ -68,7 +68,9 @@ std::string Program::to_cfile() const{ std::string body; body += "// This file is generated by the UI. There's no point in editing.\r\n"; body += "#include \""; - body += "../NativePrograms/PokemonSwShPrograms/"; + body += "../NativePrograms/"; + body += m_category.toUtf8().data(); + body += "/Programs/"; body += m_name.toUtf8().data(); body += ".h\"\r\n"; body += parameters_cpp(); @@ -76,19 +78,19 @@ std::string Program::to_cfile() const{ } QString Program::save_json() const{ // cout << QCoreApplication::applicationDirPath().toUtf8().data() << endl; - QString name = settings.path + CONFIG_FOLDER_NAME + "/" + m_name + ".json"; + QString name = settings.path + CONFIG_FOLDER_NAME + "/" + m_category + "/" + m_name + ".json"; write_json_file(name, to_json()); return name; } QString Program::save_cfile() const{ - QString name = settings.path + SOURCE_FOLDER_NAME + "/" + m_name + ".c"; + QString name = settings.path + SOURCE_FOLDER_NAME + "/" + m_category + "/" + m_name + ".c"; std::string cpp = to_cfile(); QFile file(name); if (!file.open(QFile::WriteOnly)){ - throw StringException("Unable to create source file.\r\n" + name); + PA_THROW_FileException("Unable to create source file.", name); } if (file.write(cpp.c_str(), cpp.size()) != cpp.size()){ - throw StringException("Unable to write source file.\r\n: " + name); + PA_THROW_FileException("Unable to write source file.", name); } file.close(); return name; @@ -132,8 +134,8 @@ void Program::save_and_build(const std::string& board){ try{ save_json(); save_cfile(); - }catch (const StringException& str){ - QString error = str.message(); + }catch (const StringException& e){ + QString error = e.message_qt(); run_on_main_thread([=]{ QMessageBox box; box.critical(nullptr, "Error", error); @@ -144,7 +146,7 @@ void Program::save_and_build(const std::string& board){ // Build QString hex_file = settings.path + m_name + ("-" + board + ".hex").c_str(); QString log_file = settings.path + LOG_FOLDER_NAME + "/" + m_name + ("-" + board).c_str() + ".log"; - if (build_hexfile(board, m_name, hex_file, log_file) != 0){ + if (build_hexfile(board, m_category, m_name, hex_file, log_file) != 0){ return; } diff --git a/GeneratorSource/Source/Panels/Program.h b/GeneratorSource/Source/Panels/Program.h index 3ca59880cf..b85cdf61f6 100644 --- a/GeneratorSource/Source/Panels/Program.h +++ b/GeneratorSource/Source/Panels/Program.h @@ -28,8 +28,8 @@ class Program : public RightPanel{ static const QString BUILD_BUTTON_BUSY; public: - Program(const QString& name, const QString& description); - Program(const QJsonObject& obj); + Program(QString category, QString name, QString description); + Program(QString category, const QJsonObject& obj); ~Program(); const QString& description() const{ return m_description; } diff --git a/GeneratorSource/Source/Panels/ProgramTab.cpp b/GeneratorSource/Source/Panels/ProgramTab.cpp new file mode 100644 index 0000000000..4a2d3963fe --- /dev/null +++ b/GeneratorSource/Source/Panels/ProgramTab.cpp @@ -0,0 +1,108 @@ +/* Program Tab + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include +#include "Common/Cpp/Exception.h" +#include "Common/Qt/QtJsonTools.h" +#include "Tools/PersistentSettings.h" +#include "UI/MainWindow.h" +#include "JsonSettings.h" +#include "JsonProgram.h" +#include "ProgramTab.h" + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ + +ProgramTab::ProgramTab(QWidget& parent, MainWindow& window, const QJsonValue& json) + : QListWidget(&parent) + , m_window(window) +{ + if (!json.isObject()){ + PA_THROW_ParseException("Expected an object."); + } + const QJsonObject& category = json.toObject(); + + QString category_name; + if (!json_get_string(category_name, category, "Name")){ + PA_THROW_ParseException("Expected string field: Name"); + } + + if (!json_get_string(m_display_name, category, "Display")){ + PA_THROW_ParseException("Expected string field: Display"); + } + + // Populate Settings + std::vector settings_list; + for (const auto& item : json_get_array_nothrow(category, "Settings")){ + if (!item.isString()){ + PA_THROW_ParseException("Expected string field: Settings"); + } + QString setting = item.toString(); +// settings.emplace_back(setting.toString()); +// m_list.emplace_back(); +// cout << setting.toUtf8().data() << endl; + try{ + QString path = settings.path + CONFIG_FOLDER_NAME + "/" + category_name + "/" + setting + ".json"; + std::unique_ptr config(new Settings_JsonFile(category_name, path)); + m_list.emplace_back(std::move(config)); + const QString& name = m_list.back()->name(); + if (!m_map.emplace(name, m_list.back().get()).second){ + PA_THROW_ParseException("Duplicate: Program name"); + } + addItem(name); + }catch (const StringException& e){ + cout << "Error: " << e.message() << endl; + } + } + + // Populate Programs + QString path = settings.path + SOURCE_FOLDER_NAME + "/" + category_name + "/ProgramList.txt"; + QFile file(path); + if (file.open(QFile::ReadOnly)){ + cout << "File = " << path.toUtf8().data() << endl; + QTextStream stream(&file); + while (!stream.atEnd()){ + QString line = stream.readLine(); + if (line.isEmpty()){ + continue; + } + cout << "Open: " << line.toUtf8().data() << endl; + try{ + QString path = settings.path + CONFIG_FOLDER_NAME + "/" + category_name + "/" + line + ".json"; + std::unique_ptr config(new Program_JsonFile(category_name, path)); + m_list.emplace_back(std::move(config)); + const QString& name = m_list.back()->name(); + if (!m_map.emplace(name, m_list.back().get()).second){ + PA_THROW_StringException("Duplicate: Program name"); + } + addItem(name); + }catch (const StringException& e){ + cout << "Error: " << e.message() << endl; + } + } + file.close(); + } + + + connect(this, &QListWidget::itemClicked, this, &ProgramTab::row_selected); +} + +void ProgramTab::row_selected(QListWidgetItem* item){ + auto iter = m_map.find(item->text()); + if (iter == m_map.end()){ +// std::cout << item->text().toUtf8().data() << std::endl; + PA_THROW_StringException("Invalid program name: " + item->text()); + } + + m_window.change_panel(*iter->second); +} + + +} diff --git a/GeneratorSource/Source/Panels/ProgramTab.h b/GeneratorSource/Source/Panels/ProgramTab.h new file mode 100644 index 0000000000..c0c9b5249d --- /dev/null +++ b/GeneratorSource/Source/Panels/ProgramTab.h @@ -0,0 +1,35 @@ +/* Program Tab + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_ProgramTab_H +#define PokemonAutomation_ProgramTab_H + +#include +#include +#include "ConfigSet.h" + +namespace PokemonAutomation{ + +class ProgramTab : public QListWidget{ +public: + ProgramTab(QWidget& parent, MainWindow& window, const QJsonValue& json); + + const QString& display_name() const{ return m_display_name; } + size_t items() const{ return m_list.size(); } + +public slots: + void row_selected(QListWidgetItem* item); + +private: + MainWindow& m_window; + QString m_display_name; + std::vector> m_list; + std::map m_map; +}; + + +} +#endif diff --git a/GeneratorSource/Source/Panels/ProgramTabs.cpp b/GeneratorSource/Source/Panels/ProgramTabs.cpp new file mode 100644 index 0000000000..0d527bc970 --- /dev/null +++ b/GeneratorSource/Source/Panels/ProgramTabs.cpp @@ -0,0 +1,60 @@ +/* Program Tabs + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include +#include +#include +#include "Common/Cpp/Exception.h" +#include "Common/Qt/QtJsonTools.h" +#include "Tools/PersistentSettings.h" +#include "ProgramTab.h" +#include "ProgramTabs.h" + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ + +ProgramTabs::ProgramTabs(QWidget& parent, MainWindow& window) + : QTabWidget(&parent) +{ + QString path = settings.path + CONFIG_FOLDER_NAME + "/Categories.json"; + + QFile file(path); + if (!file.open(QFile::ReadOnly)){ + QMessageBox box; + box.critical(nullptr, "Error", "Unable to open program list: " + path); + return; + } + + QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); + if (!doc.isArray()){ + QMessageBox box; + box.critical(nullptr, "Error", "Invalid program list: " + path); + return; + } + + for (const auto& item : doc.array()){ + try{ + ProgramTab* tab = new ProgramTab(*this, window, item); + addTab(tab, tab->display_name()); + if (tab->items() == 0){ + setTabEnabled(this->count() - 1, false); + } + }catch (StringException&){ + continue; + } + } + + + +} + + +} + diff --git a/GeneratorSource/Source/Panels/ProgramTabs.h b/GeneratorSource/Source/Panels/ProgramTabs.h new file mode 100644 index 0000000000..b8093d8dbc --- /dev/null +++ b/GeneratorSource/Source/Panels/ProgramTabs.h @@ -0,0 +1,27 @@ +/* Program Tabs + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_ProgramTabs_H +#define PokemonAutomation_ProgramTabs_H + +#include + +namespace PokemonAutomation{ + + +class MainWindow; + + +class ProgramTabs : public QTabWidget{ +public: + ProgramTabs(QWidget& parent, MainWindow& window); + +private: +}; + + +} +#endif diff --git a/GeneratorSource/Source/Panels/RightPanel.h b/GeneratorSource/Source/Panels/RightPanel.h index 0d8d389aa6..beae9d7dd1 100644 --- a/GeneratorSource/Source/Panels/RightPanel.h +++ b/GeneratorSource/Source/Panels/RightPanel.h @@ -18,15 +18,19 @@ class RightPanel : public QObject{ Q_OBJECT public: - RightPanel(QString name) - : m_name(std::move(name)) + RightPanel(QString category, QString name) + : m_category(std::move(category)) + , m_name(std::move(name)) {} virtual ~RightPanel() = default; + const QString& category() const{ return m_category; } const QString& name() const{ return m_name; } + virtual QWidget* make_ui(MainWindow& parent) = 0; protected: + QString m_category; QString m_name; }; diff --git a/GeneratorSource/Source/Tools/CommandRunner.cpp b/GeneratorSource/Source/Tools/CommandRunner.cpp index 941ac64c5f..1d8da4ab30 100644 --- a/GeneratorSource/Source/Tools/CommandRunner.cpp +++ b/GeneratorSource/Source/Tools/CommandRunner.cpp @@ -7,7 +7,7 @@ #include #include #include -#include "Common/Clientside/Unicode.h" +#include "Common/Cpp/Unicode.h" #include "Tools/PersistentSettings.h" #include "Tools.h" @@ -17,6 +17,7 @@ namespace PokemonAutomation{ int build_hexfile( const std::string& board, + const QString& category, const QString& program_name, const QString& hex_file, const QString& log_file @@ -36,7 +37,11 @@ int build_hexfile( ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); - QString command = module + " " + board.c_str() + " " + program_name + " > \"" + log_file + "\" 2>&1"; + QString command = "\"" + module + "\""; + command += QString(" ") + board.c_str(); + command += QString(" ") + category; + command += QString(" ") + program_name; + command += " > \"" + log_file + "\" 2>&1"; std::wstring wpath = utf8_to_wstr(command.toUtf8().data()); bool ret = CreateProcessW( nullptr, @@ -55,7 +60,11 @@ int build_hexfile( std::cout << "error = " << code << std::endl; run_on_main_thread([=]{ QMessageBox box; - box.critical(nullptr, "Error", "Unable to open: " + QString::fromWCharArray(wpath.data()) + "\r\nError Code: " + QString::number(code)); + box.critical( + nullptr, "Error", + "Unable to open: " + QString::fromWCharArray(wpath.data()) + + "\r\n\r\nError Code: " + QString::number(code) + ); // box.critical(nullptr, "Error", "Unable to open: " + module + "\r\nError Code: " + QString::number(code)); }); return 1; @@ -75,12 +84,13 @@ namespace PokemonAutomation{ int build_hexfile( const std::string& board, + const QString& category, const QString& program_name, const QString& hex_file, const QString& log_file ){ - QString module_dir = settings.path + SOURCE_FOLDER_NAME; - QString module = "./Scripts/BuildOneUnix.sh "; + QString module_dir = settings.path + SOURCE_FOLDER_NAME + "/" + category; + QString module = "../Scripts/BuildOneUnix.sh "; QString command = module + board.c_str() + " " + program_name + " gui > " + log_file + " 2>&1"; // Since most macs will have the avr tools installed in /usr/local/bin, add it to the path now diff --git a/GeneratorSource/Source/Tools/MiscTools.cpp b/GeneratorSource/Source/Tools/MiscTools.cpp index 7eba0f0081..6935858801 100644 --- a/GeneratorSource/Source/Tools/MiscTools.cpp +++ b/GeneratorSource/Source/Tools/MiscTools.cpp @@ -5,7 +5,6 @@ */ #include -#include "Common/Qt/StringException.h" #include "Common/Qt/QtJsonTools.h" #include "Tools.h" diff --git a/GeneratorSource/Source/Tools/PersistentSettings.cpp b/GeneratorSource/Source/Tools/PersistentSettings.cpp index 03c4373a85..1a2a6ce04e 100644 --- a/GeneratorSource/Source/Tools/PersistentSettings.cpp +++ b/GeneratorSource/Source/Tools/PersistentSettings.cpp @@ -8,8 +8,8 @@ #include #include #include +#include "Common/Cpp/Exception.h" #include "Common/Qt/QtJsonTools.h" -#include "Common/Qt/StringException.h" #include "Tools.h" #include "PersistentSettings.h" @@ -20,7 +20,7 @@ using std::endl; namespace PokemonAutomation{ -const QString VERSION = "v0.4.2"; +const QString VERSION = "v0.5.2"; const QString DISCORD = "https://discord.gg/cQ4gWxN"; const QString GITHUB_REPO = "https://github.com/PokemonAutomation/SwSh-Arduino"; @@ -54,7 +54,7 @@ void PersistentSettings::determine_paths(){ } path = ""; -// throw StringException("Unable to find working directory."); +// throw StringExceptionQt("Unable to find working directory."); } void PersistentSettings::load(){ determine_paths(); @@ -63,15 +63,15 @@ void PersistentSettings::load(){ try{ QJsonDocument doc = read_json_file(path + SETTINGS_NAME); if (!doc.isObject()){ - throw StringException("Invalid settings file."); + PA_THROW_ParseException("Invalid settings file."); } QJsonObject root = doc.object(); json_get_int(board_index, root, "Board", 0, 3); - }catch (const StringException& str){ - std::cout << ("Error Parsing " + SETTINGS_NAME + ": " + str.message()).toUtf8().data() << std::endl; + }catch (const StringException& e){ + std::cout << std::string("Error Parsing ") + SETTINGS_NAME.toUtf8().data() + ": " + e.message() << std::endl; } } diff --git a/GeneratorSource/Source/Tools/Tools.h b/GeneratorSource/Source/Tools/Tools.h index 5cc6d75a91..15fca72235 100644 --- a/GeneratorSource/Source/Tools/Tools.h +++ b/GeneratorSource/Source/Tools/Tools.h @@ -30,6 +30,7 @@ bool valid_switch_date(const QDate& date); // Build the .hex int build_hexfile( const std::string& board, + const QString& category, const QString& program_name, const QString& hex_file, const QString& log_file diff --git a/GeneratorSource/Source/UI/BoardList.cpp b/GeneratorSource/Source/UI/BoardList.cpp index 703aa769a9..730219fab4 100644 --- a/GeneratorSource/Source/UI/BoardList.cpp +++ b/GeneratorSource/Source/UI/BoardList.cpp @@ -1,4 +1,4 @@ -/* MCU List +/* Board List * * From: https://github.com/PokemonAutomation/Arduino-Source * diff --git a/GeneratorSource/Source/UI/MainWindow.cpp b/GeneratorSource/Source/UI/MainWindow.cpp index 38b1324775..e1a6c0d6a0 100644 --- a/GeneratorSource/Source/UI/MainWindow.cpp +++ b/GeneratorSource/Source/UI/MainWindow.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -16,8 +17,7 @@ #include #include "Tools/Tools.h" #include "Tools/PersistentSettings.h" -#include "SettingListUI.h" -#include "ProgramListUI.h" +#include "Panels/ProgramTabs.h" #include "MainWindow.h" //#include @@ -56,10 +56,19 @@ MainWindow::MainWindow(QWidget* parent) left->addWidget(new QLabel("Device and Program:", this)); - left->addSpacerItem(new QSpacerItem(10, 10)); - left->addWidget(new QLabel("Board Type:", this)); - left->addWidget(m_mcu_list = new BoardList(*this)); + QGroupBox* board_box = new QGroupBox("Board Type", m_centralwidget); + left->addWidget(board_box, 0); + QVBoxLayout* board_layout = new QVBoxLayout(board_box); + board_layout->setAlignment(Qt::AlignTop); + board_layout->addWidget(m_mcu_list = new BoardList(*this)); + + QGroupBox* program_box = new QGroupBox("Program Select", m_centralwidget); + left->addWidget(program_box, 1); + QVBoxLayout* program_layout = new QVBoxLayout(program_box); + program_layout->setAlignment(Qt::AlignTop); + program_layout->addWidget(new ProgramTabs(*program_box, *this)); +#if 0 left->addSpacerItem(new QSpacerItem(10, 10)); left->addWidget(new QLabel("Select a Program:", this)); m_program_list = new ProgramListUI(*this); @@ -69,6 +78,8 @@ MainWindow::MainWindow(QWidget* parent) left->addWidget(new QLabel("Global Settings:", this)); m_settings_list = new SettingsListUI(*this); left->addWidget(m_settings_list); +#endif + #if 0 int width = std::max( @@ -82,6 +93,9 @@ MainWindow::MainWindow(QWidget* parent) // m_program_list->setMaximumWidth(width); // m_settings_list->setMaximumWidth(width); + QGroupBox* support_box = new QGroupBox("Support (" + STRING_POKEMON + " Automation " + VERSION + ")", m_centralwidget); + left->addWidget(support_box); + QHBoxLayout* support = new QHBoxLayout(); left->addLayout(support); // support->setMargin(0); diff --git a/GeneratorSource/Source/UI/ProgramListUI.cpp b/GeneratorSource/Source/UI/ProgramListUI.cpp deleted file mode 100644 index c977e82b55..0000000000 --- a/GeneratorSource/Source/UI/ProgramListUI.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* UI List for all the Programs - * - * From: https://github.com/PokemonAutomation/Arduino-Source - * - */ - -#include -#include "Common/Qt/StringException.h" -#include "Common/Qt/QtJsonTools.h" -#include "UI/MainWindow.h" -#include "Panels/PanelList.h" -#include "ProgramListUI.h" - -//#include -//using namespace std; - -namespace PokemonAutomation{ - - -ProgramListUI::ProgramListUI(MainWindow& parent) - : m_parent(parent) - , m_text_width(0) -{ -// setSizeAdjustPolicy(SizeAdjustPolicy::AdjustToContents); -// setMinimumWidth(); -// setMaximumWidth(300); -// sizeHintForRow(100); -// sizeHintForColumn(100); - - connect(this, &QListWidget::itemClicked, this, &ProgramListUI::row_selected); - connect(this, &QListWidget::currentRowChanged, this, &ProgramListUI::row_changed); - - QFontMetrics fm(this->font()); - for (const auto& item : PROGRAM_LIST()){ - addItem(item->name()); - m_text_width = std::max(m_text_width, fm.width(item->name())); -// cout << m_text_width << endl; - } -// setMaximumWidth(m_width); -} - -void ProgramListUI::row_selected(QListWidgetItem* item){ - auto iter = PROGRAM_MAP().find(item->text()); - if (iter == PROGRAM_MAP().end()){ -// std::cout << item->text().toUtf8().data() << std::endl; - throw StringException("Invalid program name: " + item->text()); - } - - m_parent.change_panel(*iter->second); -} -void ProgramListUI::row_changed(int row){ - row_selected(this->item(row)); -} - - - -} diff --git a/GeneratorSource/Source/UI/ProgramListUI.h b/GeneratorSource/Source/UI/ProgramListUI.h deleted file mode 100644 index c79562720e..0000000000 --- a/GeneratorSource/Source/UI/ProgramListUI.h +++ /dev/null @@ -1,36 +0,0 @@ -/* UI List for all the Programs - * - * From: https://github.com/PokemonAutomation/Arduino-Source - * - */ - -#ifndef PokemonAutomation_ProgramListUI_H -#define PokemonAutomation_ProgramListUI_H - -#include -#include - -namespace PokemonAutomation{ - - -class MainWindow; - -class ProgramListUI : public QListWidget{ - Q_OBJECT - -public: - ProgramListUI(MainWindow& parent); - int text_width() const{ return m_text_width; } - -public slots: - void row_selected(QListWidgetItem* item); - void row_changed(int row); - -private: - MainWindow& m_parent; - int m_text_width; -}; - - -} -#endif diff --git a/GeneratorSource/Source/UI/SettingListUI.cpp b/GeneratorSource/Source/UI/SettingListUI.cpp deleted file mode 100644 index 63ff0b31a4..0000000000 --- a/GeneratorSource/Source/UI/SettingListUI.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* UI List for all the Settings - * - * From: https://github.com/PokemonAutomation/Arduino-Source - * - */ - -#include -#include "Common/Qt/StringException.h" -#include "Common/Qt/QtJsonTools.h" -#include "UI/MainWindow.h" -#include "Panels/PanelList.h" -#include "SettingListUI.h" - -#include -using std::cout; -using std::endl; - -namespace PokemonAutomation{ - - -SettingsListUI::SettingsListUI(MainWindow& parent) - : m_parent(parent) - , m_text_width(0) -{ -// setMaximumWidth(300); -// setSizeAdjustPolicy(QAbstractScrollArea::SizeAdjustPolicy::AdjustToContents); - - connect(this, &QListWidget::itemClicked, this, &SettingsListUI::row_selected); - connect(this, &QListWidget::currentRowChanged, this, &SettingsListUI::row_changed); - - const auto& list = SETTINGS_LIST(); - if (list.empty()){ - setMaximumHeight(50); - return; - } - - QFontMetrics fm(this->font()); -// int width = 0; - for (const auto& item : list){ - addItem(item->name()); - m_text_width = std::max(m_text_width, fm.width(item->name())); - } -// updateGeometry(); -// setMaximumWidth(m_width); - - setMaximumHeight(4 + list.size() * (sizeHintForRow(0) + 2)); -} - -#if 0 -QSize SettingsDialog::sizeHint() const{ - if (model()->rowCount() == 0) return QSize(width(), 0); - int nToShow = model()->rowCount(); - cout << "asdf" << endl; - return QSize(width(), nToShow * sizeHintForRow(0)); -} -#endif - -void SettingsListUI::row_selected(QListWidgetItem* item){ - auto iter = SETTINGS_MAP().find(item->text()); - if (iter == SETTINGS_MAP().end()){ -// std::cout << item->text().toUtf8().data() << std::endl; - throw StringException("Invalid program name: " + item->text()); - } - - m_parent.change_panel(*iter->second); -} -void SettingsListUI::row_changed(int row){ - row_selected(this->item(row)); -} - - - -} - - - diff --git a/GeneratorSource/Source/UI/SettingListUI.h b/GeneratorSource/Source/UI/SettingListUI.h deleted file mode 100644 index 4ef366dac1..0000000000 --- a/GeneratorSource/Source/UI/SettingListUI.h +++ /dev/null @@ -1,38 +0,0 @@ -/* UI List for all the Settings - * - * From: https://github.com/PokemonAutomation/Arduino-Source - * - */ - -#ifndef PokemonAutomation_SettingsListUI_H -#define PokemonAutomation_SettingsListUI_H - -#include -#include - -namespace PokemonAutomation{ - - -class MainWindow; - -class SettingsListUI : public QListWidget{ - Q_OBJECT - -public: - SettingsListUI(MainWindow& parent); - int text_width() const{ return m_text_width; } - -// virtual QSize sizeHint() const override; - -public slots: - void row_selected(QListWidgetItem* item); - void row_changed(int row); - -private: - MainWindow& m_parent; - int m_text_width; -}; - - -} -#endif diff --git a/NativePrograms/!Cleanup.cmd b/NativePrograms/!Cleanup.cmd deleted file mode 100644 index 502642f333..0000000000 --- a/NativePrograms/!Cleanup.cmd +++ /dev/null @@ -1,33 +0,0 @@ -:: Clean the build. Delete all build artifacts. - -cd %~dp0 - -del *.log -del *.d -del *.elf -del *.hex -del *.map -del *.o -del *.eep -del *.bin -del *.lss -del *.sym -del *.tmp - -::del Libraries\*.d -::del Libraries\*.o -::del Programs\*.d -::del Programs\*.o - -del obj\*.d -del obj\*.o -del obj\build-* - -del LUFA\Drivers\USB\Core\*.d -del LUFA\Drivers\USB\Core\*.o -del LUFA\Drivers\USB\Core\AVR8\*.d -del LUFA\Drivers\USB\Core\AVR8\*.o -del LUFA\Drivers\USB\Class\Common\*.d -del LUFA\Drivers\USB\Class\Common\*.o - -::pause diff --git a/NativePrograms/Cleanup.cmd b/NativePrograms/Cleanup.cmd new file mode 100644 index 0000000000..87caf9ea62 --- /dev/null +++ b/NativePrograms/Cleanup.cmd @@ -0,0 +1,8 @@ + +cd %~dp0\NintendoSwitch +@call !Cleanup.cmd + +cd %~dp0\PokemonSwSh +@call !Cleanup.cmd + + diff --git a/NativePrograms/NintendoSwitch/!BuildAll-ArduinoUnoR3.cmd b/NativePrograms/NintendoSwitch/!BuildAll-ArduinoUnoR3.cmd new file mode 100644 index 0000000000..7fc90f1c06 --- /dev/null +++ b/NativePrograms/NintendoSwitch/!BuildAll-ArduinoUnoR3.cmd @@ -0,0 +1,15 @@ +@echo off + +cd /D "%~dp0" + +if not exist Programs\ ( + echo. + echo Please unzip the folder before you can use it. + echo. + pause + exit +) + +@call ../Scripts/BuildAll.cmd ArduinoUnoR3 + + diff --git a/NativePrograms/!BuildAll-ArduinoUnoR3.cmd b/NativePrograms/NintendoSwitch/!BuildAll-ProMicro.cmd similarity index 61% rename from NativePrograms/!BuildAll-ArduinoUnoR3.cmd rename to NativePrograms/NintendoSwitch/!BuildAll-ProMicro.cmd index 72a7e6083d..b1ece4743b 100644 --- a/NativePrograms/!BuildAll-ArduinoUnoR3.cmd +++ b/NativePrograms/NintendoSwitch/!BuildAll-ProMicro.cmd @@ -2,7 +2,7 @@ cd /D "%~dp0" -if not exist Scripts\ ( +if not exist Programs\ ( echo. echo Please unzip the folder before you can use it. echo. @@ -10,6 +10,6 @@ if not exist Scripts\ ( exit ) -@call Scripts/BuildAll.cmd ArduinoUnoR3 +@call ../Scripts/BuildAll.cmd ProMicro diff --git a/NativePrograms/NintendoSwitch/!BuildAll-Teensy++2.0.cmd b/NativePrograms/NintendoSwitch/!BuildAll-Teensy++2.0.cmd new file mode 100644 index 0000000000..e30eb5dfe0 --- /dev/null +++ b/NativePrograms/NintendoSwitch/!BuildAll-Teensy++2.0.cmd @@ -0,0 +1,15 @@ +@echo off + +cd /D "%~dp0" + +if not exist Programs\ ( + echo. + echo Please unzip the folder before you can use it. + echo. + pause + exit +) + +@call ../Scripts/BuildAll.cmd TeensyPP2 + + diff --git a/NativePrograms/!BuildAll-Teensy2.0.cmd b/NativePrograms/NintendoSwitch/!BuildAll-Teensy2.0.cmd similarity index 61% rename from NativePrograms/!BuildAll-Teensy2.0.cmd rename to NativePrograms/NintendoSwitch/!BuildAll-Teensy2.0.cmd index 74dcf3e85f..84f90a817e 100644 --- a/NativePrograms/!BuildAll-Teensy2.0.cmd +++ b/NativePrograms/NintendoSwitch/!BuildAll-Teensy2.0.cmd @@ -2,7 +2,7 @@ cd /D "%~dp0" -if not exist Scripts\ ( +if not exist Programs\ ( echo. echo Please unzip the folder before you can use it. echo. @@ -10,6 +10,6 @@ if not exist Scripts\ ( exit ) -@call Scripts/BuildAll.cmd Teensy2 +@call ../Scripts/BuildAll.cmd Teensy2 diff --git a/NativePrograms/NintendoSwitch/!Cleanup.cmd b/NativePrograms/NintendoSwitch/!Cleanup.cmd new file mode 100644 index 0000000000..7832b61049 --- /dev/null +++ b/NativePrograms/NintendoSwitch/!Cleanup.cmd @@ -0,0 +1,21 @@ +:: Clean the build. Delete all build artifacts. + +cd %~dp0 + +del *.log +del *.d +del *.elf +del *.hex +del *.map +del *.o +del *.eep +del *.bin +del *.lss +del *.sym +del *.tmp + +del obj\*.d +del obj\*.o +del obj\build-* + +::pause diff --git a/NativePrograms/00-BuildAllUnix.sh b/NativePrograms/NintendoSwitch/00-BuildAllUnix.sh old mode 100755 new mode 100644 similarity index 71% rename from NativePrograms/00-BuildAllUnix.sh rename to NativePrograms/NintendoSwitch/00-BuildAllUnix.sh index 864b07ea31..a543c0de94 --- a/NativePrograms/00-BuildAllUnix.sh +++ b/NativePrograms/NintendoSwitch/00-BuildAllUnix.sh @@ -7,15 +7,22 @@ cd "$(dirname "$0")" if [[ "$OSTYPE" == "darwin"* ]]; then PLATFORM="mac" + FZF=$(which fzf) + + if [[ "$FZF" == "" ]]; then + boxed_msg "${RED}ERROR: FZF is not detected on your system. Please install it through Homebrew ${RESET}" + exit 1 + fi + elif [[ "$OSTYPE" == "linux-gnu"* ]]; then PLATFORM="linux" + FZF="../Scripts/fzf-${PLATFORM}" else boxed_msg "${RED}${OSTYPE} is not a recognized platform. Please run only on Mac or Linux${RESET}" exit 1 fi BOARD=$1 -FZF="Scripts/fzf-${PLATFORM}" function run() { if [[ -z "$BOARD" ]]; then @@ -30,7 +37,7 @@ function run() { echo "" # and send off to build - bash Scripts/BuildAllUnix.sh "$BOARD" 1> /dev/null + bash ../Scripts/BuildAllUnix.sh "$BOARD" #1> /dev/null # let them know we finished echo -e "\033[1mFinished building hex files for board: $BOARD \033[0m" @@ -41,7 +48,7 @@ function run() { } function board_prompt() { - BOARD=$(cat Scripts/Boards.txt | $FZF --height=15% --prompt="Choose your Board: ") + BOARD=$(cat ../Scripts/Boards.txt | $FZF --height=15% --prompt="Choose your Board: ") } -run \ No newline at end of file +run diff --git a/NativePrograms/00-CleanupUnix.sh b/NativePrograms/NintendoSwitch/00-CleanupUnix.sh old mode 100755 new mode 100644 similarity index 69% rename from NativePrograms/00-CleanupUnix.sh rename to NativePrograms/NintendoSwitch/00-CleanupUnix.sh index d177b56ade..3e3789e7cc --- a/NativePrograms/00-CleanupUnix.sh +++ b/NativePrograms/NintendoSwitch/00-CleanupUnix.sh @@ -27,12 +27,4 @@ rm Programs/*.o > /dev/null 2>&1 rm obj/*.d > /dev/null 2>&1 rm obj/*.o > /dev/null 2>&1 -# remove the compiled portions within the base libraries -rm LUFA/Drivers/USB/Core/*.d > /dev/null 2>&1 -rm LUFA/Drivers/USB/Core/*.o > /dev/null 2>&1 -rm LUFA/Drivers/USB/Core/AVR8/*.d > /dev/null 2>&1 -rm LUFA/Drivers/USB/Core/AVR8/*.o > /dev/null 2>&1 -rm LUFA/Drivers/USB/Class/Common/*.d > /dev/null 2>&1 -rm LUFA/Drivers/USB/Class/Common/*.d > /dev/null 2>&1 - echo "Finished cleaning build files." diff --git a/NativePrograms/00-FlashUnix.sh b/NativePrograms/NintendoSwitch/00-FlashUnix.sh old mode 100755 new mode 100644 similarity index 93% rename from NativePrograms/00-FlashUnix.sh rename to NativePrograms/NintendoSwitch/00-FlashUnix.sh index a654e0359a..0f4e3dd198 --- a/NativePrograms/00-FlashUnix.sh +++ b/NativePrograms/NintendoSwitch/00-FlashUnix.sh @@ -11,8 +11,16 @@ DEVICE_PATH=$3 if [[ "$OSTYPE" == "darwin"* ]]; then PLATFORM="mac" + FZF=$(which fzf) + + if [[ "$FZF" == "" ]]; then + boxed_msg "${RED}ERROR: FZF is not detected on your system. Please install it through Homebrew ${RESET}" + exit 1 + fi + elif [[ "$OSTYPE" == "linux-gnu"* ]]; then PLATFORM="linux" + FZF="../Scripts/fzf-${PLATFORM}" else boxed_msg "${RED}${OSTYPE} is not a recognized platform. Please run only on Mac or Linux${RESET}" exit 1 @@ -23,7 +31,6 @@ BUILD_HEX="" HEXFILE="" PROGRAM_COMMAND="program_avrdude ${MCU} ${HEXFILE}" # Default to using avrdude BOARDS=(ArduinoUnoR3 ProMicro Teensy2 TeensyPP2) -FZF="Scripts/fzf-${PLATFORM}" function run() { @@ -79,7 +86,7 @@ function build_hex { note "Running Build Script" - sh Scripts/BuildOneUnix.sh "${BOARD}" "${PROGRAM}" > /dev/null 2>&1 + sh ../Scripts/BuildOneUnix.sh "${BOARD}" "${PROGRAM}" > /dev/null 2>&1 retVal=$? if [ $retVal -ne 0 ]; then @@ -174,7 +181,7 @@ function note() { } function board_prompt() { - BOARD=$(cat Scripts/Boards.txt | $FZF --height=15% --prompt="Choose your Board: ") + BOARD=$(cat ../Scripts/Boards.txt | $FZF --height=15% --prompt="Choose your Board: ") case $BOARD in "ArduinoUnoR3") MCU=atmega16u2 diff --git a/NativePrograms/FriendDelete.c b/NativePrograms/NintendoSwitch/FriendDelete.c similarity index 92% rename from NativePrograms/FriendDelete.c rename to NativePrograms/NintendoSwitch/FriendDelete.c index 1d3eacb6f5..e0c5ee27ed 100644 --- a/NativePrograms/FriendDelete.c +++ b/NativePrograms/NintendoSwitch/FriendDelete.c @@ -7,7 +7,7 @@ */ #include "Common/SwitchFramework/SwitchControllerDefs.h" -#include "PokemonSwShPrograms/FriendDelete.h" +#include "Programs/FriendDelete.h" diff --git a/NativePrograms/PABotBase.c b/NativePrograms/NintendoSwitch/PABotBase.c similarity index 82% rename from NativePrograms/PABotBase.c rename to NativePrograms/NintendoSwitch/PABotBase.c index ee57f569d7..ac1e4b6b3c 100644 --- a/NativePrograms/PABotBase.c +++ b/NativePrograms/NintendoSwitch/PABotBase.c @@ -6,7 +6,7 @@ * */ -//#include "PokemonSwShPrograms/PABotBase.h" +//#include "Programs/PABotBase.h" // // This program has no program-specific configurable options. diff --git a/NativePrograms/NintendoSwitch/ProgramList.txt b/NativePrograms/NintendoSwitch/ProgramList.txt new file mode 100644 index 0000000000..70bab12bb4 --- /dev/null +++ b/NativePrograms/NintendoSwitch/ProgramList.txt @@ -0,0 +1,2 @@ +FriendDelete +PABotBase diff --git a/NativePrograms/PokemonSwShPrograms/FriendDelete.h b/NativePrograms/NintendoSwitch/Programs/FriendDelete.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/FriendDelete.h rename to NativePrograms/NintendoSwitch/Programs/FriendDelete.h diff --git a/NativePrograms/PokemonSwShPrograms/PABotBase.h b/NativePrograms/NintendoSwitch/Programs/PABotBase.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/PABotBase.h rename to NativePrograms/NintendoSwitch/Programs/PABotBase.h diff --git a/NativePrograms/makefile b/NativePrograms/NintendoSwitch/makefile similarity index 54% rename from NativePrograms/makefile rename to NativePrograms/NintendoSwitch/makefile index 5ac7637dae..512864a7e1 100644 --- a/NativePrograms/makefile +++ b/NativePrograms/NintendoSwitch/makefile @@ -30,6 +30,11 @@ endif ################################################################################ # Ignore all this stuff below. +PATH_PUBLIC = ../../ +PATH_INTERNAL = ../../../Internal + +CATEGORY = NintendoSwitch + #MCU = atmega16u2 ARCH = AVR8 F_CPU = 16000000 @@ -37,8 +42,8 @@ F_USB = $(F_CPU) OPTIMIZATION = s #TARGET = TurboA SRC = $(TARGET).c -LUFA_PATH = ./LUFA -CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -I./ -I../ -ILUFA/ -Wno-unused-function -Werror +LUFA_PATH = $(PATH_PUBLIC)/NativePrograms/LUFA +CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -I$(PATH_PUBLIC) -I$(PATH_PUBLIC)/NativePrograms/LUFA/ -Wno-unused-function -Werror @@ -46,40 +51,39 @@ CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -I./ -I../ -ILUFA/ -Wno-unused-function # Board ifeq ($(BOARD_TYPE), ArduinoUnoR3) MCU := atmega16u2 -SRC += DeviceFramework/Board-atmega16u2-ArduinoUnoR3.c +SRC += $(PATH_PUBLIC)/NativePrograms/DeviceFramework/Board-atmega16u2-ArduinoUnoR3.c endif ifeq ($(BOARD_TYPE), ProMicro) MCU := atmega32u4 -SRC += DeviceFramework/Board-atmega32u4-ProMicro.c +SRC += $(PATH_PUBLIC)/NativePrograms/DeviceFramework/Board-atmega32u4-ProMicro.c endif ifeq ($(BOARD_TYPE), Teensy2) MCU := atmega32u4 -SRC += DeviceFramework/Board-atmega32u4-Teensy2.c +SRC += $(PATH_PUBLIC)/NativePrograms/DeviceFramework/Board-atmega32u4-Teensy2.c endif ifeq ($(BOARD_TYPE), TeensyPP2) MCU := at90usb1286 -SRC += DeviceFramework/Board-at90usb1286-Teensy2.c +SRC += $(PATH_PUBLIC)/NativePrograms/DeviceFramework/Board-at90usb1286-Teensy2.c endif # Framework SRC += $(LUFA_SRC_USB) -SRC += ../Common/SwitchFramework/FrameworkSettings.c -SRC += DeviceFramework/DeviceSettings.c -SRC += PokemonSwShLibraries/PokemonCallbacks.c -ifneq ("$(wildcard ../../Internal/NativePrograms/SwitchFramework/Switch_PushButtons.c)","") -CC_FLAGS += -I../../Internal -SRC += ../Common/CRC32.c -SRC += ../../Internal/NativePrograms/SwitchFramework/uart.c -SRC += ../../Internal/NativePrograms/SwitchFramework/HardwareUSB.c +SRC += $(PATH_PUBLIC)/Common/SwitchFramework/FrameworkSettings.c +SRC += $(PATH_PUBLIC)/NativePrograms/DeviceFramework/DeviceSettings.c +ifneq ("$(wildcard $(PATH_INTERNAL)/NativePrograms/SwitchFramework/Switch_PushButtons.c)","") +CC_FLAGS += -I$(PATH_INTERNAL) +SRC += $(PATH_PUBLIC)/Common/CRC32.c +SRC += $(PATH_INTERNAL)/NativePrograms/SwitchFramework/uart.c +SRC += $(PATH_INTERNAL)/NativePrograms/SwitchFramework/HardwareUSB.c ifeq ($(TARGET), PABotBase) -SRC += ../../Internal/NativePrograms/SwitchFramework/CommandQueue.c +SRC += $(PATH_INTERNAL)/NativePrograms/SwitchFramework/CommandQueue.c else -SRC += ../../Internal/NativePrograms/SwitchFramework/CommandQueueNull.c +SRC += $(PATH_INTERNAL)/NativePrograms/SwitchFramework/CommandQueueNull.c endif -SRC += ../../Internal/NativePrograms/SwitchFramework/HardwareSerial.c -SRC += ../../Internal/NativePrograms/SwitchFramework/Controller.c -SRC += ../../Internal/NativePrograms/SwitchFramework/Switch_PushButtons.c -SRC += ../../Internal/NativePrograms/SwitchFramework/Switch_ScalarButtons.c +SRC += $(PATH_INTERNAL)/NativePrograms/SwitchFramework/HardwareSerial.c +SRC += $(PATH_INTERNAL)/NativePrograms/SwitchFramework/Controller.c +SRC += $(PATH_INTERNAL)/NativePrograms/SwitchFramework/Switch_PushButtons.c +SRC += $(PATH_INTERNAL)/NativePrograms/SwitchFramework/Switch_ScalarButtons.c else LD_FLAGS += obj/obj-$(MCU)/CRC32.o LD_FLAGS += obj/obj-$(MCU)/uart.o @@ -95,17 +99,16 @@ LD_FLAGS += obj/obj-$(MCU)/Switch_PushButtons.o LD_FLAGS += obj/obj-$(MCU)/Switch_ScalarButtons.o endif -# Pokemon Sword/Shield -SRC += ../Common/PokemonSwSh/PokemonSettings.c -ifneq ("$(wildcard ../../Internal/NativePrograms/PokemonSwShPrograms/$(TARGET)_Core.c)","") -SRC += ../../Internal/NativePrograms/PokemonSwShPrograms/$(TARGET)_Core.c -else ifneq ("$(wildcard PokemonSwShPrograms/$(TARGET)_Core.c)","") -SRC += PokemonSwShPrograms/$(TARGET)_Core.c +# Program +SRC += $(PATH_PUBLIC)/Common/PokemonSwSh/PokemonSettings.c +ifneq ("$(wildcard $(PATH_INTERNAL)/NativePrograms/$(CATEGORY)/$(TARGET)_Core.c)","") +SRC += $(PATH_INTERNAL)/NativePrograms/$(CATEGORY)/$(TARGET)_Core.c +else ifneq ("$(wildcard Programs/$(TARGET)_Core.c)","") +SRC += Programs/$(TARGET)_Core.c else ifneq ("$(wildcard obj/obj-$(MCU)/$(TARGET)_Core.o)","") LD_FLAGS += obj/obj-$(MCU)/$(TARGET)_Core.o endif - # Must go at the end or it blows up memory if floating-point is used. LD_FLAGS += -lm diff --git a/NativePrograms/PokemonSwSh/!BuildAll-ArduinoUnoR3.cmd b/NativePrograms/PokemonSwSh/!BuildAll-ArduinoUnoR3.cmd new file mode 100644 index 0000000000..7fc90f1c06 --- /dev/null +++ b/NativePrograms/PokemonSwSh/!BuildAll-ArduinoUnoR3.cmd @@ -0,0 +1,15 @@ +@echo off + +cd /D "%~dp0" + +if not exist Programs\ ( + echo. + echo Please unzip the folder before you can use it. + echo. + pause + exit +) + +@call ../Scripts/BuildAll.cmd ArduinoUnoR3 + + diff --git a/NativePrograms/!BuildAll-Teensy++2.0.cmd b/NativePrograms/PokemonSwSh/!BuildAll-ProMicro.cmd similarity index 61% rename from NativePrograms/!BuildAll-Teensy++2.0.cmd rename to NativePrograms/PokemonSwSh/!BuildAll-ProMicro.cmd index 3db40a1566..b1ece4743b 100644 --- a/NativePrograms/!BuildAll-Teensy++2.0.cmd +++ b/NativePrograms/PokemonSwSh/!BuildAll-ProMicro.cmd @@ -2,7 +2,7 @@ cd /D "%~dp0" -if not exist Scripts\ ( +if not exist Programs\ ( echo. echo Please unzip the folder before you can use it. echo. @@ -10,6 +10,6 @@ if not exist Scripts\ ( exit ) -@call Scripts/BuildAll.cmd TeensyPP2 +@call ../Scripts/BuildAll.cmd ProMicro diff --git a/NativePrograms/PokemonSwSh/!BuildAll-Teensy++2.0.cmd b/NativePrograms/PokemonSwSh/!BuildAll-Teensy++2.0.cmd new file mode 100644 index 0000000000..e30eb5dfe0 --- /dev/null +++ b/NativePrograms/PokemonSwSh/!BuildAll-Teensy++2.0.cmd @@ -0,0 +1,15 @@ +@echo off + +cd /D "%~dp0" + +if not exist Programs\ ( + echo. + echo Please unzip the folder before you can use it. + echo. + pause + exit +) + +@call ../Scripts/BuildAll.cmd TeensyPP2 + + diff --git a/NativePrograms/!BuildAll-ProMicro.cmd b/NativePrograms/PokemonSwSh/!BuildAll-Teensy2.0.cmd similarity index 61% rename from NativePrograms/!BuildAll-ProMicro.cmd rename to NativePrograms/PokemonSwSh/!BuildAll-Teensy2.0.cmd index 64f1d52a52..84f90a817e 100644 --- a/NativePrograms/!BuildAll-ProMicro.cmd +++ b/NativePrograms/PokemonSwSh/!BuildAll-Teensy2.0.cmd @@ -2,7 +2,7 @@ cd /D "%~dp0" -if not exist Scripts\ ( +if not exist Programs\ ( echo. echo Please unzip the folder before you can use it. echo. @@ -10,6 +10,6 @@ if not exist Scripts\ ( exit ) -@call Scripts/BuildAll.cmd ProMicro +@call ../Scripts/BuildAll.cmd Teensy2 diff --git a/NativePrograms/PokemonSwSh/!Cleanup.cmd b/NativePrograms/PokemonSwSh/!Cleanup.cmd new file mode 100644 index 0000000000..7832b61049 --- /dev/null +++ b/NativePrograms/PokemonSwSh/!Cleanup.cmd @@ -0,0 +1,21 @@ +:: Clean the build. Delete all build artifacts. + +cd %~dp0 + +del *.log +del *.d +del *.elf +del *.hex +del *.map +del *.o +del *.eep +del *.bin +del *.lss +del *.sym +del *.tmp + +del obj\*.d +del obj\*.o +del obj\build-* + +::pause diff --git a/NativePrograms/PokemonSwSh/00-BuildAllUnix.sh b/NativePrograms/PokemonSwSh/00-BuildAllUnix.sh new file mode 100644 index 0000000000..a543c0de94 --- /dev/null +++ b/NativePrograms/PokemonSwSh/00-BuildAllUnix.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash + +# change directory to library location +cd "$(dirname "$0")" + +# define the MCU, which is the board type + +if [[ "$OSTYPE" == "darwin"* ]]; then + PLATFORM="mac" + FZF=$(which fzf) + + if [[ "$FZF" == "" ]]; then + boxed_msg "${RED}ERROR: FZF is not detected on your system. Please install it through Homebrew ${RESET}" + exit 1 + fi + +elif [[ "$OSTYPE" == "linux-gnu"* ]]; then + PLATFORM="linux" + FZF="../Scripts/fzf-${PLATFORM}" +else + boxed_msg "${RED}${OSTYPE} is not a recognized platform. Please run only on Mac or Linux${RESET}" + exit 1 +fi + +BOARD=$1 + +function run() { + if [[ -z "$BOARD" ]]; then + board_prompt + fi + + # if the boards were given by integer, we can update them here + + + # say what we're building for convenience + echo "Ready to build for board: $BOARD" + echo "" + + # and send off to build + bash ../Scripts/BuildAllUnix.sh "$BOARD" #1> /dev/null + + # let them know we finished + echo -e "\033[1mFinished building hex files for board: $BOARD \033[0m" + echo "Please make sure the hex files were properly built or updated." + echo "You can now close this window if you wish." + echo "" + # really done +} + +function board_prompt() { + BOARD=$(cat ../Scripts/Boards.txt | $FZF --height=15% --prompt="Choose your Board: ") +} + +run diff --git a/NativePrograms/PokemonSwSh/00-CleanupUnix.sh b/NativePrograms/PokemonSwSh/00-CleanupUnix.sh new file mode 100644 index 0000000000..3e3789e7cc --- /dev/null +++ b/NativePrograms/PokemonSwSh/00-CleanupUnix.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# this script removes all compiled pieces to create a fresh directory + +# change directory to library location +cd "$(dirname "$0")" + +# NOTE: /dev/null forwarding is to ensure that nothing is printed if the files were already deleted +rm *.log > /dev/null 2>&1 +rm *.d > /dev/null 2>&1 +rm *.elf > /dev/null 2>&1 +rm *.hex > /dev/null 2>&1 +rm *.map > /dev/null 2>&1 +rm *.o > /dev/null 2>&1 +rm *.eep > /dev/null 2>&1 +rm *.bin > /dev/null 2>&1 +rm *.lss > /dev/null 2>&1 +rm *.sym > /dev/null 2>&1 +rm *.tmp > /dev/null 2>&1 + +# compiled pieces within Libraries, Programs, and obj +rm Libraries/*.d > /dev/null 2>&1 +rm Libraries/*.o > /dev/null 2>&1 + +rm Programs/*.d > /dev/null 2>&1 +rm Programs/*.o > /dev/null 2>&1 + +rm obj/*.d > /dev/null 2>&1 +rm obj/*.o > /dev/null 2>&1 + +echo "Finished cleaning build files." diff --git a/NativePrograms/PokemonSwSh/00-FlashUnix.sh b/NativePrograms/PokemonSwSh/00-FlashUnix.sh new file mode 100644 index 0000000000..0f4e3dd198 --- /dev/null +++ b/NativePrograms/PokemonSwSh/00-FlashUnix.sh @@ -0,0 +1,219 @@ +#!/usr/bin/env bash + +# change directory to library location +cd "$(dirname "$0")" || exit + +# Parse Command line arguments for MCU, Program and Device Path +BOARD=$1 +PROGRAM=$2 +DEVICE_PATH=$3 + + +if [[ "$OSTYPE" == "darwin"* ]]; then + PLATFORM="mac" + FZF=$(which fzf) + + if [[ "$FZF" == "" ]]; then + boxed_msg "${RED}ERROR: FZF is not detected on your system. Please install it through Homebrew ${RESET}" + exit 1 + fi + +elif [[ "$OSTYPE" == "linux-gnu"* ]]; then + PLATFORM="linux" + FZF="../Scripts/fzf-${PLATFORM}" +else + boxed_msg "${RED}${OSTYPE} is not a recognized platform. Please run only on Mac or Linux${RESET}" + exit 1 +fi + +SUDO="" +BUILD_HEX="" +HEXFILE="" +PROGRAM_COMMAND="program_avrdude ${MCU} ${HEXFILE}" # Default to using avrdude +BOARDS=(ArduinoUnoR3 ProMicro Teensy2 TeensyPP2) + +function run() { + + configure + + if [[ $BUILD_HEX == "y" ]]; then + build_hex + fi + + boxed_msg "Flashing ${PROGRAM}.hex ..." + $PROGRAM_COMMAND + + boxed_msg "Finished flashing ${HEXFILE} to ${BOARD}!" +} + +function configure() { + boxed_msg "Configuration" + + [[ -f "${HOME}/.paconfig" ]] && source "${HOME}/.paconfig" + [[ "$EUID" -ne 0 ]] && SUDO="sudo" + [[ -z "${BOARD}" ]] && board_prompt || note "Using Preconfigured BOARD [${BOARD}]" + [[ -z "${PROGRAM}" ]] && prog_prompt + + if [[ ! -f ${HEXFILE} ]]; then + question "Build ${PROGRAM}? ${WHITE}[Y/n]${RESET}" "DOBUILD" + DOBUILD="${DOBUILD:-y}" + if [ "$DOBUILD" == "y" ]; then + BUILD_HEX="y" + else + logmsg "Nothing to flash, exiting.." + exit + fi + fi + + # Logic below to determine if we need to us dfu-programmer or not + if [[ $PLATFORM == "mac" ]] && [[ ${MCU} == "atmega16u2" ]]; then + which dfu-programmer >/dev/null 2>&1 + if [[ $? -eq 0 ]]; then + question "Mac platform detected, UNO R3 configured. Connect your device and enter DFU mode, then press any key..." "use_dfu" + PROGRAM_COMMAND="program_dfu ${MCU} ${HEXFILE}" + else + logmsg "dfu-programmer not installed, run \"brew install dfu-programmer\" then rerun this script" + exit 1 + fi + fi +} + +function build_hex { + boxed_msg "Build ${PROGRAM}.c" + + note "Cleaning Build Environment" + ./00-CleanupUnix.sh >/dev/null + + + note "Running Build Script" + sh ../Scripts/BuildOneUnix.sh "${BOARD}" "${PROGRAM}" > /dev/null 2>&1 + + retVal=$? + if [ $retVal -ne 0 ]; then + boxed_msg "${RED}ERROR - CRITICAL: An error occured while building.\nPlease check logs and perhaps run the cleanup script before trying again.${RESET}" + exit 1 + else + note "${PROGRAM}.hex successfully built!" + fi + +} + +function detect_device() { + local -r delay='0.75' + local spinstr='\|/-' + local temp + while true; do + temp="${spinstr#?}" + printf "${YELLOW}Waiting for device... [%c] ${RESET}" "${spinstr}" + spinstr=${temp}${spinstr%"${temp}"} + # shellcheck disable=SC2010 + found_device_path="$(ls /dev/tty* | grep -i 'acm\|usb')" + if [[ -n "$found_device_path" ]]; then + DEVICE_PATH="${found_device_path}" + break + fi + sleep "${delay}" + printf "%0.s\b" {1..28} + done + printf " \b\b\b\b\n" + boxed_msg "Device connected at [${found_device_path}]" "short" +} + +function program_dfu { + # start with clearing the BOARD + ${SUDO} dfu-programmer "${MCU}" erase || true + # then flash the hex to the BOARD + ${SUDO} dfu-programmer "${MCU}" flash "${HEXFILE}" + if [[ $? -ne 0 ]]; then + boxed_msg "${RED}Flash Error: Check the output above for more info.${RESET}" + exit 1 + fi + # then reset the BOARD + ${SUDO} dfu-programmer "${MCU}" reset + if [[ $? -ne 0 ]]; then + boxed_msg "${RED}Device Reset Error: Check the output above for more info.${RESET}" + exit 1 + fi +} + +function program_avrdude { + if [[ $AUTODETECT_DEVICE == "y" ]]; then + note "Autodetect enabled..." + detect_device + elif [[ -z $DEVICE_PATH ]] && [[ -z $autodetect_device ]]; then + question "Would you like to attempt auto detecting your device? ${WHITE}[y/n]${RESET}" "autodetect_device" + autodetect_device="${autodetect_device:-y}" + if [[ $autodetect_device == "n" ]]; then + question "Please enter the path to your device ${WHITE}(ex. /dev/ttyACM0)${RESET}" "DEVICE_PATH" + elif [[ $autodetect_device == "y" ]]; then + detect_device + else + note "Invalid input, defaulting to autodetection" + detect_device + fi + fi + + note "Attempting to flash ${WHITE}${PROGRAM}.hex${RESET} to ${WHITE}${DEVICE_PATH}${RESET} now" + ${SUDO} avrdude -q -p "${MCU}" -P "${DEVICE_PATH}" -c avr109 -U flash:w:"${HEXFILE}" +} + +function boxed_msg() { + msg=$1 + len=$2 + [[ $len == short ]] && div="\n===============\n" || div="\n=================================\n" + echo -e "${div}${GREEN}${msg}${RESET}${div}" +} + +function question() { + echo -e "\n${YELLOW}${1}: ${RESET}" + read -r "$2" +} + +function logmsg { + msg=$1 + echo -e "${LBLUE}${msg}${RESET}" +} + +function note() { + msg=$1 + div='** ' + echo -e "${YELLOW}${div}${msg}${RESET}" +} + +function board_prompt() { + BOARD=$(cat ../Scripts/Boards.txt | $FZF --height=15% --prompt="Choose your Board: ") + case $BOARD in + "ArduinoUnoR3") + MCU=atmega16u2 + ;; + "ProMicro") + MCU=atmega32u4 + ;; + "Teensy2") + MCU=atmega32u4 + ;; + "TeensyPP2") + MCU=at90usb1286 + ;; + *) + note "Invalid Board" + exit 1 + esac +} + +function prog_prompt() { + PROGRAM=$(ls -1 *.c 2> /dev/null | sed 's/\.c//g' | $FZF --height=15% --prompt="Program to Flash: " ) + HEXFILE="${PROGRAM}.hex" +} + +## Color Helpers +RED=$'\e[1;31m' +YELLOW=$'\e[1;33m' +GREEN=$'\e[1;32m' +LBLUE=$'\e[1;34m' +WHITE=$'\e[1;37m' +RESET=$'\e[0m' + +# LEZZGOOO! +run + diff --git a/NativePrograms/AutoHost-MultiGame.c b/NativePrograms/PokemonSwSh/AutoHost-MultiGame.c similarity index 96% rename from NativePrograms/AutoHost-MultiGame.c rename to NativePrograms/PokemonSwSh/AutoHost-MultiGame.c index 3d6704beb5..2939f0c5bf 100644 --- a/NativePrograms/AutoHost-MultiGame.c +++ b/NativePrograms/PokemonSwSh/AutoHost-MultiGame.c @@ -7,7 +7,7 @@ */ #include "Common/SwitchFramework/SwitchControllerDefs.h" -#include "PokemonSwShPrograms/AutoHost-MultiGame.h" +#include "Programs/AutoHost-MultiGame.h" diff --git a/NativePrograms/AutoHost-Rolling.c b/NativePrograms/PokemonSwSh/AutoHost-Rolling.c similarity index 96% rename from NativePrograms/AutoHost-Rolling.c rename to NativePrograms/PokemonSwSh/AutoHost-Rolling.c index 19bde262c9..562db02280 100644 --- a/NativePrograms/AutoHost-Rolling.c +++ b/NativePrograms/PokemonSwSh/AutoHost-Rolling.c @@ -8,7 +8,7 @@ #include "Common/SwitchFramework/SwitchControllerDefs.h" #include "Common/PokemonSwSh/PokemonSettings.h" -#include "PokemonSwShPrograms/AutoHost-Rolling.h" +#include "Programs/AutoHost-Rolling.h" diff --git a/NativePrograms/BallThrower.c b/NativePrograms/PokemonSwSh/BallThrower.c similarity index 82% rename from NativePrograms/BallThrower.c rename to NativePrograms/PokemonSwSh/BallThrower.c index cfefce7e0c..626dc60e54 100644 --- a/NativePrograms/BallThrower.c +++ b/NativePrograms/PokemonSwSh/BallThrower.c @@ -6,7 +6,7 @@ * */ -#include "PokemonSwShPrograms/BallThrower.h" +#include "Programs/BallThrower.h" // // This program has no program-specific configurable options. diff --git a/NativePrograms/BeamReset.c b/NativePrograms/PokemonSwSh/BeamReset.c similarity index 89% rename from NativePrograms/BeamReset.c rename to NativePrograms/PokemonSwSh/BeamReset.c index 48ec96d475..18f1f97463 100644 --- a/NativePrograms/BeamReset.c +++ b/NativePrograms/PokemonSwSh/BeamReset.c @@ -7,7 +7,7 @@ */ #include "Common/SwitchFramework/SwitchControllerDefs.h" -#include "PokemonSwShPrograms/BeamReset.h" +#include "Programs/BeamReset.h" diff --git a/NativePrograms/ClothingBuyer.c b/NativePrograms/PokemonSwSh/ClothingBuyer.c similarity index 87% rename from NativePrograms/ClothingBuyer.c rename to NativePrograms/PokemonSwSh/ClothingBuyer.c index 0e87453c8e..6ff9091064 100644 --- a/NativePrograms/ClothingBuyer.c +++ b/NativePrograms/PokemonSwSh/ClothingBuyer.c @@ -6,7 +6,7 @@ * */ -#include "PokemonSwShPrograms/ClothingBuyer.h" +#include "Programs/ClothingBuyer.h" // Rotate categories. This will allow the program to eventually buy out the diff --git a/NativePrograms/CustomProgram.c b/NativePrograms/PokemonSwSh/CustomProgram.c similarity index 92% rename from NativePrograms/CustomProgram.c rename to NativePrograms/PokemonSwSh/CustomProgram.c index f86f5dd6db..a5e41b88ea 100644 --- a/NativePrograms/CustomProgram.c +++ b/NativePrograms/PokemonSwSh/CustomProgram.c @@ -24,7 +24,7 @@ // Thus to add a new program, you must edit all of the above. // -#include "PokemonSwShPrograms/CustomProgram.h" +#include "Programs/CustomProgram.h" // Setting definitions and defaults go here. diff --git a/NativePrograms/DateSpam-BerryFarmer.c b/NativePrograms/PokemonSwSh/DateSpam-BerryFarmer.c similarity index 89% rename from NativePrograms/DateSpam-BerryFarmer.c rename to NativePrograms/PokemonSwSh/DateSpam-BerryFarmer.c index c39c117cb9..c1f4979357 100644 --- a/NativePrograms/DateSpam-BerryFarmer.c +++ b/NativePrograms/PokemonSwSh/DateSpam-BerryFarmer.c @@ -6,7 +6,7 @@ * */ -#include "PokemonSwShPrograms/DateSpam-BerryFarmer.h" +#include "Programs/DateSpam-BerryFarmer.h" diff --git a/NativePrograms/DateSpam-DailyHighlightFarmer.c b/NativePrograms/PokemonSwSh/DateSpam-DailyHighlightFarmer.c similarity index 88% rename from NativePrograms/DateSpam-DailyHighlightFarmer.c rename to NativePrograms/PokemonSwSh/DateSpam-DailyHighlightFarmer.c index 9f58ea8f36..434b59eecc 100644 --- a/NativePrograms/DateSpam-DailyHighlightFarmer.c +++ b/NativePrograms/PokemonSwSh/DateSpam-DailyHighlightFarmer.c @@ -6,7 +6,7 @@ * */ -#include "PokemonSwShPrograms/DateSpam-DailyHighlightFarmer.h" +#include "Programs/DateSpam-DailyHighlightFarmer.h" diff --git a/NativePrograms/DateSpam-LotoFarmer.c b/NativePrograms/PokemonSwSh/DateSpam-LotoFarmer.c similarity index 83% rename from NativePrograms/DateSpam-LotoFarmer.c rename to NativePrograms/PokemonSwSh/DateSpam-LotoFarmer.c index bf96d570e9..35b0329f39 100644 --- a/NativePrograms/DateSpam-LotoFarmer.c +++ b/NativePrograms/PokemonSwSh/DateSpam-LotoFarmer.c @@ -7,7 +7,7 @@ */ #include "Common/SwitchFramework/SwitchControllerDefs.h" -#include "PokemonSwShPrograms/DateSpam-LotoFarmer.h" +#include "Programs/DateSpam-LotoFarmer.h" @@ -20,4 +20,4 @@ const uint32_t SKIPS = 100000; // Mash B for this long to exit the dialog. // For some languages, (like German), you may need to increase this. -const uint16_t MASH_B_DURATION = 8 * TICKS_PER_SECOND; +const uint16_t MASH_B_DURATION = 9 * TICKS_PER_SECOND; diff --git a/NativePrograms/DateSpam-StowOnSideFarmer.c b/NativePrograms/PokemonSwSh/DateSpam-StowOnSideFarmer.c similarity index 89% rename from NativePrograms/DateSpam-StowOnSideFarmer.c rename to NativePrograms/PokemonSwSh/DateSpam-StowOnSideFarmer.c index ebf85f19d3..80f375d812 100644 --- a/NativePrograms/DateSpam-StowOnSideFarmer.c +++ b/NativePrograms/PokemonSwSh/DateSpam-StowOnSideFarmer.c @@ -6,7 +6,7 @@ * */ -#include "PokemonSwShPrograms/DateSpam-StowOnSideFarmer.h" +#include "Programs/DateSpam-StowOnSideFarmer.h" diff --git a/NativePrograms/DateSpam-WattFarmer.c b/NativePrograms/PokemonSwSh/DateSpam-WattFarmer.c similarity index 89% rename from NativePrograms/DateSpam-WattFarmer.c rename to NativePrograms/PokemonSwSh/DateSpam-WattFarmer.c index 0a4e430ad0..5493cfd11e 100644 --- a/NativePrograms/DateSpam-WattFarmer.c +++ b/NativePrograms/PokemonSwSh/DateSpam-WattFarmer.c @@ -6,7 +6,7 @@ * */ -#include "PokemonSwShPrograms/DateSpam-WattFarmer.h" +#include "Programs/DateSpam-WattFarmer.h" diff --git a/NativePrograms/DaySkipperEU.c b/NativePrograms/PokemonSwSh/DaySkipperEU.c similarity index 93% rename from NativePrograms/DaySkipperEU.c rename to NativePrograms/PokemonSwSh/DaySkipperEU.c index ccb1614031..f52fac11be 100644 --- a/NativePrograms/DaySkipperEU.c +++ b/NativePrograms/PokemonSwSh/DaySkipperEU.c @@ -11,7 +11,7 @@ * */ -#include "PokemonSwShPrograms/DaySkipperEU.h" +#include "Programs/DaySkipperEU.h" diff --git a/NativePrograms/DaySkipperJPN-7.8k.c b/NativePrograms/PokemonSwSh/DaySkipperJPN-7.8k.c similarity index 93% rename from NativePrograms/DaySkipperJPN-7.8k.c rename to NativePrograms/PokemonSwSh/DaySkipperJPN-7.8k.c index 18397eecb1..cd9640d106 100644 --- a/NativePrograms/DaySkipperJPN-7.8k.c +++ b/NativePrograms/PokemonSwSh/DaySkipperJPN-7.8k.c @@ -15,7 +15,7 @@ * */ -#include "PokemonSwShPrograms/DaySkipperJPN-7.8k.h" +#include "Programs/DaySkipperJPN-7.8k.h" diff --git a/NativePrograms/DaySkipperJPN.c b/NativePrograms/PokemonSwSh/DaySkipperJPN.c similarity index 91% rename from NativePrograms/DaySkipperJPN.c rename to NativePrograms/PokemonSwSh/DaySkipperJPN.c index cf72f14ae9..14678dbff7 100644 --- a/NativePrograms/DaySkipperJPN.c +++ b/NativePrograms/PokemonSwSh/DaySkipperJPN.c @@ -6,7 +6,7 @@ * */ -#include "PokemonSwShPrograms/DaySkipperJPN.h" +#include "Programs/DaySkipperJPN.h" diff --git a/NativePrograms/DaySkipperUS.c b/NativePrograms/PokemonSwSh/DaySkipperUS.c similarity index 93% rename from NativePrograms/DaySkipperUS.c rename to NativePrograms/PokemonSwSh/DaySkipperUS.c index a3422bee19..69c32ec273 100644 --- a/NativePrograms/DaySkipperUS.c +++ b/NativePrograms/PokemonSwSh/DaySkipperUS.c @@ -11,7 +11,7 @@ * */ -#include "PokemonSwShPrograms/DaySkipperUS.h" +#include "Programs/DaySkipperUS.h" diff --git a/NativePrograms/DenRoller.c b/NativePrograms/PokemonSwSh/DenRoller.c similarity index 90% rename from NativePrograms/DenRoller.c rename to NativePrograms/PokemonSwSh/DenRoller.c index c88731396b..930a1105bf 100644 --- a/NativePrograms/DenRoller.c +++ b/NativePrograms/PokemonSwSh/DenRoller.c @@ -8,7 +8,7 @@ #include "Common/SwitchFramework/SwitchControllerDefs.h" #include "Common/PokemonSwSh/PokemonSettings.h" -#include "PokemonSwShPrograms/DenRoller.h" +#include "Programs/DenRoller.h" diff --git a/NativePrograms/EggCombined2.c b/NativePrograms/PokemonSwSh/EggCombined2.c similarity index 96% rename from NativePrograms/EggCombined2.c rename to NativePrograms/PokemonSwSh/EggCombined2.c index cecfff1527..8ec18f4a35 100644 --- a/NativePrograms/EggCombined2.c +++ b/NativePrograms/PokemonSwSh/EggCombined2.c @@ -7,7 +7,7 @@ */ #include "Common/SwitchFramework/SwitchControllerDefs.h" -#include "PokemonSwShPrograms/EggCombined2.h" +#include "Programs/EggCombined2.h" diff --git a/NativePrograms/EggFetcher2.c b/NativePrograms/PokemonSwSh/EggFetcher2.c similarity index 86% rename from NativePrograms/EggFetcher2.c rename to NativePrograms/PokemonSwSh/EggFetcher2.c index 262386fe12..571e53411d 100644 --- a/NativePrograms/EggFetcher2.c +++ b/NativePrograms/PokemonSwSh/EggFetcher2.c @@ -6,7 +6,7 @@ * */ -#include "PokemonSwShPrograms/EggFetcher2.h" +#include "Programs/EggFetcher2.h" diff --git a/NativePrograms/EggHatcher.c b/NativePrograms/PokemonSwSh/EggHatcher.c similarity index 94% rename from NativePrograms/EggHatcher.c rename to NativePrograms/PokemonSwSh/EggHatcher.c index 22c61874ca..331678ccb4 100644 --- a/NativePrograms/EggHatcher.c +++ b/NativePrograms/PokemonSwSh/EggHatcher.c @@ -7,7 +7,7 @@ */ #include "Common/SwitchFramework/SwitchControllerDefs.h" -#include "PokemonSwShPrograms/EggHatcher.h" +#include "Programs/EggHatcher.h" diff --git a/NativePrograms/EggSuperCombined2.c b/NativePrograms/PokemonSwSh/EggSuperCombined2.c similarity index 96% rename from NativePrograms/EggSuperCombined2.c rename to NativePrograms/PokemonSwSh/EggSuperCombined2.c index 2441ab0d99..e702576415 100644 --- a/NativePrograms/EggSuperCombined2.c +++ b/NativePrograms/PokemonSwSh/EggSuperCombined2.c @@ -7,7 +7,7 @@ */ #include "Common/SwitchFramework/SwitchControllerDefs.h" -#include "PokemonSwShPrograms/EggSuperCombined2.h" +#include "Programs/EggSuperCombined2.h" diff --git a/NativePrograms/EventBeamFinder.c b/NativePrograms/PokemonSwSh/EventBeamFinder.c similarity index 84% rename from NativePrograms/EventBeamFinder.c rename to NativePrograms/PokemonSwSh/EventBeamFinder.c index a45779bf38..150be0b8ba 100644 --- a/NativePrograms/EventBeamFinder.c +++ b/NativePrograms/PokemonSwSh/EventBeamFinder.c @@ -7,7 +7,7 @@ */ #include "Common/SwitchFramework/SwitchControllerDefs.h" -#include "PokemonSwShPrograms/EventBeamFinder.h" +#include "Programs/EventBeamFinder.h" diff --git a/NativePrograms/FastCodeEntry.c b/NativePrograms/PokemonSwSh/FastCodeEntry.c similarity index 86% rename from NativePrograms/FastCodeEntry.c rename to NativePrograms/PokemonSwSh/FastCodeEntry.c index 78b35a3b25..6467a365e9 100644 --- a/NativePrograms/FastCodeEntry.c +++ b/NativePrograms/PokemonSwSh/FastCodeEntry.c @@ -7,7 +7,7 @@ */ #include "Common/SwitchFramework/SwitchControllerDefs.h" -#include "PokemonSwShPrograms/FastCodeEntry.h" +#include "Programs/FastCodeEntry.h" diff --git a/NativePrograms/GodEggDuplication.c b/NativePrograms/PokemonSwSh/GodEggDuplication.c similarity index 92% rename from NativePrograms/GodEggDuplication.c rename to NativePrograms/PokemonSwSh/GodEggDuplication.c index 30fd8e93c1..8216c666b3 100644 --- a/NativePrograms/GodEggDuplication.c +++ b/NativePrograms/PokemonSwSh/GodEggDuplication.c @@ -12,7 +12,7 @@ * */ -#include "PokemonSwShPrograms/GodEggDuplication.h" +#include "Programs/GodEggDuplication.h" diff --git a/NativePrograms/GodEggItemDupe.c b/NativePrograms/PokemonSwSh/GodEggItemDupe.c similarity index 94% rename from NativePrograms/GodEggItemDupe.c rename to NativePrograms/PokemonSwSh/GodEggItemDupe.c index a1f5d3771c..ea389605b9 100644 --- a/NativePrograms/GodEggItemDupe.c +++ b/NativePrograms/PokemonSwSh/GodEggItemDupe.c @@ -6,7 +6,7 @@ * */ -#include "PokemonSwShPrograms/GodEggItemDupe.h" +#include "Programs/GodEggItemDupe.h" diff --git a/NativePrograms/MassRelease.c b/NativePrograms/PokemonSwSh/MassRelease.c similarity index 86% rename from NativePrograms/MassRelease.c rename to NativePrograms/PokemonSwSh/MassRelease.c index 3bcfa7d236..01d0482726 100644 --- a/NativePrograms/MassRelease.c +++ b/NativePrograms/PokemonSwSh/MassRelease.c @@ -6,7 +6,7 @@ * */ -#include "PokemonSwShPrograms/MassRelease.h" +#include "Programs/MassRelease.h" diff --git a/NativePrograms/MultiGameFossil.c b/NativePrograms/PokemonSwSh/MultiGameFossil.c similarity index 89% rename from NativePrograms/MultiGameFossil.c rename to NativePrograms/PokemonSwSh/MultiGameFossil.c index 2d050c786c..a1dfaf85e1 100644 --- a/NativePrograms/MultiGameFossil.c +++ b/NativePrograms/PokemonSwSh/MultiGameFossil.c @@ -6,7 +6,7 @@ * */ -#include "PokemonSwShPrograms/MultiGameFossil.h" +#include "Programs/MultiGameFossil.h" diff --git a/GeneratorConfig/ProgramList.txt b/NativePrograms/PokemonSwSh/ProgramList.txt similarity index 89% rename from GeneratorConfig/ProgramList.txt rename to NativePrograms/PokemonSwSh/ProgramList.txt index 6305516652..4553b5ecf6 100644 --- a/GeneratorConfig/ProgramList.txt +++ b/NativePrograms/PokemonSwSh/ProgramList.txt @@ -33,7 +33,6 @@ DaySkipperJPN-7.8k DenRoller AutoHost-Rolling AutoHost-MultiGame -FriendDelete EggFetcher2 EggHatcher @@ -43,11 +42,3 @@ EggSuperCombined2 FastCodeEntry GodEggDuplication GodEggItemDupe - -PABotBase - - - - - - diff --git a/NativePrograms/PokemonSwShPrograms/AutoHost-MultiGame.h b/NativePrograms/PokemonSwSh/Programs/AutoHost-MultiGame.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/AutoHost-MultiGame.h rename to NativePrograms/PokemonSwSh/Programs/AutoHost-MultiGame.h diff --git a/NativePrograms/PokemonSwShPrograms/AutoHost-Rolling.h b/NativePrograms/PokemonSwSh/Programs/AutoHost-Rolling.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/AutoHost-Rolling.h rename to NativePrograms/PokemonSwSh/Programs/AutoHost-Rolling.h diff --git a/NativePrograms/PokemonSwShPrograms/BallThrower.h b/NativePrograms/PokemonSwSh/Programs/BallThrower.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/BallThrower.h rename to NativePrograms/PokemonSwSh/Programs/BallThrower.h diff --git a/NativePrograms/PokemonSwShPrograms/BeamReset.h b/NativePrograms/PokemonSwSh/Programs/BeamReset.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/BeamReset.h rename to NativePrograms/PokemonSwSh/Programs/BeamReset.h diff --git a/NativePrograms/PokemonSwShPrograms/ClothingBuyer.h b/NativePrograms/PokemonSwSh/Programs/ClothingBuyer.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/ClothingBuyer.h rename to NativePrograms/PokemonSwSh/Programs/ClothingBuyer.h diff --git a/NativePrograms/PokemonSwShPrograms/CustomProgram.h b/NativePrograms/PokemonSwSh/Programs/CustomProgram.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/CustomProgram.h rename to NativePrograms/PokemonSwSh/Programs/CustomProgram.h diff --git a/NativePrograms/PokemonSwShPrograms/CustomProgram_Core.c b/NativePrograms/PokemonSwSh/Programs/CustomProgram_Core.c similarity index 93% rename from NativePrograms/PokemonSwShPrograms/CustomProgram_Core.c rename to NativePrograms/PokemonSwSh/Programs/CustomProgram_Core.c index 46a73af656..11ee65d3ef 100644 --- a/NativePrograms/PokemonSwShPrograms/CustomProgram_Core.c +++ b/NativePrograms/PokemonSwSh/Programs/CustomProgram_Core.c @@ -27,7 +27,7 @@ #include "Common/PokemonSwSh/PokemonSettings.h" #include "Common/PokemonSwSh/PokemonProgramIDs.h" #include "NativePrograms/DeviceFramework/DeviceSettings.h" -#include "NativePrograms/PokemonSwShPrograms/CustomProgram.h" +#include "NativePrograms/PokemonSwSh/Programs/CustomProgram.h" int main(void){ diff --git a/NativePrograms/PokemonSwShPrograms/DateSpam-BerryFarmer.h b/NativePrograms/PokemonSwSh/Programs/DateSpam-BerryFarmer.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/DateSpam-BerryFarmer.h rename to NativePrograms/PokemonSwSh/Programs/DateSpam-BerryFarmer.h diff --git a/NativePrograms/PokemonSwShPrograms/DateSpam-DailyHighlightFarmer.h b/NativePrograms/PokemonSwSh/Programs/DateSpam-DailyHighlightFarmer.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/DateSpam-DailyHighlightFarmer.h rename to NativePrograms/PokemonSwSh/Programs/DateSpam-DailyHighlightFarmer.h diff --git a/NativePrograms/PokemonSwShPrograms/DateSpam-LotoFarmer.h b/NativePrograms/PokemonSwSh/Programs/DateSpam-LotoFarmer.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/DateSpam-LotoFarmer.h rename to NativePrograms/PokemonSwSh/Programs/DateSpam-LotoFarmer.h diff --git a/NativePrograms/PokemonSwShPrograms/DateSpam-StowOnSideFarmer.h b/NativePrograms/PokemonSwSh/Programs/DateSpam-StowOnSideFarmer.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/DateSpam-StowOnSideFarmer.h rename to NativePrograms/PokemonSwSh/Programs/DateSpam-StowOnSideFarmer.h diff --git a/NativePrograms/PokemonSwShPrograms/DateSpam-WattFarmer.h b/NativePrograms/PokemonSwSh/Programs/DateSpam-WattFarmer.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/DateSpam-WattFarmer.h rename to NativePrograms/PokemonSwSh/Programs/DateSpam-WattFarmer.h diff --git a/NativePrograms/PokemonSwShPrograms/DaySkipperEU.h b/NativePrograms/PokemonSwSh/Programs/DaySkipperEU.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/DaySkipperEU.h rename to NativePrograms/PokemonSwSh/Programs/DaySkipperEU.h diff --git a/NativePrograms/PokemonSwShPrograms/DaySkipperJPN-7.8k.h b/NativePrograms/PokemonSwSh/Programs/DaySkipperJPN-7.8k.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/DaySkipperJPN-7.8k.h rename to NativePrograms/PokemonSwSh/Programs/DaySkipperJPN-7.8k.h diff --git a/NativePrograms/PokemonSwShPrograms/DaySkipperJPN.h b/NativePrograms/PokemonSwSh/Programs/DaySkipperJPN.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/DaySkipperJPN.h rename to NativePrograms/PokemonSwSh/Programs/DaySkipperJPN.h diff --git a/NativePrograms/PokemonSwShPrograms/DaySkipperUS.h b/NativePrograms/PokemonSwSh/Programs/DaySkipperUS.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/DaySkipperUS.h rename to NativePrograms/PokemonSwSh/Programs/DaySkipperUS.h diff --git a/NativePrograms/PokemonSwShPrograms/DenRoller.h b/NativePrograms/PokemonSwSh/Programs/DenRoller.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/DenRoller.h rename to NativePrograms/PokemonSwSh/Programs/DenRoller.h diff --git a/NativePrograms/PokemonSwShPrograms/EggCombined2.h b/NativePrograms/PokemonSwSh/Programs/EggCombined2.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/EggCombined2.h rename to NativePrograms/PokemonSwSh/Programs/EggCombined2.h diff --git a/NativePrograms/PokemonSwShPrograms/EggFetcher2.h b/NativePrograms/PokemonSwSh/Programs/EggFetcher2.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/EggFetcher2.h rename to NativePrograms/PokemonSwSh/Programs/EggFetcher2.h diff --git a/NativePrograms/PokemonSwShPrograms/EggHatcher.h b/NativePrograms/PokemonSwSh/Programs/EggHatcher.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/EggHatcher.h rename to NativePrograms/PokemonSwSh/Programs/EggHatcher.h diff --git a/NativePrograms/PokemonSwShPrograms/EggSuperCombined2.h b/NativePrograms/PokemonSwSh/Programs/EggSuperCombined2.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/EggSuperCombined2.h rename to NativePrograms/PokemonSwSh/Programs/EggSuperCombined2.h diff --git a/NativePrograms/PokemonSwShPrograms/EventBeamFinder.h b/NativePrograms/PokemonSwSh/Programs/EventBeamFinder.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/EventBeamFinder.h rename to NativePrograms/PokemonSwSh/Programs/EventBeamFinder.h diff --git a/NativePrograms/PokemonSwShPrograms/FastCodeEntry.h b/NativePrograms/PokemonSwSh/Programs/FastCodeEntry.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/FastCodeEntry.h rename to NativePrograms/PokemonSwSh/Programs/FastCodeEntry.h diff --git a/NativePrograms/PokemonSwShPrograms/GodEggDuplication.h b/NativePrograms/PokemonSwSh/Programs/GodEggDuplication.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/GodEggDuplication.h rename to NativePrograms/PokemonSwSh/Programs/GodEggDuplication.h diff --git a/NativePrograms/PokemonSwShPrograms/GodEggItemDupe.h b/NativePrograms/PokemonSwSh/Programs/GodEggItemDupe.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/GodEggItemDupe.h rename to NativePrograms/PokemonSwSh/Programs/GodEggItemDupe.h diff --git a/NativePrograms/PokemonSwShPrograms/MassRelease.h b/NativePrograms/PokemonSwSh/Programs/MassRelease.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/MassRelease.h rename to NativePrograms/PokemonSwSh/Programs/MassRelease.h diff --git a/NativePrograms/PokemonSwShPrograms/MultiGameFossil.h b/NativePrograms/PokemonSwSh/Programs/MultiGameFossil.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/MultiGameFossil.h rename to NativePrograms/PokemonSwSh/Programs/MultiGameFossil.h diff --git a/NativePrograms/PokemonSwShLibraries/PokemonCallbacks.c b/NativePrograms/PokemonSwSh/Programs/PokemonCallbacks.c similarity index 100% rename from NativePrograms/PokemonSwShLibraries/PokemonCallbacks.c rename to NativePrograms/PokemonSwSh/Programs/PokemonCallbacks.c diff --git a/NativePrograms/PokemonSwShLibraries/PokemonCallbacks.h b/NativePrograms/PokemonSwSh/Programs/PokemonCallbacks.h similarity index 100% rename from NativePrograms/PokemonSwShLibraries/PokemonCallbacks.h rename to NativePrograms/PokemonSwSh/Programs/PokemonCallbacks.h diff --git a/NativePrograms/PokemonSwShPrograms/ShinyHunt-Regi.h b/NativePrograms/PokemonSwSh/Programs/ShinyHunt-Regi.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/ShinyHunt-Regi.h rename to NativePrograms/PokemonSwSh/Programs/ShinyHunt-Regi.h diff --git a/NativePrograms/PokemonSwShPrograms/ShinyHunt-SwordsOfJustice.h b/NativePrograms/PokemonSwSh/Programs/ShinyHunt-SwordsOfJustice.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/ShinyHunt-SwordsOfJustice.h rename to NativePrograms/PokemonSwSh/Programs/ShinyHunt-SwordsOfJustice.h diff --git a/NativePrograms/PokemonSwShPrograms/ShinyHuntUnattended-IoATrade.h b/NativePrograms/PokemonSwSh/Programs/ShinyHuntUnattended-IoATrade.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/ShinyHuntUnattended-IoATrade.h rename to NativePrograms/PokemonSwSh/Programs/ShinyHuntUnattended-IoATrade.h diff --git a/NativePrograms/PokemonSwShPrograms/ShinyHuntUnattended-Regi.h b/NativePrograms/PokemonSwSh/Programs/ShinyHuntUnattended-Regi.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/ShinyHuntUnattended-Regi.h rename to NativePrograms/PokemonSwSh/Programs/ShinyHuntUnattended-Regi.h diff --git a/NativePrograms/PokemonSwShPrograms/ShinyHuntUnattended-Regigigas.h b/NativePrograms/PokemonSwSh/Programs/ShinyHuntUnattended-Regigigas.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/ShinyHuntUnattended-Regigigas.h rename to NativePrograms/PokemonSwSh/Programs/ShinyHuntUnattended-Regigigas.h diff --git a/NativePrograms/PokemonSwShPrograms/ShinyHuntUnattended-Regigigas2.h b/NativePrograms/PokemonSwSh/Programs/ShinyHuntUnattended-Regigigas2.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/ShinyHuntUnattended-Regigigas2.h rename to NativePrograms/PokemonSwSh/Programs/ShinyHuntUnattended-Regigigas2.h diff --git a/NativePrograms/PokemonSwShPrograms/ShinyHuntUnattended-StrongSpawn.h b/NativePrograms/PokemonSwSh/Programs/ShinyHuntUnattended-StrongSpawn.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/ShinyHuntUnattended-StrongSpawn.h rename to NativePrograms/PokemonSwSh/Programs/ShinyHuntUnattended-StrongSpawn.h diff --git a/NativePrograms/PokemonSwShPrograms/ShinyHuntUnattended-SwordsOfJustice.h b/NativePrograms/PokemonSwSh/Programs/ShinyHuntUnattended-SwordsOfJustice.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/ShinyHuntUnattended-SwordsOfJustice.h rename to NativePrograms/PokemonSwSh/Programs/ShinyHuntUnattended-SwordsOfJustice.h diff --git a/NativePrograms/PokemonSwShPrograms/SurpriseTrade.h b/NativePrograms/PokemonSwSh/Programs/SurpriseTrade.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/SurpriseTrade.h rename to NativePrograms/PokemonSwSh/Programs/SurpriseTrade.h diff --git a/NativePrograms/PokemonSwShPrograms/TradeBot.h b/NativePrograms/PokemonSwSh/Programs/TradeBot.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/TradeBot.h rename to NativePrograms/PokemonSwSh/Programs/TradeBot.h diff --git a/NativePrograms/PokemonSwShPrograms/TurboA.h b/NativePrograms/PokemonSwSh/Programs/TurboA.h similarity index 100% rename from NativePrograms/PokemonSwShPrograms/TurboA.h rename to NativePrograms/PokemonSwSh/Programs/TurboA.h diff --git a/NativePrograms/README.md b/NativePrograms/PokemonSwSh/README.md similarity index 100% rename from NativePrograms/README.md rename to NativePrograms/PokemonSwSh/README.md diff --git a/NativePrograms/README_Mac_Linux.md b/NativePrograms/PokemonSwSh/README_Mac_Linux.md similarity index 100% rename from NativePrograms/README_Mac_Linux.md rename to NativePrograms/PokemonSwSh/README_Mac_Linux.md diff --git a/NativePrograms/Sandbox.c b/NativePrograms/PokemonSwSh/Sandbox.c similarity index 94% rename from NativePrograms/Sandbox.c rename to NativePrograms/PokemonSwSh/Sandbox.c index ae216db993..4790247860 100644 --- a/NativePrograms/Sandbox.c +++ b/NativePrograms/PokemonSwSh/Sandbox.c @@ -17,7 +17,7 @@ //#include "PokemonSwShLibraries/CodeEntry.h" //#include "PokemonSwShLibraries/ProgramFlow.h" //#include "PokemonSwShLibraries/NavigateDateTime.h" -#include "DeviceFramework/HardwareLED.h" +#include "NativePrograms/DeviceFramework/HardwareLED.h" //#include "Libraries/AutoHostTools.h" //#include "Libraries/DaySkipperTools.h" //#include "Libraries/EggHelpers.h" diff --git a/NativePrograms/ShinyHunt-Regi.c b/NativePrograms/PokemonSwSh/ShinyHunt-Regi.c similarity index 91% rename from NativePrograms/ShinyHunt-Regi.c rename to NativePrograms/PokemonSwSh/ShinyHunt-Regi.c index ecda18a7ac..be8753fe9c 100644 --- a/NativePrograms/ShinyHunt-Regi.c +++ b/NativePrograms/PokemonSwSh/ShinyHunt-Regi.c @@ -7,7 +7,7 @@ */ #include "Common/SwitchFramework/SwitchControllerDefs.h" -#include "PokemonSwShPrograms/ShinyHunt-Regi.h" +#include "Programs/ShinyHunt-Regi.h" const uint16_t WAIT_TIME = 15 * TICKS_PER_SECOND; diff --git a/NativePrograms/ShinyHunt-SwordsOfJustice.c b/NativePrograms/PokemonSwSh/ShinyHunt-SwordsOfJustice.c similarity index 91% rename from NativePrograms/ShinyHunt-SwordsOfJustice.c rename to NativePrograms/PokemonSwSh/ShinyHunt-SwordsOfJustice.c index 1f29bc2c5e..ab8095346d 100644 --- a/NativePrograms/ShinyHunt-SwordsOfJustice.c +++ b/NativePrograms/PokemonSwSh/ShinyHunt-SwordsOfJustice.c @@ -7,7 +7,7 @@ */ #include "Common/SwitchFramework/SwitchControllerDefs.h" -#include "PokemonSwShPrograms/ShinyHunt-SwordsOfJustice.h" +#include "Programs/ShinyHunt-SwordsOfJustice.h" // Increase this number if you want to give yourself more time before running. const uint16_t EXIT_CAMP_TO_RUN_DELAY = 19 * TICKS_PER_SECOND; diff --git a/NativePrograms/ShinyHuntUnattended-IoATrade.c b/NativePrograms/PokemonSwSh/ShinyHuntUnattended-IoATrade.c similarity index 92% rename from NativePrograms/ShinyHuntUnattended-IoATrade.c rename to NativePrograms/PokemonSwSh/ShinyHuntUnattended-IoATrade.c index 105dfddfb2..0c7e19948e 100644 --- a/NativePrograms/ShinyHuntUnattended-IoATrade.c +++ b/NativePrograms/PokemonSwSh/ShinyHuntUnattended-IoATrade.c @@ -7,7 +7,7 @@ */ #include "Common/SwitchFramework/SwitchControllerDefs.h" -#include "PokemonSwShPrograms/ShinyHuntUnattended-IoATrade.h" +#include "Programs/ShinyHuntUnattended-IoATrade.h" // This needs to be carefully calibrated. diff --git a/NativePrograms/ShinyHuntUnattended-Regi.c b/NativePrograms/PokemonSwSh/ShinyHuntUnattended-Regi.c similarity index 94% rename from NativePrograms/ShinyHuntUnattended-Regi.c rename to NativePrograms/PokemonSwSh/ShinyHuntUnattended-Regi.c index 0119270c6a..b4dc69e99c 100644 --- a/NativePrograms/ShinyHuntUnattended-Regi.c +++ b/NativePrograms/PokemonSwSh/ShinyHuntUnattended-Regi.c @@ -7,7 +7,7 @@ */ #include "Common/SwitchFramework/SwitchControllerDefs.h" -#include "PokemonSwShPrograms/ShinyHuntUnattended-Regi.h" +#include "Programs/ShinyHuntUnattended-Regi.h" // This needs to be carefully calibrated. diff --git a/NativePrograms/ShinyHuntUnattended-Regigigas.c b/NativePrograms/PokemonSwSh/ShinyHuntUnattended-Regigigas.c similarity index 92% rename from NativePrograms/ShinyHuntUnattended-Regigigas.c rename to NativePrograms/PokemonSwSh/ShinyHuntUnattended-Regigigas.c index fb12752a33..b7497ccfb2 100644 --- a/NativePrograms/ShinyHuntUnattended-Regigigas.c +++ b/NativePrograms/PokemonSwSh/ShinyHuntUnattended-Regigigas.c @@ -7,7 +7,7 @@ */ #include "Common/SwitchFramework/SwitchControllerDefs.h" -#include "PokemonSwShPrograms/ShinyHuntUnattended-Regigigas.h" +#include "Programs/ShinyHuntUnattended-Regigigas.h" // This needs to be carefully calibrated. diff --git a/NativePrograms/ShinyHuntUnattended-Regigigas2.c b/NativePrograms/PokemonSwSh/ShinyHuntUnattended-Regigigas2.c similarity index 93% rename from NativePrograms/ShinyHuntUnattended-Regigigas2.c rename to NativePrograms/PokemonSwSh/ShinyHuntUnattended-Regigigas2.c index 0d006f276b..713fd0447b 100644 --- a/NativePrograms/ShinyHuntUnattended-Regigigas2.c +++ b/NativePrograms/PokemonSwSh/ShinyHuntUnattended-Regigigas2.c @@ -7,7 +7,7 @@ */ #include "Common/SwitchFramework/SwitchControllerDefs.h" -#include "PokemonSwShPrograms/ShinyHuntUnattended-Regigigas2.h" +#include "Programs/ShinyHuntUnattended-Regigigas2.h" // The amount of Reversal PP that you are saved with. diff --git a/NativePrograms/ShinyHuntUnattended-StrongSpawn.c b/NativePrograms/PokemonSwSh/ShinyHuntUnattended-StrongSpawn.c similarity index 92% rename from NativePrograms/ShinyHuntUnattended-StrongSpawn.c rename to NativePrograms/PokemonSwSh/ShinyHuntUnattended-StrongSpawn.c index 305f222c26..2ba9ee75eb 100644 --- a/NativePrograms/ShinyHuntUnattended-StrongSpawn.c +++ b/NativePrograms/PokemonSwSh/ShinyHuntUnattended-StrongSpawn.c @@ -7,7 +7,7 @@ */ #include "Common/SwitchFramework/SwitchControllerDefs.h" -#include "PokemonSwShPrograms/ShinyHuntUnattended-StrongSpawn.h" +#include "Programs/ShinyHuntUnattended-StrongSpawn.h" // This needs to be carefully calibrated. diff --git a/NativePrograms/ShinyHuntUnattended-SwordsOfJustice.c b/NativePrograms/PokemonSwSh/ShinyHuntUnattended-SwordsOfJustice.c similarity index 91% rename from NativePrograms/ShinyHuntUnattended-SwordsOfJustice.c rename to NativePrograms/PokemonSwSh/ShinyHuntUnattended-SwordsOfJustice.c index 0c08ed2d1b..8eeb5cbd96 100644 --- a/NativePrograms/ShinyHuntUnattended-SwordsOfJustice.c +++ b/NativePrograms/PokemonSwSh/ShinyHuntUnattended-SwordsOfJustice.c @@ -7,7 +7,7 @@ */ #include "Common/SwitchFramework/SwitchControllerDefs.h" -#include "PokemonSwShPrograms/ShinyHuntUnattended-SwordsOfJustice.h" +#include "Programs/ShinyHuntUnattended-SwordsOfJustice.h" // This needs to be carefully calibrated. diff --git a/NativePrograms/SurpriseTrade.c b/NativePrograms/PokemonSwSh/SurpriseTrade.c similarity index 90% rename from NativePrograms/SurpriseTrade.c rename to NativePrograms/PokemonSwSh/SurpriseTrade.c index 68710e2daa..d862825e8b 100644 --- a/NativePrograms/SurpriseTrade.c +++ b/NativePrograms/PokemonSwSh/SurpriseTrade.c @@ -7,7 +7,7 @@ */ #include "Common/SwitchFramework/SwitchControllerDefs.h" -#include "PokemonSwShPrograms/SurpriseTrade.h" +#include "Programs/SurpriseTrade.h" diff --git a/NativePrograms/TradeBot.c b/NativePrograms/PokemonSwSh/TradeBot.c similarity index 93% rename from NativePrograms/TradeBot.c rename to NativePrograms/PokemonSwSh/TradeBot.c index 6995758bb5..a0fdeb9263 100644 --- a/NativePrograms/TradeBot.c +++ b/NativePrograms/PokemonSwSh/TradeBot.c @@ -7,7 +7,7 @@ */ #include "Common/SwitchFramework/SwitchControllerDefs.h" -#include "PokemonSwShPrograms/TradeBot.h" +#include "Programs/TradeBot.h" // Raid Code diff --git a/NativePrograms/TurboA.c b/NativePrograms/PokemonSwSh/TurboA.c similarity index 83% rename from NativePrograms/TurboA.c rename to NativePrograms/PokemonSwSh/TurboA.c index 9ed9984ba0..286d7e9678 100644 --- a/NativePrograms/TurboA.c +++ b/NativePrograms/PokemonSwSh/TurboA.c @@ -6,7 +6,7 @@ * */ -#include "PokemonSwShPrograms/TurboA.h" +#include "Programs/TurboA.h" // // This program has no program-specific configurable options. diff --git a/NativePrograms/PokemonSwSh/makefile b/NativePrograms/PokemonSwSh/makefile new file mode 100644 index 0000000000..7e997adff1 --- /dev/null +++ b/NativePrograms/PokemonSwSh/makefile @@ -0,0 +1,130 @@ +# +# LUFA Library +# Copyright (C) Dean Camera, 2014. +# +# dean [at] fourwalledcubicle [dot] com +# www.lufa-lib.org +# +# Modified by https://github.com/PokemonAutomation/Arduino-Source +# +# -------------------------------------- +# LUFA Project Makefile. +# -------------------------------------- + +# MCU Types: +# atmega16u2 for Arduino UNO R3 +# atmega32u4 for Arduino Micro, and Teensy 2.0 +# at90usb1286 for Teensy 2.0++ + +# Set MCU and TARGET here: + +ifeq ($(BOARD_TYPE),) +BOARD_TYPE := Teensy2 +endif +ifeq ($(TARGET),) +TARGET := BallThrower +#TARGET := Sandbox +endif + + +################################################################################ +# Ignore all this stuff below. + +PATH_PUBLIC = ../../ +PATH_INTERNAL = ../../../Internal + +CATEGORY = PokemonSwSh + +#MCU = atmega16u2 +ARCH = AVR8 +F_CPU = 16000000 +F_USB = $(F_CPU) +OPTIMIZATION = s +#TARGET = TurboA +SRC = $(TARGET).c +LUFA_PATH = $(PATH_PUBLIC)/NativePrograms/LUFA +CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -I$(PATH_PUBLIC) -I$(PATH_PUBLIC)/NativePrograms/LUFA/ -Wno-unused-function -Werror + + + + +# Board +ifeq ($(BOARD_TYPE), ArduinoUnoR3) +MCU := atmega16u2 +SRC += $(PATH_PUBLIC)/NativePrograms/DeviceFramework/Board-atmega16u2-ArduinoUnoR3.c +endif +ifeq ($(BOARD_TYPE), ProMicro) +MCU := atmega32u4 +SRC += $(PATH_PUBLIC)/NativePrograms/DeviceFramework/Board-atmega32u4-ProMicro.c +endif +ifeq ($(BOARD_TYPE), Teensy2) +MCU := atmega32u4 +SRC += $(PATH_PUBLIC)/NativePrograms/DeviceFramework/Board-atmega32u4-Teensy2.c +endif +ifeq ($(BOARD_TYPE), TeensyPP2) +MCU := at90usb1286 +SRC += $(PATH_PUBLIC)/NativePrograms/DeviceFramework/Board-at90usb1286-Teensy2.c +endif + +# Framework +SRC += $(LUFA_SRC_USB) +SRC += $(PATH_PUBLIC)/Common/SwitchFramework/FrameworkSettings.c +SRC += $(PATH_PUBLIC)/NativePrograms/DeviceFramework/DeviceSettings.c +ifneq ("$(wildcard $(PATH_INTERNAL)/NativePrograms/SwitchFramework/Switch_PushButtons.c)","") +CC_FLAGS += -I$(PATH_INTERNAL) +SRC += $(PATH_PUBLIC)/Common/CRC32.c +SRC += $(PATH_INTERNAL)/NativePrograms/SwitchFramework/uart.c +SRC += $(PATH_INTERNAL)/NativePrograms/SwitchFramework/HardwareUSB.c +ifeq ($(TARGET), PABotBase) +SRC += $(PATH_INTERNAL)/NativePrograms/SwitchFramework/CommandQueue.c +else +SRC += $(PATH_INTERNAL)/NativePrograms/SwitchFramework/CommandQueueNull.c +endif +SRC += $(PATH_INTERNAL)/NativePrograms/SwitchFramework/HardwareSerial.c +SRC += $(PATH_INTERNAL)/NativePrograms/SwitchFramework/Controller.c +SRC += $(PATH_INTERNAL)/NativePrograms/SwitchFramework/Switch_PushButtons.c +SRC += $(PATH_INTERNAL)/NativePrograms/SwitchFramework/Switch_ScalarButtons.c +else +LD_FLAGS += obj/obj-$(MCU)/CRC32.o +LD_FLAGS += obj/obj-$(MCU)/uart.o +LD_FLAGS += obj/obj-$(MCU)/HardwareUSB.o +ifeq ($(TARGET), PABotBase) +LD_FLAGS += obj/obj-$(MCU)/CommandQueue.o +else +LD_FLAGS += obj/obj-$(MCU)/CommandQueueNull.o +endif +LD_FLAGS += obj/obj-$(MCU)/HardwareSerial.o +LD_FLAGS += obj/obj-$(MCU)/Controller.o +LD_FLAGS += obj/obj-$(MCU)/Switch_PushButtons.o +LD_FLAGS += obj/obj-$(MCU)/Switch_ScalarButtons.o +endif + +# Program +SRC += $(PATH_PUBLIC)/Common/PokemonSwSh/PokemonSettings.c +SRC += $(PATH_PUBLIC)/NativePrograms/$(CATEGORY)/Programs/PokemonCallbacks.c +ifneq ("$(wildcard $(PATH_INTERNAL)/NativePrograms/$(CATEGORY)/$(TARGET)_Core.c)","") +SRC += $(PATH_INTERNAL)/NativePrograms/$(CATEGORY)/$(TARGET)_Core.c +else ifneq ("$(wildcard Programs/$(TARGET)_Core.c)","") +SRC += Programs/$(TARGET)_Core.c +else ifneq ("$(wildcard obj/obj-$(MCU)/$(TARGET)_Core.o)","") +LD_FLAGS += obj/obj-$(MCU)/$(TARGET)_Core.o +endif + + +# Must go at the end or it blows up memory if floating-point is used. +LD_FLAGS += -lm + + +# Default target +all: + +# Include LUFA build script makefiles +include $(LUFA_PATH)/Build/lufa_core.mk +include $(LUFA_PATH)/Build/lufa_sources.mk +include $(LUFA_PATH)/Build/lufa_build.mk +include $(LUFA_PATH)/Build/lufa_cppcheck.mk +include $(LUFA_PATH)/Build/lufa_doxygen.mk +include $(LUFA_PATH)/Build/lufa_dfu.mk +include $(LUFA_PATH)/Build/lufa_hid.mk +include $(LUFA_PATH)/Build/lufa_avrdude.mk +include $(LUFA_PATH)/Build/lufa_atprogram.mk diff --git a/NativePrograms/Scripts/BuildAll.cmd b/NativePrograms/Scripts/BuildAll.cmd index 40e860d177..05359a304f 100644 --- a/NativePrograms/Scripts/BuildAll.cmd +++ b/NativePrograms/Scripts/BuildAll.cmd @@ -23,56 +23,6 @@ set PATH=%PATH%C:\WinAVR-20100110\bin; set PATH=%PATH%C:\WinAVR-20100110\utils\bin; -set programs= - -set programs=%programs%;TurboA -set programs=%programs%;MultiGameFossil -set programs=%programs%;MassRelease -set programs=%programs%;SurpriseTrade -set programs=%programs%;TradeBot -set programs=%programs%;ClothingBuyer -set programs=%programs%;BallThrower - -set programs=%programs%;DateSpam-WattFarmer -set programs=%programs%;DateSpam-BerryFarmer -set programs=%programs%;DateSpam-LotoFarmer -set programs=%programs%;DateSpam-StowOnSideFarmer -set programs=%programs%;DateSpam-DailyHighlightFarmer - -set programs=%programs%;ShinyHunt-Regi -set programs=%programs%;ShinyHunt-SwordsOfJustice -set programs=%programs%;ShinyHuntUnattended-Regi -set programs=%programs%;ShinyHuntUnattended-SwordsOfJustice -set programs=%programs%;ShinyHuntUnattended-StrongSpawn -set programs=%programs%;ShinyHuntUnattended-Regigigas -set programs=%programs%;ShinyHuntUnattended-Regigigas2 -set programs=%programs%;ShinyHuntUnattended-IoATrade - -set programs=%programs%;BeamReset -set programs=%programs%;EventBeamFinder -set programs=%programs%;DaySkipperJPN -set programs=%programs%;DaySkipperEU -set programs=%programs%;DaySkipperUS -set programs=%programs%;DaySkipperJPN-7.8k - -set programs=%programs%;DenRoller -set programs=%programs%;AutoHost-Rolling -set programs=%programs%;AutoHost-MultiGame -set programs=%programs%;FriendDelete - -set programs=%programs%;EggFetcher2 -set programs=%programs%;EggHatcher -set programs=%programs%;EggCombined2 -set programs=%programs%;EggSuperCombined2 - -set programs=%programs%;FastCodeEntry -set programs=%programs%;GodEggItemDupe -set programs=%programs%;GodEggDuplication - -set programs=%programs%;PABotBase -set programs=%programs%;Sandbox -set programs=%programs%;CustomProgram - echo Checking make command... @@ -106,7 +56,7 @@ copy NUL obj\build-%MCU% > NUL echo. -echo Starting build... This make take a while if your computer is slow. +echo Starting build... This may take a while if your computer is slow. echo. if not exist obj\ ( @@ -117,18 +67,18 @@ if not exist obj\ ( :: Build one first to build all the shared libraries. :: Only then can we run the rest in parallel. -for %%p in (%programs%) do ( +for /F "tokens=*" %%p in (ProgramList.txt) do ( set first=%%p - @call Scripts\BuildOne.cmd %board% %%p > %%p.log 2>&1 + @call %~dp0BuildOne.cmd %board% %%p > %%p.log 2>&1 goto :done ) :done -for %%p in (%programs%) do ( +for /F "tokens=*" %%p in (ProgramList.txt) do ( if exist %%p.c ( if [%%p] NEQ [%first%] ( echo > %%p.tmp - START /B Scripts\BuildOne.cmd %board% %%p > %%p.log 2>&1 + START /B %~dp0BuildOne.cmd %board% %%p > %%p.log 2>&1 ) ) ) @@ -136,11 +86,11 @@ for %%p in (%programs%) do ( ::@echo on :loop -for %%p in (%programs%) do ( +for /F "tokens=*" %%p in (ProgramList.txt) do ( if exist %%p.tmp goto :loop ) -for %%p in (%programs%) do ( +for /F "tokens=*" %%p in (ProgramList.txt) do ( if exist %%p.c ( if not exist %%p.hex ( echo. diff --git a/NativePrograms/Scripts/BuildAllUnix.sh b/NativePrograms/Scripts/BuildAllUnix.sh index 2d1f554c32..1b22908e6f 100755 --- a/NativePrograms/Scripts/BuildAllUnix.sh +++ b/NativePrograms/Scripts/BuildAllUnix.sh @@ -7,61 +7,14 @@ board=$1 declare -a PROGRAMS=() -# standard program list -PROGRAMS+=("TurboA") -PROGRAMS+=("MultiGameFossil") -PROGRAMS+=("MassRelease") -PROGRAMS+=("SurpriseTrade") -PROGRAMS+=("TradeBot") -PROGRAMS+=("ClothingBuyer") -PROGRAMS+=("BallThrower") - -# farming programs -PROGRAMS+=("DateSpam-WattFarmer") -PROGRAMS+=("DateSpam-BerryFarmer") -PROGRAMS+=("DateSpam-LotoFarmer") -PROGRAMS+=("DateSpam-StowOnSideFarmer") -PROGRAMS+=("DateSpam-DailyHighlightFarmer") - -# soft reset programs -PROGRAMS+=("ShinyHunt-Regi") -PROGRAMS+=("ShinyHunt-SwordsOfJustice") -PROGRAMS+=("ShinyHuntUnattended-Regi") -PROGRAMS+=("ShinyHuntUnattended-SwordsOfJustice") -PROGRAMS+=("ShinyHuntUnattended-StrongSpawn") -PROGRAMS+=("ShinyHuntUnattended-Regigigas") -PROGRAMS+=("ShinyHuntUnattended-Regigigas2") -PROGRAMS+=("ShinyHuntUnattended-IoATrade") - -# beam reset and day skipper programs -PROGRAMS+=("BeamReset") -PROGRAMS+=("EventBeamFinder") -PROGRAMS+=("DaySkipperJPN") -PROGRAMS+=("DaySkipperEU") -PROGRAMS+=("DaySkipperUS") -PROGRAMS+=("DaySkipperJPN-7.8k") - -# rolling and autohost programs -PROGRAMS+=("DenRoller") -PROGRAMS+=("AutoHost-Rolling") -PROGRAMS+=("AutoHost-MultiGame") -PROGRAMS+=("FriendDelete") - -# egg programs -PROGRAMS+=("EggFetcher2") -PROGRAMS+=("EggHatcher") -PROGRAMS+=("EggCombined2") -PROGRAMS+=("EggSuperCombined2") - -# forbidden programs -PROGRAMS+=("FastCodeEntry") -PROGRAMS+=("GodEggItemDupe") -PROGRAMS+=("GodEggDuplication") - -# other -PROGRAMS+=("PABotBase") -PROGRAMS+=("Sandbox") -PROGRAMS+=("CustomProgram") +#PROGRAMS+=("FriendDelete") +#mapfile -t PROGRAMS < ProgramList.txt +while IFS="$IFS"$'\r' read -r line; do + if [ -n "$line" ]; then + PROGRAMS+=("$line") + fi +done < ProgramList.txt + echo "Now Checking the make command..." echo "" @@ -77,11 +30,11 @@ echo "" # check the obj directory and make it if it doesn't exist if [ ! -d obj/ ]; then - mkdir obj/ + mkdir obj/ fi if [ ! -d log/ ]; then - mkdir log/ + mkdir log/ fi # build one of them first to establish the library @@ -89,8 +42,8 @@ for p in "${PROGRAMS[@]}"; do first="$p" echo "$first" - echo "sh Scripts/BuildOneUnix.sh $board $p" - sh Scripts/BuildOneUnix.sh $board $p + echo "sh ../Scripts/BuildOneUnix.sh $board $p" + sh ../Scripts/BuildOneUnix.sh $board $p retVal=$? if [ $retVal -ne 0 ]; then @@ -100,7 +53,7 @@ for p in "${PROGRAMS[@]}"; do rm obj/*.d obj/*.o echo "WARNING: Attempting build again..." 1>&2 - sh Scripts/BuildOneUnix.sh $board $p + sh ../Scripts/BuildOneUnix.sh $board $p retVal=$? # one last check, if it errors again, we'll exit @@ -120,7 +73,7 @@ done for p in "${PROGRAMS[@]}"; do if [ "$p" != "$first" ]; then # send it off and pipe it to a log file - sh Scripts/BuildOneUnix.sh $board $p 2>&1 | tee "log/$p.log" & + sh ../Scripts/BuildOneUnix.sh $board $p 2>&1 | tee "log/$p.log" & fi done diff --git a/NativePrograms/Scripts/BuildOne.cmd b/NativePrograms/Scripts/BuildOne.cmd index 7f95691f8f..2379101df0 100644 --- a/NativePrograms/Scripts/BuildOne.cmd +++ b/NativePrograms/Scripts/BuildOne.cmd @@ -12,6 +12,7 @@ if [%program%] == [] ( del "%program%.hex" make BOARD_TYPE="%board%" TARGET="%program%" +avr-size --mcu=%MCU% -C %program%.elf ::if %errorlevel% NEQ 0 ( :: echo Build Failed. Error %errorlevel% diff --git a/SerialPrograms/SerialPrograms.pro b/SerialPrograms/SerialPrograms.pro index 3b6e9b8826..24e577fa36 100644 --- a/SerialPrograms/SerialPrograms.pro +++ b/SerialPrograms/SerialPrograms.pro @@ -25,17 +25,23 @@ win32-g++{ # QMAKE_CXXFLAGS += -Wno-unused-function # QMAKE_CXXFLAGS += -Wno-missing-field-initializers - DEFINES += TESS_IMPORTS DEFINES += WIN32 - LIBS += ../SerialPrograms/libtesseractc.lib + DEFINES += TESS_IMPORTS + DEFINES += PA_TESSERACT + LIBS += ../SerialPrograms/tesseractPA.lib } win32-msvc{ QMAKE_CXXFLAGS += /std:c++latest - - DEFINES += TESS_IMPORTS DEFINES += WIN32 - LIBS += ../SerialPrograms/libtesseractc.lib + DEFINES += TESS_IMPORTS + DEFINES += PA_TESSERACT + LIBS += ../SerialPrograms/tesseractPA.lib +} +macx{ + QMAKE_CXXFLAGS += -std=c++14 + + QMAKE_INFO_PLIST = macos/Info.plist } @@ -45,9 +51,12 @@ SOURCES += \ ../ClientSource/Libraries/Logging.cpp \ ../ClientSource/Libraries/MessageConverter.cpp \ ../Common/CRC32.cpp \ - ../Common/Clientside/AsyncDispatcher.cpp \ - ../Common/Clientside/PrettyPrint.cpp \ - ../Common/Clientside/Unicode.cpp \ + ../Common/Cpp/AsyncDispatcher.cpp \ + ../Common/Cpp/Exception.cpp \ + ../Common/Cpp/PanicDump.cpp \ + ../Common/Cpp/ParallelTaskRunner.cpp \ + ../Common/Cpp/PrettyPrint.cpp \ + ../Common/Cpp/Unicode.cpp \ ../Common/PokemonSwSh/PokemonSettings.cpp \ ../Common/PokemonSwSh/PokemonSwShAutoHosts.cpp \ ../Common/PokemonSwSh/PokemonSwShDateSpam.cpp \ @@ -62,6 +71,7 @@ SOURCES += \ ../Common/Qt/Options/FossilTableOption.cpp \ ../Common/Qt/Options/MultiHostTableOption.cpp \ ../Common/Qt/Options/SimpleIntegerOption.cpp \ + ../Common/Qt/Options/StringOption.cpp \ ../Common/Qt/Options/SwitchDateOption.cpp \ ../Common/Qt/Options/TimeExpressionOption.cpp \ ../Common/Qt/QtJsonTools.cpp \ @@ -69,6 +79,7 @@ SOURCES += \ ../Common/SwitchFramework/Switch_PushButtons.cpp \ ../Common/SwitchRoutines/SwitchDigitEntry.cpp \ Source/CommonFramework/CrashDump.cpp \ + Source/CommonFramework/GlobalSettingsPanel.cpp \ Source/CommonFramework/Globals.cpp \ Source/CommonFramework/Inference/AnomalyDetector.cpp \ Source/CommonFramework/Inference/BlackScreenDetector.cpp \ @@ -76,21 +87,39 @@ SOURCES += \ Source/CommonFramework/Inference/FillGeometry.cpp \ Source/CommonFramework/Inference/FillMatrix.cpp \ Source/CommonFramework/Inference/ImageTools.cpp \ + Source/CommonFramework/Inference/VisualInferenceCallback.cpp \ + Source/CommonFramework/Inference/VisualInferenceSession.cpp \ + Source/CommonFramework/Inference/VisualInferenceWait.cpp \ + Source/CommonFramework/Language.cpp \ Source/CommonFramework/Main.cpp \ + Source/CommonFramework/OCR/DictionaryMatcher.cpp \ + Source/CommonFramework/OCR/DictionaryOCR.cpp \ + Source/CommonFramework/OCR/Filtering.cpp \ + Source/CommonFramework/OCR/LargeDictionaryMatcher.cpp \ + Source/CommonFramework/OCR/RawOCR.cpp \ + Source/CommonFramework/OCR/SmallDictionaryMatcher.cpp \ + Source/CommonFramework/OCR/StringNormalization.cpp \ + Source/CommonFramework/OCR/TextMatcher.cpp \ + Source/CommonFramework/OCR/TrainingTools.cpp \ + Source/CommonFramework/Options/EnumDropdown.cpp \ Source/CommonFramework/Options/FixedCode.cpp \ + Source/CommonFramework/Options/LanguageOCR.cpp \ Source/CommonFramework/Options/RandomCode.cpp \ Source/CommonFramework/Options/SectionDivider.cpp \ - Source/CommonFramework/Panels/RightPanel.cpp \ + Source/CommonFramework/Options/StringSelect.cpp \ + Source/CommonFramework/Panels/Panel.cpp \ + Source/CommonFramework/Panels/PanelList.cpp \ + Source/CommonFramework/Panels/RunnableComputerProgram.cpp \ + Source/CommonFramework/Panels/RunnablePanel.cpp \ Source/CommonFramework/Panels/SettingsPanel.cpp \ Source/CommonFramework/PersistentSettings.cpp \ Source/CommonFramework/Tools/BotBaseHandle.cpp \ + Source/CommonFramework/Tools/InterruptableCommands.cpp \ Source/CommonFramework/Tools/ProgramEnvironment.cpp \ Source/CommonFramework/Tools/StatsDatabase.cpp \ Source/CommonFramework/Tools/StatsTracking.cpp \ Source/CommonFramework/Widgets/CameraSelector.cpp \ - Source/CommonFramework/Widgets/ProgramList.cpp \ Source/CommonFramework/Widgets/SerialSelector.cpp \ - Source/CommonFramework/Widgets/SettingList.cpp \ Source/CommonFramework/Widgets/VideoOverlay.cpp \ Source/CommonFramework/Windows/ButtonDiagram.cpp \ Source/CommonFramework/Windows/MainWindow.cpp \ @@ -104,18 +133,32 @@ SOURCES += \ Source/NintendoSwitch/Framework/VirtualSwitchController.cpp \ Source/NintendoSwitch/Framework/VirtualSwitchControllerMapping.cpp \ Source/NintendoSwitch/FrameworkSettingsPanel.cpp \ + Source/NintendoSwitch/InferenceTraining/PokemonHome_GenerateNameOCR.cpp \ Source/NintendoSwitch/Options/FriendCodeList.cpp \ + Source/NintendoSwitch/Panels_NintendoSwitch.cpp \ Source/NintendoSwitch/Programs/FriendCodeAdder.cpp \ Source/NintendoSwitch/Programs/FriendDelete.cpp \ + Source/NintendoSwitch/Programs/PokemonHome_PageSwap.cpp \ Source/NintendoSwitch/Programs/PreventSleep.cpp \ Source/NintendoSwitch/Programs/SwitchViewer.cpp \ - Source/PanelList.cpp \ + Source/NintendoSwitch/Programs/TurboButton.cpp \ + Source/NintendoSwitch/Programs/VirtualConsole.cpp \ + Source/NintendoSwitch/TestProgram.cpp \ + Source/PanelLists.cpp \ + Source/Pokemon/Options/Pokemon_NameSelect.cpp \ + Source/Pokemon/Pokemon_EncounterStats.cpp \ + Source/Pokemon/Pokemon_NameReader.cpp \ + Source/Pokemon/Pokemon_TrainIVCheckerOCR.cpp \ + Source/Pokemon/Pokemon_TrainPokemonOCR.cpp \ + Source/PokemonBDSP/Panels_PokemonBDSP.cpp \ Source/PokemonSwSh/Inference/PokemonSwSh_BattleMenuDetector.cpp \ Source/PokemonSwSh/Inference/PokemonSwSh_BeamSetter.cpp \ Source/PokemonSwSh/Inference/PokemonSwSh_FishingDetector.cpp \ + Source/PokemonSwSh/Inference/PokemonSwSh_IVCheckerReader.cpp \ Source/PokemonSwSh/Inference/PokemonSwSh_MarkFinder.cpp \ Source/PokemonSwSh/Inference/PokemonSwSh_RaidCatchDetector.cpp \ Source/PokemonSwSh/Inference/PokemonSwSh_RaidLobbyReader.cpp \ + Source/PokemonSwSh/Inference/PokemonSwSh_ReceivePokemonDetector.cpp \ Source/PokemonSwSh/Inference/PokemonSwSh_StartBattleDetector.cpp \ Source/PokemonSwSh/Inference/PokemonSwSh_SummaryShinySymbolDetector.cpp \ Source/PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_ShinyEncounterDetector.cpp \ @@ -123,25 +166,34 @@ SOURCES += \ Source/PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_SparkleTrigger.cpp \ Source/PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_SquareDetector.cpp \ Source/PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_SquareTrigger.cpp \ + Source/PokemonSwSh/InferenceTraining/PokemonSwSh_GenerateIVCheckerOCR.cpp \ + Source/PokemonSwSh/InferenceTraining/PokemonSwSh_GenerateNameOCRPokedex.cpp \ Source/PokemonSwSh/Options/Catchability.cpp \ Source/PokemonSwSh/Options/EggStepCount.cpp \ Source/PokemonSwSh/Options/RegiSelector.cpp \ + Source/PokemonSwSh/Panels_PokemonSwSh.cpp \ Source/PokemonSwSh/PokemonSwSh_SettingsPanel.cpp \ Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_BallThrower.cpp \ Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_ClothingBuyer.cpp \ + Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_DexRecFinder.cpp \ Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_MassRelease.cpp \ Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_SurpriseTrade.cpp \ Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TradeBot.cpp \ Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TurboA.cpp \ - Source/PokemonSwSh/Programs/PokemonSwSh_OverworldTrajectory.cpp \ + Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHostStats.cpp \ + Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldMovement.cpp \ + Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTargetTracker.cpp \ + Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTrajectory.cpp \ + Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTrigger.cpp \ + Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_ShinyHuntAutonomous-Overworld.cpp \ Source/PokemonSwSh/Programs/PokemonSwSh_StartGame.cpp \ + Source/PokemonSwSh/Programs/PokemonSwSh_StatsReset.cpp \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_EncounterTracker.cpp \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_MultiGameFossil.cpp \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHunt-Regi.cpp \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-BerryTree.cpp \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Fishing.cpp \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-IoATrade.cpp \ - Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Overworld.cpp \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regi.cpp \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regigigas2.cpp \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-StrongSpawn.cpp \ @@ -177,7 +229,6 @@ SOURCES += \ Source/PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FastCodeEntry.cpp \ Source/PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FriendSearchDisconnect.cpp \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-SwordsOfJustice.cpp \ - Source/PokemonSwSh/Programs/TestProgram.cpp \ Source/PokemonSwSh/ShinyHuntTracker.cpp HEADERS += \ @@ -188,15 +239,18 @@ HEADERS += \ ../ClientSource/Connection/SerialConnectionPOSIX.h \ ../ClientSource/Connection/SerialConnectionWinAPI.h \ ../ClientSource/Connection/StreamInterface.h \ - ../ClientSource/Libraries/Compiler.h \ ../ClientSource/Libraries/Logging.h \ ../ClientSource/Libraries/MessageConverter.h \ ../Common/CRC32.h \ - ../Common/Clientside/AsyncDispatcher.h \ - ../Common/Clientside/PrettyPrint.h \ - ../Common/Clientside/SpinLock.h \ - ../Common/Clientside/Unicode.h \ ../Common/Compiler.h \ + ../Common/Cpp/AsyncDispatcher.h \ + ../Common/Cpp/Exception.h \ + ../Common/Cpp/FixedLimitVector.h \ + ../Common/Cpp/PanicDump.h \ + ../Common/Cpp/ParallelTaskRunner.h \ + ../Common/Cpp/PrettyPrint.h \ + ../Common/Cpp/SpinLock.h \ + ../Common/Cpp/Unicode.h \ ../Common/MessageProtocol.h \ ../Common/PokemonSwSh/PokemonProgramIDs.h \ ../Common/PokemonSwSh/PokemonSettings.h \ @@ -208,21 +262,23 @@ HEADERS += \ ../Common/PokemonSwSh/PokemonSwShMisc.h \ ../Common/Qt/CodeValidator.h \ ../Common/Qt/ExpressionEvaluator.h \ + ../Common/Qt/NoWheelComboBox.h \ ../Common/Qt/Options/BooleanCheckBoxOption.h \ ../Common/Qt/Options/FloatingPointOption.h \ ../Common/Qt/Options/FossilTableOption.h \ ../Common/Qt/Options/MultiHostTableOption.h \ ../Common/Qt/Options/SimpleIntegerOption.h \ + ../Common/Qt/Options/StringOption.h \ ../Common/Qt/Options/SwitchDateOption.h \ ../Common/Qt/Options/TimeExpressionOption.h \ ../Common/Qt/QtJsonTools.h \ - ../Common/Qt/StringException.h \ ../Common/SwitchFramework/FrameworkSettings.h \ ../Common/SwitchFramework/Switch_PushButtons.h \ ../Common/SwitchFramework/SwitchControllerDefs.h \ ../Common/SwitchFramework/Switch_PushButtons.h \ ../Common/SwitchRoutines/SwitchDigitEntry.h \ Source/CommonFramework/CrashDump.h \ + Source/CommonFramework/GlobalSettingsPanel.h \ Source/CommonFramework/Globals.h \ Source/CommonFramework/Inference/AnomalyDetector.h \ Source/CommonFramework/Inference/BlackScreenDetector.h \ @@ -235,19 +291,38 @@ HEADERS += \ Source/CommonFramework/Inference/InferenceTypes.h \ Source/CommonFramework/Inference/StatAccumulator.h \ Source/CommonFramework/Inference/TimeWindowStatTracker.h \ + Source/CommonFramework/Inference/VisualInferenceCallback.h \ + Source/CommonFramework/Inference/VisualInferenceSession.h \ + Source/CommonFramework/Inference/VisualInferenceWait.h \ + Source/CommonFramework/Language.h \ + Source/CommonFramework/OCR/DictionaryMatcher.h \ + Source/CommonFramework/OCR/DictionaryOCR.h \ + Source/CommonFramework/OCR/Filtering.h \ + Source/CommonFramework/OCR/LargeDictionaryMatcher.h \ + Source/CommonFramework/OCR/RawOCR.h \ + Source/CommonFramework/OCR/SmallDictionaryMatcher.h \ + Source/CommonFramework/OCR/StringNormalization.h \ + Source/CommonFramework/OCR/TesseractPA.h \ + Source/CommonFramework/OCR/TextMatcher.h \ + Source/CommonFramework/OCR/TrainingTools.h \ Source/CommonFramework/Options/BooleanCheckBox.h \ Source/CommonFramework/Options/ConfigOption.h \ + Source/CommonFramework/Options/EnumDropdown.h \ Source/CommonFramework/Options/FixedCode.h \ Source/CommonFramework/Options/FloatingPoint.h \ + Source/CommonFramework/Options/LanguageOCR.h \ Source/CommonFramework/Options/RandomCode.h \ Source/CommonFramework/Options/SectionDivider.h \ Source/CommonFramework/Options/SimpleInteger.h \ - Source/CommonFramework/Panels/RightPanel.h \ + Source/CommonFramework/Options/StringSelect.h \ + Source/CommonFramework/Panels/Panel.h \ + Source/CommonFramework/Panels/PanelList.h \ + Source/CommonFramework/Panels/RunnableComputerProgram.h \ + Source/CommonFramework/Panels/RunnablePanel.h \ Source/CommonFramework/Panels/SettingsPanel.h \ Source/CommonFramework/PersistentSettings.h \ - Source/CommonFramework/Tesseract/capi.h \ - Source/CommonFramework/Tesseract/platform.h \ Source/CommonFramework/Tools/ConsoleHandle.h \ + Source/CommonFramework/Tools/InterruptableCommands.h \ Source/CommonFramework/Tools/Logger.h \ Source/CommonFramework/Tools/ProgramEnvironment.h \ Source/CommonFramework/Tools/StatsDatabase.h \ @@ -255,9 +330,7 @@ HEADERS += \ Source/CommonFramework/Tools/VideoFeed.h \ Source/CommonFramework/Tools/BotBaseHandle.h \ Source/CommonFramework/Widgets/CameraSelector.h \ - Source/CommonFramework/Widgets/ProgramList.h \ Source/CommonFramework/Widgets/SerialSelector.h \ - Source/CommonFramework/Widgets/SettingList.h \ Source/CommonFramework/Widgets/VideoOverlay.h \ Source/CommonFramework/Windows/ButtonDiagram.h \ Source/CommonFramework/Windows/MainWindow.h \ @@ -273,21 +346,34 @@ HEADERS += \ Source/NintendoSwitch/Framework/VirtualSwitchController.h \ Source/NintendoSwitch/Framework/VirtualSwitchControllerMapping.h \ Source/NintendoSwitch/FrameworkSettingsPanel.h \ + Source/NintendoSwitch/InferenceTraining/PokemonHome_GenerateNameOCR.h \ Source/NintendoSwitch/Options/FriendCodeList.h \ Source/NintendoSwitch/Options/SwitchDate.h \ Source/NintendoSwitch/Options/TimeExpression.h \ + Source/NintendoSwitch/Panels_NintendoSwitch.h \ Source/NintendoSwitch/Programs/FriendCodeAdder.h \ Source/NintendoSwitch/Programs/FriendDelete.h \ + Source/NintendoSwitch/Programs/PokemonHome_PageSwap.h \ Source/NintendoSwitch/Programs/PreventSleep.h \ Source/NintendoSwitch/Programs/SwitchViewer.h \ + Source/NintendoSwitch/Programs/TurboButton.h \ Source/NintendoSwitch/Programs/VirtualConsole.h \ - Source/PanelList.h \ + Source/NintendoSwitch/TestProgram.h \ + Source/PanelLists.h \ + Source/Pokemon/Options/Pokemon_NameSelect.h \ + Source/Pokemon/Pokemon_EncounterStats.h \ + Source/Pokemon/Pokemon_NameReader.h \ + Source/Pokemon/Pokemon_TrainIVCheckerOCR.h \ + Source/Pokemon/Pokemon_TrainPokemonOCR.h \ + Source/PokemonBDSP/Panels_PokemonBDSP.h \ Source/PokemonSwSh/Inference/PokemonSwSh_BattleMenuDetector.h \ Source/PokemonSwSh/Inference/PokemonSwSh_BeamSetter.h \ Source/PokemonSwSh/Inference/PokemonSwSh_FishingDetector.h \ + Source/PokemonSwSh/Inference/PokemonSwSh_IVCheckerReader.h \ Source/PokemonSwSh/Inference/PokemonSwSh_MarkFinder.h \ Source/PokemonSwSh/Inference/PokemonSwSh_RaidCatchDetector.h \ Source/PokemonSwSh/Inference/PokemonSwSh_RaidLobbyReader.h \ + Source/PokemonSwSh/Inference/PokemonSwSh_ReceivePokemonDetector.h \ Source/PokemonSwSh/Inference/PokemonSwSh_StartBattleDetector.h \ Source/PokemonSwSh/Inference/PokemonSwSh_SummaryShinySymbolDetector.h \ Source/PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_ShinyEncounterDetector.h \ @@ -296,27 +382,37 @@ HEADERS += \ Source/PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_SparkleTrigger.h \ Source/PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_SquareDetector.h \ Source/PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_SquareTrigger.h \ + Source/PokemonSwSh/InferenceTraining/PokemonSwSh_GenerateIVCheckerOCR.h \ + Source/PokemonSwSh/InferenceTraining/PokemonSwSh_GenerateNameOCRPokedex.h \ Source/PokemonSwSh/Options/Catchability.h \ Source/PokemonSwSh/Options/EggStepCount.h \ Source/PokemonSwSh/Options/FossilTable.h \ Source/PokemonSwSh/Options/MultiHostTable.h \ Source/PokemonSwSh/Options/RegiSelector.h \ + Source/PokemonSwSh/Panels_PokemonSwSh.h \ Source/PokemonSwSh/PokemonSwSh_SettingsPanel.h \ Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_BallThrower.h \ Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_ClothingBuyer.h \ + Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_DexRecFinder.h \ Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_MassRelease.h \ Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_SurpriseTrade.h \ Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TradeBot.h \ Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TurboA.h \ - Source/PokemonSwSh/Programs/PokemonSwSh_OverworldTrajectory.h \ + Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperStats.h \ + Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHostStats.h \ + Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldMovement.h \ + Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTargetTracker.h \ + Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTrajectory.h \ + Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTrigger.h \ + Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_ShinyHuntAutonomous-Overworld.h \ Source/PokemonSwSh/Programs/PokemonSwSh_StartGame.h \ + Source/PokemonSwSh/Programs/PokemonSwSh_StatsReset.h \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_EncounterTracker.h \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_MultiGameFossil.h \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHunt-Regi.h \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-BerryTree.h \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Fishing.h \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-IoATrade.h \ - Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Overworld.h \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regi.h \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regigigas2.h \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-StrongSpawn.h \ @@ -358,7 +454,6 @@ HEADERS += \ Source/PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FriendSearchDisconnect.h \ Source/PokemonSwSh/Programs/ReleaseHelpers.h \ Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-SwordsOfJustice.h \ - Source/PokemonSwSh/Programs/TestProgram.h \ Source/PokemonSwSh/ShinyHuntTracker.h # Default rules for deployment. diff --git a/SerialPrograms/Source/CommonFramework/CrashDump.cpp b/SerialPrograms/Source/CommonFramework/CrashDump.cpp index dc697e5e1f..90eb2b3c14 100644 --- a/SerialPrograms/Source/CommonFramework/CrashDump.cpp +++ b/SerialPrograms/Source/CommonFramework/CrashDump.cpp @@ -5,7 +5,9 @@ */ #include -#include "Common/Clientside/Unicode.h" +#include +#include "Common/Cpp/Unicode.h" +#include "Common/Cpp/PrettyPrint.h" //#include "ClientSource/Libraries/Logging.h" #include "CrashDump.h" @@ -13,31 +15,9 @@ using std::cout; using std::endl; -namespace PokemonAutomation{ - -std::string now_to_filestring(){ -#if _WIN32 && _MSC_VER -#pragma warning(disable:4996) -#endif - - time_t t = time(0); - struct tm* now = localtime(&t); - - std::string str; - str += std::to_string(now->tm_year + 1900); - str += std::string(now->tm_mon + 1 < 10 ? "0" : "") + std::to_string(now->tm_mon + 1); - str += std::string(now->tm_mday < 10 ? "0" : "") + std::to_string(now->tm_mday); - str += "-"; - str += std::string(now->tm_hour < 10 ? "0" : "") + std::to_string(now->tm_hour); - str += std::string(now->tm_min < 10 ? "0" : "") + std::to_string(now->tm_min); - str += std::string(now->tm_sec < 10 ? "0" : "") + std::to_string(now->tm_sec); - return str; -} - -} -#if _WIN32 +#if _WIN32 && _MSC_VER #pragma comment (lib, "Dbghelp.lib") #include #include @@ -52,15 +32,19 @@ long WINAPI crash_handler(EXCEPTION_POINTERS* e){ } handled = true; - cout << "Oops... Program has crashed." << endl; - cout << "Creating mini-dump file..." << endl; - std::string filename = "SerialPrograms-"; filename += now_to_filestring(); - filename += ".dmp"; + + std::ofstream log; + log.open(filename + ".log"); + + cout << "Oops... Program has crashed." << endl; + cout << "Creating mini-dump file..." << endl; + log << "Oops... Program has crashed." << endl; + log << "Creating mini-dump file..." << endl; HANDLE handle = CreateFileW( - utf8_to_wstr(filename).c_str(), + utf8_to_wstr(filename + ".dmp").c_str(), FILE_WRITE_ACCESS, FILE_SHARE_READ, nullptr, @@ -69,7 +53,9 @@ long WINAPI crash_handler(EXCEPTION_POINTERS* e){ 0 ); if (handle == INVALID_HANDLE_VALUE){ - cout << "Unable to create dump file: " << GetLastError() << endl; + DWORD error = GetLastError(); + cout << "Unable to create dump file: " << error << endl; + log << "Unable to create dump file: " << error << endl; return EXCEPTION_EXECUTE_HANDLER; } @@ -90,9 +76,12 @@ long WINAPI crash_handler(EXCEPTION_POINTERS* e){ CloseHandle(handle); if (!ret){ - cout << "Unable to create minidump: " << GetLastError() << endl; + DWORD error = GetLastError(); + cout << "Unable to create minidump: " << error << endl; + log << "Unable to create minidump: " << error << endl; }else{ cout << "Minidump created!" << endl; + log << "Minidump created!" << endl; } return EXCEPTION_CONTINUE_SEARCH; @@ -107,7 +96,11 @@ void setup_crash_handler(){ } #else +namespace PokemonAutomation{ + void setup_crash_handler(){ // Not supported } + +} #endif diff --git a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp new file mode 100644 index 0000000000..2ac8974398 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp @@ -0,0 +1,116 @@ +/* Global Settings Panel + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "CommonFramework/Options/BooleanCheckBox.h" +#include "CommonFramework/Options/SimpleInteger.h" +#include "CommonFramework/Options/String.h" +#include "CommonFramework/PersistentSettings.h" +#include "GlobalSettingsPanel.h" + +namespace PokemonAutomation{ + + +PanelDescriptorWrapper GlobalSettings_Descriptor::INSTANCE; + +GlobalSettings_Descriptor::GlobalSettings_Descriptor() + : PanelDescriptor( + QColor(), + "GlobalSettings", + "Global Settings", + "", + "Global Settings" + ) +{} + + +GlobalSettings::GlobalSettings(const GlobalSettings_Descriptor& descriptor) + : SettingsPanelInstance(descriptor) +{ + m_options.emplace_back( + "StatsFile", + new String( + PERSISTENT_SETTINGS().stats_file, + "Stats File:
Use the stats file here. Multiple instances of the program can use the same file.", + "PA-Stats.txt" + ) + ); + m_options.emplace_back( + "Window Size (Width)", + new SimpleInteger( + PERSISTENT_SETTINGS().window_width, + "Window Size (Width):
" + "Set the width of the window. Restart application to take effect.
" + "Use this to easily set the window to a specific resolution for streaming alignment.
" + "Note that the actual resolution will be subject to your monitor's DPI scaling.", + 1280 + ) + ); + m_options.emplace_back( + "Window Size (height)", + new SimpleInteger( + PERSISTENT_SETTINGS().window_height, + "Window Size (Height):
" + "Set the height of the window. Restart application to take effect.
" + "Use this to easily set the window to a specific resolution for streaming alignment.
" + "Note that the actual resolution will be subject to your monitor's DPI scaling.", + 720 + ) + ); + m_options.emplace_back( + "LogEverything", + new BooleanCheckBox( + PERSISTENT_SETTINGS().log_everything, + "Log Everything:
Log everything to the output window and output log. Will be very spammy.", + false + ) + ); + m_options.emplace_back( + "DeveloperMode", + new BooleanCheckBox( + PERSISTENT_SETTINGS().developer_mode, + "Developer Mode:
Enable developer options. Restart application to take full effect.", + false + ) + ); + + if (PERSISTENT_SETTINGS().developer_mode){ + m_options.emplace_back( + "DISCORD_WEBHOOK_ID", + new String( + PERSISTENT_SETTINGS().DISCORD_WEBHOOK_ID, + "Discord webhook ID:
Some programs can send discord messages in your own private server. Set this to your discord webhook ID.", + "" + ) + ); + m_options.emplace_back( + "DISCORD_WEBHOOK_TOKEN", + new String( + PERSISTENT_SETTINGS().DISCORD_WEBHOOK_TOKEN, + "Discord webhook token:
Some programs can send discord messages in your own private server. Set this to your discord webhook token.", + "" + ) + ); + m_options.emplace_back( + "DISCORD_USER_ID", + new String( + PERSISTENT_SETTINGS().DISCORD_USER_ID, + "Discord user ID:
Some programs can send discord messages in your own private server. Set this to your discord user ID.", + "" + ) + ); + m_options.emplace_back( + "DISCORD_USER_SHORT_NAME", + new String( + PERSISTENT_SETTINGS().DISCORD_USER_SHORT_NAME, + "Discord user short name:
Some programs can send discord messages in your own private server. Set this to your discord user short name.", + "" + ) + ); + } +} + + +} diff --git a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h new file mode 100644 index 0000000000..2d22ceb20e --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h @@ -0,0 +1,35 @@ +/* Global Settings Panel + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_GlobalSettingsPanel_H +#define PokemonAutomation_GlobalSettingsPanel_H + +#include "CommonFramework/Panels/SettingsPanel.h" + +namespace PokemonAutomation{ + +class GlobalSettings; + +class GlobalSettings_Descriptor : public PanelDescriptor{ +public: + GlobalSettings_Descriptor(); +public: + static PanelDescriptorWrapper INSTANCE; +}; + + +class GlobalSettings : public SettingsPanelInstance{ +public: + GlobalSettings(const GlobalSettings_Descriptor& descriptor); +}; + + + + + + +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/Globals.cpp b/SerialPrograms/Source/CommonFramework/Globals.cpp index 8a199288d5..72e8edeb74 100644 --- a/SerialPrograms/Source/CommonFramework/Globals.cpp +++ b/SerialPrograms/Source/CommonFramework/Globals.cpp @@ -9,12 +9,15 @@ namespace PokemonAutomation{ -const QString VERSION = "v0.5.16"; -const QString DISCORD_LINK = "discord.gg/cQ4gWxN"; -const QString DISCORD_LINK_FULL = "https://" + DISCORD_LINK; -const QString GITHUB_REPO = "https://github.com/PokemonAutomation/SwSh-Arduino"; +const QString VERSION = "v0.7.12"; +const QString DISCORD_LINK = "discord.gg/PokemonAutomation"; +const QString DISCORD_LINK_URL = "https://discord.gg/cQ4gWxN"; +const QString ONLINE_DOC_URL = "https://github.com/PokemonAutomation/SwSh-Arduino"; +const QString PROJECT_GITHUB = "github.com/PokemonAutomation"; +const QString PROJECT_GITHUB_URL = "https://github.com/PokemonAutomation/"; const QString STRING_POKEMON = QString("Pok") + QChar(0xe9) + "mon"; +const QString STRING_POKEDEX = QString("Pok") + QChar(0xe9) + "dex"; diff --git a/SerialPrograms/Source/CommonFramework/Globals.h b/SerialPrograms/Source/CommonFramework/Globals.h index 08343b8d29..da36fed230 100644 --- a/SerialPrograms/Source/CommonFramework/Globals.h +++ b/SerialPrograms/Source/CommonFramework/Globals.h @@ -14,11 +14,14 @@ namespace PokemonAutomation{ extern const QString VERSION; extern const QString DISCORD_LINK; -extern const QString DISCORD_LINK_FULL; -extern const QString GITHUB_REPO; +extern const QString DISCORD_LINK_URL; +extern const QString ONLINE_DOC_URL; +extern const QString PROJECT_GITHUB; +extern const QString PROJECT_GITHUB_URL; const auto SERIAL_REFRESH_RATE = std::chrono::milliseconds(1000); extern const QString STRING_POKEMON; +extern const QString STRING_POKEDEX; diff --git a/SerialPrograms/Source/CommonFramework/Inference/AnomalyDetector.h b/SerialPrograms/Source/CommonFramework/Inference/AnomalyDetector.h index 60afbfe119..6f0622c97c 100644 --- a/SerialPrograms/Source/CommonFramework/Inference/AnomalyDetector.h +++ b/SerialPrograms/Source/CommonFramework/Inference/AnomalyDetector.h @@ -1,4 +1,4 @@ -/* Differential Anomaly Detector_H +/* Differential Anomaly Detector * * From: https://github.com/PokemonAutomation/Arduino-Source * diff --git a/SerialPrograms/Source/CommonFramework/Inference/BlackScreenDetector.cpp b/SerialPrograms/Source/CommonFramework/Inference/BlackScreenDetector.cpp index c758f4888b..8c4200a5ed 100644 --- a/SerialPrograms/Source/CommonFramework/Inference/BlackScreenDetector.cpp +++ b/SerialPrograms/Source/CommonFramework/Inference/BlackScreenDetector.cpp @@ -8,6 +8,7 @@ * */ +#include "Common/Compiler.h" #include "CommonFramework/Inference/ImageTools.h" #include "BlackScreenDetector.h" @@ -18,37 +19,28 @@ using std::endl; namespace PokemonAutomation{ BlackScreenDetector::BlackScreenDetector( - VideoFeed& feed, Logger& logger + VideoFeed& feed ) - : m_feed(feed) - , m_logger(logger) - , m_box(feed, 0.0, 0.0, 1.0, 1.0) + : m_box(feed, 0.1, 0.1, 0.8, 0.8) , m_has_been_black(false) {} BlackScreenDetector::BlackScreenDetector( - VideoFeed& feed, Logger& logger, + VideoFeed& feed, const InferenceBox& box ) - : m_feed(feed) - , m_logger(logger) - , m_box(feed, box) + : m_box(feed, box) , m_has_been_black(false) {} -bool BlackScreenDetector::black_is_over(){ - QImage image = m_feed.snapshot(); - if (image.isNull()){ - m_logger.log("BlackScreenDetector(): Screenshot failed.", "purple"); - return false; - } - -// ImageStats stats = pixel_stats(image); -// double average = stats.average.sum(); -// double stddev = stats.stddev.sum(); -// cout << stats.average << endl; -// m_logger.log("BlackScreenDetector(): a = " + QString::number(average) + ", s = " + QString::number(stddev), "purple"); -// if (average < 100 && stddev < 10){ +bool BlackScreenDetector::on_frame( + const QImage& frame, + std::chrono::system_clock::time_point timestamp +){ + return black_is_over(frame); +} +bool BlackScreenDetector::black_is_over(const QImage& frame){ + QImage image = extract_box(frame, m_box); if (is_black(image)){ m_has_been_black = true; return false; diff --git a/SerialPrograms/Source/CommonFramework/Inference/BlackScreenDetector.h b/SerialPrograms/Source/CommonFramework/Inference/BlackScreenDetector.h index a7aa7fe237..4414f2eccb 100644 --- a/SerialPrograms/Source/CommonFramework/Inference/BlackScreenDetector.h +++ b/SerialPrograms/Source/CommonFramework/Inference/BlackScreenDetector.h @@ -13,26 +13,23 @@ #include "CommonFramework/Tools/VideoFeed.h" #include "CommonFramework/Tools/Logger.h" +#include "CommonFramework/Inference/VisualInferenceCallback.h" namespace PokemonAutomation{ -class BlackScreenDetector{ +class BlackScreenDetector : public VisualInferenceCallbackWithCommandStop{ public: - BlackScreenDetector( - VideoFeed& feed, Logger& logger - ); - BlackScreenDetector( - VideoFeed& feed, Logger& logger, - const InferenceBox& box - ); - - bool black_is_over(); + BlackScreenDetector(VideoFeed& feed); + BlackScreenDetector(VideoFeed& feed, const InferenceBox& box); + bool black_is_over(const QImage& frame); + virtual bool on_frame( + const QImage& frame, + std::chrono::system_clock::time_point timestamp + ) override; private: - VideoFeed& m_feed; - Logger& m_logger; InferenceBoxScope m_box; bool m_has_been_black; }; diff --git a/SerialPrograms/Source/CommonFramework/Inference/ImageTools.cpp b/SerialPrograms/Source/CommonFramework/Inference/ImageTools.cpp index 9b83e2e849..b374438306 100644 --- a/SerialPrograms/Source/CommonFramework/Inference/ImageTools.cpp +++ b/SerialPrograms/Source/CommonFramework/Inference/ImageTools.cpp @@ -66,7 +66,7 @@ QImage extract_box(const QImage& image, const InferenceBox& box){ ); } -double image_diff(const QImage& x, const QImage& y){ +double image_diff_total(const QImage& x, const QImage& y){ if (x.isNull() || y.isNull()){ return -1; } @@ -83,12 +83,42 @@ double image_diff(const QImage& x, const QImage& y){ pxint_t height = x.height(); for (int r = 0; r < height; r++){ for (int c = 0; c < width; c++){ - sum += euclidean_distance(x.pixel(c, r), y.pixel(c, r)); +// sum += euclidean_distance(x.pixel(c, r), y.pixel(c, r)); + FloatPixel p = FloatPixel(x.pixel(c, r)) - FloatPixel(y.pixel(c, r)); + p *= p; + sum += p.sum(); } } +// return std::sqrt(sum / ((size_t)width * height)); return std::sqrt(sum / ((size_t)width * height)); } +QImage image_diff_greyscale(const QImage& x, const QImage& y){ + if (x.isNull() || y.isNull()){ + return QImage(); + } + if (x.width() != y.width()){ + return QImage(); + } + if (x.height() != y.height()){ + return QImage(); + } + + QImage image(x.width(), x.height(), x.format()); + pxint_t width = x.width(); + pxint_t height = x.height(); + for (int r = 0; r < height; r++){ + for (int c = 0; c < width; c++){ + double distance = euclidean_distance(x.pixel(c, r), y.pixel(c, r)); + distance *= 0.57735026918962576451; // 1 / sqrt(3) + int dist_int = std::min((int)distance, 255); + image.setPixel(c, r, qRgb(dist_int, dist_int, dist_int)); + } + } + return image; +} + + FloatPixel pixel_average(const QImage& image){ pxint_t w = image.width(); diff --git a/SerialPrograms/Source/CommonFramework/Inference/ImageTools.h b/SerialPrograms/Source/CommonFramework/Inference/ImageTools.h index 84ed1e52d2..f7a6f4da8e 100644 --- a/SerialPrograms/Source/CommonFramework/Inference/ImageTools.h +++ b/SerialPrograms/Source/CommonFramework/Inference/ImageTools.h @@ -26,7 +26,8 @@ InferenceBox translate_to_parent( QImage extract_box(const QImage& image, const PixelBox& box); QImage extract_box(const QImage& image, const InferenceBox& box); -double image_diff(const QImage& x, const QImage& y); +double image_diff_total(const QImage& x, const QImage& y); +QImage image_diff_greyscale(const QImage& x, const QImage& y); FloatPixel pixel_average(const QImage& image); FloatPixel pixel_average_normalized(const QImage& image); diff --git a/SerialPrograms/Source/CommonFramework/Inference/StatAccumulator.h b/SerialPrograms/Source/CommonFramework/Inference/StatAccumulator.h index 9ac8367aa5..39b91a5176 100644 --- a/SerialPrograms/Source/CommonFramework/Inference/StatAccumulator.h +++ b/SerialPrograms/Source/CommonFramework/Inference/StatAccumulator.h @@ -11,7 +11,7 @@ #include #include #include -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" namespace PokemonAutomation{ diff --git a/SerialPrograms/Source/CommonFramework/Inference/TimeWindowStatTracker.h b/SerialPrograms/Source/CommonFramework/Inference/TimeWindowStatTracker.h index dbf29b38b9..3c0848962e 100644 --- a/SerialPrograms/Source/CommonFramework/Inference/TimeWindowStatTracker.h +++ b/SerialPrograms/Source/CommonFramework/Inference/TimeWindowStatTracker.h @@ -28,6 +28,13 @@ class TimeWindowStatTracker{ return m_window; } + const StatObject& oldest() const{ + return m_history.begin()->second; + } + const StatObject& newest() const{ + return m_history.rbegin()->second; + } + system_clock::time_point push( const StatObject& stats, system_clock::time_point timestamp = system_clock::now() diff --git a/SerialPrograms/Source/CommonFramework/Inference/VisualInferenceCallback.cpp b/SerialPrograms/Source/CommonFramework/Inference/VisualInferenceCallback.cpp new file mode 100644 index 0000000000..bb47f908f7 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Inference/VisualInferenceCallback.cpp @@ -0,0 +1,38 @@ +/* Visual Inference Callback + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "CommonFramework/Tools/InterruptableCommands.h" +#include "VisualInferenceCallback.h" + +namespace PokemonAutomation{ + + +VisualInferenceCallbackWithCommandStop::VisualInferenceCallbackWithCommandStop() + : m_triggered(false) +{} + +void VisualInferenceCallbackWithCommandStop::register_command_stop(InterruptableCommandSession& session){ + m_command_stops.emplace_back(&session); +} + + +bool VisualInferenceCallbackWithCommandStop::process_frame( + const QImage& frame, + std::chrono::system_clock::time_point timestamp +){ + if (!on_frame(frame, timestamp)){ + return false; + } + m_triggered.store(true, std::memory_order_release); + for (InterruptableCommandSession* command : m_command_stops){ + command->stop(); + } + return true; +} + + + +} diff --git a/SerialPrograms/Source/CommonFramework/Inference/VisualInferenceCallback.h b/SerialPrograms/Source/CommonFramework/Inference/VisualInferenceCallback.h new file mode 100644 index 0000000000..1cecdcb35d --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Inference/VisualInferenceCallback.h @@ -0,0 +1,58 @@ +/* Visual Inference Callback + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_CommonFramework_VisualInferenceCallback_H +#define PokemonAutomation_CommonFramework_VisualInferenceCallback_H + +#include + +namespace PokemonAutomation{ + +class InterruptableCommandSession; + + +class VisualInferenceCallback{ +public: + // Return true if the inference session should stop. + virtual bool process_frame( + const QImage& frame, + std::chrono::system_clock::time_point timestamp + ) = 0; +}; + + + +class VisualInferenceCallbackWithCommandStop : public VisualInferenceCallback{ +public: + VisualInferenceCallbackWithCommandStop(); + + void register_command_stop(InterruptableCommandSession& session); + virtual bool on_frame( + const QImage& frame, + std::chrono::system_clock::time_point timestamp + ) = 0; + + // Returns true if this callback has returned true at least once. + bool triggered(){ + return m_triggered.load(std::memory_order_acquire); + } + +private: + virtual bool process_frame( + const QImage& frame, + std::chrono::system_clock::time_point timestamp + ) override final; + +private: + std::atomic m_triggered; + std::vector m_command_stops; +}; + + + + +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/Inference/VisualInferenceSession.cpp b/SerialPrograms/Source/CommonFramework/Inference/VisualInferenceSession.cpp new file mode 100644 index 0000000000..de73c0decb --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Inference/VisualInferenceSession.cpp @@ -0,0 +1,137 @@ +/* Async Visual Inference + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "VisualInferenceSession.h" + + +namespace PokemonAutomation{ + + + +VisualInferenceSession::VisualInferenceSession( + ProgramEnvironment& env, + VideoFeed& feed, + std::chrono::milliseconds period +) + : m_env(env) + , m_feed(feed) + , m_period(period) + , m_stop(false) +{} +VisualInferenceSession::~VisualInferenceSession(){ + stop(); +} +void VisualInferenceSession::stop(){ + m_stop.store(true, std::memory_order_release); + std::unique_lock lg(m_lock); + m_cv.notify_all(); +} + +void VisualInferenceSession::operator+=(std::function&& callback){ + std::unique_lock lg(m_lock); + m_callbacks0.emplace_back(std::move(callback)); +} +void VisualInferenceSession::operator+=(VisualInferenceCallback& callback){ + std::unique_lock lg(m_lock); + m_callbacks1.insert(&callback); +} +void VisualInferenceSession::operator-=(VisualInferenceCallback& callback){ + std::unique_lock lg(m_lock); + m_callbacks1.erase(&callback); +} + +void VisualInferenceSession::run(){ + auto wait_until = std::chrono::system_clock::now(); + wait_until += m_period; + while (true){ + m_env.check_stopping(); + if (m_stop.load(std::memory_order_acquire)){ + return; + } + + QImage screen = m_feed.snapshot(); + std::chrono::system_clock::time_point timestamp = std::chrono::system_clock::now(); + + std::unique_lock lg(m_lock); + for (auto& callback : m_callbacks0){ + if (callback(screen)){ + return; + } + } + for (VisualInferenceCallback* callback : m_callbacks1){ + if (callback->process_frame(screen, timestamp)){ + return; + } + } + + auto now = std::chrono::system_clock::now(); + auto wait = wait_until - now; + if (wait <= std::chrono::milliseconds(0)){ + wait_until = now + m_period; + }else{ + m_cv.wait_for( + lg, wait, + [=]{ + return + std::chrono::system_clock::now() >= wait_until || + m_env.is_stopping() || + m_stop.load(std::memory_order_acquire); + } + ); + wait_until += m_period; + } + } +} + + + + +VisualInferenceScope::VisualInferenceScope( + VisualInferenceSession& session, + VisualInferenceCallback& callback +) + : m_session(session) + , m_callback(callback) +{ + session += callback; +} +VisualInferenceScope::~VisualInferenceScope(){ + m_session -= m_callback; +} + + + + + +AsyncVisualInferenceSession::AsyncVisualInferenceSession( + ProgramEnvironment& env, + VideoFeed& feed, + std::chrono::milliseconds period +) + : VisualInferenceSession(env, feed, period) + , m_task(env.dispatcher().dispatch([this]{ thread_body(); })) +{} +AsyncVisualInferenceSession::~AsyncVisualInferenceSession(){ + stop(); +} +void AsyncVisualInferenceSession::stop(){ + VisualInferenceSession::stop(); + if (m_task){ + m_task->wait(); + } +} +void AsyncVisualInferenceSession::thread_body(){ + try{ + run(); + }catch (CancelledException&){} +} + + + + + + +} diff --git a/SerialPrograms/Source/CommonFramework/Inference/VisualInferenceSession.h b/SerialPrograms/Source/CommonFramework/Inference/VisualInferenceSession.h new file mode 100644 index 0000000000..8340de6c06 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Inference/VisualInferenceSession.h @@ -0,0 +1,90 @@ +/* Visual Inference Session + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_CommonFramework_VisualInferenceSession_H +#define PokemonAutomation_CommonFramework_VisualInferenceSession_H + +#include +#include "Common/Cpp/AsyncDispatcher.h" +#include "CommonFramework/Tools/ProgramEnvironment.h" +#include "CommonFramework/Tools/VideoFeed.h" +#include "VisualInferenceCallback.h" + +namespace PokemonAutomation{ + + + +class VisualInferenceSession{ +public: + VisualInferenceSession( + ProgramEnvironment& env, + VideoFeed& feed, + std::chrono::milliseconds period = std::chrono::milliseconds(50) + ); + ~VisualInferenceSession(); + + void operator+=(std::function&& callback); + void operator+=(VisualInferenceCallback& callback); + void operator-=(VisualInferenceCallback& callback); + + // Run the session. This will not return until the session is stopped. + void run(); + + // Call this from a different thread to asynchronously stop the session. + void stop(); + +private: + ProgramEnvironment& m_env; + VideoFeed& m_feed; + std::chrono::milliseconds m_period; + std::atomic m_stop; + std::vector> m_callbacks0; + std::set m_callbacks1; + std::mutex m_lock; + std::condition_variable m_cv; +}; + + + +// RAII wrapper for adding/removing infererence callbacks. +class VisualInferenceScope{ +public: + VisualInferenceScope( + VisualInferenceSession& session, + VisualInferenceCallback& callback + ); + ~VisualInferenceScope(); +private: + VisualInferenceSession& m_session; + VisualInferenceCallback& m_callback; +}; + + + + +class AsyncVisualInferenceSession : public VisualInferenceSession{ +public: + AsyncVisualInferenceSession( + ProgramEnvironment& env, + VideoFeed& feed, + std::chrono::milliseconds period = std::chrono::milliseconds(50) + ); + ~AsyncVisualInferenceSession(); + + void stop(); + +private: + void thread_body(); + +private: + std::unique_ptr m_task; +}; + + + + +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/Inference/VisualInferenceWait.cpp b/SerialPrograms/Source/CommonFramework/Inference/VisualInferenceWait.cpp new file mode 100644 index 0000000000..e905a26145 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Inference/VisualInferenceWait.cpp @@ -0,0 +1,71 @@ +/* Visual Inference Wait + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "VisualInferenceWait.h" + +namespace PokemonAutomation{ + + + +VisualInferenceWait::VisualInferenceWait( + ProgramEnvironment& env, + VideoFeed& feed, + std::chrono::milliseconds timeout, + std::chrono::milliseconds period +) + : m_env(env) + , m_feed(feed) + , m_timeout(timeout) + , m_period(period) +{} + +void VisualInferenceWait::operator+=(std::function&& callback){ + m_callbacks0.emplace_back(std::move(callback)); +} +void VisualInferenceWait::operator+=(VisualInferenceCallback& callback){ + m_callbacks1.insert(&callback); +} + +bool VisualInferenceWait::run(){ + auto start = std::chrono::system_clock::now(); + auto timeout = start + m_timeout; + auto next = start + m_period; + while (true){ + m_env.check_stopping(); + + QImage screen = m_feed.snapshot(); + std::chrono::system_clock::time_point timestamp = std::chrono::system_clock::now(); + + for (auto& callback : m_callbacks0){ + if (callback(screen)){ + return true; + } + } + for (VisualInferenceCallback* callback : m_callbacks1){ + if (callback->process_frame(screen, timestamp)){ + return true; + } + } + + auto now = std::chrono::system_clock::now(); + + if (m_timeout != std::chrono::milliseconds(0) && now >= timeout){ + return false; + } + + if (now >= next){ + next = now + m_period; + }else{ + m_env.wait(next - now); + next += m_period; + } + } +} + + + +} + diff --git a/SerialPrograms/Source/CommonFramework/Inference/VisualInferenceWait.h b/SerialPrograms/Source/CommonFramework/Inference/VisualInferenceWait.h new file mode 100644 index 0000000000..4cf8ce6399 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Inference/VisualInferenceWait.h @@ -0,0 +1,50 @@ +/* Visual Inference Wait + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + * Wait for an inference detection. + * + */ + +#ifndef PokemonAutomation_CommonFramework_VisualInferenceWait_H +#define PokemonAutomation_CommonFramework_VisualInferenceWait_H + +#include +#include +#include +#include "CommonFramework/Tools/ProgramEnvironment.h" +#include "CommonFramework/Tools/VideoFeed.h" +#include "VisualInferenceCallback.h" + +namespace PokemonAutomation{ + + +class VisualInferenceWait{ +public: + VisualInferenceWait( + ProgramEnvironment& env, + VideoFeed& feed, + std::chrono::milliseconds timeout, + std::chrono::milliseconds period = std::chrono::milliseconds(50) + ); + + void operator+=(std::function&& callback); + void operator+=(VisualInferenceCallback& callback); + + // Run inference and wait for result. Returns false if timed out. + bool run(); + +private: + ProgramEnvironment& m_env; + VideoFeed& m_feed; + std::chrono::milliseconds m_timeout; + std::chrono::milliseconds m_period; + std::vector> m_callbacks0; + std::set m_callbacks1; +}; + + + + +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/Language.cpp b/SerialPrograms/Source/CommonFramework/Language.cpp new file mode 100644 index 0000000000..f288d5fbad --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Language.cpp @@ -0,0 +1,82 @@ +/* Language + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include "Common/Cpp/Exception.h" +#include "Language.h" + +namespace PokemonAutomation{ + + + +const std::map LANGUAGE_DATA{ + {Language::None, {"none", "None", 0}}, + {Language::English, {"eng", "English", 1. / 5}}, + {Language::Japanese, {"jpn", "Japanese", 1. / 10}}, + {Language::Spanish, {"spa", "Spanish", 1. / 5}}, + {Language::French, {"fra", "French", 1. / 5}}, + {Language::German, {"deu", "German", 1. / 5}}, + {Language::Italian, {"ita", "Italian", 1. / 5}}, + {Language::Korean, {"kor", "Korean", 1. / 10}}, + {Language::ChineseSimplified, {"chi_sim", "Chinese (Simplified)", 1. / 100}}, + {Language::ChineseTraditional, {"chi_tra", "Chinese (Traditional)", 1. / 100}}, +}; + + + +bool LanguageSet::operator[](Language language) const{ + return m_set.find(language) != m_set.end(); +} +void LanguageSet::operator+=(Language language){ + m_set.insert(language); +} +void LanguageSet::operator-=(Language language){ + m_set.erase(language); +} +void LanguageSet::operator+=(const LanguageSet& set){ + for (Language language : set.m_set){ + m_set.insert(language); + } +} +void LanguageSet::operator-=(const LanguageSet& set){ + for (Language language : set.m_set){ + m_set.erase(language); + } +} + + + + + + +const LanguageData& language_data(Language language){ + auto iter = LANGUAGE_DATA.find(language); + if (iter == LANGUAGE_DATA.end()){ + PA_THROW_StringException("Invalid Language Enum: " + std::to_string((int)language)); + } + return iter->second; +} + +std::map build_code_to_enum_map(){ + std::map ret; + for (auto& iter : LANGUAGE_DATA){ + ret.emplace(iter.second.code, iter.first); + } + return ret; +} +const std::map CODE_TO_ENUM = build_code_to_enum_map(); + + +Language language_code_to_enum(const std::string& language){ + auto iter = CODE_TO_ENUM.find(language); + if (iter == CODE_TO_ENUM.end()){ + PA_THROW_StringException("Unknown Language Code: " + language); + } + return iter->second; +} + + +} diff --git a/SerialPrograms/Source/CommonFramework/Language.h b/SerialPrograms/Source/CommonFramework/Language.h new file mode 100644 index 0000000000..779432f78b --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Language.h @@ -0,0 +1,70 @@ +/* Language + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_Language_H +#define PokemonAutomation_Language_H + +#include +#include +#include +#include + +namespace PokemonAutomation{ + +enum class Language{ + None, + English, + Japanese, + Spanish, + French, + German, + Italian, + Korean, + ChineseSimplified, + ChineseTraditional, + EndOfList, +}; + +struct LanguageData{ + std::string code; + QString name; + double random_match_chance; +}; + +class LanguageSet{ +public: + LanguageSet() = default; + LanguageSet(std::initializer_list list) + : m_set(list) + {} + + bool operator[](Language language) const; + void operator+=(Language language); + void operator-=(Language language); + void operator+=(const LanguageSet& set); + void operator-=(const LanguageSet& set); + + std::set::const_iterator begin() const{ + return m_set.begin(); + } + std::set::const_iterator end() const{ + return m_set.end(); + } + + +private: + std::set m_set; +}; + + +const LanguageData& language_data(Language language); +Language language_code_to_enum(const std::string& language); + + + + +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/Main.cpp b/SerialPrograms/Source/CommonFramework/Main.cpp index 936be81fc4..f647921b30 100644 --- a/SerialPrograms/Source/CommonFramework/Main.cpp +++ b/SerialPrograms/Source/CommonFramework/Main.cpp @@ -1,9 +1,9 @@ #include -#include "Common/Qt/StringException.h" -#include "Tesseract/capi.h" +#include "Common/Cpp/Exception.h" #include "PersistentSettings.h" #include "CrashDump.h" +#include "Tools/StatsDatabase.h" #include "Windows/MainWindow.h" #include @@ -14,26 +14,32 @@ using std::endl; using namespace PokemonAutomation; -int main(int argc, char *argv[]) -{ +int main(int argc, char *argv[]){ setup_crash_handler(); QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication application(argc, argv); - cout << "Tesseract Version: " << TessVersion() << endl; - try{ - settings.read(); + PERSISTENT_SETTINGS().read(); }catch (const StringException& error){ - cout << error.message().toUtf8().data() << endl; + cout << error.what() << endl; + } + +#if 0 + { + StatSet stats; + stats.open_from_file(PERSISTENT_SETTINGS().stats_file); + stats.save_to_file(PERSISTENT_SETTINGS().stats_file); } -// int* ptr = nullptr; -// cout << *ptr << endl; +#endif - MainWindow w; - w.show(); - int ret = application.exec(); - settings.write(); + int ret; + { + MainWindow w; + w.show(); + ret = application.exec(); + } + PERSISTENT_SETTINGS().write(); return ret; } diff --git a/SerialPrograms/Source/CommonFramework/OCR/DictionaryMatcher.cpp b/SerialPrograms/Source/CommonFramework/OCR/DictionaryMatcher.cpp new file mode 100644 index 0000000000..6926f109e7 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/OCR/DictionaryMatcher.cpp @@ -0,0 +1,50 @@ +/* Dictionary Matcher + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "Common/Cpp/Exception.h" +#include "DictionaryMatcher.h" + +namespace PokemonAutomation{ +namespace OCR{ + + +const DictionaryOCR& DictionaryMatcher::dictionary(Language language) const{ + auto iter = m_database.find(language); + if (iter == m_database.end()){ + PA_THROW_StringException("Language not loaded."); + } + return iter->second; +} +DictionaryOCR& DictionaryMatcher::dictionary(Language language){ + SpinLockGuard lg(m_lock, "LargeDictionaryMatcher::dictionary()"); + auto iter = m_database.find(language); + if (iter == m_database.end()){ + PA_THROW_StringException("Language not loaded."); + } + return iter->second; +} + + +MatchResult DictionaryMatcher::match_substring( + Language language, + const QString& text +) const{ + return dictionary(language).match_substring(text); +} +MatchResult DictionaryMatcher::match_substring( + Language language, + const std::string& expected, + const QString& text +) const{ + return dictionary(language).match_substring(expected, text); +} +void DictionaryMatcher::add_candidate(Language language, std::string token, const QString& candidate){ + dictionary(language).add_candidate(std::move(token), candidate); +} + + +} +} diff --git a/SerialPrograms/Source/CommonFramework/OCR/DictionaryMatcher.h b/SerialPrograms/Source/CommonFramework/OCR/DictionaryMatcher.h new file mode 100644 index 0000000000..0493f74c33 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/OCR/DictionaryMatcher.h @@ -0,0 +1,54 @@ +/* Dictionary Matcher + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_OCR_DictionaryMatcher_H +#define PokemonAutomation_OCR_DictionaryMatcher_H + +#include +#include "Common/Cpp/SpinLock.h" +#include "CommonFramework/Language.h" +#include "DictionaryOCR.h" + +namespace PokemonAutomation{ +namespace OCR{ + + +class DictionaryMatcher{ +public: + const LanguageSet& languages() const{ return m_languages; } + + +public: + const DictionaryOCR& dictionary(Language language) const; + + MatchResult match_substring( + Language language, + const QString& text + ) const; + MatchResult match_substring( + Language language, + const std::string& expected, + const QString& text + ) const; + + +public: + // These functions are thread-safe with themselves, but not with any other + // functions in this class. + DictionaryOCR& dictionary(Language language); + void add_candidate(Language language, std::string token, const QString& candidate); + + +protected: + LanguageSet m_languages; + std::map m_database; + SpinLock m_lock; +}; + + +} +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/OCR/DictionaryOCR.cpp b/SerialPrograms/Source/CommonFramework/OCR/DictionaryOCR.cpp new file mode 100644 index 0000000000..59aac61f43 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/OCR/DictionaryOCR.cpp @@ -0,0 +1,122 @@ +/* Dictionary OCR + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include "Common/Cpp/Exception.h" +#include "Common/Qt/QtJsonTools.h" +#include "StringNormalization.h" +#include "TextMatcher.h" +#include "DictionaryOCR.h" + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ +namespace OCR{ + + +DictionaryOCR::DictionaryOCR(const QJsonObject& json, double random_match_chance, bool first_only) + : m_random_match_chance(random_match_chance) +{ + for (auto it = json.begin(); it != json.end(); ++it){ + std::string token = it.key().toUtf8().data(); + std::vector& candidates = m_database[token]; + for (const auto& item : it.value().toArray()){ + QString candidate = item.toString(); + QString normalized = normalize(candidate); + std::set& set = m_candidate_to_token[normalized]; + if (!set.empty()){ + cout << "Duplicate Candidate: " << it.key().toUtf8().data() << endl; + } + set.insert(token); + candidates.emplace_back(std::move(candidate)); + if (first_only){ + break; + } + } + } + cout << "Tokens: " << m_database.size() << ", Match Candidates: " << m_candidate_to_token.size() << endl; +} +DictionaryOCR::DictionaryOCR(const QString& json_path, double random_match_chance, bool first_only) + : DictionaryOCR(read_json_file(json_path).object(), random_match_chance, first_only) +{} + +QJsonObject DictionaryOCR::to_json() const{ + QJsonObject obj; + for (const auto& item : m_database){ + QJsonArray list; + for (const QString& candidate : item.second){ + list.append(candidate); + } + obj.insert(QString::fromUtf8(item.first.c_str()), list); + } + return obj; +} +void DictionaryOCR::save_json(const QString& json_path) const{ + write_json_file(json_path, QJsonDocument(to_json())); +} + + + +MatchResult DictionaryOCR::match_substring( + const QString& text, + double min_alpha +) const{ + return OCR::match_substring( + m_candidate_to_token, + text, + m_random_match_chance, + min_alpha + ); +} +MatchResult DictionaryOCR::match_substring( + const std::string& expected, + const QString& text, + double min_alpha +) const{ + MatchResult result = OCR::match_substring( + m_candidate_to_token, + text, + m_random_match_chance, + min_alpha + ); + result.expected_token = expected; + result.matched = result.matched && result.tokens.find(expected) != result.tokens.end(); + return result; +} +void DictionaryOCR::add_candidate(std::string token, const QString& candidate){ + if (candidate.isEmpty() || (candidate.size() == 1 && candidate[0] < 128)){ + return; + } + + SpinLockGuard lg(m_lock, "DictionaryOCR::add_candidate()"); + + auto iter = m_candidate_to_token.find(candidate); + if (iter == m_candidate_to_token.end()){ + // New candidate. Add it to both maps. + m_database[token].emplace_back(candidate); + m_candidate_to_token[candidate].insert(std::move(token)); + return; + } + + // Candidate already exists in table. + std::set& tokens = iter->second; + if (tokens.find(token) == tokens.end()){ + // Add to database only if it isn't already there. + m_database[token].emplace_back(candidate); + } + + tokens.insert(std::move(token)); +} + + + + + + +} +} diff --git a/SerialPrograms/Source/CommonFramework/OCR/DictionaryOCR.h b/SerialPrograms/Source/CommonFramework/OCR/DictionaryOCR.h new file mode 100644 index 0000000000..60eced026c --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/OCR/DictionaryOCR.h @@ -0,0 +1,58 @@ +/* Dictionary OCR + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_OCR_DictionaryOCR_H +#define PokemonAutomation_OCR_DictionaryOCR_H + +#include +#include +#include +#include +#include "Common/Cpp/SpinLock.h" +#include "CommonFramework/Tools/Logger.h" +#include "CommonFramework/OCR/TextMatcher.h" + +namespace PokemonAutomation{ +namespace OCR{ + + +class DictionaryOCR{ +public: + DictionaryOCR(const QJsonObject& json, double random_match_chance, bool first_only); + DictionaryOCR(const QString& json_path, double random_match_chance, bool first_only); + + QJsonObject to_json() const; + void save_json(const QString& json_path) const; + + MatchResult match_substring( + const QString& text, + double min_alpha = 25 + ) const; + + MatchResult match_substring( + const std::string& expected, + const QString& text, + double min_alpha = 100 + ) const; + + +public: + // This function is thread-safe with itself, but not with any other + // function in this class. + + void add_candidate(std::string token, const QString& candidate); + + +private: + SpinLock m_lock; + double m_random_match_chance; + std::map> m_database; + std::map> m_candidate_to_token; +}; + +} +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/OCR/Filtering.cpp b/SerialPrograms/Source/CommonFramework/OCR/Filtering.cpp new file mode 100644 index 0000000000..09f941f53e --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/OCR/Filtering.cpp @@ -0,0 +1,191 @@ +/* Image Filtering for OCR + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "CommonFramework/Inference/InferenceTypes.h" +#include "CommonFramework/Inference/FloatPixel.h" +#include "Filtering.h" + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ +namespace OCR{ + + + +BrightnessHistogram::BrightnessHistogram(){ + memset(m_count, 0, sizeof(m_count)); +} +BrightnessHistogram::BrightnessHistogram(const QImage& image) + : BrightnessHistogram() +{ + for (int y = 0; y < image.height(); y++){ + for (int x = 0; x < image.width(); x++){ + *this += image.pixel(x, y); + } + } +} + +void BrightnessHistogram::operator+=(QRgb pixel){ + m_pixels++; + uint16_t sum = (uint16_t)(qRed(pixel) + qBlue(pixel) + qGreen(pixel)); + m_count[sum / BUCKET_SIZE]++; +} + + +std::string BrightnessHistogram::dump() const{ + std::string str = "[" + std::to_string(m_count[0]); + for (size_t c = 1; c < BUCKETS; c++){ + str += ", " + std::to_string(m_count[c]); + } + str += "]"; + return str; +} + + + +void TextImageFilter::apply(QImage& image) const{ + if (black_text){ + for (int y = 0; y < image.height(); y++){ + for (int x = 0; x < image.width(); x++){ + QRgb pixel = image.pixel(x, y); + int sum = qRed(pixel) + qGreen(pixel) + qBlue(pixel); + pixel = sum < threshold ? qRgb(0, 0, 0) : qRgb(255, 255, 255); + image.setPixel(x, y, pixel); + + } + } + }else{ + for (int y = 0; y < image.height(); y++){ + for (int x = 0; x < image.width(); x++){ + QRgb pixel = image.pixel(x, y); + int sum = qRed(pixel) + qGreen(pixel) + qBlue(pixel); + pixel = sum > threshold ? qRgb(0, 0, 0) : qRgb(255, 255, 255); + image.setPixel(x, y, pixel); + + } + } + } +} + + + + +TextImageFilter make_OCR_filter(const QImage& image){ + const size_t BUCKETS = BrightnessHistogram::BUCKETS; + const uint16_t BUCKET_SIZE = BrightnessHistogram::BUCKET_SIZE; + + BrightnessHistogram histogram(image); +// cout << histogram.dump() << endl; + + uint32_t largest = 0; + size_t largest_index = 0; + for (size_t c = 0; c < BUCKETS; c++){ + if (largest < histogram[c]){ + largest = histogram[c]; + largest_index = c; + } + } + + size_t lo = std::max((int)largest_index - 2, 0); + size_t hi = std::min(largest_index + 2, BUCKETS); + + size_t below = 0; + for (size_t c = 0; c < lo; c++){ + below += histogram[c]; + } + + size_t above = 0; + for (size_t c = hi; c < BUCKETS; c++){ + above += histogram[c]; + } + + +#if 0 + TextImageFilter filter; + if (below < above){ + filter.black_text = false; + filter.threshold = hi * BUCKET_SIZE; + filter.threshold = 768 - (768 - filter.threshold) / 2; + }else{ + filter.black_text = true; + filter.threshold = lo * BUCKET_SIZE; + filter.threshold /= 2; + } + +#if 0 + cout << "lo = " << lo << endl; + cout << "largest_index = " << largest_index << endl; + cout << "hi = " << hi << endl; + cout << "below = " << below << endl; + cout << "above = " << above << endl; + cout << "threshold = " << filter.threshold << endl; +#endif +#else + + TextImageFilter filter; + if (largest_index < BUCKETS / 3){ + filter.black_text = false; + filter.threshold = hi * BUCKET_SIZE; + filter.threshold = 768 - (768 - filter.threshold) / 2; + }else{ + filter.black_text = true; + filter.threshold = lo * BUCKET_SIZE; + filter.threshold /= 2; + } + +#if 0 + cout << "lo = " << lo << endl; + cout << "largest_index = " << largest_index << endl; + cout << "hi = " << hi << endl; + cout << "threshold = " << filter.threshold << endl; +#endif +#endif + + + return filter; +} + + + + +void binary_filter_black_text(QImage& image, int max_rgb_sum){ + pxint_t w = image.width(); + pxint_t h = image.height(); +#if 0 + int min = 0; + for (pxint_t r = 0; r < h; r++){ + for (pxint_t c = 0; c < w; c++){ + QRgb pixel = image.pixel(c, r); + int sum = qRed(pixel) + qGreen(pixel) + qBlue(pixel); + min = std::min(min, sum); + } + } +#endif + +// cout << "min = " << min << endl; +// int threshold = min + 250; +// int threshold = 250; + + for (pxint_t r = 0; r < h; r++){ + for (pxint_t c = 0; c < w; c++){ + QRgb pixel = image.pixel(c, r); + int sum = qRed(pixel) + qGreen(pixel) + qBlue(pixel); + pixel = sum < max_rgb_sum ? qRgb(0, 0, 0) : qRgb(255, 255, 255); + image.setPixel(c, r, pixel); + } + } + +// static size_t c = 0; +// image.save("test-" + QString::number(c++) + ".png"); +} + + + +} +} + diff --git a/SerialPrograms/Source/CommonFramework/OCR/Filtering.h b/SerialPrograms/Source/CommonFramework/OCR/Filtering.h new file mode 100644 index 0000000000..2b0983ce19 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/OCR/Filtering.h @@ -0,0 +1,64 @@ +/* Image Filtering for OCR + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_OCR_Filtering_H +#define PokemonAutomation_OCR_Filtering_H + +#include + +namespace PokemonAutomation{ +namespace OCR{ + + +class BrightnessHistogram{ +public: + static const size_t BUCKETS = 24; + static const uint16_t BUCKET_SIZE = 3 * 256 / BUCKETS; + +public: + BrightnessHistogram(); + BrightnessHistogram(const QImage& image); + + void operator+=(QRgb pixel); + + uint32_t operator[](size_t bucket) const{ + return m_count[bucket]; + } + const uint32_t* histogram() const{ + return m_count; + } + + std::string dump() const; + + +private: + size_t m_pixels = 0; + uint32_t m_count[BUCKETS]; +}; + + + +struct TextImageFilter{ + bool black_text; + uint16_t threshold; + + void apply(QImage& image) const; +}; + + +TextImageFilter make_OCR_filter(const QImage& image); + + + +void binary_filter_black_text(QImage& image, int max_rgb_sum = 250); + + + + + +} +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/OCR/LargeDictionaryMatcher.cpp b/SerialPrograms/Source/CommonFramework/OCR/LargeDictionaryMatcher.cpp new file mode 100644 index 0000000000..dd4a80f546 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/OCR/LargeDictionaryMatcher.cpp @@ -0,0 +1,57 @@ +/* Large Database Matcher + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include +#include +#include "Common/Cpp/Exception.h" +#include "Common/Qt/QtJsonTools.h" +#include "CommonFramework/PersistentSettings.h" +#include "StringNormalization.h" +#include "TextMatcher.h" +#include "LargeDictionaryMatcher.h" + +namespace PokemonAutomation{ +namespace OCR{ + + + +LargeDictionaryMatcher::LargeDictionaryMatcher(const QString& json_file_prefix, bool first_only) + : m_prefix(PERSISTENT_SETTINGS().resource_path + json_file_prefix) +{ + for (size_t c = 1; c < (size_t)Language::EndOfList; c++){ + Language language = (Language)c; + const LanguageData& data = language_data(language); + const std::string& code = data.code; + try{ + m_database.emplace( + std::piecewise_construct, + std::forward_as_tuple(language), + std::forward_as_tuple(m_prefix + code.c_str() + ".json", data.random_match_chance, first_only) + ); + m_languages += language; + }catch (FileException&){} + } +} + +void LargeDictionaryMatcher::save(Language language, const QString& json_path) const{ + dictionary(language).save_json(json_path); +} + +#if 0 +void LargeDictionaryMatcher::update(Language language) const{ + const std::string& code = language_data(language).code; + save(language, m_prefix + "-" + code.c_str() + ".json"); +} +#endif + + + + + + +} +} diff --git a/SerialPrograms/Source/CommonFramework/OCR/LargeDictionaryMatcher.h b/SerialPrograms/Source/CommonFramework/OCR/LargeDictionaryMatcher.h new file mode 100644 index 0000000000..eb49e16b1f --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/OCR/LargeDictionaryMatcher.h @@ -0,0 +1,31 @@ +/* Large Dictionary Matcher + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_OCR_LargeDictionaryMatcher_H +#define PokemonAutomation_OCR_LargeDictionaryMatcher_H + +#include "DictionaryMatcher.h" + +namespace PokemonAutomation{ +namespace OCR{ + + +class LargeDictionaryMatcher : public DictionaryMatcher{ +public: + LargeDictionaryMatcher(const QString& json_file_prefix, bool first_only = false); + + void save(Language language, const QString& json_path) const; +// void update(Language language) const; + + +private: + QString m_prefix; +}; + + +} +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/OCR/RawOCR.cpp b/SerialPrograms/Source/CommonFramework/OCR/RawOCR.cpp new file mode 100644 index 0000000000..4af2251f5e --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/OCR/RawOCR.cpp @@ -0,0 +1,142 @@ +/* Raw Text Recognition + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include +#include +#include "Common/Cpp/Exception.h" +#include "Common/Cpp/SpinLock.h" +#include "CommonFramework/PersistentSettings.h" +#include "TesseractPA.h" +#include "RawOCR.h" + +namespace PokemonAutomation{ +namespace OCR{ + + + + +bool language_available(Language language){ + QString path = PERSISTENT_SETTINGS().resource_path; + path += "Tesseract/"; + path += language_data(language).code.c_str(); + path += ".traineddata"; + QFile file(path); + return file.exists(); +} + + + +class TesseractPool{ +public: + TesseractPool(Language language) + : m_language_code(language_data(language).code) + , m_training_data_path( + std::string(PERSISTENT_SETTINGS().resource_path.toUtf8().data()) + "Tesseract/" + ) + {} + + QString run(const QImage& image){ + TesseractAPI* instance; + do{ + { + SpinLockGuard lg(m_lock, "TesseractPool::run()"); + if (!m_idle.empty()){ + instance = m_idle.back(); + m_idle.pop_back(); + break; + } + } + + // Make sure training data exists. + std::string path = m_training_data_path + m_language_code + ".traineddata"; + QFile file(QString::fromUtf8(path.c_str())); + if (!file.exists()){ + return QString(); + } + + std::unique_ptr api( + new TesseractAPI(m_training_data_path.c_str(), m_language_code.c_str()) + ); + if (!api->valid()){ + PA_THROW_StringException("Could not initialize TesseractAPI."); + } + + SpinLockGuard lg(m_lock, "TesseractPool::run()"); + + m_instances.emplace_back(std::move(api)); + try{ + m_idle.emplace_back(m_instances.back().get()); + }catch (...){ + m_instances.pop_back(); + throw; + } + instance = m_idle.back(); + m_idle.pop_back(); + }while (false); + +// auto start = std::chrono::system_clock::now(); + TesseractString str = instance->read32( + image.bits(), + image.width(), + image.height(), + image.bytesPerLine() + ); +// auto end = std::chrono::system_clock::now(); +// cout << std::chrono::duration_cast(end - start).count() << endl; + + { + SpinLockGuard lg(m_lock, "TesseractPool::run()"); + m_idle.emplace_back(instance); + } + + return str.c_str() == nullptr + ? QString() + : QString::fromUtf8(str.c_str()); + } + +private: + const std::string& m_language_code; + const std::string m_training_data_path; + + SpinLock m_lock; + std::vector> m_instances; + std::vector m_idle; +}; + +SpinLock ocr_pool_lock; +std::map ocr_pool; + + +QString ocr_read(Language language, const QImage& image){ +// static size_t c = 0; +// image.save("test-" + QString::number(c++) + ".png"); + + const QImage& ready = image.format() == QImage::Format_RGB32 + ? image + : image.convertToFormat(QImage::Format_RGB32); + + std::map::iterator iter; + { + SpinLockGuard lg(ocr_pool_lock, "ocr_read()"); + iter = ocr_pool.find(language); + if (iter == ocr_pool.end()){ + iter = ocr_pool.emplace(language, language).first; + } + } + return iter->second.run(ready); +} + + + + + +} +} + + + + diff --git a/SerialPrograms/Source/CommonFramework/OCR/RawOCR.h b/SerialPrograms/Source/CommonFramework/OCR/RawOCR.h new file mode 100644 index 0000000000..293adaf33d --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/OCR/RawOCR.h @@ -0,0 +1,25 @@ +/* Raw Text Recognition + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_OCR_RawOCR_H +#define PokemonAutomation_OCR_RawOCR_H + +#include +#include "CommonFramework/Language.h" + +namespace PokemonAutomation{ +namespace OCR{ + + +bool language_available(Language language); + +QString ocr_read(Language language, const QImage& image); + + + +} +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/OCR/SmallDictionaryMatcher.cpp b/SerialPrograms/Source/CommonFramework/OCR/SmallDictionaryMatcher.cpp new file mode 100644 index 0000000000..9c8c7b0f66 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/OCR/SmallDictionaryMatcher.cpp @@ -0,0 +1,54 @@ +/* Small Database Matcher + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include "Common/Cpp/Exception.h" +#include "Common/Qt/QtJsonTools.h" +#include "CommonFramework/PersistentSettings.h" +#include "StringNormalization.h" +#include "TextMatcher.h" +#include "SmallDictionaryMatcher.h" + +namespace PokemonAutomation{ +namespace OCR{ + + + +SmallDictionaryMatcher::SmallDictionaryMatcher(const QString& json_offset, bool first_only) + : SmallDictionaryMatcher( + read_json_file(PERSISTENT_SETTINGS().resource_path + json_offset).object(), + first_only + ) +{} +SmallDictionaryMatcher::SmallDictionaryMatcher(const QJsonObject& json, bool first_only){ + for (auto iter = json.begin(); iter != json.end(); ++iter){ + Language language = language_code_to_enum(iter.key().toUtf8().data()); + const LanguageData& data = language_data(language); + m_database.emplace( + std::piecewise_construct, + std::forward_as_tuple(language), + std::forward_as_tuple(iter->toObject(), data.random_match_chance, first_only) + ); + m_languages += language; + } +} + + +void SmallDictionaryMatcher::save(const QString& json_path) const{ + QJsonObject root; + for (const auto& item : m_database){ + root.insert( + language_data(item.first).code.c_str(), + item.second.to_json() + ); + } + write_json_file(json_path, QJsonDocument(root)); +} + + + +} +} diff --git a/SerialPrograms/Source/CommonFramework/OCR/SmallDictionaryMatcher.h b/SerialPrograms/Source/CommonFramework/OCR/SmallDictionaryMatcher.h new file mode 100644 index 0000000000..c2d04f91b2 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/OCR/SmallDictionaryMatcher.h @@ -0,0 +1,28 @@ +/* Small Dictionary Matcher + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_OCR_SmallDictionaryMatcher_H +#define PokemonAutomation_OCR_SmallDictionaryMatcher_H + +#include +#include "DictionaryMatcher.h" + +namespace PokemonAutomation{ +namespace OCR{ + + +class SmallDictionaryMatcher : public DictionaryMatcher{ +public: + SmallDictionaryMatcher(const QString& json_offset, bool first_only = false); + SmallDictionaryMatcher(const QJsonObject& json, bool first_only = false); + + void save(const QString& json_path) const; +}; + + +} +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/OCR/StringNormalization.cpp b/SerialPrograms/Source/CommonFramework/OCR/StringNormalization.cpp new file mode 100644 index 0000000000..d18bc35cb6 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/OCR/StringNormalization.cpp @@ -0,0 +1,128 @@ +/* String Normalization + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include +#include "Common/Cpp/Exception.h" +#include "Common/Qt/QtJsonTools.h" +#include "CommonFramework/PersistentSettings.h" +#include "StringNormalization.h" + +namespace PokemonAutomation{ +namespace OCR{ + + + + +QString normalize(QString text){ + text = text.normalized(QString::NormalizationForm_KD); + text = remove_non_alphanumeric(text); + text = run_character_reductions(text); + text = text.toLower(); + return text; +} + + + + +QString remove_non_alphanumeric(const QString& text){ + QString str; + for (QChar ch : text){ + if (ch.isLetterOrNumber()){ + str += ch; + continue; + } +#if 0 + if (ch == QChar(0x3099)){ // Japanese dakuten. + str += ch; + continue; + } + if (ch == QChar(0x309A)){ // Japanese handakuten. + str += ch; + continue; + } +#endif + } + return str; +} +QString remove_white_space(const QString& text){ + QString str; + for (QChar ch : text){ + if (!ch.isSpace()){ + str += ch; + } + } + return str; +} +bool strip_leading_trailing_non_alphanumeric(QString& text){ + bool changed = false; + int s = 0; + int e = text.size(); + while (s < e && !text[s].isLetterOrNumber()){ + s++; + changed = true; + } + while (s < e && !text[e - 1].isLetterOrNumber()){ + e--; + changed = true; + } + if (changed){ + text = QString(text.data() + s, e - s); + } + return changed; +} + + + + +std::map make_substitution_map(){ + QJsonObject obj = read_json_file( + PERSISTENT_SETTINGS().resource_path + "Tesseract/CharacterReductions.json" + ).object(); + + std::map map; + for (auto item = obj.begin(); item != obj.end(); ++item){ + QString target = item.key(); + QString sources = item.value().toString(); + for (QChar ch : sources){ + auto iter = map.find(ch); + if (iter != map.end()){ + PA_THROW_StringException(QString("Duplicate character reduction: ") + ch); + } + map[ch] = target; + } + } + return map; +} +const std::map& SUBSTITUTION_MAP(){ + static std::map map = make_substitution_map(); + return map; +} +QString run_character_reductions(const QString& text){ + const std::map& map = SUBSTITUTION_MAP(); + + QString str; + for (QChar ch : text){ + auto iter = map.find(ch); + if (iter == map.end()){ + str += ch; + }else{ + str += iter->second; + } + } + return str; +} + + + + + + + + +} +} + diff --git a/SerialPrograms/Source/CommonFramework/OCR/StringNormalization.h b/SerialPrograms/Source/CommonFramework/OCR/StringNormalization.h new file mode 100644 index 0000000000..2e81477cb4 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/OCR/StringNormalization.h @@ -0,0 +1,27 @@ +/* String Normalization + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_OCR_StringNormalization_H +#define PokemonAutomation_OCR_StringNormalization_H + +#include + +namespace PokemonAutomation{ +namespace OCR{ + +QString remove_white_space(const QString& text); +QString remove_non_alphanumeric(const QString& text); +bool strip_leading_trailing_non_alphanumeric(QString& text); + +QString run_character_reductions(const QString& text); + +QString normalize(QString text); + + + +} +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/OCR/TesseractPA.h b/SerialPrograms/Source/CommonFramework/OCR/TesseractPA.h new file mode 100644 index 0000000000..aed1cefaa5 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/OCR/TesseractPA.h @@ -0,0 +1,165 @@ +/* Tesseract Wrapper + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_TesseractPA_H +#define PokemonAutomation_TesseractPA_H + +#include + +//#define TESSERACT_STATIC + +#ifdef TESSERACT_STATIC +#define TESSERACT_EXPORT +#else + +#ifdef _WIN32 + +#ifdef _WINDLL +#define TESSERACT_EXPORT __declspec(dllexport) +#else +#define TESSERACT_EXPORT __declspec(dllimport) +#endif + +#else + +#define TESSERACT_EXPORT __attribute__((visibility("default"))) + +#endif +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + +struct TesseractAPI_internal; +TESSERACT_EXPORT TesseractAPI_internal* TesseractAPI_construct( + const char* path, const char* language +); +TESSERACT_EXPORT void TesseractAPI_destroy(TesseractAPI_internal* api); + +//TESSERACT_EXPORT char* TesseractAPI_read_file(TesseractAPI_internal* api, const char* filepath); +TESSERACT_EXPORT char* TesseractAPI_read_bitmap( + TesseractAPI_internal* api, + const unsigned char* data, + size_t width, size_t height, + size_t bytes_per_pixel, size_t bytes_per_line, + size_t ppi +); +TESSERACT_EXPORT void Tesseract_delete(char* text); + + +#ifdef __cplusplus +} +#endif + + + + +class TesseractString{ +public: + ~TesseractString(){ +#ifdef PA_TESSERACT + if (m_str != nullptr){ + Tesseract_delete(m_str); + } +#endif + } + TesseractString(const TesseractString&) = delete; + void operator=(const TesseractString&) = delete; + TesseractString(TesseractString&& x) + : m_str(x.m_str) + { + x.m_str = nullptr; + } + void operator=(TesseractString&& x){ + m_str = x.m_str; + x.m_str = nullptr; + } + +public: + const char* c_str() const{ + return m_str; + } + +private: + TesseractString(char* str) + : m_str(str) + {} + +private: + friend class TesseractAPI; + char* m_str; +}; + + +class TesseractAPI{ +public: + ~TesseractAPI(){ +#ifdef PA_TESSERACT + if (m_api != nullptr){ + TesseractAPI_destroy(m_api); + } +#endif + } + TesseractAPI(const TesseractAPI&) = delete; + void operator=(const TesseractAPI&) = delete; + TesseractAPI(TesseractAPI&& x) + : m_api(x.m_api) + { + x.m_api = nullptr; + } + void operator=(TesseractAPI&& x){ + m_api = x.m_api; + x.m_api = nullptr; + } + +public: + TesseractAPI(const char* path, const char* language) +#ifdef PA_TESSERACT + : m_api(TesseractAPI_construct(path, language)) +#endif + {} + + bool valid() const{ return m_api != nullptr; } + +// TesseractString read(const char* filepath){ +//#ifdef PA_TESSERACT +// return TesseractAPI_read_file(m_api, filepath); +//#else +// return nullptr; +//#endif +// } + TesseractString read32( + const unsigned char* data, + size_t width, size_t height, + size_t bytes_per_line, size_t ppi = 100 + ){ +#ifdef PA_TESSERACT + return TesseractAPI_read_bitmap( + m_api, + data, + width, height, + sizeof(uint32_t), + bytes_per_line, + ppi + ); +#else + return nullptr; +#endif + } + +private: + TesseractAPI_internal* m_api = nullptr; +}; + + + + +#endif + diff --git a/SerialPrograms/Source/CommonFramework/OCR/TextMatcher.cpp b/SerialPrograms/Source/CommonFramework/OCR/TextMatcher.cpp new file mode 100644 index 0000000000..85d078f806 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/OCR/TextMatcher.cpp @@ -0,0 +1,335 @@ +/* Text Inference Tools + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include "Common/Cpp/SpinLock.h" +#include "Common/Cpp/Exception.h" +#include "StringNormalization.h" +#include "TextMatcher.h" + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ +namespace OCR{ + +void print(const std::vector& v){ + std::string str = "{"; + bool first = true; + for (size_t x : v){ + if (!first){ + str += ", "; + } + first = false; + str += std::to_string(x); + } + str += "}"; + cout << str << endl; +} + + +size_t levenshtein_distance(const QString& x, const QString& y){ + size_t xlen = x.size(); + size_t ylen = y.size(); + + std::vector v0(ylen + 1); + std::vector v1(ylen + 1); + + for (size_t i = 0; i <= ylen; i++){ + v0[i] = i; + } + + for (size_t i = 0; i < xlen; i++){ + v1[0] = i + 1; + + for (size_t j = 0; j < ylen; j++){ + size_t delete_cost = v0[j + 1] + 1; + size_t insert_cost = v1[j] + 1; + size_t sub_cost = v0[j]; + if (x[(int)i] != y[(int)j]){ + sub_cost += 1; + } + v1[j + 1] = std::min({delete_cost, insert_cost, sub_cost}); + } + + std::swap(v0, v1); + } + + return v0[ylen]; +} +size_t levenshtein_distance_substring(const QString& substring, const QString& fullstring){ + size_t xlen = fullstring.size(); + size_t ylen = substring.size(); + + std::vector v0(ylen + 1); + std::vector v1(ylen + 1); + + for (size_t i = 0; i <= ylen; i++){ + v0[i] = i; + } +// print(v0); + + size_t min = ylen; + + for (size_t i = 0; i < xlen; i++){ + v1[0] = 0; + + for (size_t j = 0; j < ylen; j++){ + size_t delete_cost = v0[j + 1] + 1; + size_t insert_cost = v1[j] + 1; + size_t sub_cost = v0[j]; + if (fullstring[(int)i] != substring[(int)j]){ + sub_cost += 1; + } + v1[j + 1] = std::min({delete_cost, insert_cost, sub_cost}); + } + + std::swap(v0, v1); + + min = std::min(min, v0[ylen]); +// print(v0); + } + + return min; +} + + +std::map> binomial_table; +SpinLock binomial_lock; +std::vector binomial_row_u64(size_t degree){ + std::vector row; + + uint64_t a = (uint64_t)degree; + uint64_t b = 1; + { + row.emplace_back(1); + } + { + row.emplace_back(a); + a--; + b++; + } + while (a > b){ + row.emplace_back(row.back() * a / b); + a--; + b++; + } + + return row; +} +uint64_t binomial_coefficient_u64(size_t degree, size_t index){ + + if (degree > 62){ + PA_THROW_StringException("Cannot go beyond degree 62."); + } + + SpinLockGuard lg(binomial_lock, "binomial_coefficient_u64()"); + + auto iter = binomial_table.find(degree); + std::vector& row = iter != binomial_table.end() + ? iter->second + : binomial_table[degree] = binomial_row_u64(degree); + + if (index > degree / 2){ + index = degree - index; + } + + return row[index]; +} + + +double random_match_probability(size_t total, size_t matched, double random_match_chance){ + double c_match = 1 - random_match_chance; + + double misses[62]; + { + double miss = 1; + misses[0] = miss; + for (size_t c = 1; c <= total - matched; c++){ + miss *= c_match; + misses[c] = miss; + } + } + + double hits = 1; + + size_t m = 0; + for (; m < matched; m++){ + hits *= random_match_chance; + } + + double probability = 0; + for (; m < total; m++){ + double binomial = (double)binomial_coefficient_u64(total, m); + probability += hits * binomial * misses[total - m]; + hits *= random_match_chance; + } + probability += hits; + return probability; +} + + + + + + +void MatchResult::log(Logger* logger, const QString& extra) const{ + if (logger == nullptr){ + return; + } + + QString str = "OCR Result: "; + + if (!expected_token.empty()){ + str += "Expected ("; + str += expected_token.c_str(); + str += "): "; + } + + str += "\""; + for (QChar ch : ocr_text){ + if (ch != '\r' && ch != '\n'){ + str += ch; + } + } + str += "\" -> "; + str += "\"" + normalized_text + "\" -> "; + + QString candidate_str; + if (candidates.size() > 5){ + candidate_str += "(" + QString::number(candidates.size()) + " candidates)"; + }else{ + candidate_str += "("; + for (size_t c = 0; c < candidates.size(); c++){ + candidate_str += "\"" + candidates[c] + "\""; + if (c + 1 < candidates.size()){ + candidate_str += ", "; + } + } + candidate_str += ")"; + } + + QString token_str; + if (tokens.size() > 5){ + token_str += "(" + QString::number(candidates.size()) + " matches)"; + }else{ + token_str += "("; + bool first = true; + for (const std::string& token : tokens){ + if (!first){ + token_str += ", "; + } + first = false; + token_str += "\"" + QString(token.c_str()) + "\""; + } + token_str += ")"; + } + + str += candidate_str; + str += ": "; + str += token_str; +// str += " (error = " + QString::number(exact_match_error) + ")"; + str += " (alpha = " + QString::number(alpha) + ")"; + + if (!extra.isEmpty()){ + str += " ===> "; + str += extra; + } + + logger->log(str, matched ? Qt::blue : Qt::red); +} + + + + +MatchResult match_substring( + const std::map>& database, + const QString& text, + double random_match_chance, + double min_alpha +){ + MatchResult result; + result.ocr_text = text; + result.normalized_text = normalize(text); + + const QString& normalized = result.normalized_text; + + // Search for exact match of candidate. + auto iter = database.find(normalized); + if (iter != database.end()){ + result.matched = true; +// result.exact_match_error = 0; + result.alpha = 1. / random_match_probability(normalized.size(), normalized.size(), random_match_chance); + result.candidates = {normalized}; + result.tokens = iter->second; + return result; + } + + + bool exact_substring_match = false; +// double best_error = 1.0; + double best_alpha = 0; + std::vector candidates; + std::set tokens; + + for (auto item : database){ + double token_length = item.first.size(); + +// double error = (double)levenshtein_distance(item.first, normalized); +// error /= token_length; + + size_t distance = levenshtein_distance_substring(item.first, normalized); + size_t matched = token_length - distance; + double alpha = 1. / random_match_probability(token_length, matched, random_match_chance); + +// double alpha = (token_length - (double)distance) / std::sqrt(token_length); + + if (distance == 0){ + exact_substring_match = true; + } + +#if 0 + if (error < 1.0 && best_error > error){ + best_error = error; + candidates.clear(); + candidates.emplace_back(item.first); + tokens = item.second; + }else if (best_error < 1.0 && best_error == error){ + candidates.emplace_back(item.first); + tokens.insert(item.second.begin(), item.second.end()); + } +#else + if (alpha > 2.0 && best_alpha < alpha){ +// best_error = error; + best_alpha = alpha; + candidates.clear(); + candidates.emplace_back(item.first); + tokens = item.second; + }else if (alpha > 2.0 && best_alpha == alpha){ + candidates.emplace_back(item.first); + tokens.insert(item.second.begin(), item.second.end()); + } +#endif + } + result.matched = exact_substring_match || best_alpha >= min_alpha; +// result.exact_match_error = best_error; + result.alpha = best_alpha; + result.candidates = candidates; + result.tokens = tokens; + return result; +} + + + + + + + + +} +} + diff --git a/SerialPrograms/Source/CommonFramework/OCR/TextMatcher.h b/SerialPrograms/Source/CommonFramework/OCR/TextMatcher.h new file mode 100644 index 0000000000..e5bf4fd01d --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/OCR/TextMatcher.h @@ -0,0 +1,54 @@ +/* Text Matcher + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_OCR_TextMatcher_H +#define PokemonAutomation_OCR_TextMatcher_H + +#include +#include +#include +#include +#include "CommonFramework/Tools/Logger.h" + +namespace PokemonAutomation{ +namespace OCR{ + + + +size_t levenshtein_distance(const QString& x, const QString& y); +size_t levenshtein_distance_substring(const QString& substring, const QString& fullstring); + +// Mathematically equivalent to: +// BinomialCDF[total, 1 - random_match_chance, total - matched] +double random_match_probability(size_t total, size_t matched, double random_match_chance); + +struct MatchResult{ + bool matched = false; +// double exact_match_error = 1.0; + double alpha = 0; + QString ocr_text; + QString normalized_text; + std::vector candidates; + std::set tokens; + std::string expected_token; + + void log(Logger* logger, const QString& extra = QString()) const; +}; + + +MatchResult match_substring( + const std::map>& database, + const QString& text, + double random_match_chance, + double min_alpha +); + + + + +} +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/OCR/TrainingTools.cpp b/SerialPrograms/Source/CommonFramework/OCR/TrainingTools.cpp new file mode 100644 index 0000000000..15c7b39793 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/OCR/TrainingTools.cpp @@ -0,0 +1,226 @@ +/* Training Tools + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include "Common/Cpp/PrettyPrint.h" +#include "Common/Cpp/ParallelTaskRunner.h" +#include "CommonFramework/PersistentSettings.h" +#include "CommonFramework/OCR/RawOCR.h" +#include "CommonFramework/OCR/Filtering.h" +#include "SmallDictionaryMatcher.h" +#include "LargeDictionaryMatcher.h" +#include "TrainingTools.h" + +namespace PokemonAutomation{ +namespace OCR{ + + + +std::string extract_name(const QString& filename){ + std::string name = filename.toUtf8().data(); + while (!name.empty()){ + char ch = name.back(); + name.pop_back(); + if (ch == '.'){ + break; + } + } + while (!name.empty()){ + char ch = name.back(); + name.pop_back(); + if (ch == '-'){ + break; + } + } + while (!name.empty()){ + char ch = name.back(); + name.pop_back(); + if (ch == '-'){ + break; + } + } + return name; +} + + + +TrainingSession::TrainingSession( + ProgramEnvironment& env, + const QString& training_data_directory +) + : m_directory(PERSISTENT_SETTINGS().training_data + training_data_directory) + , m_total_samples(0) +{ + if (!m_directory.isEmpty() && m_directory.back() != '/' && m_directory.back() != '\\'){ + m_directory += "/"; + } + + env.log("Parsing training data in: " + m_directory); + + QDirIterator iter(m_directory, QDir::AllDirs); + while (iter.hasNext()){ + iter.next(); + QString sample_directory = iter.fileName() + "/"; + for (size_t c = 1; c < (size_t)Language::EndOfList; c++){ + Language language = (Language)c; + const std::string& code = language_data(language).code; + QString folder = sample_directory + code.c_str() + "/"; + QDirIterator iter(m_directory + folder, QStringList() << "*.png", QDir::Files); + while (iter.hasNext()){ + iter.next(); +// QString file = iter.next(); + m_samples[language].emplace_back( + OCR::extract_name(iter.fileName()), + folder + iter.fileName() + ); + m_total_samples++; + + env.check_stopping(); + } + } + env.check_stopping(); + } + + env.log( + "Parsing Complete: Languages = " + tostr_u_commas(m_samples.size()) + + ", Samples = " + tostr_u_commas(m_total_samples) + ); +} + + +void TrainingSession::generate_small_dictionary( + ProgramEnvironment& env, + const QString& ocr_json_file, + const QString& output_json_file, + bool incremental, + size_t threads +){ + env.log("Generating OCR Data..."); + + OCR::SmallDictionaryMatcher baseline(ocr_json_file, !incremental); + OCR::SmallDictionaryMatcher trained(ocr_json_file, !incremental); + + ParallelTaskRunner task_runner(0, threads); + + std::atomic matched = 0; + std::atomic failed = 0; + for (const auto& language : m_samples){ + const LanguageData& language_info = language_data(language.first); + env.log("Starting Language: " + language_info.name); +// cout << (int)item.first << " : " << item.second.size() << endl; + for (const TrainingSample& sample : language.second){ + task_runner.dispatch([&]{ + QImage image(m_directory + sample.filepath); + if (image.isNull()){ + env.log("Skipping: " + sample.filepath); + return; + } + OCR::make_OCR_filter(image).apply(image); + QString text = OCR::ocr_read(language.first, image); + + OCR::MatchResult result = baseline.match_substring( + language.first, + sample.token, + text + ); + if (result.matched){ + matched++; +// result.log(&env.logger(), sample.filepath); + }else{ + failed++; + result.log(&env.logger(), sample.filepath); + trained.add_candidate(language.first, sample.token, result.normalized_text); + } + +// cout << "matched = " << matched << ", failed = " << failed << endl; + }); + + env.check_stopping(); + } + + task_runner.wait_for_everything(); + + env.check_stopping(); + } + + env.log("Languages: " + tostr_u_commas(m_samples.size())); + env.log("Samples: " + tostr_u_commas(m_total_samples)); + env.log("Matched: " + tostr_u_commas(matched)); + env.log("Missed: " + tostr_u_commas(failed)); + + trained.save(output_json_file); +} + +void TrainingSession::generate_large_dictionary( + ProgramEnvironment& env, + const QString& ocr_json_directory, + const QString& output_prefix, + bool incremental, + size_t threads +) const{ + env.log("Generating OCR Data..."); + + OCR::LargeDictionaryMatcher baseline(ocr_json_directory + output_prefix, !incremental); + OCR::LargeDictionaryMatcher trained(ocr_json_directory + output_prefix, !incremental); + + ParallelTaskRunner task_runner(0, threads); + + std::atomic matched = 0; + std::atomic failed = 0; + for (const auto& language : m_samples){ + const LanguageData& language_info = language_data(language.first); + env.log("Starting Language: " + language_info.name); +// cout << (int)item.first << " : " << item.second.size() << endl; + for (const TrainingSample& sample : language.second){ + task_runner.dispatch([&]{ + QImage image(m_directory + sample.filepath); + if (image.isNull()){ + env.log("Skipping: " + sample.filepath); + return; + } + OCR::make_OCR_filter(image).apply(image); + QString text = OCR::ocr_read(language.first, image); + + OCR::MatchResult result = baseline.match_substring( + language.first, + sample.token, + text + ); + if (result.matched){ + matched++; + }else{ + failed++; + result.log(&env.logger(), sample.filepath); + trained.add_candidate(language.first, sample.token, result.normalized_text); + } + + }); + + env.check_stopping(); + } + + task_runner.wait_for_everything(); + + QString json = output_prefix + language_info.code.c_str() + ".json"; + trained.save(language.first, json); + + env.check_stopping(); + } + + env.log("Languages: " + tostr_u_commas(m_samples.size())); + env.log("Samples: " + tostr_u_commas(m_total_samples)); + env.log("Matched: " + tostr_u_commas(matched)); + env.log("Missed: " + tostr_u_commas(failed)); +} + + + + + + +} +} + diff --git a/SerialPrograms/Source/CommonFramework/OCR/TrainingTools.h b/SerialPrograms/Source/CommonFramework/OCR/TrainingTools.h new file mode 100644 index 0000000000..77b7bfa911 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/OCR/TrainingTools.h @@ -0,0 +1,63 @@ +/* Training Tools + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_OCR_TrainingTools_H +#define PokemonAutomation_OCR_TrainingTools_H + +#include +#include +#include +#include +#include "CommonFramework/Language.h" +#include "CommonFramework/Tools/ProgramEnvironment.h" + +namespace PokemonAutomation{ +namespace OCR{ + + +struct TrainingSample{ + std::string token; + QString filepath; +}; + + +class TrainingSession{ +public: + TrainingSession( + ProgramEnvironment& env, + const QString& training_data_directory + ); + + void generate_small_dictionary( + ProgramEnvironment& env, + const QString& ocr_json_file, + const QString& output_json_file, + bool incremental, + size_t threads + ); + void generate_large_dictionary( + ProgramEnvironment& env, + const QString& ocr_json_directory, + const QString& output_prefix, + bool incremental, + size_t threads + ) const; + +private: + QString m_directory; + size_t m_total_samples; + std::map> m_samples; +}; + + + + +std::string extract_name(const QString& filename); + + +} +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/Options/EnumDropdown.cpp b/SerialPrograms/Source/CommonFramework/Options/EnumDropdown.cpp new file mode 100644 index 0000000000..c602839590 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Options/EnumDropdown.cpp @@ -0,0 +1,104 @@ +/* Enum Dropdown Option + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include +#include "Common/Qt/NoWheelComboBox.h" +#include "EnumDropdown.h" + +namespace PokemonAutomation{ + + +EnumDropdown::EnumDropdown( + QString label, + std::vector cases, + size_t default_index +) + : ConfigOption(std::move(label)) + , m_case_list(std::move(cases)) + , m_default(default_index) + , m_current(default_index) +{ + if (default_index >= m_case_list.size()){ + throw "Index is too large."; + } + + for (size_t index = 0; index < m_case_list.size(); index++){ + const QString& item = m_case_list[index]; + auto ret = m_case_map.emplace( + std::piecewise_construct, + std::forward_as_tuple(item), + std::forward_as_tuple(index) + ); + if (!ret.second){ + throw "Duplicate enum label."; + } + } +} + + +void EnumDropdown::load_json(const QJsonValue& json){ + if (!json.isString()){ + return; + } + QString str = json.toString(); + auto iter = m_case_map.find(str); + if (iter != m_case_map.end()){ + m_current = iter->second; + } +} +QJsonValue EnumDropdown::to_json() const{ + return QJsonValue(m_case_list[m_current]); +} + +void EnumDropdown::restore_defaults(){ + m_current = m_default; +} + +ConfigOptionUI* EnumDropdown::make_ui(QWidget& parent){ + return new EnumDropdownUI(parent, *this); +} + + + +EnumDropdownUI::EnumDropdownUI(QWidget& parent, EnumDropdown& value) + : QWidget(&parent) + , m_value(value) +{ + QHBoxLayout* layout = new QHBoxLayout(this); + QLabel* text = new QLabel(m_value.m_label, this); + layout->addWidget(text, 1); + text->setWordWrap(true); + m_box = new NoWheelComboBox(&parent); + layout->addWidget(m_box); + + for (const QString& item : m_value.m_case_list){ + m_box->addItem(item); + } + m_box->setCurrentIndex((int)m_value.m_current); + layout->addWidget(m_box, 1); + + connect( + m_box, static_cast(&QComboBox::currentIndexChanged), + this, [=](int index){ + if (index < 0){ + m_value.restore_defaults(); + return; + } + m_value.m_current = index; + } + ); +} + + +void EnumDropdownUI::restore_defaults(){ + m_value.restore_defaults(); + m_box->setCurrentIndex((int)m_value); +} + + + +} diff --git a/SerialPrograms/Source/CommonFramework/Options/EnumDropdown.h b/SerialPrograms/Source/CommonFramework/Options/EnumDropdown.h new file mode 100644 index 0000000000..6b49f0058e --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Options/EnumDropdown.h @@ -0,0 +1,59 @@ +/* Enum Dropdown Option + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_EnumDropdown_H +#define PokemonAutomation_EnumDropdown_H + +#include +#include +#include "ConfigOption.h" + +namespace PokemonAutomation{ + + +class EnumDropdown : public ConfigOption{ +public: + EnumDropdown( + QString label, + std::vector cases, + size_t default_index + ); + + operator size_t() const{ return m_current; } + + virtual void load_json(const QJsonValue& json) override; + virtual QJsonValue to_json() const override; + + virtual void restore_defaults() override; + + virtual ConfigOptionUI* make_ui(QWidget& parent) override; + +private: + friend class EnumDropdownUI; + + std::vector m_case_list; + std::map m_case_map; + size_t m_default; + size_t m_current; +}; + + + +class EnumDropdownUI : public ConfigOptionUI, public QWidget{ +public: + EnumDropdownUI(QWidget& parent, EnumDropdown& value); + virtual QWidget* widget() override{ return this; } + virtual void restore_defaults() override; + +private: + EnumDropdown& m_value; + QComboBox* m_box; +}; + + + +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/Options/FixedCode.cpp b/SerialPrograms/Source/CommonFramework/Options/FixedCode.cpp index 6397157bf9..2294149bc4 100644 --- a/SerialPrograms/Source/CommonFramework/Options/FixedCode.cpp +++ b/SerialPrograms/Source/CommonFramework/Options/FixedCode.cpp @@ -6,7 +6,7 @@ #include #include -#include "Common/Qt/StringException.h" +#include "Common/Cpp/Exception.h" #include "Common/Qt/CodeValidator.h" #include "FixedCode.h" @@ -56,8 +56,8 @@ QString FixedCodeUI::sanitized_code(const QString& text) const{ QString message; try{ message = "Code: " + sanitize_code(m_value.m_digits, text); - }catch (const StringException& str){ - message = "" + str.message() + ""; + }catch (const ParseException& e){ + message = "" + e.message_qt() + ""; } return message; } diff --git a/SerialPrograms/Source/CommonFramework/Options/LanguageOCR.cpp b/SerialPrograms/Source/CommonFramework/Options/LanguageOCR.cpp new file mode 100644 index 0000000000..844eb70b3d --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Options/LanguageOCR.cpp @@ -0,0 +1,180 @@ +/* Language OCR Option + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include +#include +#include +#include "Common/Cpp/Exception.h" +#include "Common/Qt/NoWheelComboBox.h" +#include "CommonFramework/Globals.h" +#include "CommonFramework/OCR/RawOCR.h" +#include "LanguageOCR.h" + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ + + + +LanguageOCR::LanguageOCR(QString label, const LanguageSet& languages, bool required) + : ConfigOption(std::move(label)) + , m_default(0) + , m_current(0) +{ + size_t index = 0; + if (!required && !languages[Language::None]){ + m_case_list.emplace_back( + Language::None, + true + ); + m_case_map.emplace( + std::piecewise_construct, + std::forward_as_tuple(Language::None), + std::forward_as_tuple(index) + ); + index++; + } + for (Language language : languages){ + m_case_list.emplace_back( + language, + language == Language::None || OCR::language_available(language) + ); + m_case_map.emplace( + std::piecewise_construct, + std::forward_as_tuple(language), + std::forward_as_tuple(index) + ); + index++; + } +} + + + +void LanguageOCR::load_json(const QJsonValue& json){ + if (!json.isString()){ + return; + } + QString str = json.toString(); + Language language; + try{ + language = language_code_to_enum(str.toUtf8().data()); + }catch (const StringException&){ + return; + } + + auto iter = m_case_map.find(language); + if (iter != m_case_map.end()){ + m_current = iter->second; + } +} +QJsonValue LanguageOCR::to_json() const{ + return QJsonValue(language_data(m_case_list[m_current].first).code.c_str()); +} + +bool LanguageOCR::is_valid() const{ + return m_case_list[m_current].second; +} +void LanguageOCR::restore_defaults(){ + m_current = m_default; +} + +ConfigOptionUI* LanguageOCR::make_ui(QWidget& parent){ + return new LanguageOCRUI(parent, *this); +} + + + +LanguageOCRUI::LanguageOCRUI(QWidget& parent, LanguageOCR& value) + : QWidget(&parent) + , m_value(value) +{ + QHBoxLayout* hbox = new QHBoxLayout(this); + QLabel* text = new QLabel(m_value.m_label, this); + hbox->addWidget(text, 1); + text->setWordWrap(true); + + QVBoxLayout* vbox = new QVBoxLayout(); + hbox->addLayout(vbox, 1); + m_box = new NoWheelComboBox(&parent); + + for (const auto& item : m_value.m_case_list){ + m_box->addItem(language_data(item.first).name); + auto* model = qobject_cast(m_box->model()); + if (model == nullptr){ + continue; + } + QStandardItem* line_handle = model->item(m_box->count() - 1); + if (line_handle != nullptr){ +// line_handle->setEnabled(item.second); + if (!item.second){ + QFont font = line_handle->font(); + font.setStrikeOut(true); + line_handle->setFont(font); + + QBrush brush = line_handle->foreground(); + brush.setColor(Qt::red); + line_handle->setForeground(brush); + } + } + } + m_box->setCurrentIndex((int)m_value.m_current); + vbox->addWidget(m_box); + + m_status = new QLabel(this); + m_status->setTextFormat(Qt::RichText); + m_status->setTextInteractionFlags(Qt::TextBrowserInteraction); + m_status->setOpenExternalLinks(true); + vbox->addWidget(m_status); + + update_status(); + + connect( + m_box, static_cast(&QComboBox::currentIndexChanged), + this, [=](int index){ + if (index < 0){ + m_value.restore_defaults(); + return; + } + m_value.m_current = index; + +// const LanguageData& data = language_data(m_value); +// cout << "index = " << index << ", " << data.code << endl; + + update_status(); + } + ); +} + +void LanguageOCRUI::update_status(){ + const std::pair& item = m_value.m_case_list[m_value.m_current]; + const LanguageData& data = language_data(m_value); + if (item.second){ + m_status->setVisible(false); + }else{ + m_status->setText( + "No text recognition data found for " + data.name + ".\r" + + "Download from here." + ); + m_status->setVisible(true); + } +} + +void LanguageOCRUI::restore_defaults(){ + m_value.restore_defaults(); + m_box->setCurrentIndex((int)m_value); +} + + + + + + + +} + diff --git a/SerialPrograms/Source/CommonFramework/Options/LanguageOCR.h b/SerialPrograms/Source/CommonFramework/Options/LanguageOCR.h new file mode 100644 index 0000000000..8b1eed3aba --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Options/LanguageOCR.h @@ -0,0 +1,66 @@ +/* Language OCR Option + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_LanguageOCR_H +#define PokemonAutomation_LanguageOCR_H + +#include +#include +#include +#include "CommonFramework/Language.h" +#include "ConfigOption.h" + +namespace PokemonAutomation{ + + +class LanguageOCR : public ConfigOption{ +public: + LanguageOCR(QString label, const LanguageSet& languages, bool required = true); + + operator bool() const{ return m_case_list[m_current].first != Language::None && m_case_list[m_current].second; } + operator size_t() const{ return m_current; } + operator Language() const{ return m_case_list[m_current].first; } + + virtual void load_json(const QJsonValue& json) override; + virtual QJsonValue to_json() const override; + + virtual bool is_valid() const override; + virtual void restore_defaults() override; + + virtual ConfigOptionUI* make_ui(QWidget& parent) override; + +private: + friend class LanguageOCRUI; + + std::vector> m_case_list; + std::map m_case_map; + size_t m_default; + size_t m_current; +}; + + + +class LanguageOCRUI : public ConfigOptionUI, public QWidget{ +public: + LanguageOCRUI(QWidget& parent, LanguageOCR& value); + virtual QWidget* widget() override{ return this; } + virtual void restore_defaults() override; + +private: + void update_status(); + +private: + LanguageOCR& m_value; + QComboBox* m_box; + QLabel* m_status; + bool m_updating = false; +}; + + + + +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/Options/RandomCode.cpp b/SerialPrograms/Source/CommonFramework/Options/RandomCode.cpp index bf9b784f34..45cbd9baa7 100644 --- a/SerialPrograms/Source/CommonFramework/Options/RandomCode.cpp +++ b/SerialPrograms/Source/CommonFramework/Options/RandomCode.cpp @@ -8,7 +8,7 @@ #include #include #include -#include "Common/Qt/StringException.h" +#include "Common/Cpp/Exception.h" #include "Common/Qt/QtJsonTools.h" #include "Common/Qt/CodeValidator.h" #include "RandomCode.h" @@ -154,8 +154,8 @@ QString RandomCodeUI::sanitized_code(const QString& text) const{ QString message; try{ message = "Fixed Raid Code: " + sanitize_code(m_value.m_current.total_digits(), text); - }catch (const StringException& str){ - message = "" + str.message() + ""; + }catch (const ParseException& e){ + message = "" + e.message_qt() + ""; } return message; } diff --git a/SerialPrograms/Source/CommonFramework/Options/String.h b/SerialPrograms/Source/CommonFramework/Options/String.h new file mode 100644 index 0000000000..6ea754f807 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Options/String.h @@ -0,0 +1,68 @@ +/* String Option + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_String_H +#define PokemonAutomation_String_H + +#include "Common/Qt/Options/StringOption.h" +#include "ConfigOption.h" + +namespace PokemonAutomation{ + + +class String : public ConfigOption, public StringOption{ +public: + String( + QString& backing, + QString label, + QString default_value + ) + : ConfigOption(label) + , StringOption(backing, std::move(label), default_value) + {} + String( + QString label, + QString default_value + ) + : ConfigOption(label) + , StringOption(std::move(label), default_value) + {} + + virtual void load_json(const QJsonValue& json) override{ + load_current(json); + } + virtual QJsonValue to_json() const override{ + return write_current(); + } + + virtual void restore_defaults() override{ + StringOption::restore_defaults(); + } + + virtual ConfigOptionUI* make_ui(QWidget& parent) override; +}; + + +class StringUI : public ConfigOptionUI, public StringOptionUI{ +public: + StringUI(QWidget& parent, StringOption& value) + : StringOptionUI(parent, value) + {} + virtual QWidget* widget() override{ return this; } + virtual void restore_defaults() override{ + StringOptionUI::restore_defaults(); + } +}; + + +inline ConfigOptionUI* String::make_ui(QWidget& parent){ + return new StringUI(parent, *this); +} + + +} +#endif + diff --git a/SerialPrograms/Source/CommonFramework/Options/StringSelect.cpp b/SerialPrograms/Source/CommonFramework/Options/StringSelect.cpp new file mode 100644 index 0000000000..3cdfa75de7 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Options/StringSelect.cpp @@ -0,0 +1,115 @@ +/* String Select + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include +#include +#include "Common/Qt/NoWheelComboBox.h" +#include "StringSelect.h" + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ + + +StringSelect::StringSelect( + QString label, + std::vector cases, + size_t default_index +) + : ConfigOption(std::move(label)) + , m_case_list(std::move(cases)) + , m_default(default_index) + , m_current(default_index) +{ + if (default_index >= m_case_list.size()){ + throw "Index is too large."; + } + + for (size_t index = 0; index < m_case_list.size(); index++){ + const QString& item = m_case_list[index]; + auto ret = m_case_map.emplace( + std::piecewise_construct, + std::forward_as_tuple(item), + std::forward_as_tuple(index) + ); + if (!ret.second){ + throw "Duplicate enum label."; + } + } +} + +void StringSelect::load_json(const QJsonValue& json){ + if (!json.isString()){ + return; + } + QString str = json.toString(); + auto iter = m_case_map.find(str); + if (iter != m_case_map.end()){ + m_current = iter->second; + } +} +QJsonValue StringSelect::to_json() const{ + return QJsonValue(m_case_list[m_current]); +} + +void StringSelect::restore_defaults(){ + m_current = m_default; +} + +ConfigOptionUI* StringSelect::make_ui(QWidget& parent){ + return new StringSelectUI(parent, *this); +} + + + +StringSelectUI::StringSelectUI(QWidget& parent, StringSelect& value) + : QWidget(&parent) + , m_value(value) +{ + QHBoxLayout* layout = new QHBoxLayout(this); + QLabel* text = new QLabel(m_value.m_label, this); + layout->addWidget(text, 1); + text->setWordWrap(true); + m_box = new NoWheelComboBox(&parent); + + m_box->setEditable(true); + m_box->setInsertPolicy(QComboBox::NoInsert); + m_box->completer()->setCompletionMode(QCompleter::PopupCompletion); + m_box->completer()->setFilterMode(Qt::MatchContains); + + for (const QString& item : m_value.m_case_list){ + m_box->addItem(item); + } + m_box->setCurrentIndex((int)m_value.m_current); + layout->addWidget(m_box, 1); + + connect( + m_box, static_cast(&QComboBox::currentIndexChanged), + this, [=](int index){ + if (index < 0){ + m_value.restore_defaults(); + return; + } + m_value.m_current = index; + cout << "index = " << index << endl; + } + ); +} + + +void StringSelectUI::restore_defaults(){ + m_value.restore_defaults(); + m_box->setCurrentIndex((int)m_value); +} + + + + + +} diff --git a/SerialPrograms/Source/CommonFramework/Options/StringSelect.h b/SerialPrograms/Source/CommonFramework/Options/StringSelect.h new file mode 100644 index 0000000000..5fd7419518 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Options/StringSelect.h @@ -0,0 +1,60 @@ +/* String Select + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_StringSelect_H +#define PokemonAutomation_StringSelect_H + +#include +#include "ConfigOption.h" + +namespace PokemonAutomation{ + + +class StringSelect : public ConfigOption{ +public: + StringSelect( + QString label, + std::vector cases, + size_t default_index + ); + + operator size_t() const{ return m_current; } + operator const QString&() const{ return m_case_list[m_current]; } + + virtual void load_json(const QJsonValue& json) override; + virtual QJsonValue to_json() const override; + + virtual void restore_defaults() override; + + virtual ConfigOptionUI* make_ui(QWidget& parent) override; + +private: + friend class StringSelectUI; + + std::vector m_case_list; + std::map m_case_map; + size_t m_default; + size_t m_current; +}; + + + +class StringSelectUI : public ConfigOptionUI, public QWidget{ +public: + StringSelectUI(QWidget& parent, StringSelect& value); + virtual QWidget* widget() override{ return this; } + virtual void restore_defaults() override; + +private: + StringSelect& m_value; + QComboBox* m_box; + bool m_updating = false; +}; + + + +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/Panels/Panel.cpp b/SerialPrograms/Source/CommonFramework/Panels/Panel.cpp new file mode 100644 index 0000000000..cf4be2c42b --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Panels/Panel.cpp @@ -0,0 +1,92 @@ +/* Panel + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include +#include +#include +#include "CommonFramework/Globals.h" +#include "CommonFramework/PersistentSettings.h" +#include "Panel.h" + +namespace PokemonAutomation{ + + + +PanelDescriptor::PanelDescriptor( + QColor color, + std::string identifier, + QString display_name, + QString doc_link, + QString description +) + : m_color(std::move(color)) + , m_identifier(std::move(identifier)) + , m_display_name(std::move(display_name)) + , m_doc_link(std::move(doc_link)) + , m_description(std::move(description)) +{} +std::unique_ptr PanelDescriptor::make_panel() const{ + return std::unique_ptr(new PanelInstance(*this)); +} + + + +PanelInstance::PanelInstance(const PanelDescriptor& descriptor) + : m_descriptor(descriptor) +{} + +void PanelInstance::from_json(){ + from_json(PERSISTENT_SETTINGS().panels[m_descriptor.identifier().c_str()]); +} +QJsonValue PanelInstance::to_json() const{ + return QJsonValue(); +} +QWidget* PanelInstance::make_widget(QWidget& parent, PanelListener& listener){ + return new PanelWidget(parent, *this, listener); +} + + + +PanelWidget::PanelWidget( + QWidget& parent, + PanelInstance& instance, + PanelListener& listener +) + : QWidget(&parent) + , m_instance(instance) + , m_listener(listener) +{} + +QWidget* PanelWidget::make_header(QWidget& parent){ + QGroupBox* description_box = new QGroupBox("Current Program", &parent); + QVBoxLayout* vbox = new QVBoxLayout(description_box); + +// description_box->ev + + QString name_text = "Name: " + m_instance.descriptor().display_name(); + if (m_instance.descriptor().doc_link().size() > 0){ + QString path = ONLINE_DOC_URL + "/blob/master/Documentation/" + m_instance.descriptor().doc_link(); + name_text += " (online documentation)"; + } + QLabel* name = new QLabel(name_text, description_box); + name->setTextFormat(Qt::RichText); + name->setTextInteractionFlags(Qt::TextBrowserInteraction); + name->setOpenExternalLinks(true); + vbox->addWidget(name); + + QString description = "Description: "; + description += m_instance.descriptor().description(); + QLabel* text = new QLabel(description, description_box); + vbox->addWidget(text); + text->setWordWrap(true); + + return description_box; +} + + + +} diff --git a/SerialPrograms/Source/CommonFramework/Panels/Panel.h b/SerialPrograms/Source/CommonFramework/Panels/Panel.h new file mode 100644 index 0000000000..acb29d02f9 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Panels/Panel.h @@ -0,0 +1,108 @@ +/* Panel + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_Panel_H +#define PokemonAutomation_Panel_H + +#include +#include +#include "Common/Compiler.h" + +namespace PokemonAutomation{ + +class OutputWindow; +class PanelInstance; + + +struct PanelListener{ + virtual void on_panel_construct(std::unique_ptr panel) = 0; + virtual OutputWindow& output_window() = 0; + virtual void on_busy(PanelInstance& panel) = 0; + virtual void on_idle(PanelInstance& panel) = 0; +}; + + + +class PanelDescriptor{ +public: + PanelDescriptor( + QColor color, + std::string identifier, + QString display_name, + QString doc_link, + QString description + ); + virtual ~PanelDescriptor() = default; + + QColor color() const{ return m_color; } + const std::string& identifier() const{ return m_identifier; } + const QString& display_name() const{ return m_display_name; } + const QString& doc_link() const{ return m_doc_link; } + const QString& description() const{ return m_description; } + + virtual std::unique_ptr make_panel() const = 0; + +private: + const QColor m_color; + const std::string m_identifier; + const QString m_display_name; + const QString m_doc_link; + const QString m_description; +}; + +template +class PanelDescriptorWrapper : public Descriptor{ +public: + using Descriptor::Descriptor; + virtual std::unique_ptr make_panel() const override{ + return std::unique_ptr(new Instance(*this)); + } +}; + + + +class PanelInstance{ +public: + PanelInstance(const PanelDescriptor& descriptor); + virtual ~PanelInstance() = default; + + const PanelDescriptor& descriptor() const{ return m_descriptor; } + + virtual QWidget* make_widget(QWidget& parent, PanelListener& listener); + +public: + // Serialization + void from_json(); + virtual void from_json(const QJsonValue& json){} + virtual QJsonValue to_json() const; + +protected: + const PanelDescriptor& m_descriptor; +}; + + + +class PanelWidget : public QWidget{ +public: + PanelWidget( + QWidget& parent, + PanelInstance& instance, + PanelListener& listener + ); + virtual ~PanelWidget() = default; + +protected: + virtual QWidget* make_header(QWidget& parent); + +protected: + PanelInstance& m_instance; + PanelListener& m_listener; +}; + + + +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/Panels/PanelList.cpp b/SerialPrograms/Source/CommonFramework/Panels/PanelList.cpp new file mode 100644 index 0000000000..7d5a23b920 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Panels/PanelList.cpp @@ -0,0 +1,72 @@ +/* Panel List + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include "Common/Cpp/Exception.h" +#include "CommonFramework/PersistentSettings.h" +#include "PanelList.h" + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ + + +PanelList::PanelList(QTabWidget& parent, QString label, PanelListener& listener) + : QListWidget(&parent) + , m_label(label) + , m_listener(listener) +{} +void PanelList::add_divider(QString label){ + m_panels.emplace_back(std::move(label), nullptr); +} +void PanelList::finish_panel_setup(){ + QFontMetrics fm(this->font()); + for (const auto& item : m_panels){ + if (item.second == nullptr){ + addItem(item.first); + QListWidgetItem* list_item = this->item(this->count() - 1); + QFont font = list_item->font(); + font.setBold(true); + list_item->setFont(font); +// list_item->setTextAlignment(Qt::AlignCenter); + continue; + } + + const QString& display_name = item.second->display_name(); + if (!m_panel_map.emplace(display_name, item.second.get()).second){ +// cout << ("Duplicate program name: " + display_name).toUtf8().data() << endl; + PA_THROW_StringException("Duplicate program name: " + display_name); + } + + addItem(display_name); + QListWidgetItem* list_item = this->item(this->count() - 1); + list_item->setForeground(item.second->color()); + list_item->setToolTip(item.second->description()); + } + connect( + this, &QListWidget::itemClicked, + this, [=](QListWidgetItem* item){ + auto iter = m_panel_map.find(item->text()); + if (iter == m_panel_map.end()){ + return; + } + const PanelDescriptor* descriptor = iter->second; + std::unique_ptr panel = descriptor->make_panel(); + panel->from_json(PERSISTENT_SETTINGS().panels[descriptor->identifier().c_str()]); + m_listener.on_panel_construct(std::move(panel)); + } + ); +} + + + + + +} + + diff --git a/SerialPrograms/Source/CommonFramework/Panels/PanelList.h b/SerialPrograms/Source/CommonFramework/Panels/PanelList.h new file mode 100644 index 0000000000..b82e72e921 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Panels/PanelList.h @@ -0,0 +1,56 @@ +/* Panel List + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PanelList_H +#define PokemonAutomation_PanelList_H + +#include +#include +#include "CommonFramework/Panels/Panel.h" + +namespace PokemonAutomation{ + + +class PanelList : public QListWidget{ +public: + PanelList(QTabWidget& parent, QString label, PanelListener& listener); + + const QString& label() const{ return m_label; } + size_t items() const{ return m_panels.size(); } + +protected: + void add_divider(QString label); + + template + void add_settings(Args&&... args){ + add_program(std::forward(args)...); + // Need to force initialize a settings panel so that it loads and + // updates the globals from serialization. + m_panels.back().second->make_panel()->from_json(); + } + + template + void add_program(Args&&... args){ + std::unique_ptr panel( + new PanelDescriptorWrapper(std::forward(args)...) + ); + m_panels.emplace_back(panel->display_name(), std::move(panel)); + } + void finish_panel_setup(); + +protected: + QString m_label; + PanelListener& m_listener; + std::vector>> m_panels; +private: + std::map m_panel_map; +}; + + + + +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/Panels/RightPanel.cpp b/SerialPrograms/Source/CommonFramework/Panels/RightPanel.cpp deleted file mode 100644 index b29913fd05..0000000000 --- a/SerialPrograms/Source/CommonFramework/Panels/RightPanel.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* Right-Side Panel Options - * - * From: https://github.com/PokemonAutomation/Arduino-Source - * - */ - -#include -#include -#include -#include "CommonFramework/Globals.h" -#include "CommonFramework/Windows/MainWindow.h" -#include "RightPanel.h" - -namespace PokemonAutomation{ - - -RightPanel::RightPanel( - QColor color, - QString name, - QString doc_link, - QString description -) - : m_color(std::move(color)) - , m_name(std::move(name)) - , m_doc_link(std::move(doc_link)) - , m_description(std::move(description)) -{} -QJsonValue RightPanel::to_json() const{ - return QJsonValue(); -} - -QWidget* RightPanel::make_ui(MainWindow& window){ - RightPanelUI* widget = new RightPanelUI(*this); - widget->construct(); - return widget; -} - -RightPanelUI::RightPanelUI(RightPanel& factory) - : m_factory(factory) -{} -void RightPanelUI::construct(){ - QVBoxLayout* layout = new QVBoxLayout(this); - layout->setMargin(0); - - QGroupBox* description_box = new QGroupBox("Current Program", this); - layout->addWidget(description_box); - - QVBoxLayout* vbox = new QVBoxLayout(description_box); -// layout->setAlignment(Qt::AlignTop); - - QString name_text = "Name: " + m_factory.m_name; - if (m_factory.m_doc_link.size() > 0){ - QString path = GITHUB_REPO + "/blob/master/Documentation/" + m_factory.m_doc_link; - name_text += " (online documentation)"; - } - QLabel* name = new QLabel(name_text, description_box); - name->setTextFormat(Qt::RichText); - name->setTextInteractionFlags(Qt::TextBrowserInteraction); - name->setOpenExternalLinks(true); - vbox->addWidget(name); - -#if 0 - { - QString path = GITHUB_REPO + "/blob/master/Documentation/Programs/" + factory.name() + ".md"; - QLabel* text = new QLabel("Online Documentation for " + factory.name() + ""); - layout.addWidget(text); - text->setTextFormat(Qt::RichText); - text->setTextInteractionFlags(Qt::TextBrowserInteraction); - text->setOpenExternalLinks(true); - } -#endif - - QString description = "Description: "; - description += m_factory.m_description; - QLabel* text = new QLabel(description, description_box); - vbox->addWidget(text); - text->setWordWrap(true); - - append_description(*description_box, *vbox); - - make_body(*this, *layout); -} - - - - - -} diff --git a/SerialPrograms/Source/CommonFramework/Panels/RightPanel.h b/SerialPrograms/Source/CommonFramework/Panels/RightPanel.h deleted file mode 100644 index 20da655437..0000000000 --- a/SerialPrograms/Source/CommonFramework/Panels/RightPanel.h +++ /dev/null @@ -1,68 +0,0 @@ -/* Right-Side Panel Options - * - * From: https://github.com/PokemonAutomation/Arduino-Source - * - */ - -#ifndef PokemonAutomation_RightPanel_H -#define PokemonAutomation_RightPanel_H - -#include -#include -#include "Common/Compiler.h" - -//#include -//using std::cout; -//using std::endl; - -namespace PokemonAutomation{ - - -class MainWindow; -class RightPanelUI; - - -class RightPanel{ -public: - virtual ~RightPanel() = default; - - RightPanel(QColor color, QString name, QString doc_link, QString description); - - virtual QJsonValue to_json() const; - - QColor color() const{ return m_color; } - const QString& name() const{ return m_name; } - const QString& description() const{ return m_description; } - - virtual QWidget* make_ui(MainWindow& window); - -protected: - friend class RightPanelUI; - const QColor m_color; - const QString m_name; - const QString m_doc_link; - const QString m_description; -}; - - -class RightPanelUI : public QWidget{ - friend class RightPanel; - -protected: - RightPanelUI(RightPanel& factory); - virtual void construct(); - virtual void append_description(QWidget& parent, QVBoxLayout& layout){} - virtual void make_body(QWidget& parent, QVBoxLayout& layout){} - -public: - bool is_running() const{ return m_running; } - -protected: - RightPanel& m_factory; - bool m_running = false; -}; - - - -} -#endif diff --git a/SerialPrograms/Source/CommonFramework/Panels/RunnableComputerProgram.cpp b/SerialPrograms/Source/CommonFramework/Panels/RunnableComputerProgram.cpp new file mode 100644 index 0000000000..0aa47d7ddc --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Panels/RunnableComputerProgram.cpp @@ -0,0 +1,92 @@ +/* Runnable Computer Program + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include "Common/Cpp/Exception.h" +#include "RunnableComputerProgram.h" + +namespace PokemonAutomation{ + + +RunnableComputerProgramDescriptor::RunnableComputerProgramDescriptor( + std::string identifier, + QString display_name, + QString doc_link, + QString description +) + : RunnablePanelDescriptor( + Qt::darkCyan, + std::move(identifier), + std::move(display_name), + std::move(doc_link), + std::move(description) + ) +{} + + + + +QWidget* RunnableComputerProgramInstance::make_widget(QWidget& parent, PanelListener& listener){ + return RunnableComputerProgramWidget::make(parent, *this, listener); +} + + + +RunnableComputerProgramWidget::~RunnableComputerProgramWidget(){ + if (!m_destructing){ + stop(); + m_destructing = true; + } +} + +RunnableComputerProgramWidget* RunnableComputerProgramWidget::make( + QWidget& parent, + RunnableComputerProgramInstance& instance, + PanelListener& listener +){ + RunnableComputerProgramWidget* widget = new RunnableComputerProgramWidget(parent, instance, listener); + widget->construct(); + return widget; +} +void RunnableComputerProgramWidget::run_program(){ + if (m_state.load(std::memory_order_acquire) != ProgramState::RUNNING){ + return; + } + + RunnableComputerProgramInstance& instance = static_cast(m_instance); + + ProgramEnvironment env(m_logger, nullptr, nullptr); + connect( + this, &RunnableComputerProgramWidget::signal_cancel, + &env, [&]{ + env.signal_stop(); + }, + Qt::DirectConnection + ); + connect( + &env, &ProgramEnvironment::set_status, + this, &RunnableComputerProgramWidget::set_status + ); + + try{ + m_logger.log("Starting Program: " + instance.descriptor().identifier() + ""); + instance.program(env); + m_logger.log("Ending Program..."); + }catch (CancelledException&){ + m_logger.log("Stopping Program..."); + }catch (StringException& e){ + signal_error(e.message_qt()); + } + + m_logger.log("Entering STOPPED state."); + m_state.store(ProgramState::STOPPED, std::memory_order_release); + signal_reset(); + m_logger.log("Now in STOPPED state."); +} + + + +} diff --git a/SerialPrograms/Source/CommonFramework/Panels/RunnableComputerProgram.h b/SerialPrograms/Source/CommonFramework/Panels/RunnableComputerProgram.h new file mode 100644 index 0000000000..f7dd52a059 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Panels/RunnableComputerProgram.h @@ -0,0 +1,59 @@ +/* Runnable Computer Program + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_RunnableComputerProgram_H +#define PokemonAutomation_RunnableComputerProgram_H + +#include "CommonFramework/Tools/ProgramEnvironment.h" +#include "RunnablePanel.h" + +namespace PokemonAutomation{ + +class RunnableComputerProgramDescriptor : public RunnablePanelDescriptor{ +public: + RunnableComputerProgramDescriptor( + std::string identifier, + QString display_name, + QString doc_link, + QString description + ); +}; + + + +class RunnableComputerProgramInstance : public RunnablePanelInstance{ +public: + using RunnablePanelInstance::RunnablePanelInstance; + + const RunnableComputerProgramDescriptor& descriptor() const{ + return static_cast(m_descriptor); + } + + virtual QWidget* make_widget(QWidget& parent, PanelListener& listener) override; + virtual void program(ProgramEnvironment& env) = 0; +}; + + + +class RunnableComputerProgramWidget : public RunnablePanelWidget{ +public: + static RunnableComputerProgramWidget* make( + QWidget& parent, + RunnableComputerProgramInstance& instance, + PanelListener& listener + ); + +private: + using RunnablePanelWidget::RunnablePanelWidget; + virtual ~RunnableComputerProgramWidget(); + + virtual void run_program() override; +}; + + + +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/Panels/RunnablePanel.cpp b/SerialPrograms/Source/CommonFramework/Panels/RunnablePanel.cpp new file mode 100644 index 0000000000..4e5e91b7a3 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Panels/RunnablePanel.cpp @@ -0,0 +1,260 @@ +/* Runnable Computer Program + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include +#include +#include +#include "Common/Cpp/PanicDump.h" +#include "Common/Qt/QtJsonTools.h" +#include "RunnablePanel.h" + +namespace PokemonAutomation{ + + + +void RunnablePanelInstance::from_json(const QJsonValue& json){ + const QJsonObject& obj = json.toObject(); + for (auto& item : m_options){ + if (!item.second.isEmpty()){ + item.first->load_json(json_get_value_nothrow(obj, item.second)); + } + } +} +QJsonValue RunnablePanelInstance::to_json() const{ + QJsonObject obj; + for (auto& item : m_options){ + if (!item.second.isEmpty()){ + obj.insert(item.second, item.first->to_json()); + } + } + return obj; +} + +bool RunnablePanelInstance::is_valid() const{ + for (const auto& item : m_options){ + if (!item.first->is_valid()){ + return false; + } + } + return true; +} +void RunnablePanelInstance::restore_defaults(){ + for (const auto& item : m_options){ + item.first->restore_defaults(); + } +} + + + +void RunnablePanelWidget::stop(){ + m_state.store(ProgramState::STOPPING, std::memory_order_release); + on_stop(); + if (m_thread.joinable()){ + m_thread.join(); + } +} +RunnablePanelWidget::~RunnablePanelWidget(){ + if (!m_destructing){ + stop(); + m_destructing = true; + } +} + + + +RunnablePanelWidget::RunnablePanelWidget( + QWidget& parent, + RunnablePanelInstance& instance, + PanelListener& listener +) + : PanelWidget(parent, instance, listener) + , m_logger(listener.output_window(), "Program") + , m_status_bar(nullptr) + , m_start_button(nullptr) + , m_state(ProgramState::STOPPED) +{} +void RunnablePanelWidget::construct(){ + QVBoxLayout* layout = new QVBoxLayout(this); + layout->setMargin(0); + layout->addWidget(make_header(*this)); + + QScrollArea* scroll = new QScrollArea(this); + layout->addWidget(scroll); + scroll->setWidgetResizable(true); + + scroll->setWidget(make_options(*scroll)); + m_status_bar = make_status_bar(*this); + layout->addWidget(m_status_bar); + layout->addWidget(make_actions(*this)); +} +QWidget* RunnablePanelWidget::make_options(QWidget& parent){ + QWidget* options_widget = new QWidget(&parent); + + QVBoxLayout* options_layout = new QVBoxLayout(options_widget); + options_layout->setAlignment(Qt::AlignTop); + + RunnablePanelInstance& instance = static_cast(m_instance); + for (auto& item : instance.m_options){ + m_options.emplace_back(item.first->make_ui(parent)); + options_layout->addWidget(m_options.back()->widget()); + } + + return options_widget; +} +QLabel* RunnablePanelWidget::make_status_bar(QWidget& parent){ + QLabel* status_bar = new QLabel(&parent); + status_bar = new QLabel(&parent); + status_bar->setVisible(false); + status_bar->setAlignment(Qt::AlignCenter); +// status_bar->setText("Encounters: 1,267 - Corrections: 0 - Star Shinies: 1 - Square Shinies: 0"); + QFont font = status_bar->font(); + font.setPointSize(10); + status_bar->setFont(font); + return status_bar; +} +QWidget* RunnablePanelWidget::make_actions(QWidget& parent){ + QGroupBox* actions_widget = new QGroupBox("Actions", &parent); + + QHBoxLayout* action_layout = new QHBoxLayout(actions_widget); + action_layout->setMargin(0); + + { + m_start_button = new QPushButton("Start Program!", &parent); + action_layout->addWidget(m_start_button, 2); + QFont font = m_start_button->font(); + font.setPointSize(16); + m_start_button->setFont(font); + } + { + m_default_button = new QPushButton("Restore Defaults", &parent); + action_layout->addWidget(m_default_button, 1); + QFont font = m_default_button->font(); + font.setPointSize(16); + m_default_button->setFont(font); + } + + update_ui(); + connect( + this, &RunnablePanelWidget::signal_reset, + this, [=]{ update_ui(); } + ); + connect( + this, &RunnablePanelWidget::signal_error, + this, [](QString message){ + QMessageBox box; + box.critical(nullptr, "Error", message); + } + ); + connect( + m_start_button, &QPushButton::clicked, + this, [=](bool){ + switch (m_state.load(std::memory_order_acquire)){ + case ProgramState::STOPPED: + if (!settings_valid()){ + QMessageBox box; + box.critical(nullptr, "Error", "Settings are not valid."); + return; + } + if (m_thread.joinable()){ + m_thread.join(); + } +// m_window.open_output_window(); + m_state.store(ProgramState::RUNNING, std::memory_order_release); + m_thread = std::thread( + run_with_catch, + "RunnablePanelWidget::run_program()", + [=]{ run_program(); } + ); + break; + case ProgramState::RUNNING: + case ProgramState::FINISHED: + m_state.store(ProgramState::STOPPING, std::memory_order_release); + on_stop(); + break; + case ProgramState::STOPPING: + break; + } + update_ui(); + } + ); + connect( + m_default_button, &QPushButton::clicked, + this, [=](bool){ + restore_defaults(); + } + ); + + return actions_widget; +} + + + +bool RunnablePanelWidget::settings_valid() const{ + RunnablePanelInstance& instance = static_cast(m_instance); + return instance.is_valid(); +} +void RunnablePanelWidget::restore_defaults(){ + for (ConfigOptionUI* item : m_options){ + item->restore_defaults(); + } +} +void RunnablePanelWidget::update_ui(){ + ProgramState state = m_state.load(std::memory_order_acquire); + if (m_start_button == nullptr){ + return; + } + m_start_button->setEnabled(state != ProgramState::STOPPING); + switch (state){ + case ProgramState::STOPPED: + m_start_button->setText("Start Program..."); +// m_start_button->setEnabled(settings_valid()); + m_listener.on_idle(m_instance); + break; + case ProgramState::RUNNING: + m_start_button->setText("Stop Program..."); + m_listener.on_busy(m_instance); + break; + case ProgramState::FINISHED: + m_start_button->setText("Program Finished! Click to stop."); + m_listener.on_busy(m_instance); + break; + case ProgramState::STOPPING: + m_start_button->setText("Stopping Program..."); + m_listener.on_busy(m_instance); + break; + } + + bool enabled = state == ProgramState::STOPPED; + m_default_button->setEnabled(enabled); + for (ConfigOptionUI* option : m_options){ + option->widget()->setEnabled(enabled); + } +} + + +void RunnablePanelWidget::set_status(QString status){ + if (status.size() <= 0){ + m_status_bar->setVisible(false); + m_status_bar->setText(status); + }else{ + m_status_bar->setText(status); + m_status_bar->setVisible(true); + } +} + +void RunnablePanelWidget::on_stop(){ + signal_cancel(); +} + + + + + + + + +} diff --git a/SerialPrograms/Source/CommonFramework/Panels/RunnablePanel.h b/SerialPrograms/Source/CommonFramework/Panels/RunnablePanel.h new file mode 100644 index 0000000000..88d9be8fb4 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Panels/RunnablePanel.h @@ -0,0 +1,118 @@ +/* Runnable Panel + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_RunnablePanel_H +#define PokemonAutomation_RunnablePanel_H + +#include +#include +#include +#include "CommonFramework/Globals.h" +#include "CommonFramework/Options/ConfigOption.h" +#include "CommonFramework/Windows/OutputWindow.h" +#include "CommonFramework/Panels/Panel.h" + +namespace PokemonAutomation{ + + +#if 0 +class RunnableProgramDescriptor : public PanelDescriptor{ +public: + RunnableProgramDescriptor( + std::string identifier, + QString display_name, + QString doc_link, + QString description + ); +}; +#endif +using RunnablePanelDescriptor = PanelDescriptor; + + + +class RunnablePanelInstance : public PanelInstance{ +public: + using PanelInstance::PanelInstance; + + const RunnablePanelDescriptor& descriptor() const{ + return static_cast(m_descriptor); + } + + bool is_valid() const; + void restore_defaults(); + +public: + // Serialization + virtual void from_json(const QJsonValue& json) override; + virtual QJsonValue to_json() const override; + +protected: + friend class RunnablePanelWidget; + + std::vector> m_options; +}; + + + +class RunnablePanelWidget : public PanelWidget{ + Q_OBJECT + +public: + virtual ~RunnablePanelWidget(); +protected: + void stop(); + +protected: + RunnablePanelWidget( + QWidget& parent, + RunnablePanelInstance& instance, + PanelListener& listener + ); + void construct(); + virtual QWidget* make_options(QWidget& parent); + virtual QLabel* make_status_bar(QWidget& parent); + virtual QWidget* make_actions(QWidget& parent); + +protected: + virtual bool settings_valid() const; + virtual void restore_defaults(); + + virtual void update_ui(); + void set_status(QString status); + + virtual void on_stop(); + + virtual void run_program() = 0; + + + + +signals: + void signal_cancel(); + void signal_error(QString message); + void signal_reset(); + +protected: + friend class RunnablePanelInstance; + + TaggedLogger m_logger; + + std::vector m_options; + QLabel* m_status_bar; + + QPushButton* m_start_button; + QPushButton* m_default_button; + + std::atomic m_state; + std::thread m_thread; + + bool m_destructing = false; +}; + + + +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/Panels/SettingsPanel.cpp b/SerialPrograms/Source/CommonFramework/Panels/SettingsPanel.cpp index ff7b972144..d55a796469 100644 --- a/SerialPrograms/Source/CommonFramework/Panels/SettingsPanel.cpp +++ b/SerialPrograms/Source/CommonFramework/Panels/SettingsPanel.cpp @@ -4,29 +4,32 @@ * */ -#include #include +#include #include #include -#include "Common/Qt/StringException.h" #include "Common/Qt/QtJsonTools.h" #include "SettingsPanel.h" +#include using std::cout; using std::endl; namespace PokemonAutomation{ -void SettingsPanel::from_json(const QJsonValue& json){ - QJsonObject obj = json_get_object_nothrow(json.toObject(), m_name); + +void SettingsPanelInstance::from_json(const QJsonValue& json){ +// cout << QJsonDocument(json.toObject()).toJson().data() << endl; +// QJsonObject obj = json_get_object_nothrow(json.toObject(), m_descriptor.name()); + QJsonObject obj = json.toObject(); for (auto& item : m_options){ if (!item.first.isEmpty()){ item.second->load_json(json_get_value_nothrow(obj, item.first)); } } } -QJsonValue SettingsPanel::to_json() const{ +QJsonValue SettingsPanelInstance::to_json() const{ QJsonObject obj; for (auto& item : m_options){ if (!item.first.isEmpty()){ @@ -35,47 +38,63 @@ QJsonValue SettingsPanel::to_json() const{ } return obj; } +QWidget* SettingsPanelInstance::make_widget(QWidget& parent, PanelListener& listener){ + return SettingsPanelWidget::make(parent, *this, listener); +} -QWidget* SettingsPanel::make_ui(MainWindow& window){ - SettingsPanelUI* widget = new SettingsPanelUI(*this); + +SettingsPanelWidget* SettingsPanelWidget::make( + QWidget& parent, + SettingsPanelInstance& instance, + PanelListener& listener +){ + SettingsPanelWidget* widget = new SettingsPanelWidget(parent, instance, listener); widget->construct(); return widget; } - -SettingsPanelUI::SettingsPanelUI(SettingsPanel& factory) - : RightPanelUI(factory) - , m_factory(factory) +SettingsPanelWidget::SettingsPanelWidget( + QWidget& parent, + SettingsPanelInstance& instance, + PanelListener& listener +) + : PanelWidget(parent, instance, listener) {} +void SettingsPanelWidget::construct(){ + QVBoxLayout* layout = new QVBoxLayout(this); + layout->setMargin(0); + layout->addWidget(make_header(*this)); - - -void SettingsPanelUI::make_body(QWidget& parent, QVBoxLayout& layout){ - QScrollArea* scroll = new QScrollArea(&parent); - layout.addWidget(scroll); + QScrollArea* scroll = new QScrollArea(this); + layout->addWidget(scroll); scroll->setWidgetResizable(true); - QWidget* options_widget = new QWidget(scroll); - (new QVBoxLayout(scroll))->addWidget(options_widget); - scroll->setWidget(options_widget); + scroll->setWidget(make_options(*scroll)); + layout->addWidget(make_actions(*this)); +} +QWidget* SettingsPanelWidget::make_options(QWidget& parent){ + QWidget* options_widget = new QWidget(&parent); + (new QVBoxLayout(&parent))->addWidget(options_widget); QVBoxLayout* options_layout = new QVBoxLayout(options_widget); options_layout->setAlignment(Qt::AlignTop); - for (auto& item : m_factory.m_options){ - m_options.emplace_back(item.second->make_ui(parent)); + SettingsPanelInstance& instance = static_cast(m_instance); + for (auto& item : instance.m_options){ + m_options.emplace_back(item.second->make_ui(*options_widget)); options_layout->addWidget(m_options.back()->widget()); } - + return options_widget; +} +QWidget* SettingsPanelWidget::make_actions(QWidget& parent){ QGroupBox* actions_widget = new QGroupBox("Actions", &parent); - layout.addWidget(actions_widget); QHBoxLayout* action_layout = new QHBoxLayout(actions_widget); action_layout->setMargin(0); { - m_default_button = new QPushButton("Restore Defaults", &parent); + m_default_button = new QPushButton("Restore Defaults", actions_widget); action_layout->addWidget(m_default_button, 1); QFont font = m_default_button->font(); font.setPointSize(16); @@ -88,13 +107,17 @@ void SettingsPanelUI::make_body(QWidget& parent, QVBoxLayout& layout){ restore_defaults(); } ); + + return actions_widget; } -void SettingsPanelUI::restore_defaults(){ +void SettingsPanelWidget::restore_defaults(){ for (ConfigOptionUI* item : m_options){ item->restore_defaults(); } } + + } diff --git a/SerialPrograms/Source/CommonFramework/Panels/SettingsPanel.h b/SerialPrograms/Source/CommonFramework/Panels/SettingsPanel.h index 145227140f..1b4d01c5c2 100644 --- a/SerialPrograms/Source/CommonFramework/Panels/SettingsPanel.h +++ b/SerialPrograms/Source/CommonFramework/Panels/SettingsPanel.h @@ -10,43 +10,61 @@ #include #include #include "CommonFramework/Options/ConfigOption.h" -#include "RightPanel.h" +#include "Panel.h" namespace PokemonAutomation{ -class SettingsPanel : public RightPanel{ + +class SettingsPanelInstance : public PanelInstance{ public: - using RightPanel::RightPanel; + using PanelInstance::PanelInstance; - void from_json(const QJsonValue& json); - virtual QJsonValue to_json() const override; + virtual QWidget* make_widget(QWidget& parent, PanelListener& listener) override; - virtual QWidget* make_ui(MainWindow& window) override; +public: + // Serialization + virtual void from_json(const QJsonValue& json) override; + virtual QJsonValue to_json() const override; protected: - friend class SettingsPanelUI; + friend class SettingsPanelWidget; + std::vector>> m_options; }; -class SettingsPanelUI : public RightPanelUI{ - friend class SettingsPanel; - +class SettingsPanelWidget : public PanelWidget{ public: - SettingsPanelUI(SettingsPanel& factory); - virtual void make_body(QWidget& parent, QVBoxLayout& layout) override; + static SettingsPanelWidget* make( + QWidget& parent, + SettingsPanelInstance& instance, + PanelListener& listener + ); void restore_defaults(); private: - SettingsPanel& m_factory; + SettingsPanelWidget( + QWidget& parent, + SettingsPanelInstance& instance, + PanelListener& listener + ); + void construct(); + QWidget* make_options(QWidget& parent); + QWidget* make_actions(QWidget& parent); + +private: + friend class SettingsPanelInstance; + std::vector m_options; QPushButton* m_default_button; }; + + } #endif diff --git a/SerialPrograms/Source/CommonFramework/PersistentSettings.cpp b/SerialPrograms/Source/CommonFramework/PersistentSettings.cpp index 27cdd48a30..65f0202252 100644 --- a/SerialPrograms/Source/CommonFramework/PersistentSettings.cpp +++ b/SerialPrograms/Source/CommonFramework/PersistentSettings.cpp @@ -5,81 +5,119 @@ */ #include +#include #include #include #include #include -#include "Common/Qt/StringException.h" +#include "Common/Cpp/Exception.h" #include "Common/Qt/QtJsonTools.h" #include "NintendoSwitch/Framework/VirtualSwitchControllerMapping.h" -#include "PanelList.h" #include "PersistentSettings.h" +#include +using std::cout; +using std::endl; + namespace PokemonAutomation{ -PersistentSettings settings; +PersistentSettings& PERSISTENT_SETTINGS(){ + static PersistentSettings settings; + return settings; +} + + +PersistentSettings::PersistentSettings() + : stats_file("PA-Stats.txt") +// , window_size(1280, 720) + , window_width(1280) + , window_height(720) + , naughty_mode(false) + , developer_mode(false) + , log_everything(false) +{ + // Find the resource directory. + QString path = QCoreApplication::applicationDirPath(); + for (size_t c = 0; c < 5; c++){ + QFile file(path + "/Resources/"); +// cout << path.toUtf8().data() << endl; + if (file.exists()){ + resource_path = path + "/Resources/"; + training_data = path + "/TrainingData/"; + break; + } + path += "/.."; + } + if (resource_path.isEmpty()){ + resource_path = QCoreApplication::applicationDirPath() + "/../Resources/"; + training_data = QCoreApplication::applicationDirPath() + "/../TrainingData/"; + } +// cout << "resources = " << resource_path.toUtf8().data() << endl; +} + void PersistentSettings::write() const{ QJsonObject root; -// root.insert("00-ConfigPath", QJsonValue(config_path)); -// root.insert("01-SourcePath", QJsonValue(source_path)); root.insert("01-StatsFile", QJsonValue(stats_file)); { QJsonArray res; - res.append(QJsonValue(window_size.width())); - res.append(QJsonValue(window_size.height())); + res.append(QJsonValue((int)window_width)); + res.append(QJsonValue((int)window_height)); root.insert("02-WindowSize", res); } root.insert("03-NaughtyMode", QJsonValue(naughty_mode)); root.insert("04-DeveloperMode", QJsonValue(developer_mode)); - root.insert("05-LogEverything", QJsonValue(log_everything.load(std::memory_order_acquire))); + root.insert("05-LogEverything", QJsonValue(log_everything)); +// root.insert("06-ResourcePath", QJsonValue(resource_path)); - root.insert("10-SwitchKeyboardMapping", NintendoSwitch::read_keyboard_mapping()); + root.insert("20-DISCORD_WEBHOOK_ID", DISCORD_WEBHOOK_ID); + root.insert("21-DISCORD_WEBHOOK_TOKEN", DISCORD_WEBHOOK_TOKEN); + root.insert("22-DISCORD_USER_ID", DISCORD_USER_ID); + root.insert("23-DISCORD_USER_SHORT_NAME", DISCORD_USER_SHORT_NAME); - QJsonObject settings; - for (const auto& panel : SETTINGS_MAP()){ - settings.insert(panel.first, panel.second->to_json()); - } - root.insert("98-SharedSettings", settings); + root.insert("50-SwitchKeyboardMapping", NintendoSwitch::read_keyboard_mapping()); - QJsonObject programs; - for (const auto& panel : PROGRAM_MAP()){ - programs.insert(panel.first, panel.second->to_json()); - } - root.insert("99-ProgramSettings", programs); + root.insert("99-Panels", panels); +// cout << QJsonDocument(panels).toJson().data() << endl; write_json_file(QCoreApplication::applicationFilePath() + "-Settings.json", QJsonDocument(root)); } void PersistentSettings::read(){ QJsonDocument doc = read_json_file(QCoreApplication::applicationFilePath() + "-Settings.json"); if (!doc.isObject()){ - throw StringException("Invalid settings file."); + PA_THROW_ParseException("Invalid settings file."); } QJsonObject root = doc.object(); -// json_get_string(config_path, root, "00-ConfigPath"); -// json_get_string(source_path, root, "01-SourcePath"); json_get_string(stats_file, root, "01-StatsFile"); - stat_sets.open_from_file(stats_file); { QJsonArray res = json_get_array_nothrow(root, "02-WindowSize"); if (res.size() == 2){ - window_size = QSize( - res[0].toInt(window_size.width()), - res[1].toInt(window_size.height()) - ); + window_width = res[0].toInt(window_width); + window_height = res[1].toInt(window_height); +// window_size = QSize( +// res[0].toInt(window_size.width()), +// res[1].toInt(window_size.height()) +// ); } } json_get_bool(naughty_mode, root, "03-NaughtyMode"); json_get_bool(developer_mode, root, "04-DeveloperMode"); json_get_bool(log_everything, root, "05-LogEverything"); - NintendoSwitch::set_keyboard_mapping(json_get_array_nothrow(root, "10-SwitchKeyboardMapping")); - settings = json_get_object_nothrow(root, "98-SharedSettings"); - programs = json_get_object_nothrow(root, "99-ProgramSettings"); +// json_get_string(resource_path, root, "06-ResourcePath"); + + json_get_string(DISCORD_WEBHOOK_ID, root, "20-DISCORD_WEBHOOK_ID"); + json_get_string(DISCORD_WEBHOOK_TOKEN, root, "21-DISCORD_WEBHOOK_TOKEN"); + json_get_string(DISCORD_USER_ID, root, "22-DISCORD_USER_ID"); + json_get_string(DISCORD_USER_SHORT_NAME, root, "23-DISCORD_USER_SHORT_NAME"); + + NintendoSwitch::set_keyboard_mapping(json_get_array_nothrow(root, "50-SwitchKeyboardMapping")); + + panels = json_get_object_nothrow(root, "99-Panels"); } diff --git a/SerialPrograms/Source/CommonFramework/PersistentSettings.h b/SerialPrograms/Source/CommonFramework/PersistentSettings.h index e054eaae26..de9884587f 100644 --- a/SerialPrograms/Source/CommonFramework/PersistentSettings.h +++ b/SerialPrograms/Source/CommonFramework/PersistentSettings.h @@ -11,36 +11,42 @@ #include #include #include -#include "Tools/StatsDatabase.h" +//#include "Tools/StatsDatabase.h" namespace PokemonAutomation{ class PersistentSettings{ public: - PersistentSettings() - : log_everything(false) - {} + PersistentSettings(); void write() const; void read(); public: -// QString config_path = "GeneratorConfig"; -// QString source_path = "DeviceSource"; - QString stats_file = "PA-Stats.txt"; - QSize window_size = QSize(960, 540); - bool naughty_mode = false; - bool developer_mode = false; - std::atomic log_everything; - - StatSet stat_sets; - - QJsonObject settings; - QJsonObject programs; + QString stats_file; +// QSize window_size; + uint32_t window_width; + uint32_t window_height; + bool naughty_mode; + bool developer_mode; + bool log_everything; + + QString resource_path; + QString training_data; + +public: + // Settings Panel + QString DISCORD_WEBHOOK_ID; + QString DISCORD_WEBHOOK_TOKEN; + QString DISCORD_USER_ID; + QString DISCORD_USER_SHORT_NAME; + +public: + QJsonObject panels; }; -extern PersistentSettings settings; +PersistentSettings& PERSISTENT_SETTINGS(); diff --git a/SerialPrograms/Source/CommonFramework/Tesseract/capi.h b/SerialPrograms/Source/CommonFramework/Tesseract/capi.h deleted file mode 100644 index 7ed64ef4d9..0000000000 --- a/SerialPrograms/Source/CommonFramework/Tesseract/capi.h +++ /dev/null @@ -1,628 +0,0 @@ -/////////////////////////////////////////////////////////////////////// -// File: capi.h -// Description: C-API TessBaseAPI -// -// (C) Copyright 2012, Google Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -/////////////////////////////////////////////////////////////////////// - -#ifndef API_CAPI_H_ -#define API_CAPI_H_ - -#if defined(TESSERACT_API_BASEAPI_H_) && !defined(TESS_CAPI_INCLUDE_BASEAPI) -# define TESS_CAPI_INCLUDE_BASEAPI -#endif - -#ifdef TESS_CAPI_INCLUDE_BASEAPI -# include "baseapi.h" -# include "ocrclass.h" -# include "pageiterator.h" -# include "renderer.h" -# include "resultiterator.h" -#else -# include -# include -# include "platform.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef TESS_CALL -# if defined(WIN32) -# define TESS_CALL __cdecl -# else -# define TESS_CALL -# endif -#endif - -#ifndef BOOL -# define BOOL int -# define TRUE 1 -# define FALSE 0 -#endif - -#ifdef TESS_CAPI_INCLUDE_BASEAPI -typedef tesseract::TessResultRenderer TessResultRenderer; -typedef tesseract::TessTextRenderer TessTextRenderer; -typedef tesseract::TessHOcrRenderer TessHOcrRenderer; -typedef tesseract::TessAltoRenderer TessAltoRenderer; -typedef tesseract::TessTsvRenderer TessTsvRenderer; -typedef tesseract::TessPDFRenderer TessPDFRenderer; -typedef tesseract::TessUnlvRenderer TessUnlvRenderer; -typedef tesseract::TessBoxTextRenderer TessBoxTextRenderer; -typedef tesseract::TessWordStrBoxRenderer TessWordStrBoxRenderer; -typedef tesseract::TessLSTMBoxRenderer TessLSTMBoxRenderer; -typedef tesseract::TessBaseAPI TessBaseAPI; -typedef tesseract::PageIterator TessPageIterator; -typedef tesseract::ResultIterator TessResultIterator; -typedef tesseract::MutableIterator TessMutableIterator; -typedef tesseract::ChoiceIterator TessChoiceIterator; -typedef tesseract::OcrEngineMode TessOcrEngineMode; -typedef tesseract::PageSegMode TessPageSegMode; -typedef tesseract::ImageThresholder TessImageThresholder; -typedef tesseract::PageIteratorLevel TessPageIteratorLevel; -typedef tesseract::DictFunc TessDictFunc; -typedef tesseract::ProbabilityInContextFunc TessProbabilityInContextFunc; -// typedef tesseract::ParamsModelClassifyFunc TessParamsModelClassifyFunc; -typedef tesseract::FillLatticeFunc TessFillLatticeFunc; -typedef tesseract::Dawg TessDawg; -typedef tesseract::TruthCallback TessTruthCallback; -typedef tesseract::Orientation TessOrientation; -typedef tesseract::ParagraphJustification TessParagraphJustification; -typedef tesseract::WritingDirection TessWritingDirection; -typedef tesseract::TextlineOrder TessTextlineOrder; -typedef PolyBlockType TessPolyBlockType; -#else -typedef struct TessResultRenderer TessResultRenderer; -typedef struct TessTextRenderer TessTextRenderer; -typedef struct TessHOcrRenderer TessHOcrRenderer; -typedef struct TessPDFRenderer TessPDFRenderer; -typedef struct TessUnlvRenderer TessUnlvRenderer; -typedef struct TessBoxTextRenderer TessBoxTextRenderer; -typedef struct TessBaseAPI TessBaseAPI; -typedef struct TessPageIterator TessPageIterator; -typedef struct TessResultIterator TessResultIterator; -typedef struct TessMutableIterator TessMutableIterator; -typedef struct TessChoiceIterator TessChoiceIterator; -typedef enum TessOcrEngineMode { - OEM_TESSERACT_ONLY, - OEM_LSTM_ONLY, - OEM_TESSERACT_LSTM_COMBINED, - OEM_DEFAULT -} TessOcrEngineMode; -typedef enum TessPageSegMode { - PSM_OSD_ONLY, - PSM_AUTO_OSD, - PSM_AUTO_ONLY, - PSM_AUTO, - PSM_SINGLE_COLUMN, - PSM_SINGLE_BLOCK_VERT_TEXT, - PSM_SINGLE_BLOCK, - PSM_SINGLE_LINE, - PSM_SINGLE_WORD, - PSM_CIRCLE_WORD, - PSM_SINGLE_CHAR, - PSM_SPARSE_TEXT, - PSM_SPARSE_TEXT_OSD, - PSM_RAW_LINE, - PSM_COUNT -} TessPageSegMode; -typedef enum TessPageIteratorLevel { - RIL_BLOCK, - RIL_PARA, - RIL_TEXTLINE, - RIL_WORD, - RIL_SYMBOL -} TessPageIteratorLevel; -typedef enum TessPolyBlockType { - PT_UNKNOWN, - PT_FLOWING_TEXT, - PT_HEADING_TEXT, - PT_PULLOUT_TEXT, - PT_EQUATION, - PT_INLINE_EQUATION, - PT_TABLE, - PT_VERTICAL_TEXT, - PT_CAPTION_TEXT, - PT_FLOWING_IMAGE, - PT_HEADING_IMAGE, - PT_PULLOUT_IMAGE, - PT_HORZ_LINE, - PT_VERT_LINE, - PT_NOISE, - PT_COUNT -} TessPolyBlockType; -typedef enum TessOrientation { - ORIENTATION_PAGE_UP, - ORIENTATION_PAGE_RIGHT, - ORIENTATION_PAGE_DOWN, - ORIENTATION_PAGE_LEFT -} TessOrientation; -typedef enum TessParagraphJustification { - JUSTIFICATION_UNKNOWN, - JUSTIFICATION_LEFT, - JUSTIFICATION_CENTER, - JUSTIFICATION_RIGHT -} TessParagraphJustification; -typedef enum TessWritingDirection { - WRITING_DIRECTION_LEFT_TO_RIGHT, - WRITING_DIRECTION_RIGHT_TO_LEFT, - WRITING_DIRECTION_TOP_TO_BOTTOM -} TessWritingDirection; -typedef enum TessTextlineOrder { - TEXTLINE_ORDER_LEFT_TO_RIGHT, - TEXTLINE_ORDER_RIGHT_TO_LEFT, - TEXTLINE_ORDER_TOP_TO_BOTTOM -} TessTextlineOrder; -typedef struct ETEXT_DESC ETEXT_DESC; -#endif - -typedef bool (*TessCancelFunc)(void* cancel_this, int words); -typedef bool (*TessProgressFunc)(ETEXT_DESC* ths, int left, int right, int top, - int bottom); - -struct Pix; -struct Boxa; -struct Pixa; - -/* General free functions */ - -TESS_API const char* TESS_CALL TessVersion(); -TESS_API void TESS_CALL TessDeleteText(const char* text); -TESS_API void TESS_CALL TessDeleteTextArray(char** arr); -TESS_API void TESS_CALL TessDeleteIntArray(const int* arr); - -/* Renderer API */ -TESS_API TessResultRenderer* TESS_CALL -TessTextRendererCreate(const char* outputbase); -TESS_API TessResultRenderer* TESS_CALL -TessHOcrRendererCreate(const char* outputbase); -TESS_API TessResultRenderer* TESS_CALL -TessHOcrRendererCreate2(const char* outputbase, BOOL font_info); -TESS_API TessResultRenderer* TESS_CALL -TessAltoRendererCreate(const char* outputbase); -TESS_API TessResultRenderer* TESS_CALL -TessTsvRendererCreate(const char* outputbase); -TESS_API TessResultRenderer* TESS_CALL TessPDFRendererCreate( - const char* outputbase, const char* datadir, BOOL textonly); -TESS_API TessResultRenderer* TESS_CALL -TessUnlvRendererCreate(const char* outputbase); -TESS_API TessResultRenderer* TESS_CALL -TessBoxTextRendererCreate(const char* outputbase); -TESS_API TessResultRenderer* TESS_CALL -TessLSTMBoxRendererCreate(const char* outputbase); -TESS_API TessResultRenderer* TESS_CALL -TessWordStrBoxRendererCreate(const char* outputbase); - -TESS_API void TESS_CALL TessDeleteResultRenderer(TessResultRenderer* renderer); -TESS_API void TESS_CALL TessResultRendererInsert(TessResultRenderer* renderer, - TessResultRenderer* next); -TESS_API TessResultRenderer* TESS_CALL -TessResultRendererNext(TessResultRenderer* renderer); -TESS_API BOOL TESS_CALL TessResultRendererBeginDocument( - TessResultRenderer* renderer, const char* title); -TESS_API BOOL TESS_CALL TessResultRendererAddImage(TessResultRenderer* renderer, - TessBaseAPI* api); -TESS_API BOOL TESS_CALL -TessResultRendererEndDocument(TessResultRenderer* renderer); - -TESS_API const char* TESS_CALL -TessResultRendererExtention(TessResultRenderer* renderer); -TESS_API const char* TESS_CALL -TessResultRendererTitle(TessResultRenderer* renderer); -TESS_API int TESS_CALL TessResultRendererImageNum(TessResultRenderer* renderer); - -/* Base API */ - -TESS_API TessBaseAPI* TESS_CALL TessBaseAPICreate(); -TESS_API void TESS_CALL TessBaseAPIDelete(TessBaseAPI* handle); - -TESS_API size_t TESS_CALL TessBaseAPIGetOpenCLDevice(TessBaseAPI* handle, - void** device); - -TESS_API void TESS_CALL TessBaseAPISetInputName(TessBaseAPI* handle, - const char* name); -TESS_API const char* TESS_CALL TessBaseAPIGetInputName(TessBaseAPI* handle); - -TESS_API void TESS_CALL TessBaseAPISetInputImage(TessBaseAPI* handle, - struct Pix* pix); -TESS_API struct Pix* TESS_CALL TessBaseAPIGetInputImage(TessBaseAPI* handle); - -TESS_API int TESS_CALL TessBaseAPIGetSourceYResolution(TessBaseAPI* handle); -TESS_API const char* TESS_CALL TessBaseAPIGetDatapath(TessBaseAPI* handle); - -TESS_API void TESS_CALL TessBaseAPISetOutputName(TessBaseAPI* handle, - const char* name); - -TESS_API BOOL TESS_CALL TessBaseAPISetVariable(TessBaseAPI* handle, - const char* name, - const char* value); -TESS_API BOOL TESS_CALL TessBaseAPISetDebugVariable(TessBaseAPI* handle, - const char* name, - const char* value); - -TESS_API BOOL TESS_CALL TessBaseAPIGetIntVariable(const TessBaseAPI* handle, - const char* name, int* value); -TESS_API BOOL TESS_CALL TessBaseAPIGetBoolVariable(const TessBaseAPI* handle, - const char* name, - BOOL* value); -TESS_API BOOL TESS_CALL TessBaseAPIGetDoubleVariable(const TessBaseAPI* handle, - const char* name, - double* value); -TESS_API const char* TESS_CALL -TessBaseAPIGetStringVariable(const TessBaseAPI* handle, const char* name); - -TESS_API void TESS_CALL TessBaseAPIPrintVariables(const TessBaseAPI* handle, - FILE* fp); -TESS_API BOOL TESS_CALL TessBaseAPIPrintVariablesToFile( - const TessBaseAPI* handle, const char* filename); - -#ifdef TESS_CAPI_INCLUDE_BASEAPI - -TESS_API BOOL TESS_CALL TessBaseAPIGetVariableAsString(TessBaseAPI* handle, - const char* name, - STRING* val); - -TESS_API int TESS_CALL TessBaseAPIInit( - TessBaseAPI* handle, const char* datapath, const char* language, - TessOcrEngineMode mode, char** configs, int configs_size, - const STRING* vars_vec, size_t vars_vec_size, const STRING* vars_values, - size_t vars_values_size, BOOL set_only_init_params); - -#endif // def TESS_CAPI_INCLUDE_BASEAPI - -TESS_API int TESS_CALL TessBaseAPIInit1(TessBaseAPI* handle, - const char* datapath, - const char* language, - TessOcrEngineMode oem, char** configs, - int configs_size); -TESS_API int TESS_CALL TessBaseAPIInit2(TessBaseAPI* handle, - const char* datapath, - const char* language, - TessOcrEngineMode oem); -TESS_API int TESS_CALL TessBaseAPIInit3(TessBaseAPI* handle, - const char* datapath, - const char* language); - -TESS_API int TESS_CALL TessBaseAPIInit4( - TessBaseAPI* handle, const char* datapath, const char* language, - TessOcrEngineMode mode, char** configs, int configs_size, char** vars_vec, - char** vars_values, size_t vars_vec_size, BOOL set_only_non_debug_params); - -TESS_API const char* TESS_CALL -TessBaseAPIGetInitLanguagesAsString(const TessBaseAPI* handle); -TESS_API char** TESS_CALL -TessBaseAPIGetLoadedLanguagesAsVector(const TessBaseAPI* handle); -TESS_API char** TESS_CALL -TessBaseAPIGetAvailableLanguagesAsVector(const TessBaseAPI* handle); - -TESS_API int TESS_CALL TessBaseAPIInitLangMod(TessBaseAPI* handle, - const char* datapath, - const char* language); -TESS_API void TESS_CALL TessBaseAPIInitForAnalysePage(TessBaseAPI* handle); - -TESS_API void TESS_CALL TessBaseAPIReadConfigFile(TessBaseAPI* handle, - const char* filename); -TESS_API void TESS_CALL TessBaseAPIReadDebugConfigFile(TessBaseAPI* handle, - const char* filename); - -TESS_API void TESS_CALL TessBaseAPISetPageSegMode(TessBaseAPI* handle, - TessPageSegMode mode); -TESS_API TessPageSegMode TESS_CALL -TessBaseAPIGetPageSegMode(const TessBaseAPI* handle); - -TESS_API char* TESS_CALL TessBaseAPIRect(TessBaseAPI* handle, - const unsigned char* imagedata, - int bytes_per_pixel, - int bytes_per_line, int left, int top, - int width, int height); - -TESS_API void TESS_CALL TessBaseAPIClearAdaptiveClassifier(TessBaseAPI* handle); - -TESS_API void TESS_CALL TessBaseAPISetImage(TessBaseAPI* handle, - const unsigned char* imagedata, - int width, int height, - int bytes_per_pixel, - int bytes_per_line); -TESS_API void TESS_CALL TessBaseAPISetImage2(TessBaseAPI* handle, - struct Pix* pix); - -TESS_API void TESS_CALL TessBaseAPISetSourceResolution(TessBaseAPI* handle, - int ppi); - -TESS_API void TESS_CALL TessBaseAPISetRectangle(TessBaseAPI* handle, int left, - int top, int width, int height); - -#ifdef TESS_CAPI_INCLUDE_BASEAPI -TESS_API void TESS_CALL TessBaseAPISetThresholder( - TessBaseAPI* handle, TessImageThresholder* thresholder); -#endif - -TESS_API struct Pix* TESS_CALL -TessBaseAPIGetThresholdedImage(TessBaseAPI* handle); -TESS_API struct Boxa* TESS_CALL TessBaseAPIGetRegions(TessBaseAPI* handle, - struct Pixa** pixa); -TESS_API struct Boxa* TESS_CALL TessBaseAPIGetTextlines(TessBaseAPI* handle, - struct Pixa** pixa, - int** blockids); -TESS_API struct Boxa* TESS_CALL -TessBaseAPIGetTextlines1(TessBaseAPI* handle, BOOL raw_image, int raw_padding, - struct Pixa** pixa, int** blockids, int** paraids); -TESS_API struct Boxa* TESS_CALL TessBaseAPIGetStrips(TessBaseAPI* handle, - struct Pixa** pixa, - int** blockids); -TESS_API struct Boxa* TESS_CALL TessBaseAPIGetWords(TessBaseAPI* handle, - struct Pixa** pixa); -TESS_API struct Boxa* TESS_CALL -TessBaseAPIGetConnectedComponents(TessBaseAPI* handle, struct Pixa** cc); -TESS_API struct Boxa* TESS_CALL TessBaseAPIGetComponentImages( - TessBaseAPI* handle, TessPageIteratorLevel level, BOOL text_only, - struct Pixa** pixa, int** blockids); -TESS_API struct Boxa* TESS_CALL TessBaseAPIGetComponentImages1( - TessBaseAPI* handle, TessPageIteratorLevel level, BOOL text_only, - BOOL raw_image, int raw_padding, struct Pixa** pixa, int** blockids, - int** paraids); - -TESS_API int TESS_CALL -TessBaseAPIGetThresholdedImageScaleFactor(const TessBaseAPI* handle); - -TESS_API TessPageIterator* TESS_CALL -TessBaseAPIAnalyseLayout(TessBaseAPI* handle); - -TESS_API int TESS_CALL TessBaseAPIRecognize(TessBaseAPI* handle, - ETEXT_DESC* monitor); - -#ifndef DISABLED_LEGACY_ENGINE -TESS_API int TESS_CALL TessBaseAPIRecognizeForChopTest(TessBaseAPI* handle, - ETEXT_DESC* monitor); -#endif - -TESS_API BOOL TESS_CALL TessBaseAPIProcessPages(TessBaseAPI* handle, - const char* filename, - const char* retry_config, - int timeout_millisec, - TessResultRenderer* renderer); -TESS_API BOOL TESS_CALL TessBaseAPIProcessPage(TessBaseAPI* handle, - struct Pix* pix, int page_index, - const char* filename, - const char* retry_config, - int timeout_millisec, - TessResultRenderer* renderer); - -TESS_API TessResultIterator* TESS_CALL -TessBaseAPIGetIterator(TessBaseAPI* handle); -TESS_API TessMutableIterator* TESS_CALL -TessBaseAPIGetMutableIterator(TessBaseAPI* handle); - -TESS_API char* TESS_CALL TessBaseAPIGetUTF8Text(TessBaseAPI* handle); -TESS_API char* TESS_CALL TessBaseAPIGetHOCRText(TessBaseAPI* handle, - int page_number); - -TESS_API char* TESS_CALL TessBaseAPIGetAltoText(TessBaseAPI* handle, - int page_number); -TESS_API char* TESS_CALL TessBaseAPIGetTsvText(TessBaseAPI* handle, - int page_number); - -TESS_API char* TESS_CALL TessBaseAPIGetBoxText(TessBaseAPI* handle, - int page_number); -TESS_API char* TESS_CALL TessBaseAPIGetLSTMBoxText(TessBaseAPI* handle, - int page_number); -TESS_API char* TESS_CALL TessBaseAPIGetWordStrBoxText(TessBaseAPI* handle, - int page_number); - -TESS_API char* TESS_CALL TessBaseAPIGetUNLVText(TessBaseAPI* handle); -TESS_API int TESS_CALL TessBaseAPIMeanTextConf(TessBaseAPI* handle); - -TESS_API int* TESS_CALL TessBaseAPIAllWordConfidences(TessBaseAPI* handle); - -#ifndef DISABLED_LEGACY_ENGINE -TESS_API BOOL TESS_CALL TessBaseAPIAdaptToWordStr(TessBaseAPI* handle, - TessPageSegMode mode, - const char* wordstr); -#endif // ndef DISABLED_LEGACY_ENGINE - -TESS_API void TESS_CALL TessBaseAPIClear(TessBaseAPI* handle); -TESS_API void TESS_CALL TessBaseAPIEnd(TessBaseAPI* handle); - -TESS_API int TESS_CALL TessBaseAPIIsValidWord(TessBaseAPI* handle, - const char* word); -TESS_API BOOL TESS_CALL TessBaseAPIGetTextDirection(TessBaseAPI* handle, - int* out_offset, - float* out_slope); - -#ifdef TESS_CAPI_INCLUDE_BASEAPI - -TESS_API void TESS_CALL TessBaseAPISetDictFunc(TessBaseAPI* handle, - TessDictFunc f); - -TESS_API void TESS_CALL TessBaseAPIClearPersistentCache(TessBaseAPI* handle); - -TESS_API void TESS_CALL TessBaseAPISetProbabilityInContextFunc( - TessBaseAPI* handle, TessProbabilityInContextFunc f); - -// Call TessDeleteText(*best_script_name) to free memory allocated by this -// function -TESS_API BOOL TESS_CALL TessBaseAPIDetectOrientationScript( - TessBaseAPI* handle, int* orient_deg, float* orient_conf, - const char** script_name, float* script_conf); - -#endif // def TESS_CAPI_INCLUDE_BASEAPI - -TESS_API const char* TESS_CALL TessBaseAPIGetUnichar(TessBaseAPI* handle, - int unichar_id); - -TESS_API void TESS_CALL TessBaseAPISetMinOrientationMargin(TessBaseAPI* handle, - double margin); - -#ifdef TESS_CAPI_INCLUDE_BASEAPI - -TESS_API const TessDawg* TESS_CALL TessBaseAPIGetDawg(const TessBaseAPI* handle, - int i); - -TESS_API int TESS_CALL TessBaseAPINumDawgs(const TessBaseAPI* handle); - -TESS_API TessOcrEngineMode TESS_CALL TessBaseAPIOem(const TessBaseAPI* handle); - -TESS_API void TESS_CALL TessBaseAPIInitTruthCallback(TessBaseAPI* handle, - TessTruthCallback* cb); - -TESS_API void TESS_CALL TessBaseGetBlockTextOrientations( - TessBaseAPI* handle, int** block_orientation, bool** vertical_writing); - -#endif - -/* Page iterator */ - -TESS_API void TESS_CALL TessPageIteratorDelete(TessPageIterator* handle); - -TESS_API TessPageIterator* TESS_CALL -TessPageIteratorCopy(const TessPageIterator* handle); - -TESS_API void TESS_CALL TessPageIteratorBegin(TessPageIterator* handle); - -TESS_API BOOL TESS_CALL TessPageIteratorNext(TessPageIterator* handle, - TessPageIteratorLevel level); - -TESS_API BOOL TESS_CALL TessPageIteratorIsAtBeginningOf( - const TessPageIterator* handle, TessPageIteratorLevel level); - -TESS_API BOOL TESS_CALL TessPageIteratorIsAtFinalElement( - const TessPageIterator* handle, TessPageIteratorLevel level, - TessPageIteratorLevel element); - -TESS_API BOOL TESS_CALL TessPageIteratorBoundingBox( - const TessPageIterator* handle, TessPageIteratorLevel level, int* left, - int* top, int* right, int* bottom); - -TESS_API TessPolyBlockType TESS_CALL -TessPageIteratorBlockType(const TessPageIterator* handle); - -TESS_API struct Pix* TESS_CALL TessPageIteratorGetBinaryImage( - const TessPageIterator* handle, TessPageIteratorLevel level); - -TESS_API struct Pix* TESS_CALL TessPageIteratorGetImage( - const TessPageIterator* handle, TessPageIteratorLevel level, int padding, - struct Pix* original_image, int* left, int* top); - -TESS_API BOOL TESS_CALL TessPageIteratorBaseline(const TessPageIterator* handle, - TessPageIteratorLevel level, - int* x1, int* y1, int* x2, - int* y2); - -TESS_API void TESS_CALL TessPageIteratorOrientation( - TessPageIterator* handle, TessOrientation* orientation, - TessWritingDirection* writing_direction, TessTextlineOrder* textline_order, - float* deskew_angle); - -TESS_API void TESS_CALL TessPageIteratorParagraphInfo( - TessPageIterator* handle, TessParagraphJustification* justification, - BOOL* is_list_item, BOOL* is_crown, int* first_line_indent); - -/* Result iterator */ - -TESS_API void TESS_CALL TessResultIteratorDelete(TessResultIterator* handle); -TESS_API TessResultIterator* TESS_CALL -TessResultIteratorCopy(const TessResultIterator* handle); -TESS_API TessPageIterator* TESS_CALL -TessResultIteratorGetPageIterator(TessResultIterator* handle); -TESS_API const TessPageIterator* TESS_CALL -TessResultIteratorGetPageIteratorConst(const TessResultIterator* handle); -TESS_API TessChoiceIterator* TESS_CALL -TessResultIteratorGetChoiceIterator(const TessResultIterator* handle); - -TESS_API BOOL TESS_CALL TessResultIteratorNext(TessResultIterator* handle, - TessPageIteratorLevel level); -TESS_API char* TESS_CALL TessResultIteratorGetUTF8Text( - const TessResultIterator* handle, TessPageIteratorLevel level); -TESS_API float TESS_CALL TessResultIteratorConfidence( - const TessResultIterator* handle, TessPageIteratorLevel level); -TESS_API const char* TESS_CALL -TessResultIteratorWordRecognitionLanguage(const TessResultIterator* handle); -TESS_API const char* TESS_CALL TessResultIteratorWordFontAttributes( - const TessResultIterator* handle, BOOL* is_bold, BOOL* is_italic, - BOOL* is_underlined, BOOL* is_monospace, BOOL* is_serif, BOOL* is_smallcaps, - int* pointsize, int* font_id); - -TESS_API BOOL TESS_CALL -TessResultIteratorWordIsFromDictionary(const TessResultIterator* handle); -TESS_API BOOL TESS_CALL -TessResultIteratorWordIsNumeric(const TessResultIterator* handle); -TESS_API BOOL TESS_CALL -TessResultIteratorSymbolIsSuperscript(const TessResultIterator* handle); -TESS_API BOOL TESS_CALL -TessResultIteratorSymbolIsSubscript(const TessResultIterator* handle); -TESS_API BOOL TESS_CALL -TessResultIteratorSymbolIsDropcap(const TessResultIterator* handle); - -TESS_API void TESS_CALL TessChoiceIteratorDelete(TessChoiceIterator* handle); -TESS_API BOOL TESS_CALL TessChoiceIteratorNext(TessChoiceIterator* handle); -TESS_API const char* TESS_CALL -TessChoiceIteratorGetUTF8Text(const TessChoiceIterator* handle); -TESS_API float TESS_CALL -TessChoiceIteratorConfidence(const TessChoiceIterator* handle); - -/* Progress monitor */ - -TESS_API ETEXT_DESC* TESS_CALL TessMonitorCreate(); -TESS_API void TESS_CALL TessMonitorDelete(ETEXT_DESC* monitor); -TESS_API void TESS_CALL TessMonitorSetCancelFunc(ETEXT_DESC* monitor, - TessCancelFunc cancelFunc); -TESS_API void TESS_CALL TessMonitorSetCancelThis(ETEXT_DESC* monitor, - void* cancelThis); -TESS_API void* TESS_CALL TessMonitorGetCancelThis(ETEXT_DESC* monitor); -TESS_API void TESS_CALL -TessMonitorSetProgressFunc(ETEXT_DESC* monitor, TessProgressFunc progressFunc); -TESS_API int TESS_CALL TessMonitorGetProgress(ETEXT_DESC* monitor); -TESS_API void TESS_CALL TessMonitorSetDeadlineMSecs(ETEXT_DESC* monitor, - int deadline); - -#ifndef DISABLED_LEGACY_ENGINE - -# ifdef TESS_CAPI_INCLUDE_BASEAPI -TESS_API void TESS_CALL TessBaseAPISetFillLatticeFunc(TessBaseAPI* handle, - TessFillLatticeFunc f); - -TESS_API void TESS_CALL TessBaseAPIGetFeaturesForBlob( - TessBaseAPI* handle, TBLOB* blob, INT_FEATURE_STRUCT* int_features, - int* num_features, int* FeatureOutlineIndex); - -TESS_API ROW* TESS_CALL TessFindRowForBox(BLOCK_LIST* blocks, int left, int top, - int right, int bottom); - -TESS_API void TESS_CALL TessBaseAPIRunAdaptiveClassifier( - TessBaseAPI* handle, TBLOB* blob, int num_max_matches, int* unichar_ids, - float* ratings, int* num_matches_returned); - -TESS_API ROW* TESS_CALL TessMakeTessOCRRow(float baseline, float xheight, - float descender, float ascender); - -TESS_API TBLOB* TESS_CALL TessMakeTBLOB(Pix* pix); - -TESS_API void TESS_CALL TessNormalizeTBLOB(TBLOB* tblob, ROW* row, - BOOL numeric_mode); - -TESS_API BLOCK_LIST* TESS_CALL -TessBaseAPIFindLinesCreateBlockList(TessBaseAPI* handle); - -TESS_API void TESS_CALL TessDeleteBlockList(BLOCK_LIST* block_list); - -# endif // def TESS_CAPI_INCLUDE_BASEAPI - -#endif // ndef DISABLED_LEGACY_ENGINE - -#ifdef __cplusplus -} -#endif - -#endif // API_CAPI_H_ diff --git a/SerialPrograms/Source/CommonFramework/Tesseract/platform.h b/SerialPrograms/Source/CommonFramework/Tesseract/platform.h deleted file mode 100644 index 99424bc8bd..0000000000 --- a/SerialPrograms/Source/CommonFramework/Tesseract/platform.h +++ /dev/null @@ -1,59 +0,0 @@ -/////////////////////////////////////////////////////////////////////// -// File: platform.h -// Description: Place holder -// -// (C) Copyright 2006, Google Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -/////////////////////////////////////////////////////////////////////// - -#ifndef TESSERACT_CCUTIL_PLATFORM_H_ -#define TESSERACT_CCUTIL_PLATFORM_H_ - -#define DLLSYM -#ifndef _WIN32 -# ifdef __cplusplus -# include -# else /* C compiler*/ -# include -# endif /* __cplusplus */ -# ifndef PATH_MAX -# define MAX_PATH 4096 -# else -# define MAX_PATH PATH_MAX -# endif -#endif - -#if defined(_WIN32) || defined(__CYGWIN__) -# if defined(TESS_EXPORTS) -# define TESS_API __declspec(dllexport) -# elif defined(TESS_IMPORTS) -# define TESS_API __declspec(dllimport) -# else -# define TESS_API -# endif -# define TESS_LOCAL -#else -# if __GNUC__ >= 4 -# if defined(TESS_EXPORTS) || defined(TESS_IMPORTS) -# define TESS_API __attribute__((visibility("default"))) -# define TESS_LOCAL __attribute__((visibility("hidden"))) -# else -# define TESS_API -# define TESS_LOCAL -# endif -# else -# define TESS_API -# define TESS_LOCAL -# endif -#endif - -#endif // TESSERACT_CCUTIL_PLATFORM_H_ diff --git a/SerialPrograms/Source/CommonFramework/Tools/BotBaseHandle.cpp b/SerialPrograms/Source/CommonFramework/Tools/BotBaseHandle.cpp index a6fb692556..45ce1f0c6e 100644 --- a/SerialPrograms/Source/CommonFramework/Tools/BotBaseHandle.cpp +++ b/SerialPrograms/Source/CommonFramework/Tools/BotBaseHandle.cpp @@ -4,7 +4,9 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include +#include "Common/Cpp/PrettyPrint.h" +#include "Common/Cpp/PanicDump.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "ClientSource/Libraries/MessageConverter.h" #include "ClientSource/Connection/SerialConnection.h" @@ -93,10 +95,8 @@ void BotBaseHandle::reset(const QSerialPortInfo& port){ std::unique_ptr connection(new SerialConnection(name, PABB_BAUD_RATE)); m_botbase.reset(new PABotBase(std::move(connection), nullptr)); m_current_pabotbase.store(PABotBaseLevel::NOT_PABOTBASE, std::memory_order_release); - }catch (const char* str){ - error = str; - }catch (const std::string& str){ - error = str; + }catch (const StringException& e){ + error = e.message(); } if (error.empty()){ m_state.store(State::CONNECTING, std::memory_order_release); @@ -107,7 +107,7 @@ void BotBaseHandle::reset(const QSerialPortInfo& port){ return; } - m_status_thread = std::thread(&BotBaseHandle::thread_body, this); + m_status_thread = std::thread(run_with_catch, "BotBaseHandle::thread_body()", [=]{ thread_body(); }); } void BotBaseHandle::verify_protocol(){ @@ -115,7 +115,9 @@ void BotBaseHandle::verify_protocol(){ uint32_t version_hi = protocol / 100; uint32_t version_lo = protocol % 100; if (version_hi != PABB_PROTOCOL_VERSION / 100 || version_lo < PABB_PROTOCOL_VERSION % 100){ - throw "Incompatible version. Client: " + std::to_string(PABB_PROTOCOL_VERSION) + ", Device: " + std::to_string(protocol); + PA_THROW_StringException( + "Incompatible version. Client: " + std::to_string(PABB_PROTOCOL_VERSION) + ", Device: " + std::to_string(protocol) + ); } } uint8_t BotBaseHandle::verify_pabotbase(){ @@ -125,7 +127,9 @@ uint8_t BotBaseHandle::verify_pabotbase(){ PABotBaseLevel type = program_id_to_botbase_level(program_id); m_current_pabotbase.store(type, std::memory_order_release); if (type < m_minimum_pabotbase){ - throw "PABotBase level not met. (" + program_name(program_id) + ")"; + PA_THROW_StringException( + "PABotBase level not met. (" + program_name(program_id) + ")" + ); } return program_id; } @@ -136,21 +140,19 @@ void BotBaseHandle::thread_body(){ // Connect { - std::string error; + QString error; try{ m_botbase->connect(); - }catch (const char* str){ - error = str; - }catch (const std::string& str){ - error = str; }catch (CancelledException&){ m_botbase->stop(); on_stopped(""); return; + }catch (const StringException& e){ + error = e.message_qt(); } - if (!error.empty()){ + if (!error.isEmpty()){ m_botbase->stop(); - on_stopped(("" + error + "").c_str()); + on_stopped("" + error + ""); return; } } @@ -159,19 +161,17 @@ void BotBaseHandle::thread_body(){ { uint8_t program_id = 0; uint32_t version = 0; - std::string error; + QString error; try{ verify_protocol(); program_id = verify_pabotbase(); version = m_botbase->program_version(); - }catch (const char* str){ - error = str; - }catch (const std::string& str){ - error = str; }catch (CancelledException&){ return; + }catch (const StringException& e){ + error = e.message_qt(); } - if (error.empty()){ + if (error.isEmpty()){ m_state.store(State::READY, std::memory_order_release); on_ready(( "Program: " + @@ -180,7 +180,7 @@ void BotBaseHandle::thread_body(){ ).c_str()); }else{ m_state.store(State::STOPPED, std::memory_order_release); - on_stopped(("" + error + "").c_str()); + on_stopped("" + error + ""); m_botbase->stop(); return; } @@ -211,29 +211,28 @@ void BotBaseHandle::thread_body(){ } }); + BotBaseContext context(*m_botbase); while (true){ if (m_state.load(std::memory_order_acquire) != State::READY){ break; } std::string str; - std::string error; + QString error; try{ // cout << "system_clock()" << endl; - uint32_t wallclock = system_clock(*m_botbase); + uint32_t wallclock = system_clock(context); // cout << "system_clock() - done" << endl; str = ticks_to_time(wallclock); - }catch (const char* str){ - error = str; - }catch (const std::string& str){ - error = str; }catch (CancelledException&){ break; + }catch (const StringException& e){ + error = e.message_qt(); } - if (error.empty()){ + if (error.isEmpty()){ uptime_status(("Up Time: " + str + "").c_str()); }else{ - uptime_status(QString("Up Time: ") + error.c_str() + ""); + uptime_status("Up Time: " + error + ""); error.clear(); } diff --git a/SerialPrograms/Source/CommonFramework/Tools/BotBaseHandle.h b/SerialPrograms/Source/CommonFramework/Tools/BotBaseHandle.h index b892d85a5e..67505d933d 100644 --- a/SerialPrograms/Source/CommonFramework/Tools/BotBaseHandle.h +++ b/SerialPrograms/Source/CommonFramework/Tools/BotBaseHandle.h @@ -98,7 +98,7 @@ bool BotBaseHandle::try_send_request(Parameters& params){ if (!accepting_commands()){ return false; } - return botbase()->try_issue_request(params); + return botbase()->try_issue_request(nullptr, params); } diff --git a/SerialPrograms/Source/CommonFramework/Tools/ConsoleHandle.h b/SerialPrograms/Source/CommonFramework/Tools/ConsoleHandle.h index 79e77ddf24..32eaaf75bf 100644 --- a/SerialPrograms/Source/CommonFramework/Tools/ConsoleHandle.h +++ b/SerialPrograms/Source/CommonFramework/Tools/ConsoleHandle.h @@ -23,20 +23,24 @@ class ConsoleHandle{ VideoFeed& video ) : m_index(index) - , m_botbase(botbase) + , m_context(botbase) , m_video(video) {} size_t index() const{ return m_index; } - BotBase& botbase(){ return m_botbase; } + + BotBase& botbase(){ return m_context.botbase(); } + BotBaseContext& context(){ return m_context; } VideoFeed& video(){ return m_video; } - operator BotBase&(){ return m_botbase; } + operator BotBase&(){ return m_context.botbase(); } operator VideoFeed&(){ return m_video; } + operator BotBaseContext&(){ return m_context; } private: size_t m_index; - BotBase& m_botbase; +// BotBase& m_botbase; + BotBaseContext m_context; VideoFeed& m_video; }; diff --git a/SerialPrograms/Source/CommonFramework/Tools/InterruptableCommands.cpp b/SerialPrograms/Source/CommonFramework/Tools/InterruptableCommands.cpp new file mode 100644 index 0000000000..fd5312240d --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Tools/InterruptableCommands.cpp @@ -0,0 +1,82 @@ +/* Async Command Set + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "InterruptableCommands.h" + +namespace PokemonAutomation{ + + + +InterruptableCommandSession::CommandSet::CommandSet( + BotBase& botbase, + std::function&& lambda +) + : context(botbase) + , commands(std::move(lambda)) +{} + +InterruptableCommandSession::InterruptableCommandSession(BotBase& botbase) + : m_botbase(botbase) +{} + +bool InterruptableCommandSession::run(std::function&& lambda){ + { + SpinLockGuard lg(m_lock, "InterruptableCommandSession::run() - start"); + if (m_current){ + return false; + } + + m_current.reset(new CommandSet( + m_botbase, std::move(lambda) + )); + } + while (true){ + if (m_current->context.botbase().state() != BotBase::State::RUNNING){ + throw CancelledException(); + } + + try{ + m_current->commands(m_current->context); + break; + }catch (CancelledException&){ + SpinLockGuard lg(m_lock, "InterruptableCommandSession::run() - cancelled"); + m_current = std::move(m_pending); + if (m_current){ + continue; + }else{ + break; + } + } + } + { + SpinLockGuard lg(m_lock, "InterruptableCommandSession::run() - end"); + m_current.reset(); + m_pending.reset(); + } + return true; +} + + +void InterruptableCommandSession::interrupt_with(std::function&& lambda){ + SpinLockGuard lg(m_lock, "InterruptableCommandSession::interrupt_with()"); + if (m_current){ + m_current->context.cancel(); + m_pending.reset(new CommandSet(m_botbase, std::move(lambda))); + } +} + +void InterruptableCommandSession::stop(){ + SpinLockGuard lg(m_lock, "InterruptableCommandSession::stop()"); + if (m_current){ + m_current->context.cancel(); + } +} + + + + +} + diff --git a/SerialPrograms/Source/CommonFramework/Tools/InterruptableCommands.h b/SerialPrograms/Source/CommonFramework/Tools/InterruptableCommands.h new file mode 100644 index 0000000000..ac9a22bf92 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Tools/InterruptableCommands.h @@ -0,0 +1,60 @@ +/* Interruptable Commands + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_InterruptableCommands_H +#define PokemonAutomation_InterruptableCommands_H + +#include +#include "Common/Cpp/SpinLock.h" +#include "Common/Cpp/AsyncDispatcher.h" +#include "ClientSource/Connection/BotBase.h" + + +namespace PokemonAutomation{ + + +class InterruptableCommandSession{ + +public: + InterruptableCommandSession(BotBase& botbase); + +public: + // Execution Thread + + // Run commands. Return when all commands are finished. + // Returns false if there is already something running. + bool run(std::function&& lambda); + +public: + // External Threads + + // If there is a command running right now, interrupt it with a different one. + void interrupt_with(std::function&& lambda); + + // Stop the currently running command. + void stop(); + +private: + struct CommandSet{ + CommandSet(BotBase& botbase, std::function&& lambda); + BotBaseContext context; + std::function commands; + }; + + SpinLock m_lock; + BotBase& m_botbase; + std::unique_ptr m_current; + std::unique_ptr m_pending; +}; + + + + + + + +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/Tools/ProgramEnvironment.cpp b/SerialPrograms/Source/CommonFramework/Tools/ProgramEnvironment.cpp index 81aeb51480..dae71a8363 100644 --- a/SerialPrograms/Source/CommonFramework/Tools/ProgramEnvironment.cpp +++ b/SerialPrograms/Source/CommonFramework/Tools/ProgramEnvironment.cpp @@ -24,11 +24,14 @@ ProgramEnvironment::ProgramEnvironment( -void ProgramEnvironment::update_stats(){ +void ProgramEnvironment::update_stats(const std::string& override_current){ std::string current; - if (m_current_stats){ + if (!override_current.empty()){ + current = override_current; + }else if (m_current_stats){ current = m_current_stats->to_str(); } + std::string historical; if (m_historical_stats){ historical = m_historical_stats->to_str(); diff --git a/SerialPrograms/Source/CommonFramework/Tools/ProgramEnvironment.h b/SerialPrograms/Source/CommonFramework/Tools/ProgramEnvironment.h index 1f9c0c5be2..d536e5da1d 100644 --- a/SerialPrograms/Source/CommonFramework/Tools/ProgramEnvironment.h +++ b/SerialPrograms/Source/CommonFramework/Tools/ProgramEnvironment.h @@ -12,6 +12,7 @@ #include #include #include +#include "Common/Cpp/AsyncDispatcher.h" #include "ClientSource/Connection/BotBase.h" #include "Logger.h" #include "StatsTracking.h" @@ -37,7 +38,9 @@ class ProgramEnvironment : public QObject{ void log(Args&&... args); Logger& logger(){ return m_logger; } - void update_stats(); + AsyncDispatcher& dispatcher(){ return m_dispatcher; } + + void update_stats(const std::string& override_current = ""); template StatsType& stats(); @@ -62,6 +65,7 @@ class ProgramEnvironment : public QObject{ std::condition_variable m_cv; Logger& m_logger; + AsyncDispatcher m_dispatcher; StatsTracker* m_current_stats; const StatsTracker* m_historical_stats; }; diff --git a/SerialPrograms/Source/CommonFramework/Tools/StatsDatabase.cpp b/SerialPrograms/Source/CommonFramework/Tools/StatsDatabase.cpp index b0493fcb39..37ebf567fd 100644 --- a/SerialPrograms/Source/CommonFramework/Tools/StatsDatabase.cpp +++ b/SerialPrograms/Source/CommonFramework/Tools/StatsDatabase.cpp @@ -15,6 +15,27 @@ using std::endl; namespace PokemonAutomation{ +const std::map STATS_DATABASE_ALIASES{ + {"Dex Rec Finder", "PokemonSwSh:DexRecFinder"}, + {"Day Skipper (JPN)", "PokemonSwSh:DaySkipperJPN"}, + {"Day Skipper (EU)", "PokemonSwSh:DaySkipperEU"}, + {"Day Skipper (US)", "PokemonSwSh:DaySkipperUS"}, + {"Day Skipper (JPN) - 7.8k", "PokemonSwSh:DaySkipperJPN7p8k"}, + {"Purple Beam Finder", "PokemonSwSh:PurpleBeamFinder"}, + {"Auto-Host Multi-Game", "PokemonSwSh:AutoHostMultiGame"}, + {"Auto-Host Rolling", "PokemonSwSh:AutoHostRolling"}, + {"Stats Reset", "PokemonSwSh:StatsReset"}, + {"Shiny Hunt Autonomous - Regi", "PokemonSwSh:ShinyHuntAutonomousRegi"}, + {"Shiny Hunt Autonomous - Swords Of Justice", "PokemonSwSh:ShinyHuntAutonomousSwordsOfJustice"}, + {"Shiny Hunt Autonomous - Strong Spawn", "PokemonSwSh:ShinyHuntAutonomousStrongSpawn"}, + {"Shiny Hunt Autonomous - Regigigas2", "PokemonSwSh:ShinyHuntAutonomousRegigigas2"}, + {"Shiny Hunt Autonomous - IoA Trade", "PokemonSwSh:ShinyHuntAutonomousIoATrade"}, + {"Shiny Hunt Autonomous - Berry Tree", "PokemonSwSh:ShinyHuntAutonomousBerryTree"}, + {"Shiny Hunt Autonomous - Whistling", "PokemonSwSh:ShinyHuntAutonomousWhistling"}, + {"Shiny Hunt Autonomous - Fishing", "PokemonSwSh:ShinyHuntAutonomousFishing"}, + {"Shiny Hunt Autonomous - Overworld", "PokemonSwSh:ShinyHuntAutonomousOverworld"}, +}; + StatLine::StatLine(const StatsTracker& tracker) @@ -89,8 +110,8 @@ StatList* StatSet::find(const std::string& label){ : &iter->second; } #endif -StatList& StatSet::operator[](const std::string& label){ - return m_data[label]; +StatList& StatSet::operator[](const std::string& identifier){ + return m_data[identifier]; } std::string StatSet::to_str() const{ @@ -127,7 +148,7 @@ void StatSet::open_from_file(const QString& filepath){ bool StatSet::update_file( const QString& filepath, - const std::string& label, + const std::string& identifier, const StatsTracker& tracker ){ QFile file(filepath); @@ -139,7 +160,7 @@ bool StatSet::update_file( StatSet set; set.load_from_string(data.c_str()); - set[label] += tracker; + set[identifier] += tracker; data = set.to_str(); file.seek(0); @@ -193,6 +214,11 @@ void StatSet::load_from_string(const char* ptr){ continue; } + auto iter = STATS_DATABASE_ALIASES.find(line); + if (iter != STATS_DATABASE_ALIASES.end()){ + line = iter->second; + } + StatList& program = m_data[line]; while (true){ if (!get_line(line, ptr)){ diff --git a/SerialPrograms/Source/CommonFramework/Tools/StatsDatabase.h b/SerialPrograms/Source/CommonFramework/Tools/StatsDatabase.h index 2f9d6ca248..1177c3a4fd 100644 --- a/SerialPrograms/Source/CommonFramework/Tools/StatsDatabase.h +++ b/SerialPrograms/Source/CommonFramework/Tools/StatsDatabase.h @@ -50,7 +50,7 @@ class StatList{ class StatSet{ public: // StatList* find(const std::string& label); - StatList& operator[](const std::string& label); + StatList& operator[](const std::string& identifier); std::string to_str() const; @@ -59,7 +59,7 @@ class StatSet{ static bool update_file( const QString& filepath, - const std::string& label, + const std::string& identifier, const StatsTracker& tracker ); diff --git a/SerialPrograms/Source/CommonFramework/Tools/StatsTracking.cpp b/SerialPrograms/Source/CommonFramework/Tools/StatsTracking.cpp index 9b151f9625..69661ea693 100644 --- a/SerialPrograms/Source/CommonFramework/Tools/StatsTracking.cpp +++ b/SerialPrograms/Source/CommonFramework/Tools/StatsTracking.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "ProgramEnvironment.h" #include "StatsTracking.h" @@ -21,12 +21,29 @@ StatsTracker::Stat::Stat(std::string&& p_label, bool p_omit_if_zero) , omit_if_zero(p_omit_if_zero) {} std::string StatsTracker::to_str() const{ + std::map stats; + for (const auto& item : m_stats){ + auto alias = m_aliases.find(item.first); + + // Not an alias. + if (alias == m_aliases.end()){ + stats[item.first] += item.second; + continue; + } + + // Find alias target. + auto iter = m_stats.find(alias->second); + if (iter != m_stats.end()){ + stats[alias->second] += item.second; + } + } + std::string str; for (const Stat& stat : m_display_order){ - auto iter = m_stats.find(stat.label); + auto iter = stats.find(stat.label); uint64_t count = 0; - if (iter != m_stats.end()){ - count = iter->second; + if (iter != stats.end()){ + count += iter->second; } if (stat.omit_if_zero && count == 0){ continue; diff --git a/SerialPrograms/Source/CommonFramework/Tools/StatsTracking.h b/SerialPrograms/Source/CommonFramework/Tools/StatsTracking.h index 1cda2babd8..f3957087f5 100644 --- a/SerialPrograms/Source/CommonFramework/Tools/StatsTracking.h +++ b/SerialPrograms/Source/CommonFramework/Tools/StatsTracking.h @@ -34,6 +34,7 @@ class StatsTracker{ std::vector m_display_order; std::map m_stats; + std::map m_aliases; }; diff --git a/SerialPrograms/Source/CommonFramework/Widgets/CameraSelector.cpp b/SerialPrograms/Source/CommonFramework/Widgets/CameraSelector.cpp index 8a570ff7fd..0cb24dfc3d 100644 --- a/SerialPrograms/Source/CommonFramework/Widgets/CameraSelector.cpp +++ b/SerialPrograms/Source/CommonFramework/Widgets/CameraSelector.cpp @@ -8,7 +8,6 @@ #include #include #include "Common/Compiler.h" -#include "Common/Qt/StringException.h" #include "Common/Qt/QtJsonTools.h" #include "CameraSelector.h" @@ -274,7 +273,7 @@ void CameraSelectorUI::reset_video(){ } m_resolution_box->clear(); - int index = 0; + int index = -1; bool resolution_match = false; for (int c = 0; c < m_resolutions.size(); c++){ const QSize& size = m_resolutions[c]; @@ -290,9 +289,13 @@ void CameraSelectorUI::reset_video(){ index = c; } } - m_value.m_resolution = m_resolutions[index]; - m_resolution_box->setCurrentIndex(index); - m_resolution_box->activated(index); + if (index >= 0){ + m_value.m_resolution = m_resolutions[index]; + m_resolution_box->setCurrentIndex(index); + m_resolution_box->activated(index); + }else{ + m_value.m_resolution = QSize(); + } m_overlay->raise(); // update_size(); diff --git a/SerialPrograms/Source/CommonFramework/Widgets/ProgramList.cpp b/SerialPrograms/Source/CommonFramework/Widgets/ProgramList.cpp deleted file mode 100644 index 44d9e84a5f..0000000000 --- a/SerialPrograms/Source/CommonFramework/Widgets/ProgramList.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* UI List for all the Programs - * - * From: https://github.com/PokemonAutomation/Arduino-Source - * - */ - -#include "Common/Qt/StringException.h" -#include "CommonFramework/Panels/RightPanel.h" -#include "CommonFramework/Windows/MainWindow.h" -#include "PanelList.h" -#include "ProgramList.h" - -#include -using std::cout; -using std::endl; - -namespace PokemonAutomation{ - - -ProgramListUI::ProgramListUI(MainWindow& parent) - : m_parent(parent) - , m_text_width(0) - , m_current(nullptr) - , m_active_panel(nullptr) -{ - QFontMetrics fm(this->font()); - for (const auto& item : PROGRAM_LIST()){ - addItem(item->name()); - QListWidgetItem* list_item = this->item(this->count() - 1); - list_item->setForeground(item->color()); - m_text_width = std::max(m_text_width, fm.width(item->name())); -// cout << m_text_width << " / " << list_item->sizeHint().width() << endl; - } -// setMaximumWidth(m_text_width); - - connect(this, &QListWidget::itemClicked, this, &ProgramListUI::row_selected); -// connect(this, &QListWidget::currentRowChanged, this, &ProgramListUI::row_changed); -} - -void ProgramListUI::row_selected(QListWidgetItem* item){ -// if (m_current == item){ -// return; -// } - - auto iter = PROGRAM_MAP().find(item->text()); - if (iter == PROGRAM_MAP().end()){ -// std::cout << item->text().toUtf8().data() << std::endl; - throw StringException("Invalid program name: " + item->text()); - } - m_parent.change_panel(*iter->second); - m_current = item; -} - - -} diff --git a/SerialPrograms/Source/CommonFramework/Widgets/ProgramList.h b/SerialPrograms/Source/CommonFramework/Widgets/ProgramList.h deleted file mode 100644 index b46eb3727d..0000000000 --- a/SerialPrograms/Source/CommonFramework/Widgets/ProgramList.h +++ /dev/null @@ -1,38 +0,0 @@ -/* UI List for all the Programs - * - * From: https://github.com/PokemonAutomation/Arduino-Source - * - */ - -#ifndef PokemonAutomation_ProgramListUI_H -#define PokemonAutomation_ProgramListUI_H - -#include -#include - -namespace PokemonAutomation{ - - -class RightPanelObject; -class MainWindow; - -class ProgramListUI : public QListWidget{ - Q_OBJECT - -public: - ProgramListUI(MainWindow& parent); - int text_width() const{ return m_text_width; } - -public slots: - void row_selected(QListWidgetItem* item); - -private: - MainWindow& m_parent; - int m_text_width; - QListWidgetItem* m_current; - RightPanelObject* m_active_panel; -}; - - -} -#endif diff --git a/SerialPrograms/Source/CommonFramework/Widgets/SerialSelector.cpp b/SerialPrograms/Source/CommonFramework/Widgets/SerialSelector.cpp index d422fcf4b6..2d962c8ad2 100644 --- a/SerialPrograms/Source/CommonFramework/Widgets/SerialSelector.cpp +++ b/SerialPrograms/Source/CommonFramework/Widgets/SerialSelector.cpp @@ -5,8 +5,8 @@ */ #include +#include #include -#include "Common/Qt/StringException.h" #include "Common/Qt/QtJsonTools.h" #include "SerialSelector.h" @@ -204,6 +204,18 @@ void SerialSelectorUI::reset(){ stop(); on_ready(false); refresh(); + +// if (m_value.m_port.description().indexOf("Labs") != -1){ + if (m_value.m_port.description().indexOf("Prolific") != -1){ + QMessageBox box; + box.warning( + nullptr, + "Warning", + "Prolific controller detected!

These controllers are known to have reliability issues. Proceed at your own risk!" + ); + } + + m_connection.reset(m_value.m_port); } diff --git a/SerialPrograms/Source/CommonFramework/Widgets/SettingList.cpp b/SerialPrograms/Source/CommonFramework/Widgets/SettingList.cpp deleted file mode 100644 index 5b32ea1e28..0000000000 --- a/SerialPrograms/Source/CommonFramework/Widgets/SettingList.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* UI List for all the Settings - * - * From: https://github.com/PokemonAutomation/Arduino-Source - * - */ - -#include "Common/Qt/StringException.h" -#include "CommonFramework/Panels/RightPanel.h" -#include "CommonFramework/Windows/MainWindow.h" -#include "PanelList.h" -#include "SettingList.h" - -namespace PokemonAutomation{ - - -SettingListUI::SettingListUI(MainWindow& parent) - : m_parent(parent) - , m_text_width(0) - , m_current(nullptr) - , m_active_panel(nullptr) -{ - connect(this, &QListWidget::itemClicked, this, &SettingListUI::row_selected); -// connect(this, &QListWidget::currentRowChanged, this, &SettingListUI::row_changed); - - const auto& list = SETTINGS_LIST(); - if (list.empty()){ - setMaximumHeight(50); - return; - } - - QFontMetrics fm(this->font()); - for (const auto& item : SETTINGS_LIST()){ - addItem(item->name()); - this->item(this->count() - 1)->setForeground(item->color()); - m_text_width = std::max(m_text_width, fm.width(item->name())); -// cout << m_text_width << endl; - } -// setMaximumWidth(m_width); - - setMaximumHeight(4 + (int)list.size() * (sizeHintForRow(0) + 2)); -} - -void SettingListUI::row_selected(QListWidgetItem* item){ -// if (m_current == item){ -// return; -// } - - auto iter = SETTINGS_MAP().find(item->text()); - if (iter == SETTINGS_MAP().end()){ -// std::cout << item->text().toUtf8().data() << std::endl; - throw StringException("Invalid program name: " + item->text()); - } - m_parent.change_panel(*iter->second); - m_current = item; -} - - - -} diff --git a/SerialPrograms/Source/CommonFramework/Widgets/SettingList.h b/SerialPrograms/Source/CommonFramework/Widgets/SettingList.h deleted file mode 100644 index 46ddbf88dd..0000000000 --- a/SerialPrograms/Source/CommonFramework/Widgets/SettingList.h +++ /dev/null @@ -1,39 +0,0 @@ -/* UI List for all the Settings - * - * From: https://github.com/PokemonAutomation/Arduino-Source - * - */ - -#ifndef PokemonAutomation_SettingListUI_H -#define PokemonAutomation_SettingListUI_H - -#include -#include - -namespace PokemonAutomation{ - - -class RightPanelObject; -class MainWindow; - -class SettingListUI : public QListWidget{ - Q_OBJECT - -public: - SettingListUI(MainWindow& parent); - int text_width() const{ return m_text_width; } - -public slots: - void row_selected(QListWidgetItem* item); - -private: - MainWindow& m_parent; - int m_text_width; - QListWidgetItem* m_current; - RightPanelObject* m_active_panel; -}; - - -} -#endif - diff --git a/SerialPrograms/Source/CommonFramework/Widgets/VideoOverlay.cpp b/SerialPrograms/Source/CommonFramework/Widgets/VideoOverlay.cpp index 386fabd1da..c8abb9a44f 100644 --- a/SerialPrograms/Source/CommonFramework/Widgets/VideoOverlay.cpp +++ b/SerialPrograms/Source/CommonFramework/Widgets/VideoOverlay.cpp @@ -48,6 +48,7 @@ void VideoOverlay::update_size(const QSize& widget_size, const QSize& video_size int width = (int)(m_scale * video_size.width() + 0.5); width = std::min(width, widget_size.width()); + m_display_size = QSize(width, widget_size.height()); m_offset_x = (widget_size.width() - width + 1) / 2; this->resize(widget_size); @@ -68,11 +69,23 @@ void VideoOverlay::paintEvent(QPaintEvent*){ // << " " << (int)(height * box->y + 0.5) // << ", " << (int)(width * box->width + 0.5) // << " x " << (int)(height * box->height + 0.5) << endl; +// cout << painter.pen().width() << endl; + + // Compute coordinates. Clip so that it stays in-bounds. + int xmin = std::max((int)(width * box->x + 0.5), 1) + m_offset_x; + int ymin = std::max((int)(height * box->y + 0.5), 1); +// int xmax = std::min(xmin + (int)(width * box->width + 0.5), m_display_size.width() - painter.pen().width()); +// int ymax = std::min(ymin + (int)(height * box->height + 0.5), m_display_size.height() - painter.pen().width()); + int xmax = std::min(xmin + (int)(width * box->width + 0.5), m_display_size.width() - 1); + int ymax = std::min(ymin + (int)(height * box->height + 0.5), m_display_size.height() - 1); + +// cout << "m_video_size.width() = " << m_widget_size.width() << ", xmax = " << xmax << endl; + painter.drawRect( - (int)(width * box->x + m_offset_x + 0.5), - (int)(height * box->y + 0.5), - (int)(width * box->width + 0.5), - (int)(height * box->height + 0.5) + xmin, + ymin, + xmax - xmin, + ymax - ymin ); } } diff --git a/SerialPrograms/Source/CommonFramework/Widgets/VideoOverlay.h b/SerialPrograms/Source/CommonFramework/Widgets/VideoOverlay.h index 24014734bc..b97a1cc31a 100644 --- a/SerialPrograms/Source/CommonFramework/Widgets/VideoOverlay.h +++ b/SerialPrograms/Source/CommonFramework/Widgets/VideoOverlay.h @@ -9,7 +9,7 @@ #include #include -#include "Common/Clientside/SpinLock.h" +#include "Common/Cpp/SpinLock.h" #include "CommonFramework/Tools/VideoFeed.h" namespace PokemonAutomation{ @@ -30,6 +30,7 @@ class VideoOverlay : public QWidget{ private: QSize m_video_size; + QSize m_display_size; int m_offset_x; double m_scale; diff --git a/SerialPrograms/Source/CommonFramework/Windows/ButtonDiagram.cpp b/SerialPrograms/Source/CommonFramework/Windows/ButtonDiagram.cpp index b7a2400145..205d908d68 100644 --- a/SerialPrograms/Source/CommonFramework/Windows/ButtonDiagram.cpp +++ b/SerialPrograms/Source/CommonFramework/Windows/ButtonDiagram.cpp @@ -10,33 +10,23 @@ //#include //#include //#include +#include "CommonFramework/PersistentSettings.h" #include "ButtonDiagram.h" #include using std::cout; using std::endl; + +namespace PokemonAutomation{ + + ButtonDiagram::ButtonDiagram(QWidget& parent) : QMainWindow(&parent) { setWindowTitle("Controller Keyboard Mapping"); - // Find the image. - QString path = QCoreApplication::applicationDirPath() + "/"; - for (int c = 0; c < 5; c++){ -// cout << (path + "Button Layout.jpg").toUtf8().data() << endl; - QString filepath = path + "Button Layout.jpg"; -// QFile file(filepath); -// QMessageBox box0; -// box0.critical(nullptr, "Error", "Exists = " + QString::number(file.exists())); - m_image = QPixmap(filepath); - if (!m_image.isNull()){ - break; - } -// QMessageBox box; -// box.critical(nullptr, "Error", path + "Button Layout.jpg"); - path += "../"; - } + m_image = QPixmap(PERSISTENT_SETTINGS().resource_path + "/NintendoSwitch/ButtonLayout.jpg"); m_image_label = new QLabel(this); setCentralWidget(m_image_label); @@ -69,3 +59,7 @@ void ButtonDiagram::resizeEvent(QResizeEvent*){ m_image_label->setPixmap(m_image.scaled(iw, ih, Qt::KeepAspectRatio, Qt::SmoothTransformation)); } + + +} + diff --git a/SerialPrograms/Source/CommonFramework/Windows/ButtonDiagram.h b/SerialPrograms/Source/CommonFramework/Windows/ButtonDiagram.h index 18e3c6167b..dac320140a 100644 --- a/SerialPrograms/Source/CommonFramework/Windows/ButtonDiagram.h +++ b/SerialPrograms/Source/CommonFramework/Windows/ButtonDiagram.h @@ -7,6 +7,8 @@ #include #include +namespace PokemonAutomation{ + class ButtonDiagram : public QMainWindow{ public: ButtonDiagram(QWidget& parent); @@ -18,3 +20,6 @@ class ButtonDiagram : public QMainWindow{ QPixmap m_image; QLabel* m_image_label; }; + + +} diff --git a/SerialPrograms/Source/CommonFramework/Windows/MainWindow.cpp b/SerialPrograms/Source/CommonFramework/Windows/MainWindow.cpp index b25f695169..c8492a1e27 100644 --- a/SerialPrograms/Source/CommonFramework/Windows/MainWindow.cpp +++ b/SerialPrograms/Source/CommonFramework/Windows/MainWindow.cpp @@ -13,14 +13,15 @@ #include #include "CommonFramework/Globals.h" #include "CommonFramework/PersistentSettings.h" -#include "CommonFramework/Panels/RightPanel.h" -#include "CommonFramework/Widgets/ProgramList.h" -#include "CommonFramework/Widgets/SettingList.h" +#include "CommonFramework/GlobalSettingsPanel.h" +#include "PanelLists.h" #include "ButtonDiagram.h" #include "MainWindow.h" + //#include +//#include #include using std::cout; using std::endl; @@ -30,12 +31,13 @@ namespace PokemonAutomation{ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) - , m_right_panel_widget(nullptr) + , m_current_panel_widget(nullptr) { if (objectName().isEmpty()){ setObjectName(QString::fromUtf8("MainWindow")); } - resize(settings.window_size.width(), settings.window_size.height()); +// QSize window_size = PERSISTENT_SETTINGS().window_size; + resize(PERSISTENT_SETTINGS().window_width, PERSISTENT_SETTINGS().window_height); centralwidget = new QWidget(this); centralwidget->setObjectName(QString::fromUtf8("centralwidget")); setCentralWidget(centralwidget); @@ -53,30 +55,14 @@ MainWindow::MainWindow(QWidget* parent) hbox->addLayout(left_layout, 0); - QGroupBox* program_box = new QGroupBox("Program List", centralwidget); + QGroupBox* program_box = new QGroupBox("Program Select", centralwidget); left_layout->addWidget(program_box, 1); QVBoxLayout* program_layout = new QVBoxLayout(program_box); program_layout->setAlignment(Qt::AlignTop); - m_program_list = new ProgramListUI(*this); - program_layout->addWidget(m_program_list); - QGroupBox* setting_box = new QGroupBox("Global Settings", centralwidget); - left_layout->addWidget(setting_box, 0); - QVBoxLayout* setting_layout = new QVBoxLayout(setting_box); - setting_layout->setAlignment(Qt::AlignTop); - m_setting_list = new SettingListUI(*this); - setting_layout->addWidget(m_setting_list); + m_program_list = new ProgramTabs(*this, *this); + program_layout->addWidget(m_program_list); -#if 0 - int width = std::max( - m_program_list->text_width(), - m_settings_list->text_width() - ); -#else -// int width = 250; -#endif -// program_box->setMaximumWidth(width); -// setting_box->setMaximumWidth(width); QGroupBox* support_box = new QGroupBox("Support (" + STRING_POKEMON + " Automation " + VERSION + ")", centralwidget); left_layout->addWidget(support_box); @@ -89,10 +75,18 @@ MainWindow::MainWindow(QWidget* parent) QVBoxLayout* links = new QVBoxLayout(); support->addLayout(links); + { + QLabel* github = new QLabel(support_box); + links->addWidget(github); + github->setText("Online Documentation"); + github->setTextFormat(Qt::RichText); + github->setTextInteractionFlags(Qt::TextBrowserInteraction); + github->setOpenExternalLinks(true); + } { QLabel* discord = new QLabel(support_box); links->addWidget(discord); - discord->setText("Discord: " + DISCORD_LINK + ""); + discord->setText("" + DISCORD_LINK + ""); discord->setTextFormat(Qt::RichText); discord->setTextInteractionFlags(Qt::TextBrowserInteraction); discord->setOpenExternalLinks(true); @@ -100,18 +94,33 @@ MainWindow::MainWindow(QWidget* parent) { QLabel* github = new QLabel(support_box); links->addWidget(github); - github->setText("Online Documentation"); + github->setText("" + PROJECT_GITHUB + ""); +// github->setText("GitHub Repository"); github->setTextFormat(Qt::RichText); github->setTextInteractionFlags(Qt::TextBrowserInteraction); github->setOpenExternalLinks(true); } { - QLabel* github = new QLabel(support_box); - links->addWidget(github); - github->setText("GitHub Repository"); - github->setTextFormat(Qt::RichText); - github->setTextInteractionFlags(Qt::TextBrowserInteraction); - github->setOpenExternalLinks(true); + QLabel* about = new QLabel(support_box); + links->addWidget(about); + about->setText("" + "About this Program" + ""); + about->setTextFormat(Qt::RichText); + connect( + about, &QLabel::linkActivated, + this, [](const QString&){ + QMessageBox box; + box.information( + nullptr, + "About", + STRING_POKEMON + " Automation Feedback Programs (" + VERSION + ")
" + + "Copyright: 2020 - 2021
" + + "
" + "Made by the " + STRING_POKEMON + " Automation Discord Server.
" + "
" + "This program uses Qt and dynamically links to unmodified Qt libraries under LGPL.
" + ); + } + ); } QVBoxLayout* buttons = new QVBoxLayout(); @@ -138,6 +147,7 @@ MainWindow::MainWindow(QWidget* parent) } ); +#if 0 QPushButton* about = new QPushButton("About", support_box); buttons->addWidget(about); connect( @@ -156,6 +166,17 @@ MainWindow::MainWindow(QWidget* parent) ); } ); +#endif + + QPushButton* settings = new QPushButton("Settings", support_box); + m_settings = settings; + buttons->addWidget(settings); + connect( + settings, &QPushButton::clicked, + this, [=](bool){ + on_panel_construct(GlobalSettings_Descriptor::INSTANCE.make_panel()); + } + ); QVBoxLayout* right = new QVBoxLayout(); m_right_panel_layout = right; @@ -165,42 +186,68 @@ MainWindow::MainWindow(QWidget* parent) } MainWindow::~MainWindow(){ -// cout << "~MainWindow() - start" << endl; - if (m_right_panel_widget != nullptr){ - m_right_panel_layout->removeWidget(m_right_panel_widget); - delete m_right_panel_widget; - m_right_panel_widget = nullptr; - } -// Sleep(1000); -// cout << "~MainWindow() - finish" << endl; + close_panel(); } -void MainWindow::left_panel_enabled(bool enabled){ - m_program_list->setEnabled(enabled); - m_setting_list->setEnabled(enabled); -} -void MainWindow::change_panel(RightPanel& factory){ - if (m_right_panel_widget != nullptr){ - m_right_panel_layout->removeWidget(m_right_panel_widget); - delete m_right_panel_widget; - m_right_panel_widget = nullptr; - } - m_right_panel_widget = factory.make_ui(*this); - m_right_panel_layout->addWidget(m_right_panel_widget); -} + void MainWindow::open_output_window(){ m_output_window->show(); } -void MainWindow::closeEvent(QCloseEvent *event){ +void MainWindow::closeEvent(QCloseEvent* event){ m_output_window->close(); QMainWindow::closeEvent(event); } void MainWindow::resizeEvent(QResizeEvent* event){ - settings.window_size = size(); +// PERSISTENT_SETTINGS().window_size = size(); + PERSISTENT_SETTINGS().window_width = width(); + PERSISTENT_SETTINGS().window_height = height(); } +void MainWindow::close_panel(){ + // Must destroy the widget first since it references the instance. + if (m_current_panel_widget != nullptr){ + m_right_panel_layout->removeWidget(m_current_panel_widget); + delete m_current_panel_widget; + m_current_panel_widget = nullptr; + } + + // Now it's safe to destroy the instance. + if (m_current_panel == nullptr){ + return; + } + + const std::string& identifier = m_current_panel->descriptor().identifier(); + PERSISTENT_SETTINGS().panels[identifier.c_str()] = m_current_panel->to_json(); + + m_current_panel.reset(); +} + +void MainWindow::on_panel_construct(std::unique_ptr panel){ + close_panel(); + + // Make new widget. + m_current_panel_widget = panel->make_widget(*this, *this); + m_current_panel = std::move(panel); + m_right_panel_layout->addWidget(m_current_panel_widget); +} +void MainWindow::on_busy(PanelInstance& panel){ + if (m_program_list){ + m_program_list->setEnabled(false); + m_settings->setEnabled(false); + } +} +void MainWindow::on_idle(PanelInstance& panel){ + if (m_program_list){ + m_program_list->setEnabled(true); + m_settings->setEnabled(true); + } +} + + + + } diff --git a/SerialPrograms/Source/CommonFramework/Windows/MainWindow.h b/SerialPrograms/Source/CommonFramework/Windows/MainWindow.h index d1c39702f6..0e2d3ae1c7 100644 --- a/SerialPrograms/Source/CommonFramework/Windows/MainWindow.h +++ b/SerialPrograms/Source/CommonFramework/Windows/MainWindow.h @@ -9,24 +9,19 @@ #include #include +#include "CommonFramework/Panels/Panel.h" +#include "PanelLists.h" #include "OutputWindow.h" namespace PokemonAutomation{ -class RightPanel; -class ProgramListUI; -class SettingListUI; - -class MainWindow : public QMainWindow{ +class MainWindow : public QMainWindow, public PanelListener{ public: MainWindow(QWidget* parent = nullptr); ~MainWindow(); - OutputWindow& output_window() const{ return *m_output_window; } - - void left_panel_enabled(bool enabled); - void change_panel(RightPanel& factory); +// OutputWindow& output_window() const{ return *m_output_window; } void open_output_window(); @@ -34,16 +29,27 @@ class MainWindow : public QMainWindow{ virtual void closeEvent(QCloseEvent* event) override; virtual void resizeEvent(QResizeEvent* event) override; + void close_panel(); + + virtual void on_panel_construct(std::unique_ptr panel) override; +public: // Make private. + virtual OutputWindow& output_window() override{ return *m_output_window; } +private: + virtual void on_busy(PanelInstance& panel) override; + virtual void on_idle(PanelInstance& panel) override; + private: QWidget* centralwidget; QMenuBar* menubar; // QStatusBar* statusbar; - ProgramListUI* m_program_list; - SettingListUI* m_setting_list; - + ProgramTabs* m_program_list = nullptr; QVBoxLayout* m_right_panel_layout; - QWidget* m_right_panel_widget; + + QWidget* m_settings; + + std::unique_ptr m_current_panel; + QWidget* m_current_panel_widget; std::unique_ptr m_output_window; }; diff --git a/SerialPrograms/Source/CommonFramework/Windows/OutputWindow.cpp b/SerialPrograms/Source/CommonFramework/Windows/OutputWindow.cpp index 902e3f9dec..923b9cb7cb 100644 --- a/SerialPrograms/Source/CommonFramework/Windows/OutputWindow.cpp +++ b/SerialPrograms/Source/CommonFramework/Windows/OutputWindow.cpp @@ -54,7 +54,7 @@ void TaggedLogger::log(const QString& msg, QColor color){ SerialLogger::SerialLogger(OutputWindow& window, QString tag) : TaggedLogger(window, std::move(tag)) - , PokemonAutomation::MessageLogger(settings.log_everything) + , PokemonAutomation::MessageLogger(PERSISTENT_SETTINGS().log_everything) {} void SerialLogger::log(std::string msg){ TaggedLogger::log(msg, "green"); @@ -105,11 +105,38 @@ OutputWindow::~OutputWindow(){ } void OutputWindow::log(QString msg, QColor color){ - if (color.isValid()){ - m_text->append("" + msg + ""); - }else{ - m_text->append("" + msg + ""); + // Replace all newlines with: + //
for the output window. + // \r\n for the log file. + + QString window_str = ""; + QString file_str; + bool pending_carrage_return = false; + for (QChar ch : msg){ + if (pending_carrage_return && ch == '\n'){ + window_str += "
"; + file_str += "\r\n"; + pending_carrage_return = false; + continue; + } + pending_carrage_return = false; + if (ch == '\n'){ + window_str += "
"; + file_str += "\r\n"; + continue; + } + window_str += ch; + file_str += ch; } + + if (file_str.back() == "\n"){ + window_str.resize(window_str.size() - 4); + file_str.resize(file_str.size() - 2); + } + + window_str += "
"; + m_text->append(window_str); + msg += "\r\n"; m_log_file.write(msg.toUtf8().data()); m_log_file.flush(); diff --git a/SerialPrograms/Source/NintendoSwitch/FixedInterval.h b/SerialPrograms/Source/NintendoSwitch/FixedInterval.h index e226299b24..f26679dab4 100644 --- a/SerialPrograms/Source/NintendoSwitch/FixedInterval.h +++ b/SerialPrograms/Source/NintendoSwitch/FixedInterval.h @@ -15,32 +15,35 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ -inline void ssf_press_button2(BotBase& device, Button button, uint16_t duration, uint16_t hold){ - pbf_press_button(device, button, hold, duration < hold ? 0 : duration - hold); +inline void ssf_press_button2(const BotBaseContext& context, Button button, uint16_t duration, uint16_t hold){ + pbf_press_button(context, button, hold, duration < hold ? 0 : duration - hold); } -inline void ssf_press_button1(BotBase& device, Button button, uint16_t duration){ - ssf_press_button2(device, button, duration, 5); +inline void ssf_press_button1(const BotBaseContext& context, Button button, uint16_t duration){ + ssf_press_button2(context, button, duration, 5); } -inline void ssf_press_dpad2(BotBase& device, DpadPosition dpad, uint16_t duration, uint16_t hold){ - pbf_press_dpad(device, dpad, hold, duration < hold ? 0 : duration - hold); +inline void ssf_press_dpad2(const BotBaseContext& context, DpadPosition dpad, uint16_t duration, uint16_t hold){ + pbf_press_dpad(context, dpad, hold, duration < hold ? 0 : duration - hold); } -inline void ssf_press_dpad1(BotBase& device, DpadPosition dpad, uint16_t duration){ - ssf_press_dpad2(device, dpad, duration, 5); +inline void ssf_press_dpad1(const BotBaseContext& context, DpadPosition dpad, uint16_t duration){ + ssf_press_dpad2(context, dpad, duration, 5); } -inline void ssf_press_joystick2(BotBase& device, bool left, uint8_t x, uint8_t y, uint16_t duration, uint16_t hold){ +inline void ssf_press_joystick2(const BotBaseContext& context, bool left, uint8_t x, uint8_t y, uint16_t duration, uint16_t hold){ if (left){ - pbf_move_left_joystick(device, x, y, hold, duration < hold ? 0 : duration - hold); + pbf_move_left_joystick(context, x, y, hold, duration < hold ? 0 : duration - hold); }else{ - pbf_move_right_joystick(device, x, y, hold, duration < hold ? 0 : duration - hold); + pbf_move_right_joystick(context, x, y, hold, duration < hold ? 0 : duration - hold); } } -inline void ssf_hold_joystick1(BotBase& device, bool left, uint8_t x, uint8_t y, uint16_t hold){ - ssf_press_joystick2(device, left, x, y, hold, hold); +inline void ssf_hold_joystick1(const BotBaseContext& context, bool left, uint8_t x, uint8_t y, uint16_t hold){ + ssf_press_joystick2(context, left, x, y, hold, hold); } + + +#if 0 inline void ssf_press_button2(Button button, uint16_t duration, uint16_t hold){ ssf_press_button2(*global_connection, button, duration, hold); } @@ -61,6 +64,7 @@ inline void ssf_press_joystick2(bool left, uint8_t x, uint8_t y, uint16_t durati inline void ssf_hold_joystick1(bool left, uint8_t x, uint8_t y, uint16_t hold){ ssf_hold_joystick1(*global_connection, left, x, y, hold); } +#endif diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/MultiSwitchProgram.cpp b/SerialPrograms/Source/NintendoSwitch/Framework/MultiSwitchProgram.cpp index 19bbccf173..44fc1cf4d4 100644 --- a/SerialPrograms/Source/NintendoSwitch/Framework/MultiSwitchProgram.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Framework/MultiSwitchProgram.cpp @@ -11,14 +11,15 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ + + MultiSwitchProgramEnvironment::MultiSwitchProgramEnvironment( Logger& logger, StatsTracker* current_stats, const StatsTracker* historical_stats, - std::vector p_switches + FixedLimitVector p_switches ) : ProgramEnvironment(logger, current_stats, historical_stats) - , dispatcher(p_switches.size()) , consoles(std::move(p_switches)) {} @@ -31,7 +32,7 @@ void MultiSwitchProgramEnvironment::run_in_parallel( size_t s, size_t e, const std::function& func ){ - dispatcher.run_in_parallel( + dispatcher().run_in_parallel( s, e, [&](size_t index){ func(consoles[index]); @@ -42,47 +43,73 @@ void MultiSwitchProgramEnvironment::run_in_parallel( -MultiSwitchProgram::MultiSwitchProgram( - FeedbackType feedback, - PABotBaseLevel min_pabotbase, - QString name, +MultiSwitchProgramDescriptor::MultiSwitchProgramDescriptor( + std::string identifier, + QString display_name, QString doc_link, QString description, + FeedbackType feedback, + PABotBaseLevel min_pabotbase_level, size_t min_switches, size_t max_switches, - size_t switches + size_t default_switches ) - : RunnableProgram( - feedback, min_pabotbase, - std::move(name), + : RunnableSwitchProgramDescriptor( + std::move(identifier), + std::move(display_name), std::move(doc_link), - std::move(description) + std::move(description), + feedback, + min_pabotbase_level ) + , m_min_switches(min_switches) + , m_max_switches(max_switches) + , m_default_switches(default_switches) +{} + + + +MultiSwitchProgramInstance::MultiSwitchProgramInstance(const MultiSwitchProgramDescriptor& descriptor) + : RunnableSwitchProgramInstance(descriptor) , m_switches( - min_pabotbase, feedback, - min_switches, - max_switches, - switches + descriptor.min_pabotbase_level(), + descriptor.feedback(), + descriptor.min_switches(), + descriptor.max_switches(), + descriptor.default_switches() ) { m_setup = &m_switches; } +QWidget* MultiSwitchProgramInstance::make_widget(QWidget& parent, PanelListener& listener){ + return MultiSwitchProgramWidget::make(parent, *this, listener); +} + -MultiSwitchProgramUI::MultiSwitchProgramUI(MultiSwitchProgram& factory, MainWindow& window) - : RunnableProgramUI(factory, window) -{ - this->construct(); -} -MultiSwitchProgramUI::~MultiSwitchProgramUI(){ stop(); } -void MultiSwitchProgramUI::program( +MultiSwitchProgramWidget::~MultiSwitchProgramWidget(){ + if (!m_destructing){ + stop(); + m_destructing = true; + } +} +MultiSwitchProgramWidget* MultiSwitchProgramWidget::make( + QWidget& parent, + MultiSwitchProgramInstance& instance, + PanelListener& listener +){ + MultiSwitchProgramWidget* widget = new MultiSwitchProgramWidget(parent, instance, listener); + widget->construct(); + return widget; +} +void MultiSwitchProgramWidget::run_program( StatsTracker* current_stats, const StatsTracker* historical_stats ){ - MultiSwitchProgram& factory = static_cast(m_factory); - std::vector switches; - for (size_t c = 0; c < factory.count(); c++){ + MultiSwitchProgramInstance& instance = static_cast(m_instance); + FixedLimitVector switches(instance.count()); + for (size_t c = 0; c < instance.count(); c++){ SwitchSystem& system = static_cast(*m_setup)[c]; switches.emplace_back( c, @@ -96,7 +123,7 @@ void MultiSwitchProgramUI::program( std::move(switches) ); connect( - this, &RunnableProgramUI::signal_cancel, + this, &RunnableSwitchProgramWidget::signal_cancel, &env, [&]{ env.signal_stop(); }, @@ -108,11 +135,12 @@ void MultiSwitchProgramUI::program( this->set_status(std::move(status)); } ); - PokemonAutomation::global_connection = nullptr; - factory.program(env); + instance.program(env); } + + } } diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/MultiSwitchProgram.h b/SerialPrograms/Source/NintendoSwitch/Framework/MultiSwitchProgram.h index c153b4e721..d8d870d8de 100644 --- a/SerialPrograms/Source/NintendoSwitch/Framework/MultiSwitchProgram.h +++ b/SerialPrograms/Source/NintendoSwitch/Framework/MultiSwitchProgram.h @@ -7,7 +7,7 @@ #ifndef PokemonAutomation_MultiSwitchProgram_H #define PokemonAutomation_MultiSwitchProgram_H -#include "Common/Clientside/AsyncDispatcher.h" +#include "Common/Cpp/FixedLimitVector.h" #include "CommonFramework/Tools/ProgramEnvironment.h" #include "CommonFramework/Tools/ConsoleHandle.h" #include "MultiSwitchSystem.h" @@ -19,8 +19,7 @@ namespace NintendoSwitch{ class MultiSwitchProgramEnvironment : public ProgramEnvironment{ public: - AsyncDispatcher dispatcher; - std::vector consoles; + FixedLimitVector consoles; // Run the specified lambda for all switches in parallel. void run_in_parallel( @@ -34,62 +33,84 @@ class MultiSwitchProgramEnvironment : public ProgramEnvironment{ ); private: + friend class MultiSwitchProgramWidget; friend class MultiSwitchProgramUI; MultiSwitchProgramEnvironment( Logger& logger, StatsTracker* current_stats, const StatsTracker* historical_stats, - std::vector p_switches + FixedLimitVector p_switches ); }; -class MultiSwitchProgram : public RunnableProgram{ + +class MultiSwitchProgramDescriptor : public RunnableSwitchProgramDescriptor{ public: - MultiSwitchProgram( - FeedbackType feedback, - PABotBaseLevel min_pabotbase, - QString name, + MultiSwitchProgramDescriptor( + std::string identifier, + QString display_name, QString doc_link, QString description, + FeedbackType feedback, + PABotBaseLevel min_pabotbase_level, size_t min_switches, size_t max_switches, - size_t switches + size_t default_switches ); + size_t min_switches() const{ return m_min_switches; } + size_t max_switches() const{ return m_max_switches; } + size_t default_switches() const{ return m_default_switches; } + +private: + const size_t m_min_switches; + const size_t m_max_switches; + const size_t m_default_switches; +}; + + + +class MultiSwitchProgramInstance : public RunnableSwitchProgramInstance{ +public: + MultiSwitchProgramInstance(const MultiSwitchProgramDescriptor& descriptor); + size_t count() const{ return m_switches.count(); } - virtual void program(MultiSwitchProgramEnvironment& env) const = 0; + + virtual QWidget* make_widget(QWidget& parent, PanelListener& listener) override; + virtual void program(MultiSwitchProgramEnvironment& env) = 0; private: + friend class MultiSwitchProgramWidget; + MultiSwitchSystemFactory m_switches; }; -class MultiSwitchProgramUI final : public RunnableProgramUI{ + +class MultiSwitchProgramWidget : public RunnableSwitchProgramWidget{ public: - MultiSwitchProgramUI(MultiSwitchProgram& factory, MainWindow& window); - ~MultiSwitchProgramUI(); + static MultiSwitchProgramWidget* make( + QWidget& parent, + MultiSwitchProgramInstance& instance, + PanelListener& listener + ); + +private: + using RunnableSwitchProgramWidget::RunnableSwitchProgramWidget; + virtual ~MultiSwitchProgramWidget(); - virtual void program( +private: + virtual void run_program( StatsTracker* current_stats, const StatsTracker* historical_stats ) override; + +private: + friend class MultiSwitchProgramInstance; }; -template -class MultiSwitchProgramWrapper final : public Program{ -public: - MultiSwitchProgramWrapper() = default; - MultiSwitchProgramWrapper(const QJsonValue& json) - : Program() - { - this->from_json(json); - } - virtual QWidget* make_ui(MainWindow& window) override{ - return new MultiSwitchProgramUI(*this, window); - } -}; diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/MultiSwitchSystem.cpp b/SerialPrograms/Source/NintendoSwitch/Framework/MultiSwitchSystem.cpp index e9e342d710..5ee83c550a 100644 --- a/SerialPrograms/Source/NintendoSwitch/Framework/MultiSwitchSystem.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Framework/MultiSwitchSystem.cpp @@ -7,7 +7,6 @@ #include #include #include -#include "Common/Qt/StringException.h" #include "Common/Qt/QtJsonTools.h" #include "MultiSwitchSystem.h" diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/RunnableSwitchProgram.cpp b/SerialPrograms/Source/NintendoSwitch/Framework/RunnableSwitchProgram.cpp index 80d3de6976..2f2184439c 100644 --- a/SerialPrograms/Source/NintendoSwitch/Framework/RunnableSwitchProgram.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Framework/RunnableSwitchProgram.cpp @@ -4,13 +4,13 @@ * */ -#include #include #include #include #include #include -#include "Common/Qt/StringException.h" +#include "Common/Cpp/Exception.h" +#include "Common/Cpp/PanicDump.h" #include "Common/Qt/QtJsonTools.h" #include "ClientSource/Connection/PABotBase.h" #include "CommonFramework/Tools/StatsDatabase.h" @@ -18,12 +18,14 @@ #include "CommonFramework/Windows/MainWindow.h" #include "RunnableSwitchProgram.h" +#include +using std::cout; +using std::endl; + namespace PokemonAutomation{ namespace NintendoSwitch{ -using std::cout; -using std::endl; QColor pick_color(FeedbackType feedback, PABotBaseLevel size){ switch (size){ @@ -36,297 +38,154 @@ QColor pick_color(FeedbackType feedback, PABotBaseLevel size){ } return QColor(); } - -RunnableProgram::RunnableProgram( - FeedbackType feedback, - PABotBaseLevel min_pabotbase_level, - QString name, +RunnableSwitchProgramDescriptor::RunnableSwitchProgramDescriptor( + std::string identifier, + QString display_name, QString doc_link, - QString description + QString description, + FeedbackType feedback, + PABotBaseLevel min_pabotbase_level ) - : RightPanel(pick_color(feedback, min_pabotbase_level), name, std::move(doc_link), description) + : RunnablePanelDescriptor( + pick_color(feedback, min_pabotbase_level), + std::move(identifier), + std::move(display_name), + std::move(doc_link), + std::move(description) + ) , m_feedback(feedback) , m_min_pabotbase_level(min_pabotbase_level) - , m_setup(nullptr) {} -void RunnableProgram::from_json(const QJsonValue& json){ - const QJsonObject& obj = json_get_object_nothrow(json.toObject(), m_name); + + + + +void RunnableSwitchProgramInstance::from_json(const QJsonValue& json){ + const QJsonObject& obj = json.toObject(); m_setup->load_json(json_get_value_nothrow(obj, "SwitchSetup")); - for (auto& item : m_options){ - if (!item.second.isEmpty()){ - item.first->load_json(json_get_value_nothrow(obj, item.second)); - } - } + RunnablePanelInstance::from_json(json); } -QJsonValue RunnableProgram::to_json() const{ - QJsonObject obj; +QJsonValue RunnableSwitchProgramInstance::to_json() const{ + QJsonObject obj = RunnablePanelInstance::to_json().toObject(); obj.insert("SwitchSetup", m_setup->to_json()); - for (auto& item : m_options){ - if (!item.second.isEmpty()){ - obj.insert(item.second, item.first->to_json()); - } - } return obj; } -bool RunnableProgram::is_valid() const{ - for (const auto& item : m_options){ - if (!item.first->is_valid()){ - return false; - } - } - return true; -} -void RunnableProgram::restore_defaults(){ - for (const auto& item : m_options){ - item.first->restore_defaults(); - } -} -QWidget* RunnableProgram::make_ui(MainWindow& window){ - RunnableProgramUI* widget = new RunnableProgramUI(*this, window); - widget->construct(); - return widget; + +RunnableSwitchProgramWidget::~RunnableSwitchProgramWidget(){ + if (!m_destructing){ + stop(); + m_destructing = true; + } } -RunnableProgramUI::RunnableProgramUI(RunnableProgram& factory, MainWindow& window) - : RightPanelUI(factory) - , m_name(factory.name()) - , m_window(window) - , m_logger(window.output_window(), "Program") +RunnableSwitchProgramWidget::RunnableSwitchProgramWidget( + QWidget& parent, + RunnableSwitchProgramInstance& instance, + PanelListener& listener +) + : RunnablePanelWidget(parent, instance, listener) , m_setup(nullptr) - , m_status_bar(nullptr) - , m_start_button(nullptr) - , m_state(ProgramState::STOPPED) {} -void RunnableProgramUI::append_description(QWidget& parent, QVBoxLayout& layout){ - RunnableProgram& factory = static_cast(m_factory); +void RunnableSwitchProgramWidget::construct(){ + RunnablePanelWidget::construct(); + update_historical_stats(); +} +QWidget* RunnableSwitchProgramWidget::make_header(QWidget& parent){ + RunnableSwitchProgramInstance& instance = static_cast(m_instance); + QWidget* header = PanelWidget::make_header(parent); + QLayout* layout = header->layout(); QLabel* text = nullptr; - switch (factory.m_feedback){ + switch (instance.descriptor().feedback()){ case FeedbackType::NONE: text = new QLabel( "(This program does not use feedback. It can run without video input.)", - &parent + header ); break; case FeedbackType::OPTIONAL_: text = new QLabel( "(This program will use video feedback if it is available. Video input is not required.)", - &parent + header ); break; case FeedbackType::REQUIRED: text = new QLabel( "(This program requires video feedback. Please make sure you choose the correct capture device.)", - &parent + header ); break; } - layout.addWidget(text); text->setWordWrap(true); + layout->addWidget(text); - switch (factory.m_min_pabotbase_level){ + switch (instance.descriptor().min_pabotbase_level()){ case PABotBaseLevel::NOT_PABOTBASE: break; case PABotBaseLevel::PABOTBASE_12KB:{ #if 0 QLabel* text = new QLabel( "(This program will run on both Arduino Uno R3 and Teensy 2.0.)", - &parent + header ); - layout.addWidget(text); text->setWordWrap(true); + layout->addWidget(text); #endif break; }case PABotBaseLevel::PABOTBASE_31KB:{ QLabel* text = new QLabel( "(This program requires a Teensy or higher. PABotBase for Arduino Uno R3 does not have all the features required by this program.)", - &parent + header ); - layout.addWidget(text); text->setWordWrap(true); + layout->addWidget(text); break; } } -} -void RunnableProgramUI::make_body(QWidget& parent, QVBoxLayout& layout){ - QScrollArea* scroll = new QScrollArea(&parent); - layout.addWidget(scroll); - scroll->setWidgetResizable(true); - - QWidget* options_widget = new QWidget(scroll); - (new QVBoxLayout(scroll))->addWidget(options_widget); - scroll->setWidget(options_widget); - - QVBoxLayout* options_layout = new QVBoxLayout(options_widget); - options_layout->setAlignment(Qt::AlignTop); - - - RunnableProgram& factory = static_cast(m_factory); - m_setup = factory.m_setup->make_ui(*options_widget, m_window.output_window()); - options_layout->addWidget(m_setup); - for (auto& item : factory.m_options){ - m_options.emplace_back(item.first->make_ui(parent)); - options_layout->addWidget(m_options.back()->widget()); - } - RightPanelUI::connect( - m_setup, &SwitchSetup::on_state_changed, - this, &RunnableProgramUI::update_ui - ); - - m_status_bar = new QLabel(&parent); - m_status_bar->setVisible(false); - m_status_bar->setAlignment(Qt::AlignCenter); - layout.addWidget(m_status_bar); -// m_status_bar->setText("Encounters: 1,267 - Corrections: 0 - Star Shinies: 1 - Square Shinies: 0"); - QFont font = m_status_bar->font(); -// cout << font.pointSize() << endl; - int font_size = font.pointSize(); - font.setPointSize(font_size + font_size / 2); - m_status_bar->setFont(font); - update_historical_stats(); - QGroupBox* actions_widget = new QGroupBox("Actions", &parent); - layout.addWidget(actions_widget); + return header; +} +QWidget* RunnableSwitchProgramWidget::make_options(QWidget& parent){ + QWidget* options_widget = RunnablePanelWidget::make_options(parent); - QHBoxLayout* action_layout = new QHBoxLayout(actions_widget); - action_layout->setMargin(0); + RunnableSwitchProgramInstance& instance = static_cast(m_instance); + m_setup = instance.m_setup->make_ui(*options_widget, m_listener.output_window()); + static_cast(options_widget->layout())->insertWidget(0, m_setup); - { - m_start_button = new QPushButton("Start Program!", &parent); - action_layout->addWidget(m_start_button, 2); - QFont font = m_start_button->font(); - font.setPointSize(16); - m_start_button->setFont(font); - } - { - m_default_button = new QPushButton("Restore Defaults", &parent); - action_layout->addWidget(m_default_button, 1); - QFont font = m_default_button->font(); - font.setPointSize(16); - m_default_button->setFont(font); - } - - update_ui(); + return options_widget; +} +QWidget* RunnableSwitchProgramWidget::make_actions(QWidget& parent){ + QWidget* actions_widget = RunnablePanelWidget::make_actions(parent); connect( - this, &RunnableProgramUI::signal_reset, + this, &RunnableSwitchProgramWidget::signal_reset, this, [=]{ - reset_connections(); - update_ui(); - } - ); - connect( - this, &RunnableProgramUI::signal_error, - this, [](QString message){ - QMessageBox box; - box.critical(nullptr, "Error", message); - } - ); - connect( - m_start_button, &QPushButton::clicked, - this, [=](bool){ - switch (m_state.load(std::memory_order_acquire)){ - case ProgramState::STOPPED: - if (!settings_valid()){ - QMessageBox box; - box.critical(nullptr, "Error", "Settings are not valid."); - return; - } - if (m_thread.joinable()){ - m_thread.join(); - } -// m_window.open_output_window(); - m_state.store(ProgramState::RUNNING, std::memory_order_release); - m_thread = std::thread(&RunnableProgramUI::run_program, this); - break; - case ProgramState::RUNNING: - case ProgramState::FINISHED: - m_state.store(ProgramState::STOPPING, std::memory_order_release); - on_stop(); - break; - case ProgramState::STOPPING: - break; + if (m_setup){ + m_setup->reset_serial(); } - update_ui(); } ); - connect( - m_default_button, &QPushButton::clicked, - this, [=](bool){ - restore_defaults(); - } - ); -} -RunnableProgramUI::~RunnableProgramUI(){ - stop(); -} -void RunnableProgramUI::stop(){ - m_state.store(ProgramState::STOPPING, std::memory_order_release); - on_stop(); - if (m_thread.joinable()){ - m_thread.join(); - } + return actions_widget; } -bool RunnableProgramUI::settings_valid() const{ - RunnableProgram& factory = static_cast(m_factory); - return factory.is_valid() && m_setup && m_setup->serial_ok(); -} -void RunnableProgramUI::restore_defaults(){ - for (ConfigOptionUI* item : m_options){ - item->restore_defaults(); - } + +bool RunnableSwitchProgramWidget::settings_valid() const{ + return RunnablePanelWidget::settings_valid() && m_setup && m_setup->serial_ok(); } -ProgramState RunnableProgramUI::update_ui(){ +void RunnableSwitchProgramWidget::update_ui(){ + RunnablePanelWidget::update_ui(); ProgramState state = m_state.load(std::memory_order_acquire); - if (m_start_button == nullptr){ - return state; - } - m_start_button->setEnabled(state != ProgramState::STOPPING); - switch (state){ - case ProgramState::STOPPED: - m_start_button->setText("Start Program..."); -// m_start_button->setEnabled(settings_valid()); - m_window.left_panel_enabled(true); - break; - case ProgramState::RUNNING: - m_start_button->setText("Stop Program..."); - m_window.left_panel_enabled(false); - break; - case ProgramState::FINISHED: - m_start_button->setText("Program Finished! Click to stop."); - m_window.left_panel_enabled(false); - break; - case ProgramState::STOPPING: - m_start_button->setText("Stopping Program..."); - m_window.left_panel_enabled(false); - break; - } - if (m_setup) m_setup->update_ui(state); - - bool enabled = state == ProgramState::STOPPED; - m_default_button->setEnabled(enabled); - for (ConfigOptionUI* option : m_options){ - option->widget()->setEnabled(enabled); - } - - return state; -} -void RunnableProgramUI::on_stop(){ - signal_cancel(); - if (m_setup) m_setup->stop_serial(); -} -void RunnableProgramUI::reset_connections(){ - if (m_setup) m_setup->reset_serial(); } -void RunnableProgramUI::update_historical_stats(){ - RunnableProgram& factory = static_cast(m_factory); - m_stats = factory.make_stats(); +void RunnableSwitchProgramWidget::update_historical_stats(){ + RunnableSwitchProgramInstance& instance = static_cast(m_instance); + m_stats = instance.make_stats(); if (m_stats){ - settings.stat_sets.open_from_file(settings.stats_file); - StatList& list = settings.stat_sets[m_name.toUtf8().data()]; + StatSet stats; + stats.open_from_file(PERSISTENT_SETTINGS().stats_file); + const std::string& identifier = instance.descriptor().identifier(); + StatList& list = stats[identifier]; if (list.size() != 0){ list.aggregate(*m_stats); } @@ -334,53 +193,44 @@ void RunnableProgramUI::update_historical_stats(){ m_status_bar->setVisible(true); } } -void RunnableProgramUI::set_status(QString status){ - if (status.size() <= 0){ - m_status_bar->setVisible(false); - m_status_bar->setText(status); - }else{ - m_status_bar->setText(status); - m_status_bar->setVisible(true); - } -} -void RunnableProgramUI::show_stats_warning() const{ - QMessageBox box; - box.critical( - nullptr, - "Error", - "Unable to update stats file. You will need to do this manually." - ); +void RunnableSwitchProgramWidget::on_stop(){ + RunnablePanelWidget::on_stop(); + if (m_setup){ + m_setup->stop_serial(); + } } -void RunnableProgramUI::run_program(){ +void RunnableSwitchProgramWidget::run_program(){ if (m_state.load(std::memory_order_acquire) != ProgramState::RUNNING){ return; } - RunnableProgram& factory = static_cast(m_factory); - std::unique_ptr current_stats = factory.make_stats(); - - std::string program_name = m_name.toUtf8().data(); + RunnableSwitchProgramInstance& instance = static_cast(m_instance); + std::unique_ptr current_stats = instance.make_stats(); - // Update historical stats. +// std::string program_name = instance.descriptor().display_name().toUtf8().data(); update_historical_stats(); try{ - m_logger.log("Starting Program: " + m_name + ""); - program(current_stats.get(), m_stats.get()); + m_logger.log("Starting Program: " + instance.descriptor().identifier() + ""); + run_program(current_stats.get(), m_stats.get()); m_setup->wait_for_all_requests(); m_logger.log("Ending Program..."); - }catch (PokemonAutomation::CancelledException&){ + }catch (CancelledException&){ m_logger.log("Stopping Program..."); - }catch (const char* str){ - signal_error(str); + }catch (StringException& e){ + signal_error(e.message_qt()); } // Update historical stats. if (current_stats){ - bool ok = StatSet::update_file(settings.stats_file, program_name, *current_stats); + bool ok = StatSet::update_file( + PERSISTENT_SETTINGS().stats_file, + instance.descriptor().identifier(), + *current_stats + ); if (ok){ m_logger.log("Stats successfully saved!", "Blue"); }else{ @@ -392,7 +242,7 @@ void RunnableProgramUI::run_program(){ ); // show_stats_warning(); } - settings.stat_sets.open_from_file(settings.stats_file); +// settings.stat_sets.open_from_file(settings.stats_file); } @@ -403,26 +253,19 @@ void RunnableProgramUI::run_program(){ // cout << "Now in STOPPED state." << endl; } -BotBase& RunnableProgramUI::sanitize_botbase(BotBase* botbase){ + + +BotBase& RunnableSwitchProgramWidget::sanitize_botbase(BotBase* botbase){ if (botbase != nullptr){ return *botbase; } - throw StringException("Cannot Start: Serial connection not ready."); + PA_THROW_StringException("Cannot Start: Serial connection not ready."); } - - - - - - - - - } } diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/RunnableSwitchProgram.h b/SerialPrograms/Source/NintendoSwitch/Framework/RunnableSwitchProgram.h index 86309c3485..32310b9380 100644 --- a/SerialPrograms/Source/NintendoSwitch/Framework/RunnableSwitchProgram.h +++ b/SerialPrograms/Source/NintendoSwitch/Framework/RunnableSwitchProgram.h @@ -13,108 +13,102 @@ #include "CommonFramework/Globals.h" #include "CommonFramework/Tools/StatsTracking.h" #include "CommonFramework/Options/ConfigOption.h" -#include "CommonFramework/Panels/RightPanel.h" +#include "CommonFramework/Panels/Panel.h" +#include "CommonFramework/Panels/RunnablePanel.h" #include "SwitchSetup.h" namespace PokemonAutomation{ namespace NintendoSwitch{ -using PABotBase = PokemonAutomation::PABotBase; -using BotBase = BotBase; - - - - -class RunnableProgram : public RightPanel{ +class RunnableSwitchProgramDescriptor : public RunnablePanelDescriptor{ public: - RunnableProgram( - FeedbackType feedback, - PABotBaseLevel min_pabotbase_level, - QString name, + RunnableSwitchProgramDescriptor( + std::string identifier, + QString display_name, QString doc_link, - QString description + QString description, + FeedbackType feedback, + PABotBaseLevel min_pabotbase_level ); - void from_json(const QJsonValue& json); - virtual QJsonValue to_json() const override; - bool is_valid() const; - void restore_defaults(); - - virtual std::unique_ptr make_stats() const{ return nullptr; } - virtual QWidget* make_ui(MainWindow& window) override; + FeedbackType feedback() const{ return m_feedback; } + PABotBaseLevel min_pabotbase_level() const{ return m_min_pabotbase_level; } protected: - friend class RunnableProgramUI; const FeedbackType m_feedback; const PABotBaseLevel m_min_pabotbase_level; - SwitchSetupFactory* m_setup; - std::vector> m_options; }; -class RunnableProgramUI : public RightPanelUI{ - Q_OBJECT - friend class RunnableProgram; + +class RunnableSwitchProgramInstance : public RunnablePanelInstance{ +public: + using RunnablePanelInstance::RunnablePanelInstance; + + const RunnableSwitchProgramDescriptor& descriptor() const{ + return static_cast(m_descriptor); + } + + virtual std::unique_ptr make_stats() const{ return nullptr; } + +public: + // Serialization + virtual void from_json(const QJsonValue& json) override; + virtual QJsonValue to_json() const override; protected: - RunnableProgramUI(RunnableProgram& factory, MainWindow& parent); - virtual void append_description(QWidget& parent, QVBoxLayout& layout) override; - virtual void make_body(QWidget& parent, QVBoxLayout& layout) override; + friend class RunnableSwitchProgramWidget; + SwitchSetupFactory* m_setup = nullptr; +}; + + + +class RunnableSwitchProgramWidget : public RunnablePanelWidget{ public: - virtual ~RunnableProgramUI(); - void stop(); + virtual ~RunnableSwitchProgramWidget(); - virtual bool settings_valid() const; - void restore_defaults(); - virtual ProgramState update_ui(); +protected: + RunnableSwitchProgramWidget( + QWidget& parent, + RunnableSwitchProgramInstance& instance, + PanelListener& listener + ); + void construct(); + virtual QWidget* make_header(QWidget& parent) override; + virtual QWidget* make_options(QWidget& parent) override; + virtual QWidget* make_actions(QWidget& parent) override; - void set_status(QString status); +protected: + virtual bool settings_valid() const override; -private: - void on_stop(); - void reset_connections(); + virtual void update_ui() override; void update_historical_stats(); - virtual void program( - StatsTracker* current_stats, - const StatsTracker* historical_stats - ){} - - void run_program(); -signals: - void signal_cancel(); - void signal_error(QString message); - void signal_reset(); + virtual void on_stop() override; -public slots: - void show_stats_warning() const; + virtual void run_program() override; + virtual void run_program( + StatsTracker* current_stats, + const StatsTracker* historical_stats + ) = 0; protected: static BotBase& sanitize_botbase(BotBase* botbase); protected: - const QString& m_name; - MainWindow& m_window; - TaggedLogger m_logger; + friend class RunnableSwitchProgramInstance; SwitchSetup* m_setup; - std::vector m_options; - - QLabel* m_status_bar; - QPushButton* m_start_button; - QPushButton* m_default_button; std::unique_ptr m_stats; - -// ProgramEnvironment m_environment; - std::atomic m_state; - std::thread m_thread; }; + + } } #endif diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/SingleSwitchProgram.cpp b/SerialPrograms/Source/NintendoSwitch/Framework/SingleSwitchProgram.cpp index 861a7b7537..4d9536ce3d 100644 --- a/SerialPrograms/Source/NintendoSwitch/Framework/SingleSwitchProgram.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Framework/SingleSwitchProgram.cpp @@ -11,37 +11,39 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ -SingleSwitchProgram::SingleSwitchProgram( - FeedbackType feedback, - PABotBaseLevel min_pabotbase, - QString name, - QString doc_link, - QString description -) - : RunnableProgram( - feedback, min_pabotbase, - std::move(name), - std::move(doc_link), - std::move(description) - ) + +SingleSwitchProgramInstance::SingleSwitchProgramInstance(const RunnableSwitchProgramDescriptor& descriptor) + : RunnableSwitchProgramInstance(descriptor) , m_switch( "Switch Settings", "Switch 0", - min_pabotbase, feedback + descriptor.min_pabotbase_level(), + descriptor.feedback() ) { m_setup = &m_switch; } - -SingleSwitchProgramUI::SingleSwitchProgramUI(SingleSwitchProgram& factory, MainWindow& window) - : RunnableProgramUI(factory, window) -{ - this->construct(); +QWidget* SingleSwitchProgramInstance::make_widget(QWidget& parent, PanelListener& listener){ + return SingleSwitchProgramWidget::make(parent, *this, listener); } -SingleSwitchProgramUI::~SingleSwitchProgramUI(){ stop(); } -void SingleSwitchProgramUI::program( +SingleSwitchProgramWidget::~SingleSwitchProgramWidget(){ + if (!m_destructing){ + stop(); + m_destructing = true; + } +} +SingleSwitchProgramWidget* SingleSwitchProgramWidget::make( + QWidget& parent, + SingleSwitchProgramInstance& instance, + PanelListener& listener +){ + SingleSwitchProgramWidget* widget = new SingleSwitchProgramWidget(parent, instance, listener); + widget->construct(); + return widget; +} +void SingleSwitchProgramWidget::run_program( StatsTracker* current_stats, const StatsTracker* historical_stats ){ @@ -53,7 +55,7 @@ void SingleSwitchProgramUI::program( system->camera() ); connect( - this, &RunnableProgramUI::signal_cancel, + this, &RunnableSwitchProgramWidget::signal_cancel, &env, [&]{ env.signal_stop(); }, @@ -61,16 +63,15 @@ void SingleSwitchProgramUI::program( ); connect( &env, &ProgramEnvironment::set_status, - this, [=](QString status){ - this->set_status(std::move(status)); - } + this, &SingleSwitchProgramWidget::set_status ); - PokemonAutomation::global_connection = &(BotBase&)env.console; - SingleSwitchProgram& factory = static_cast(m_factory); - factory.program(env); + SingleSwitchProgramInstance& instance = static_cast(m_instance); + instance.program(env); } + + } } diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/SingleSwitchProgram.h b/SerialPrograms/Source/NintendoSwitch/Framework/SingleSwitchProgram.h index b4e6d71718..6f2dd28ad1 100644 --- a/SerialPrograms/Source/NintendoSwitch/Framework/SingleSwitchProgram.h +++ b/SerialPrograms/Source/NintendoSwitch/Framework/SingleSwitchProgram.h @@ -21,7 +21,7 @@ class SingleSwitchProgramEnvironment : public ProgramEnvironment{ ConsoleHandle console; private: - friend class SingleSwitchProgramUI; + friend class SingleSwitchProgramWidget; template SingleSwitchProgramEnvironment( Logger& logger, @@ -35,51 +35,46 @@ class SingleSwitchProgramEnvironment : public ProgramEnvironment{ }; -class SingleSwitchProgram : public RunnableProgram{ -public: - SingleSwitchProgram( - FeedbackType feedback, - PABotBaseLevel min_pabotbase, - QString name, - QString doc_link, - QString description - ); - virtual void program(SingleSwitchProgramEnvironment& env) const = 0; +class SingleSwitchProgramInstance : public RunnableSwitchProgramInstance{ +public: + SingleSwitchProgramInstance(const RunnableSwitchProgramDescriptor& descriptor); + virtual QWidget* make_widget(QWidget& parent, PanelListener& listener) override; + virtual void program(SingleSwitchProgramEnvironment& env) = 0; private: + friend class SingleSwitchProgramWidget; + SwitchSystemFactory m_switch; }; -class SingleSwitchProgramUI final : public RunnableProgramUI{ + +class SingleSwitchProgramWidget : public RunnableSwitchProgramWidget{ public: - SingleSwitchProgramUI(SingleSwitchProgram& factory, MainWindow& window); - ~SingleSwitchProgramUI(); + static SingleSwitchProgramWidget* make( + QWidget& parent, + SingleSwitchProgramInstance& instance, + PanelListener& listener + ); + +private: + using RunnableSwitchProgramWidget::RunnableSwitchProgramWidget; + virtual ~SingleSwitchProgramWidget(); - virtual void program( +private: + virtual void run_program( StatsTracker* current_stats, const StatsTracker* historical_stats ) override; -}; - -template -class SingleSwitchProgramWrapper final : public Program{ -public: - SingleSwitchProgramWrapper() = default; - SingleSwitchProgramWrapper(const QJsonValue& json) - : Program() - { - this->from_json(json); - } - virtual QWidget* make_ui(MainWindow& window) override{ - return new SingleSwitchProgramUI(*this, window); - } +private: + friend class SingleSwitchProgramInstance; }; + } } #endif diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/SwitchSystem.cpp b/SerialPrograms/Source/NintendoSwitch/Framework/SwitchSystem.cpp index aaf6f85e3f..f54ceec548 100644 --- a/SerialPrograms/Source/NintendoSwitch/Framework/SwitchSystem.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Framework/SwitchSystem.cpp @@ -8,7 +8,6 @@ #include #include #include -#include "Common/Qt/StringException.h" #include "Common/Qt/QtJsonTools.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "SwitchCommandRow.h" diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/VirtualSwitchController.cpp b/SerialPrograms/Source/NintendoSwitch/Framework/VirtualSwitchController.cpp index 5549827db9..629fb8355b 100644 --- a/SerialPrograms/Source/NintendoSwitch/Framework/VirtualSwitchController.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Framework/VirtualSwitchController.cpp @@ -6,6 +6,7 @@ #include #include +#include "Common/Cpp/Exception.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSwShMisc.h" #include "ClientSource/Connection/BotBase.h" @@ -197,9 +198,9 @@ void VirtualController::thread_loop(){ params.right_joystick_y = right_y; params.ticks = m_granularity; while (m_botbase.try_send_request(params)); - }catch (const char*){ - }catch (std::string&){ - }catch (PokemonAutomation::CancelledException&){} + }catch (PokemonAutomation::CancelledException&){ + }catch (const StringException&){ + } }while (false); diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/VirtualSwitchController.h b/SerialPrograms/Source/NintendoSwitch/Framework/VirtualSwitchController.h index 9e5c50ed35..f4fcaba7cb 100644 --- a/SerialPrograms/Source/NintendoSwitch/Framework/VirtualSwitchController.h +++ b/SerialPrograms/Source/NintendoSwitch/Framework/VirtualSwitchController.h @@ -11,7 +11,7 @@ #include #include #include -#include "Common/Clientside/SpinLock.h" +#include "Common/Cpp/SpinLock.h" #include "CommonFramework/Globals.h" #include "CommonFramework/Tools/BotBaseHandle.h" #include "CommonFramework/Tools/Logger.h" diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/VirtualSwitchControllerMapping.cpp b/SerialPrograms/Source/NintendoSwitch/Framework/VirtualSwitchControllerMapping.cpp index 4b7cc14bf5..ff0d8878a9 100644 --- a/SerialPrograms/Source/NintendoSwitch/Framework/VirtualSwitchControllerMapping.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Framework/VirtualSwitchControllerMapping.cpp @@ -7,7 +7,7 @@ #include #include #include -#include "Common/Qt/StringException.h" +#include "Common/Cpp/Exception.h" #include "Common/Qt/QtJsonTools.h" #include "VirtualSwitchControllerMapping.h" @@ -124,6 +124,7 @@ const ControllerButton_Button CONTROLLER_BUTTON_LCLICK (BUTTON_LCLICK); const ControllerButton_Button CONTROLLER_BUTTON_RCLICK (BUTTON_RCLICK); const ControllerButton_Button CONTROLLER_BUTTON_HOME (BUTTON_HOME); const ControllerButton_Button CONTROLLER_BUTTON_CAPTURE (BUTTON_CAPTURE); +const ControllerButton_Button CONTROLLER_BUTTON_AR (BUTTON_A | BUTTON_R); const std::map& STRING_TO_BUTTON_MAP(){ static const std::map map{ @@ -163,6 +164,8 @@ const std::map& STRING_TO_BUTTON_MAP(){ {"CONTROLLER_BUTTON_HOME", CONTROLLER_BUTTON_HOME}, {"CONTROLLER_BUTTON_CAPTURE", CONTROLLER_BUTTON_CAPTURE}, + + {"CONTROLLER_BUTTON_AR", CONTROLLER_BUTTON_AR}, }; return map; } @@ -236,6 +239,8 @@ std::vector> keyboard_mapping{ {Qt::Key::Key_Escape, CONTROLLER_BUTTON_HOME}, {Qt::Key::Key_Insert, CONTROLLER_BUTTON_CAPTURE}, + + {Qt::Key::Key_Y, CONTROLLER_BUTTON_AR}, }; std::map make_keyboard_map( @@ -245,7 +250,7 @@ std::map make_keyboard_map( for (const auto& item : mapping){ auto iter = map.find(item.first); if (iter != map.end()){ - throw StringException("Duplicate Key: " + QString::number((uint32_t)item.first)); + PA_THROW_StringException("Duplicate Key: " + QString::number((uint32_t)item.first)); } map.emplace( std::piecewise_construct, @@ -285,6 +290,10 @@ QJsonArray read_keyboard_mapping(){ return array; } void set_keyboard_mapping(const QJsonArray& json){ + if (json.isEmpty()){ + return; + } + std::vector> mapping; for (const auto& item : json){ diff --git a/SerialPrograms/Source/NintendoSwitch/FrameworkSettingsPanel.cpp b/SerialPrograms/Source/NintendoSwitch/FrameworkSettingsPanel.cpp index 83c7198ae4..27e8acbac4 100644 --- a/SerialPrograms/Source/NintendoSwitch/FrameworkSettingsPanel.cpp +++ b/SerialPrograms/Source/NintendoSwitch/FrameworkSettingsPanel.cpp @@ -5,7 +5,9 @@ */ #include "Common/SwitchFramework/FrameworkSettings.h" +#include "CommonFramework/PersistentSettings.h" #include "CommonFramework/Options/BooleanCheckBox.h" +#include "CommonFramework/Options/String.h" #include "NintendoSwitch/Options/TimeExpression.h" #include "FrameworkSettingsPanel.h" @@ -17,13 +19,20 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ -FrameworkSettings::FrameworkSettings() - : SettingsPanel( +FrameworkSettings_Descriptor::FrameworkSettings_Descriptor() + : PanelDescriptor( QColor(), + "NintendoSwitch:GlobalSettings", "Framework Settings", "", - "Global Framework Settings" + "Switch Framework Settings" ) +{} + + + +FrameworkSettings::FrameworkSettings(const FrameworkSettings_Descriptor& descriptor) + : SettingsPanelInstance(descriptor) { m_options.emplace_back( "CONNECT_CONTROLLER_DELAY", @@ -49,6 +58,14 @@ FrameworkSettings::FrameworkSettings() false ) ); + m_options.emplace_back( + "START_GAME_INTERNET_CHECK_DELAY", + new TimeExpression( + START_GAME_INTERNET_CHECK_DELAY, + "Start Game Internet Check Delay:
If starting the game requires checking the internet, wait this long for it.", + "3 * TICKS_PER_SECOND" + ) + ); m_options.emplace_back( "TOLERATE_SYSTEM_UPDATE_MENU_FAST", new BooleanCheckBox( @@ -66,11 +83,7 @@ FrameworkSettings::FrameworkSettings() ) ); } -FrameworkSettings::FrameworkSettings(const QJsonValue& json) - : FrameworkSettings() -{ - from_json(json); -} + diff --git a/SerialPrograms/Source/NintendoSwitch/FrameworkSettingsPanel.h b/SerialPrograms/Source/NintendoSwitch/FrameworkSettingsPanel.h index 7b9892413f..c322d6566b 100644 --- a/SerialPrograms/Source/NintendoSwitch/FrameworkSettingsPanel.h +++ b/SerialPrograms/Source/NintendoSwitch/FrameworkSettingsPanel.h @@ -13,13 +13,20 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ -class FrameworkSettings : public SettingsPanel{ +class FrameworkSettings_Descriptor : public PanelDescriptor{ public: - FrameworkSettings(); - FrameworkSettings(const QJsonValue& json); + FrameworkSettings_Descriptor(); }; + +class FrameworkSettings : public SettingsPanelInstance{ +public: + FrameworkSettings(const FrameworkSettings_Descriptor& descriptor); +}; + + + } } #endif diff --git a/SerialPrograms/Source/NintendoSwitch/InferenceTraining/PokemonHome_GenerateNameOCR.cpp b/SerialPrograms/Source/NintendoSwitch/InferenceTraining/PokemonHome_GenerateNameOCR.cpp new file mode 100644 index 0000000000..81f769bd4e --- /dev/null +++ b/SerialPrograms/Source/NintendoSwitch/InferenceTraining/PokemonHome_GenerateNameOCR.cpp @@ -0,0 +1,107 @@ +/* Pokemon Home Generate Name OCR + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include "Common/Cpp/Exception.h" +#include "Common/Cpp/PrettyPrint.h" +#include "Common/Qt/QtJsonTools.h" +#include "Common/SwitchFramework/Switch_PushButtons.h" +#include "CommonFramework/PersistentSettings.h" +#include "CommonFramework/Inference/ImageTools.h" +#include "CommonFramework/OCR/Filtering.h" +#include "PokemonHome_GenerateNameOCR.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonHome{ + + +GenerateNameOCRData_Descriptor::GenerateNameOCRData_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonHome:GenerateNameOCR", + STRING_POKEMON + " Home: Generate Name OCR", + "", + "Generate " + STRING_POKEMON + " Name OCR data by iterating the National " + STRING_POKEDEX + ".", + FeedbackType::REQUIRED, + PABotBaseLevel::PABOTBASE_12KB + ) +{} + + + +GenerateNameOCRData::GenerateNameOCRData(const GenerateNameOCRData_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) + , LANGUAGE( + "Game Language:", + m_reader.languages() + ) + , DELAY( + "Delay Between Each Iteration:", + "30" + ) +{ + m_options.emplace_back(&LANGUAGE, "LANGUAGE"); + m_options.emplace_back(&DELAY, "DELAY"); +} + + +void GenerateNameOCRData::program(SingleSwitchProgramEnvironment& env){ + + QJsonArray array = read_json_file( + PERSISTENT_SETTINGS().resource_path + "Pokemon/Pokedex/Pokedex-National.json" + ).array(); + + std::vector tokens; + for (const auto& item : array){ + QString token = item.toString(); + if (token.size() <= 0){ + PA_THROW_StringException("Expected non-empty string for Pokemon token."); + } + tokens.emplace_back(token.toUtf8().data()); + } + + + InferenceBoxScope box(env.console, 0.705, 0.815, 0.219, 0.055); + QString language_code = language_data(LANGUAGE).code.c_str(); + + for (const std::string& token : tokens){ + env.console.botbase().wait_for_all_requests(); + + QImage screen = env.console.video().snapshot(); + QImage image = extract_box(screen, box); + + QString path = "PokemonNameOCR/"; + path += language_code; + path += "/"; + + QDir dir(path); + if (!dir.exists()){ + dir.mkpath("."); + } + + path += token.c_str(); + path += "-"; + path += now_to_filestring().c_str(); + path += ".png"; + image.save(path); + + pbf_press_dpad(env.console, DPAD_RIGHT, 10, DELAY); + + OCR::make_OCR_filter(image).apply(image); + + OCR::MatchResult result = m_reader.read_exact(LANGUAGE, token, image); + result.log(&env.logger()); + } + + +} + + + + +} +} +} diff --git a/SerialPrograms/Source/NintendoSwitch/InferenceTraining/PokemonHome_GenerateNameOCR.h b/SerialPrograms/Source/NintendoSwitch/InferenceTraining/PokemonHome_GenerateNameOCR.h new file mode 100644 index 0000000000..1358c66c20 --- /dev/null +++ b/SerialPrograms/Source/NintendoSwitch/InferenceTraining/PokemonHome_GenerateNameOCR.h @@ -0,0 +1,46 @@ +/* Pokemon Home Generate Name OCR + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PokemonHome_GenerateNameOCR_H +#define PokemonAutomation_PokemonHome_GenerateNameOCR_H + +#include "CommonFramework/Options/LanguageOCR.h" +#include "NintendoSwitch/Options/TimeExpression.h" +#include "NintendoSwitch/Framework/SingleSwitchProgram.h" +#include "Pokemon/Pokemon_NameReader.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonHome{ + + +class GenerateNameOCRData_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + GenerateNameOCRData_Descriptor(); +}; + + + +class GenerateNameOCRData : public SingleSwitchProgramInstance{ + +public: + GenerateNameOCRData(const GenerateNameOCRData_Descriptor& descriptor); + + virtual void program(SingleSwitchProgramEnvironment& env) override; + +private: + Pokemon::PokemonNameReader m_reader; + + LanguageOCR LANGUAGE; + TimeExpression DELAY; +}; + + + +} +} +} +#endif diff --git a/SerialPrograms/Source/NintendoSwitch/Panels_NintendoSwitch.cpp b/SerialPrograms/Source/NintendoSwitch/Panels_NintendoSwitch.cpp new file mode 100644 index 0000000000..f28f0559d4 --- /dev/null +++ b/SerialPrograms/Source/NintendoSwitch/Panels_NintendoSwitch.cpp @@ -0,0 +1,71 @@ +/* Nintendo Switch Panels + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "Common/Qt/QtJsonTools.h" +#include "CommonFramework/PersistentSettings.h" +#include "CommonFramework/Windows/MainWindow.h" +#include "Panels_NintendoSwitch.h" + +#include "FrameworkSettingsPanel.h" + +#include "Programs/VirtualConsole.h" +#include "Programs/SwitchViewer.h" + +#include "Programs/TurboButton.h" +#include "Programs/PreventSleep.h" +#include "Programs/FriendCodeAdder.h" +#include "Programs/FriendDelete.h" + +#include "Programs/PokemonHome_PageSwap.h" + +#include "TestProgram.h" +#include "NintendoSwitch/InferenceTraining/PokemonHome_GenerateNameOCR.h" +#include "Pokemon/Pokemon_TrainIVCheckerOCR.h" +#include "Pokemon/Pokemon_TrainPokemonOCR.h" + + +namespace PokemonAutomation{ +namespace NintendoSwitch{ + + +Panels::Panels(QTabWidget& parent, PanelListener& listener) + : PanelList(parent, "Switch", listener) +{ + PersistentSettings& settings = PERSISTENT_SETTINGS(); + + add_divider("---- Settings ----"); + add_settings(); + + add_divider("---- Virtual Consoles ----"); + add_program(); + add_program(); + + add_divider("---- Programs ----"); + add_program(); + add_program(); + add_program(); + add_program(); + +// add_divider("---- " + STRING_POKEMON + " Home ----"); + add_program(); + + if (settings.developer_mode){ + add_divider("---- Developer Tools ----"); + add_program(); + add_program(); + add_program(); + add_program(); + } + + + finish_panel_setup(); +} + + + + +} +} diff --git a/SerialPrograms/Source/NintendoSwitch/Panels_NintendoSwitch.h b/SerialPrograms/Source/NintendoSwitch/Panels_NintendoSwitch.h new file mode 100644 index 0000000000..a903671460 --- /dev/null +++ b/SerialPrograms/Source/NintendoSwitch/Panels_NintendoSwitch.h @@ -0,0 +1,25 @@ +/* Nintendo Switch Panels + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_NintendoSwitchPanels_H +#define PokemonAutomation_NintendoSwitchPanels_H + +#include "CommonFramework/Panels/PanelList.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ + + +class Panels : public PanelList{ +public: + Panels(QTabWidget& parent, PanelListener& listener); +}; + + + +} +} +#endif diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/FriendCodeAdder.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/FriendCodeAdder.cpp index a7e5a6ee4e..be192da1a5 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/FriendCodeAdder.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/FriendCodeAdder.cpp @@ -15,13 +15,20 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ -FriendCodeAdder::FriendCodeAdder() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, +FriendCodeAdder_Descriptor::FriendCodeAdder_Descriptor() + : RunnableSwitchProgramDescriptor( + "NintendoSwitch:FriendCodeAdder", "Friend Code Adder", "SerialPrograms/FriendCodeAdder.md", - "Add a list of friend codes." + "Add a list of friend codes.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + +FriendCodeAdder::FriendCodeAdder(const FriendCodeAdder_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , USER_SLOT( "User Slot:
Send friend requests for this profile.", 1, 1, 8 @@ -50,8 +57,8 @@ FriendCodeAdder::FriendCodeAdder() m_options.emplace_back(&TOGGLE_BEST_STATUS_DELAY, "TOGGLE_BEST_STATUS_DELAY"); } -void FriendCodeAdder::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); +void FriendCodeAdder::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); bool first = true; for (const QString& line : FRIEND_CODES.lines()){ @@ -60,20 +67,20 @@ void FriendCodeAdder::program(SingleSwitchProgramEnvironment& env) const{ continue; } - home_to_add_friends(USER_SLOT - 1, 3, first); + home_to_add_friends(env.console, USER_SLOT - 1, 3, first); first = false; - ssf_press_button1(BUTTON_A, OPEN_CODE_PAD_DELAY); - enter_digits(12, &code[0]); + ssf_press_button1(env.console, BUTTON_A, OPEN_CODE_PAD_DELAY); + enter_digits(env.console, 12, &code[0]); - pbf_wait(SEARCH_TIME); - ssf_press_button1(BUTTON_A, TOGGLE_BEST_STATUS_DELAY); - ssf_press_button1(BUTTON_A, TOGGLE_BEST_STATUS_DELAY); - pbf_press_button(BUTTON_HOME, 10, SETTINGS_TO_HOME_DELAY); + pbf_wait(env.console, SEARCH_TIME); + ssf_press_button1(env.console, BUTTON_A, TOGGLE_BEST_STATUS_DELAY); + ssf_press_button1(env.console, BUTTON_A, TOGGLE_BEST_STATUS_DELAY); + pbf_press_button(env.console, BUTTON_HOME, 10, SETTINGS_TO_HOME_DELAY); } - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/FriendCodeAdder.h b/SerialPrograms/Source/NintendoSwitch/Programs/FriendCodeAdder.h index 17b302e144..87f535d583 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/FriendCodeAdder.h +++ b/SerialPrograms/Source/NintendoSwitch/Programs/FriendCodeAdder.h @@ -4,8 +4,8 @@ * */ -#ifndef PokemonAutomation_FriendCodeAdder_H -#define PokemonAutomation_FriendCodeAdder_H +#ifndef PokemonAutomation_NintendoSwitch_FriendCodeAdder_H +#define PokemonAutomation_NintendoSwitch_FriendCodeAdder_H #include "CommonFramework/Options/SectionDivider.h" #include "CommonFramework/Options/SimpleInteger.h" @@ -17,11 +17,17 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ -class FriendCodeAdder : public SingleSwitchProgram{ +class FriendCodeAdder_Descriptor : public RunnableSwitchProgramDescriptor{ public: - FriendCodeAdder(); + FriendCodeAdder_Descriptor(); +}; + + +class FriendCodeAdder : public SingleSwitchProgramInstance{ +public: + FriendCodeAdder(const FriendCodeAdder_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger USER_SLOT; diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/FriendDelete.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/FriendDelete.cpp index 1f930e2b22..380a3b35d0 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/FriendDelete.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/FriendDelete.cpp @@ -13,13 +13,20 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ -FriendDelete::FriendDelete() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, +FriendDelete_Descriptor::FriendDelete_Descriptor() + : RunnableSwitchProgramDescriptor( + "NintendoSwitch:FriendDelete", "Friend Delete", "NativePrograms/FriendDelete.md", - "Mass delete/block all those unwanted friends." + "Mass delete/block all those unwanted friends.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + +FriendDelete::FriendDelete(const FriendDelete_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , FRIENDS_TO_DELETE( "Number of Friends to Delete:", 3, 0, 300 @@ -47,30 +54,32 @@ FriendDelete::FriendDelete() m_options.emplace_back(&DELETE_FRIEND_DELAY, "DELETE_FRIEND_DELAY"); m_options.emplace_back(&FINISH_DELETE_DELAY, "FINISH_DELETE_DELAY"); } - -void FriendDelete::program(SingleSwitchProgramEnvironment& env) const{ - pbf_press_button(BUTTON_A, 5, 5); +void FriendDelete::program(SingleSwitchProgramEnvironment& env){ + pbf_press_button(env.console, BUTTON_A, 5, 5); for (uint16_t c = 0; c < FRIENDS_TO_DELETE; c++){ - pbf_press_button(BUTTON_A, 5, VIEW_FRIEND_DELAY); // View friend - pbf_press_dpad(DPAD_DOWN, 5, 5); - pbf_press_button(BUTTON_A, 10, 90); // Click on Options + pbf_press_button(env.console, BUTTON_A, 5, VIEW_FRIEND_DELAY); // View friend + pbf_press_dpad(env.console, DPAD_DOWN, 5, 5); + pbf_press_button(env.console, BUTTON_A, 10, 90); // Click on Options if (BLOCK_FRIENDS){ - pbf_press_dpad(DPAD_DOWN, 5, 5); + pbf_press_dpad(env.console, DPAD_DOWN, 5, 5); } - pbf_press_button(BUTTON_A, 10, 90); // Click on Remove/Block Friend + pbf_press_button(env.console, BUTTON_A, 10, 90); // Click on Remove/Block Friend if (BLOCK_FRIENDS){ - pbf_press_button(BUTTON_A, 5, VIEW_FRIEND_DELAY); // Confirm + pbf_press_button(env.console, BUTTON_A, 5, VIEW_FRIEND_DELAY); // Confirm } - pbf_press_button(BUTTON_A, 5, DELETE_FRIEND_DELAY); // Confirm - pbf_press_button(BUTTON_A, 5, FINISH_DELETE_DELAY); // Finish delete friend. + pbf_press_button(env.console, BUTTON_A, 5, DELETE_FRIEND_DELAY); // Confirm + pbf_press_button(env.console, BUTTON_A, 5, FINISH_DELETE_DELAY); // Finish delete friend. } - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } + + + } } diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/FriendDelete.h b/SerialPrograms/Source/NintendoSwitch/Programs/FriendDelete.h index 3271339e1f..e3ed6b77e0 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/FriendDelete.h +++ b/SerialPrograms/Source/NintendoSwitch/Programs/FriendDelete.h @@ -4,8 +4,8 @@ * */ -#ifndef PokemonAutomation_PokemonSwSh_FriendDelete_H -#define PokemonAutomation_PokemonSwSh_FriendDelete_H +#ifndef PokemonAutomation_NintendoSwitch_FriendDelete_H +#define PokemonAutomation_NintendoSwitch_FriendDelete_H #include "CommonFramework/Options/BooleanCheckBox.h" #include "CommonFramework/Options/SimpleInteger.h" @@ -16,11 +16,17 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ -class FriendDelete : public SingleSwitchProgram{ +class FriendDelete_Descriptor : public RunnableSwitchProgramDescriptor{ public: - FriendDelete(); + FriendDelete_Descriptor(); +}; + - virtual void program(SingleSwitchProgramEnvironment& env) const override; + +class FriendDelete : public SingleSwitchProgramInstance{ +public: + FriendDelete(const FriendDelete_Descriptor& descriptor); + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger FRIENDS_TO_DELETE; @@ -32,6 +38,7 @@ class FriendDelete : public SingleSwitchProgram{ + } } #endif diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/PokemonHome_PageSwap.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/PokemonHome_PageSwap.cpp new file mode 100644 index 0000000000..4fde092d6f --- /dev/null +++ b/SerialPrograms/Source/NintendoSwitch/Programs/PokemonHome_PageSwap.cpp @@ -0,0 +1,105 @@ +/* Pokemon Home Page Swap + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "Common/SwitchFramework/Switch_PushButtons.h" +#include "Common/PokemonSwSh/PokemonSwShGameEntry.h" +#include "PokemonHome_PageSwap.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonHome{ + + + +PageSwap_Descriptor::PageSwap_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonHome:PageSwap", + STRING_POKEMON + " Home: Page Swap", + "SerialPrograms/PokemonHome-PageSwap.md", + "Swap 30 boxes (1 page) in " + STRING_POKEMON + " Home.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB + ) +{} + + + +PageSwap::PageSwap(const PageSwap_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) + , DODGE_SYSTEM_UPDATE_WINDOW( + "Dodge System Update Window:", + false + ) +{ + m_options.emplace_back(&DODGE_SYSTEM_UPDATE_WINDOW, "DODGE_SYSTEM_UPDATE_WINDOW"); +} + +void PageSwap::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + resume_game_no_interact(env.console, DODGE_SYSTEM_UPDATE_WINDOW); + + const uint16_t PICKUP_DELAY = 50; + const uint16_t SCROLL_DELAY = 20; + + for (uint8_t i = 0; i < 2; i++){ + for (uint8_t j = 0; j < 3; j++){ + pbf_press_button(env.console, BUTTON_Y, 10, PICKUP_DELAY); + for (uint8_t c = 0; c < 6; c++){ + pbf_press_dpad(env.console, DPAD_RIGHT, 10, SCROLL_DELAY); + } + pbf_press_button(env.console, BUTTON_Y, 10, PICKUP_DELAY); + pbf_press_dpad(env.console, DPAD_RIGHT, 10, SCROLL_DELAY); + pbf_press_button(env.console, BUTTON_Y, 10, PICKUP_DELAY); + for (uint8_t c = 0; c < 6; c++){ + pbf_press_dpad(env.console, DPAD_LEFT, 10, SCROLL_DELAY); + } + pbf_press_button(env.console, BUTTON_Y, 10, PICKUP_DELAY); + pbf_press_dpad(env.console, DPAD_RIGHT, 10, SCROLL_DELAY); + } + pbf_press_dpad(env.console, DPAD_DOWN, 10, SCROLL_DELAY); + for (uint8_t j = 0; j < 3; j++){ + pbf_press_button(env.console, BUTTON_Y, 10, PICKUP_DELAY); + for (uint8_t c = 0; c < 6; c++){ + pbf_press_dpad(env.console, DPAD_LEFT, 10, SCROLL_DELAY); + } + pbf_press_button(env.console, BUTTON_Y, 10, PICKUP_DELAY); + pbf_press_dpad(env.console, DPAD_RIGHT, 10, SCROLL_DELAY); + pbf_press_button(env.console, BUTTON_Y, 10, PICKUP_DELAY); + for (uint8_t c = 0; c < 6; c++){ + pbf_press_dpad(env.console, DPAD_RIGHT, 10, SCROLL_DELAY); + } + pbf_press_button(env.console, BUTTON_Y, 10, PICKUP_DELAY); + pbf_press_dpad(env.console, DPAD_RIGHT, 10, SCROLL_DELAY); + } + pbf_press_dpad(env.console, DPAD_DOWN, 10, SCROLL_DELAY); + } + for (uint8_t j = 0; j < 3; j++){ + pbf_press_button(env.console, BUTTON_Y, 10, PICKUP_DELAY); + for (uint8_t c = 0; c < 6; c++){ + pbf_press_dpad(env.console, DPAD_RIGHT, 10, SCROLL_DELAY); + } + pbf_press_button(env.console, BUTTON_Y, 10, PICKUP_DELAY); + pbf_press_dpad(env.console, DPAD_RIGHT, 10, SCROLL_DELAY); + pbf_press_button(env.console, BUTTON_Y, 10, PICKUP_DELAY); + for (uint8_t c = 0; c < 6; c++){ + pbf_press_dpad(env.console, DPAD_LEFT, 10, SCROLL_DELAY); + } + pbf_press_button(env.console, BUTTON_Y, 10, PICKUP_DELAY); + pbf_press_dpad(env.console, DPAD_RIGHT, 10, SCROLL_DELAY); + } + + end_program_callback(env.console); + end_program_loop(env.console); +} + + + + + + +} +} +} diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/PokemonHome_PageSwap.h b/SerialPrograms/Source/NintendoSwitch/Programs/PokemonHome_PageSwap.h new file mode 100644 index 0000000000..ca071c5854 --- /dev/null +++ b/SerialPrograms/Source/NintendoSwitch/Programs/PokemonHome_PageSwap.h @@ -0,0 +1,37 @@ +/* Pokemon Home Page Swap + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PokemonHome_PageSwap_H +#define PokemonAutomation_PokemonHome_PageSwap_H + +#include "CommonFramework/Options/BooleanCheckBox.h" +#include "NintendoSwitch/Framework/SingleSwitchProgram.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonHome{ + +class PageSwap_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + PageSwap_Descriptor(); +}; + + +class PageSwap : public SingleSwitchProgramInstance{ +public: + PageSwap(const PageSwap_Descriptor& descriptor); + + virtual void program(SingleSwitchProgramEnvironment& env) override; + +private: + BooleanCheckBox DODGE_SYSTEM_UPDATE_WINDOW; +}; + + +} +} +} +#endif diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/PreventSleep.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/PreventSleep.cpp index 9c760855b4..24df66fac1 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/PreventSleep.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/PreventSleep.cpp @@ -12,18 +12,26 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ -PreventSleep::PreventSleep() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, +PreventSleep_Descriptor::PreventSleep_Descriptor() + : RunnableSwitchProgramDescriptor( + "NintendoSwitch:PreventSleep", "Prevent Sleep", "SerialPrograms/PreventSleep.md", - "Press B every 15 seconds to keep the Switch from sleeping." + "Press B every 15 seconds to keep the Switch from sleeping.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) {} -void PreventSleep::program(SingleSwitchProgramEnvironment& env) const{ + + +PreventSleep::PreventSleep(const PreventSleep_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) +{} + +void PreventSleep::program(SingleSwitchProgramEnvironment& env){ while (true){ - ssf_press_button2(BUTTON_B, 15 * TICKS_PER_SECOND, 10); + ssf_press_button2(env.console, BUTTON_B, 15 * TICKS_PER_SECOND, 10); } } diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/PreventSleep.h b/SerialPrograms/Source/NintendoSwitch/Programs/PreventSleep.h index 63da9f2ec2..3862ace115 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/PreventSleep.h +++ b/SerialPrograms/Source/NintendoSwitch/Programs/PreventSleep.h @@ -4,8 +4,8 @@ * */ -#ifndef PokemonAutomation_PreventSleep_H -#define PokemonAutomation_PreventSleep_H +#ifndef PokemonAutomation_NintendoSwitch_PreventSleep_H +#define PokemonAutomation_NintendoSwitch_PreventSleep_H #include "NintendoSwitch/Framework/SingleSwitchProgram.h" @@ -13,11 +13,17 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ -class PreventSleep : public SingleSwitchProgram{ +class PreventSleep_Descriptor : public RunnableSwitchProgramDescriptor{ public: - PreventSleep(); + PreventSleep_Descriptor(); +}; + + +class PreventSleep : public SingleSwitchProgramInstance{ +public: + PreventSleep(const PreventSleep_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; }; diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/SwitchViewer.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/SwitchViewer.cpp index 9339bd78ad..53e2e03c9d 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/SwitchViewer.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/SwitchViewer.cpp @@ -4,4 +4,76 @@ * */ +#include +#include "SwitchViewer.h" +namespace PokemonAutomation{ +namespace NintendoSwitch{ + + +SwitchViewer_Descriptor::SwitchViewer_Descriptor() + : PanelDescriptor( + QColor(), + "NintendoSwitch:SwitchViewer", + "Switch Viewer", + "SerialPrograms/SwitchViewer.md", + "View status information from one or more running programs." + ) +{} + + + +SwitchViewer::SwitchViewer(const SwitchViewer_Descriptor& descriptor) + : PanelInstance(descriptor) + , m_switches( + PABotBaseLevel::NOT_PABOTBASE, FeedbackType::NONE, + 1, 4, 1 + ) +{} +void SwitchViewer::from_json(const QJsonValue& json){ + m_switches.load_json(json.toObject()); +} +QJsonValue SwitchViewer::to_json() const{ + return m_switches.to_json(); +} +QWidget* SwitchViewer::make_widget(QWidget& parent, PanelListener& listener){ + return SwitchViewer_Widget::make(parent, *this, listener); +} + + + +SwitchViewer_Widget* SwitchViewer_Widget::make( + QWidget& parent, + SwitchViewer& instance, + PanelListener& listener +){ + SwitchViewer_Widget* widget = new SwitchViewer_Widget(parent, instance, listener); + widget->construct(); + return widget; +} +SwitchViewer_Widget::SwitchViewer_Widget( + QWidget& parent, + SwitchViewer& instance, + PanelListener& listener +) + : PanelWidget(parent, instance, listener) +{} +void SwitchViewer_Widget::construct(){ + QVBoxLayout* layout = new QVBoxLayout(this); + layout->setMargin(0); + layout->addWidget(make_header(*this)); + + SwitchViewer& instance = static_cast(m_instance); + m_switches = (MultiSwitchSystem*)instance.m_switches.make_ui(*this, m_listener.output_window()); + layout->addWidget(m_switches); +} + + + + + + + + +} +} diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/SwitchViewer.h b/SerialPrograms/Source/NintendoSwitch/Programs/SwitchViewer.h index 9dcb984bd3..6127b0dc7d 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/SwitchViewer.h +++ b/SerialPrograms/Source/NintendoSwitch/Programs/SwitchViewer.h @@ -4,75 +4,64 @@ * */ -#ifndef PokemonAutomation_SwitchViewer_H -#define PokemonAutomation_SwitchViewer_H +#ifndef PokemonAutomation_NintendoSwitch_SwitchViewer_H +#define PokemonAutomation_NintendoSwitch_SwitchViewer_H #include -#include "CommonFramework/Panels/RightPanel.h" -#include "CommonFramework/Windows/MainWindow.h" +#include "CommonFramework/Panels/Panel.h" #include "NintendoSwitch/Framework/MultiSwitchSystem.h" namespace PokemonAutomation{ namespace NintendoSwitch{ -class SwitchViewer : public RightPanel{ +class SwitchViewer_Descriptor : public PanelDescriptor{ public: - SwitchViewer() - : RightPanel( - QColor(), - "Switch Viewer", - "SerialPrograms/SwitchViewer.md", - "View status information from one or more running programs." - ) - , m_switches( - PABotBaseLevel::NOT_PABOTBASE, FeedbackType::NONE, - 1, 4, 1 - ) - {} - SwitchViewer(const QJsonValue& json) - : SwitchViewer() - { - m_switches.load_json(json.toObject().value(m_name)); - } - virtual QJsonValue to_json() const override{ - return m_switches.to_json(); - } - - virtual QWidget* make_ui(MainWindow& window) override; + SwitchViewer_Descriptor(); +}; + + + +class SwitchViewer : public PanelInstance{ +public: + SwitchViewer(const SwitchViewer_Descriptor& descriptor); + virtual QWidget* make_widget(QWidget& parent, PanelListener& listener) override; + +public: + // Serialization + virtual void from_json(const QJsonValue& json) override; + virtual QJsonValue to_json() const override; private: - friend class SwitchViewerUI; + friend class SwitchViewer_Widget; + MultiSwitchSystemFactory m_switches; }; -class SwitchViewerUI final: public RightPanelUI{ - friend class SwitchViewer; + +class SwitchViewer_Widget : public PanelWidget{ +public: + static SwitchViewer_Widget* make( + QWidget& parent, + SwitchViewer& instance, + PanelListener& listener + ); private: - SwitchViewerUI(SwitchViewer& factory, MainWindow& window) - : RightPanelUI(factory) - , m_window(window) - {} - virtual void make_body(QWidget& parent, QVBoxLayout& layout) override{ - SwitchViewer& factory = static_cast(m_factory); - m_switches = (MultiSwitchSystem*)factory.m_switches.make_ui(parent, m_window.output_window()); - layout.addWidget(m_switches); - } + SwitchViewer_Widget( + QWidget& parent, + SwitchViewer& instance, + PanelListener& listener + ); + void construct(); private: - MainWindow& m_window; MultiSwitchSystem* m_switches; }; -QWidget* SwitchViewer::make_ui(MainWindow& window){ - SwitchViewerUI* widget = new SwitchViewerUI(*this, window); - widget->construct(); - return widget; -} } diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/TurboButton.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/TurboButton.cpp new file mode 100644 index 0000000000..94dcbdfd46 --- /dev/null +++ b/SerialPrograms/Source/NintendoSwitch/Programs/TurboButton.cpp @@ -0,0 +1,68 @@ +/* Turbo Button + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "Common/SwitchFramework/Switch_PushButtons.h" +#include "TurboButton.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ + + + +TurboButton_Descriptor::TurboButton_Descriptor() + : RunnableSwitchProgramDescriptor( + "NintendoSwitch:TurboButton", + "Turbo Button", + "", + "Mash a controller button. (similar to turbo controller)", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB + ) +{} + + + +TurboButton::TurboButton(const TurboButton_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) + , BUTTON( + "Button to Mash:", + { + "Y", + "B", + "A", + "X", + "L", + "R", + "ZL", + "ZR", + "Minus (-)", + "Plus (+)", + "L-Click (left joystick click)", + "R-Click (right joystick click)", + "Home", + "Capture", + }, + 2 + ) + , PERIOD( + "Period (time between presses):", + "8", 8 + ) +{ + m_options.emplace_back(&BUTTON, "BUTTON"); + m_options.emplace_back(&PERIOD, "PERIOD"); +} +void TurboButton::program(SingleSwitchProgramEnvironment& env){ + while (true){ + pbf_press_button(env.console, (Button)1 << BUTTON, 5, PERIOD - 5); + } +} + + + +} +} + diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/TurboButton.h b/SerialPrograms/Source/NintendoSwitch/Programs/TurboButton.h new file mode 100644 index 0000000000..bba80f923e --- /dev/null +++ b/SerialPrograms/Source/NintendoSwitch/Programs/TurboButton.h @@ -0,0 +1,40 @@ +/* Turbo Button + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_NintendoSwitch_TurboButton_H +#define PokemonAutomation_NintendoSwitch_TurboButton_H + +#include "CommonFramework/Options/EnumDropdown.h" +#include "NintendoSwitch/Options/TimeExpression.h" +#include "NintendoSwitch/Framework/SingleSwitchProgram.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ + + +class TurboButton_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + TurboButton_Descriptor(); +}; + + +class TurboButton : public SingleSwitchProgramInstance{ +public: + TurboButton(const TurboButton_Descriptor& descriptor); + + virtual void program(SingleSwitchProgramEnvironment& env) override; + +private: + EnumDropdown BUTTON; + TimeExpression PERIOD; +}; + + + +} +} +#endif + diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/VirtualConsole.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/VirtualConsole.cpp new file mode 100644 index 0000000000..e713c690fd --- /dev/null +++ b/SerialPrograms/Source/NintendoSwitch/Programs/VirtualConsole.cpp @@ -0,0 +1,76 @@ +/* Virtual Game Console + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "VirtualConsole.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ + +VirtualConsole_Descriptor::VirtualConsole_Descriptor() + : PanelDescriptor( + QColor(), + "NintendoSwitch:VirtualConsole", + "Virtual Console", + "SerialPrograms/VirtualConsole.md", + "Play your Switch from your computer. Device logging is logged to the output window." + ) +{} + + + +VirtualConsole::VirtualConsole(const VirtualConsole_Descriptor& descriptor) + : PanelInstance(descriptor) + , m_switch( + "Switch Settings", "Switch 0", + PABotBaseLevel::NOT_PABOTBASE, FeedbackType::NONE + ) +{} +void VirtualConsole::from_json(const QJsonValue& json){ + m_switch.load_json(json.toObject()); +} +QJsonValue VirtualConsole::to_json() const{ + return m_switch.to_json(); +} +QWidget* VirtualConsole::make_widget(QWidget& parent, PanelListener& listener){ + return VirtualConsole_Widget::make(parent, *this, listener); +} + + + +VirtualConsole_Widget* VirtualConsole_Widget::make( + QWidget& parent, + VirtualConsole& instance, + PanelListener& listener +){ + VirtualConsole_Widget* widget = new VirtualConsole_Widget(parent, instance, listener); + widget->construct(); + return widget; +} +VirtualConsole_Widget::VirtualConsole_Widget( + QWidget& parent, + VirtualConsole& instance, + PanelListener& listener +) + : PanelWidget(parent, instance, listener) +{} +void VirtualConsole_Widget::construct(){ + QVBoxLayout* layout = new QVBoxLayout(this); + layout->setMargin(0); + layout->addWidget(make_header(*this)); + + VirtualConsole& instance = static_cast(m_instance); + m_switch = (SwitchSystem*)instance.m_switch.make_ui(*this, m_listener.output_window()); + layout->addWidget(m_switch); +} + + + + + + +} +} + diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/VirtualConsole.h b/SerialPrograms/Source/NintendoSwitch/Programs/VirtualConsole.h index 897ba33a6d..37a4c45197 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/VirtualConsole.h +++ b/SerialPrograms/Source/NintendoSwitch/Programs/VirtualConsole.h @@ -4,12 +4,11 @@ * */ -#ifndef PokemonAutomation_VirtualConsole_H -#define PokemonAutomation_VirtualConsole_H +#ifndef PokemonAutomation_NintendoSwitch_VirtualConsole_H +#define PokemonAutomation_NintendoSwitch_VirtualConsole_H #include #include "Common/Qt/QtJsonTools.h" -#include "CommonFramework/Panels/RightPanel.h" #include "CommonFramework/Windows/MainWindow.h" #include "NintendoSwitch/Framework/SwitchSystem.h" @@ -17,68 +16,54 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ -class VirtualConsoleUI; +class VirtualConsole_Descriptor : public PanelDescriptor{ +public: + VirtualConsole_Descriptor(); +}; + + + +class VirtualConsole : public PanelInstance{ +public: + VirtualConsole(const VirtualConsole_Descriptor& descriptor); + virtual QWidget* make_widget(QWidget& parent, PanelListener& listener) override; -class VirtualConsole : public RightPanel{ public: - VirtualConsole() - : RightPanel( - QColor(), - "Virtual Console", - "SerialPrograms/VirtualConsole.md", - "Play your Switch from your computer. Device logging is logged to the output window." - ) - , m_switch( - "Switch Settings", "Switch 0", - PABotBaseLevel::NOT_PABOTBASE, FeedbackType::NONE - ) - {} - VirtualConsole(const QJsonValue& json) - : VirtualConsole() - { - m_switch.load_json(json.toObject().value(m_name)); - } - virtual QJsonValue to_json() const override{ - return m_switch.to_json(); - } - - virtual QWidget* make_ui(MainWindow& window) override; + // Serialization + VirtualConsole(PanelListener& listener, const QJsonValue& json); + virtual void from_json(const QJsonValue& json) override; + virtual QJsonValue to_json() const override; private: - friend class VirtualConsoleUI; + friend class VirtualConsole_Widget; + SwitchSystemFactory m_switch; }; -class VirtualConsoleUI final : public RightPanelUI{ - friend class VirtualConsole; + +class VirtualConsole_Widget : public PanelWidget{ +public: + static VirtualConsole_Widget* make( + QWidget& parent, + VirtualConsole& instance, + PanelListener& listener + ); private: - VirtualConsoleUI(VirtualConsole& factory, MainWindow& window) - : RightPanelUI(factory) - , m_window(window) - {} - virtual void make_body(QWidget& parent, QVBoxLayout& layout) override{ - VirtualConsole& factory = static_cast(m_factory); - m_switch = (SwitchSystem*)factory.m_switch.make_ui(parent, m_window.output_window()); - layout.addWidget(m_switch); - -// QLabel* controls = new QLabel("Controls", this); -// layout.addWidget(controls); - } + VirtualConsole_Widget( + QWidget& parent, + VirtualConsole& instance, + PanelListener& listener + ); + void construct(); private: - MainWindow& m_window; SwitchSystem* m_switch; }; -inline QWidget* VirtualConsole::make_ui(MainWindow& window){ - VirtualConsoleUI* widget = new VirtualConsoleUI(*this, window); - widget->construct(); - return widget; -} } diff --git a/SerialPrograms/Source/NintendoSwitch/TestProgram.cpp b/SerialPrograms/Source/NintendoSwitch/TestProgram.cpp new file mode 100644 index 0000000000..da51978c89 --- /dev/null +++ b/SerialPrograms/Source/NintendoSwitch/TestProgram.cpp @@ -0,0 +1,261 @@ +/* Test Program + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +//#include +#include "Common/Cpp/Exception.h" +#include "Common/Cpp/PrettyPrint.h" +#include "Common/Qt/QtJsonTools.h" +#include "Common/SwitchFramework/FrameworkSettings.h" +#include "Common/SwitchFramework/Switch_PushButtons.h" +#include "Common/PokemonSwSh/PokemonSettings.h" +#include "Common/PokemonSwSh/PokemonSwShGameEntry.h" +#include "Common/PokemonSwSh/PokemonSwShDateSpam.h" +#include "ClientSource/Libraries/Logging.h" +#include "CommonFramework/PersistentSettings.h" +#include "CommonFramework/Tools/StatsTracking.h" +#include "CommonFramework/Tools/StatsDatabase.h" +#include "CommonFramework/Tools/InterruptableCommands.h" +#include "CommonFramework/Inference/ImageTools.h" +#include "CommonFramework/Inference/InferenceThrottler.h" +#include "CommonFramework/Inference/FillGeometry.h" +#include "CommonFramework/Inference/AnomalyDetector.h" +#include "CommonFramework/Inference/ColorClustering.h" +#include "CommonFramework/Inference/StatAccumulator.h" +#include "CommonFramework/Inference/TimeWindowStatTracker.h" +#include "CommonFramework/Inference/VisualInferenceSession.h" +#include "CommonFramework/OCR/RawOCR.h" +#include "CommonFramework/OCR/Filtering.h" +#include "CommonFramework/OCR/StringNormalization.h" +#include "CommonFramework/OCR/TextMatcher.h" +#include "CommonFramework/OCR/LargeDictionaryMatcher.h" +#include "PokemonSwSh/ShinyHuntTracker.h" +#include "PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_ShinyFilters.h" +#include "PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_SparkleTrigger.h" +#include "PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_SquareTrigger.h" +#include "PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_SquareDetector.h" +#include "PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_ShinyTrigger.h" +#include "PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_ShinyEncounterDetector.h" +#include "PokemonSwSh/Inference/PokemonSwSh_StartBattleDetector.h" +#include "PokemonSwSh/Inference/PokemonSwSh_SummaryShinySymbolDetector.h" +#include "PokemonSwSh/Inference/PokemonSwSh_RaidCatchDetector.h" +#include "PokemonSwSh/Inference/PokemonSwSh_BattleMenuDetector.h" +#include "PokemonSwSh/Inference/PokemonSwSh_FishingDetector.h" +#include "PokemonSwSh/Inference/PokemonSwSh_MarkFinder.h" +#include "PokemonSwSh/Inference/PokemonSwSh_ReceivePokemonDetector.h" +#include "TestProgram.h" + +#include + +//#include +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ +namespace NintendoSwitch{ + + +TestProgram_Descriptor::TestProgram_Descriptor() + : RunnableSwitchProgramDescriptor( + "NintendoSwitch:TestProgram", + "Test Program", + "", + "Test Program", + FeedbackType::REQUIRED, + PABotBaseLevel::PABOTBASE_12KB + ) +{} + + + +TestProgram::TestProgram(const TestProgram_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) + , LANGUAGE( + "OCR Language:", +// m_iv_checker_reader.languages() +#if 1 + { +// Language::None, + Language::English, + Language::Spanish, + Language::French, + Language::German, + Language::Italian, + Language::Japanese, + Language::Korean, + Language::ChineseSimplified, + Language::ChineseTraditional, + }, + false +#endif + ) + , DROPDOWN( + "Test Dropdown:", + { + "case 0", + "case 1", + "case 2", + "case 3", + }, 0 + ) + , STRING_SELECT( + "Test Select:", + { + "Bulbasaur", + "Charmander", + "Charmeleon", + "Charizard", + "Squirtle", + "Chikorita", + }, 0 + ) + +{ + m_options.emplace_back(&LANGUAGE, "LANGUAGE"); + m_options.emplace_back(&DROPDOWN, "DROPDOWN"); + m_options.emplace_back(&STRING_SELECT, "STRING_SELECT"); +} + + + + + + + +void TestProgram::program(SingleSwitchProgramEnvironment& env){ + using namespace OCR; + + BotBase& botbase = env.console; + VideoFeed& feed = env.console; + +// cout << levenshtein_distance_substring("asdf", "a") << endl; +// cout << random_match_probability(10, 10, 1. / 3) << endl; + + + env.log("asdf\nqwer"); + +// QSystemTrayIcon icon; +// icon.show(); +// icon.showMessage("title", "asdf"); + + +#if 0 + QImage image( + PERSISTENT_SETTINGS().training_data + +// "PokemonNameOCR/PokemonNameOCR (Kim-SwShPokedex-0)/kor/clefairy-20210618-201635.png" +// "PokemonNameOCR/PokemonNameOCR (Kim-SwShPokedex-0)/kor/cleffa-20210618-202023.png" +// "PokemonNameOCR/PokemonNameOCR (Kim-SwShPokedex-1)/chi_tra/frillish-20210619-023228.png" + "PokemonNameOCR/PokemonNameOCR (Kim-SwShPokedex-0)/deu/cleffa-20210618-203904.png" +// "IVCheckerOCR/IVCheckerOCR (Kim-0)/eng/Decent-20210619-200037b.png" + ); + + BrightnessHistogram histogram(image); + cout << histogram.dump() << endl; + +// OCR::binary_filter_black_text(image); + make_OCR_filter(image).apply(image); + + image.save("test.png"); + + QString text = OCR::ocr_read(LANGUAGE, image); + env.log("OCR Read: " + text); +#endif + + + +// OCR::LargeDictionaryMatcher name_matcher("Pokemon/PokemonNameOCR/PokemonOCR"); + + + +// OCR::LargeDatabaseOCR database(PERSISTENT_SETTINGS().resource_path + "Pokemon/PokemonNameOCR/PokemonOCR-eng.json"); + +// database.write("text.json"); + + +// cout << levenshtein_distance("asdfqwer", "asdfqwer") << endl; +// cout << levenshtein_distance("asdfqwer", "asddfqwe") << endl; + +// ReceivePokemonDetector detector(feed); +// detector.receive_is_over(feed.snapshot()); + +// generate_names_file(); + + +#if 0 + QString text = "asdf"; + env.log(text); + + text = OCR::normalize(text); + env.log(text); +#endif + +#if 0 + text = text.normalized(QString::NormalizationForm_KD); +// text = OCR::remove_non_alphanumeric(text); + env.log(text); + + for (QChar ch : text){ + cout << ch.unicode() << endl; + } +#endif + + +#if 0 + IVCheckerReaderScope reader(m_iv_checker_reader, feed, LANGUAGE); + + IVCheckerReader::Results results = reader.read(&env.logger(), feed.snapshot()); + + cout << IVCheckerReader::enum_to_token(results.hp) << endl; + cout << IVCheckerReader::enum_to_token(results.attack) << endl; + cout << IVCheckerReader::enum_to_token(results.defense) << endl; + cout << IVCheckerReader::enum_to_token(results.spatk) << endl; + cout << IVCheckerReader::enum_to_token(results.spdef) << endl; + cout << IVCheckerReader::enum_to_token(results.speed) << endl; +#endif + + + +// QChar ch(0x4ED6); +// cout << ch.isLetterOrNumber() << endl; + + +#if 0 + InferenceBoxScope box0(env.console, InferenceBox(0.75, 0.531 + 0 * 0.1115, 0.18, 0.059)); + InferenceBoxScope box1(env.console, InferenceBox(0.75, 0.531 + 1 * 0.1115, 0.18, 0.059)); + InferenceBoxScope box2(env.console, InferenceBox(0.75, 0.531 + 2 * 0.1115, 0.18, 0.059)); + InferenceBoxScope box3(env.console, InferenceBox(0.75, 0.531 + 3 * 0.1115, 0.18, 0.059)); + + +// InferenceBoxScope box(env.console, InferenceBox(0.76, 0.04, 0.15, 0.044)); + +// QImage frame = feed.snapshot(); +// frame = extract_box(frame, box); + +// QString str = TextInference::ocr_read(frame, LANGUAGE); +// cout << str.toUtf8().data() << endl; + +// env.log(str); + + +#endif + env.wait(std::chrono::seconds(60)); + + +} + + + + + + + +} +} + + + + diff --git a/SerialPrograms/Source/NintendoSwitch/TestProgram.h b/SerialPrograms/Source/NintendoSwitch/TestProgram.h new file mode 100644 index 0000000000..37cae3230d --- /dev/null +++ b/SerialPrograms/Source/NintendoSwitch/TestProgram.h @@ -0,0 +1,45 @@ +/* Test Program + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PokemonSwSh_TestProgram_H +#define PokemonAutomation_PokemonSwSh_TestProgram_H + +#include "CommonFramework/Options/EnumDropdown.h" +#include "CommonFramework/Options/StringSelect.h" +#include "CommonFramework/Options/LanguageOCR.h" +#include "NintendoSwitch/Framework/SingleSwitchProgram.h" +#include "PokemonSwSh/Inference/PokemonSwSh_IVCheckerReader.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ + +using namespace PokemonSwSh; + +class TestProgram_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + TestProgram_Descriptor(); +}; + + +class TestProgram : public SingleSwitchProgramInstance{ +public: + TestProgram(const TestProgram_Descriptor& descriptor); + + virtual void program(SingleSwitchProgramEnvironment& env) override; + +private: + IVCheckerReader m_iv_checker_reader; + LanguageOCR LANGUAGE; + EnumDropdown DROPDOWN; + StringSelect STRING_SELECT; +}; + + + +} +} +#endif + diff --git a/SerialPrograms/Source/PanelList.cpp b/SerialPrograms/Source/PanelList.cpp deleted file mode 100644 index 15715a86df..0000000000 --- a/SerialPrograms/Source/PanelList.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/* List of all Panels - * - * From: https://github.com/PokemonAutomation/Arduino-Source - * - */ - -#include -#include "Common/Qt/StringException.h" -#include "CommonFramework/PersistentSettings.h" -#include "PanelList.h" - -#include "NintendoSwitch/FrameworkSettingsPanel.h" -#include "PokemonSwSh/PokemonSwSh_SettingsPanel.h" - -#include "NintendoSwitch/Programs/VirtualConsole.h" -#include "NintendoSwitch/Programs/SwitchViewer.h" - -#include "PokemonSwSh/Programs/TestProgram.h" - -#include "NintendoSwitch/Programs/PreventSleep.h" -#include "NintendoSwitch/Programs/FriendCodeAdder.h" -#include "NintendoSwitch/Programs/FriendDelete.h" -#include "PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FastCodeEntry.h" -#include "PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FriendSearchDisconnect.h" - -#include "PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TurboA.h" -#include "PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_MassRelease.h" -#include "PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_SurpriseTrade.h" -#include "PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TradeBot.h" -#include "PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_ClothingBuyer.h" -#include "PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_BallThrower.h" - -#include "PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-WattFarmer.h" -#include "PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-BerryFarmer.h" -#include "PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-LotoFarmer.h" -#include "PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-StowOnSideFarmer.h" -#include "PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-DailyHighlightFarmer.h" - -#include "PokemonSwSh/Programs/DenHunting/PokemonSwSh_BeamReset.h" -#include "PokemonSwSh/Programs/DenHunting/PokemonSwSh_PurpleBeamFinder.h" -#include "PokemonSwSh/Programs/DenHunting/PokemonSwSh_EventBeamFinder.h" -#include "PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperJPN.h" -#include "PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperEU.h" -#include "PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperUS.h" -#include "PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperJPN-7.8k.h" - -#include "PokemonSwSh/Programs/Hosting/PokemonSwSh_DenRoller.h" -#include "PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHost-Rolling.h" -#include "PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHost-MultiGame.h" - -#include "PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_MultiGameFossil.h" -#include "PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regi.h" -#include "PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-SwordsOfJustice.h" -#include "PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-StrongSpawn.h" -#include "PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regigigas2.h" -#include "PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-IoATrade.h" - -#include "PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regi.h" -#include "PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-SwordsOfJustice.h" -#include "PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-StrongSpawn.h" -#include "PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regigigas2.h" -#include "PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-IoATrade.h" -#include "PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-BerryTree.h" -#include "PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Whistling.h" -#include "PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Fishing.h" -#include "PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Overworld.h" - -#include "PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggFetcher2.h" -#include "PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggHatcher.h" -#include "PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggCombined2.h" -#include "PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggSuperCombined2.h" -#include "PokemonSwSh/Programs/EggPrograms/PokemonSwSh_GodEggDuplication.h" -#include "PokemonSwSh/Programs/EggPrograms/PokemonSwSh_GodEggItemDupe.h" - -#include "PokemonSwSh/Programs/PokemonSwSh_SynchronizedSpinning.h" -#include "PokemonSwSh/Programs/PokemonSwSh_RaidItemFarmerOKHO.h" - -namespace PokemonAutomation{ - -using namespace NintendoSwitch; -using namespace PokemonSwSh; - -using std::cout; -using std::endl; - -const std::vector>& SETTINGS_LIST(){ - static std::vector> list; - if (!list.empty()){ - return list; - } - - list.emplace_back(new FrameworkSettings(settings.settings)); - list.emplace_back(new PokemonSettings(settings.settings)); - - return list; -} -const std::map& SETTINGS_MAP(){ - static std::map map; - if (!map.empty()){ - return map; - } - for (const auto& setting : SETTINGS_LIST()){ - auto ret = map.emplace(setting->name(), setting.get()); - if (!ret.second){ - cout << ("Duplicate setting name: " + setting->name()).toUtf8().data() << endl; - throw StringException("Duplicate setting name: " + setting->name()); - } - } - return map; -} - -const std::vector>& PROGRAM_LIST(){ - static std::vector> list; - if (!list.empty()){ - return list; - } - - list.emplace_back(new VirtualConsole(settings.programs)); - list.emplace_back(new SwitchViewer(settings.programs)); - - if (settings.developer_mode){ - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - } - - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - if (settings.developer_mode){ - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - } - - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - if (settings.naughty_mode){ - list.emplace_back(new SingleSwitchProgramWrapper(settings.programs)); - } - - list.emplace_back(new MultiSwitchProgramWrapper(settings.programs)); - list.emplace_back(new MultiSwitchProgramWrapper(settings.programs)); - - return list; -} -const std::map& PROGRAM_MAP(){ - static std::map map; - if (!map.empty()){ - return map; - } - for (const auto& program : PROGRAM_LIST()){ - auto ret = map.emplace(program->name(), program.get()); - if (!ret.second){ - cout << ("Duplicate program name: " + program->name()).toUtf8().data() << endl; - throw StringException("Duplicate program name: " + program->name()); - } - } - return map; -} - - - -} diff --git a/SerialPrograms/Source/PanelList.h b/SerialPrograms/Source/PanelList.h deleted file mode 100644 index ea215a5961..0000000000 --- a/SerialPrograms/Source/PanelList.h +++ /dev/null @@ -1,26 +0,0 @@ -/* List of all Panels - * - * From: https://github.com/PokemonAutomation/Arduino-Source - * - */ - -#ifndef PokemonAutomation_PanelList_H -#define PokemonAutomation_PanelList_H - -#include -#include -#include -#include "CommonFramework/Panels/RightPanel.h" - -namespace PokemonAutomation{ - - -const std::vector>& SETTINGS_LIST(); -const std::map& SETTINGS_MAP(); - -const std::vector>& PROGRAM_LIST(); -const std::map& PROGRAM_MAP(); - - -} -#endif diff --git a/SerialPrograms/Source/PanelLists.cpp b/SerialPrograms/Source/PanelLists.cpp new file mode 100644 index 0000000000..478408d00c --- /dev/null +++ b/SerialPrograms/Source/PanelLists.cpp @@ -0,0 +1,53 @@ +/* Left-Side Panel + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include "Common/Qt/QtJsonTools.h" +#include "CommonFramework/PersistentSettings.h" +#include "NintendoSwitch/Panels_NintendoSwitch.h" +#include "PokemonSwSh/Panels_PokemonSwSh.h" +#include "PokemonBDSP/Panels_PokemonBDSP.h" +#include "PanelLists.h" + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ + + +ProgramTabs::ProgramTabs(QWidget& parent, PanelListener& listener) + : QTabWidget(&parent) +{ + add(new NintendoSwitch::Panels(*this, listener)); + add(new NintendoSwitch::PokemonSwSh::Panels(*this, listener)); + if (PERSISTENT_SETTINGS().developer_mode){ + add(new NintendoSwitch::PokemonBDSP::Panels(*this, listener)); + } +} + +void ProgramTabs::add(PanelList* list){ + addTab(list, list->label()); + if (list->items() == 0){ + setTabEnabled((int)m_lists.size(), false); + } + m_lists.emplace_back(list); +} + +QSize ProgramTabs::sizeHint() const{ + QSize size = QTabWidget::sizeHint(); +// cout << size.width() << " x " << size.height() << endl; +// cout << this->size().width() << " x " << this->size().height() << endl; + size.setWidth(size.width() + 10); + return size; +} + + + + + + +} diff --git a/SerialPrograms/Source/PanelLists.h b/SerialPrograms/Source/PanelLists.h new file mode 100644 index 0000000000..d567485f5d --- /dev/null +++ b/SerialPrograms/Source/PanelLists.h @@ -0,0 +1,33 @@ +/* Program Tabs + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_ProgramTabs_H +#define PokemonAutomation_ProgramTabs_H + +#include +#include "CommonFramework/Panels/PanelList.h" + +namespace PokemonAutomation{ + + +class ProgramTabs : public QTabWidget{ +public: + ProgramTabs(QWidget& parent, PanelListener& listener); + + virtual QSize sizeHint() const override; + +private: + void add(PanelList* list); + +private: + std::vector m_lists; +}; + + + + +} +#endif diff --git a/SerialPrograms/Source/Pokemon/Options/Pokemon_NameSelect.cpp b/SerialPrograms/Source/Pokemon/Options/Pokemon_NameSelect.cpp new file mode 100644 index 0000000000..14efde41e2 --- /dev/null +++ b/SerialPrograms/Source/Pokemon/Options/Pokemon_NameSelect.cpp @@ -0,0 +1,77 @@ +/* Pokemon Name Select + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include "Common/Cpp/Exception.h" +#include "Common/Qt/QtJsonTools.h" +#include "CommonFramework/PersistentSettings.h" +#include "Pokemon_NameSelect.h" + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ +namespace Pokemon{ + + +PokemonNameSelectData::PokemonNameSelectData(const QString& json_file){ + QJsonArray array = read_json_file( + PERSISTENT_SETTINGS().resource_path + json_file + ).array(); + QJsonObject obj = read_json_file( + PERSISTENT_SETTINGS().resource_path + "Pokemon/PokemonNameOCR/PokemonOCR-eng.json" + ).object(); + for (const auto& item : array){ + QString token = item.toString(); +// cout << token.toUtf8().data() << endl; + if (token.size() <= 0){ + PA_THROW_StringException("Expected non-empty string for Pokemon token."); + } + auto iter = obj.find(token); + if (iter == obj.end()){ + PA_THROW_StringException("Pokemon token not found in database: " + token); + } + QJsonArray array = iter.value().toArray(); + if (array.empty()){ + PA_THROW_StringException("No display names or candidates found for: " + token); + } + QString display = array[0].toString(); + if (display.size() <= 0){ + PA_THROW_StringException("Expected non-empty string for display name. Token: " + token); + } + m_list.emplace_back(display); + m_display_to_token.emplace( + std::move(display), + token.toUtf8().data() + ); + } +} + + + +PokemonNameSelect::PokemonNameSelect( + QString label, + const QString& json_file +) + : PokemonNameSelectData(json_file) + , StringSelect(std::move(label), cases(), 0) +{} + +const std::string& PokemonNameSelect::token() const{ + const QString& display = (const QString&)*this; + auto iter = m_display_to_token.find(display); + if (iter == m_display_to_token.end()){ + PA_THROW_StringException("Display name not found in database: " + display); + } + return iter->second; +} + + + + +} +} diff --git a/SerialPrograms/Source/Pokemon/Options/Pokemon_NameSelect.h b/SerialPrograms/Source/Pokemon/Options/Pokemon_NameSelect.h new file mode 100644 index 0000000000..b8e8bc320b --- /dev/null +++ b/SerialPrograms/Source/Pokemon/Options/Pokemon_NameSelect.h @@ -0,0 +1,41 @@ +/* Pokemon Name Select + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_Pokemon_PokemonNameSelect_H +#define PokemonAutomation_Pokemon_PokemonNameSelect_H + +#include "CommonFramework/Options/StringSelect.h" + +namespace PokemonAutomation{ +namespace Pokemon{ + + +struct PokemonNameSelectData{ + PokemonNameSelectData(const QString& json_file); + const std::vector& cases() const{ return m_list; } + +protected: + std::vector m_list; + std::map m_display_to_token; +}; + + +class PokemonNameSelect : public PokemonNameSelectData, public StringSelect{ +public: + PokemonNameSelect( + QString label, + const QString& json_file + ); + + const std::string& token() const; + +private: +}; + + +} +} +#endif diff --git a/SerialPrograms/Source/Pokemon/Pokemon_EncounterStats.cpp b/SerialPrograms/Source/Pokemon/Pokemon_EncounterStats.cpp new file mode 100644 index 0000000000..2a467f8ecd --- /dev/null +++ b/SerialPrograms/Source/Pokemon/Pokemon_EncounterStats.cpp @@ -0,0 +1,94 @@ +/* Pokemon Encounter Stats + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "Common/Cpp/PrettyPrint.h" +#include "Pokemon_EncounterStats.h" + +namespace PokemonAutomation{ +namespace Pokemon{ + + +bool operator<(const PokemonEncounterSet& x, const PokemonEncounterSet& y){ + auto iter0 = x.m_set.begin(); + auto iter1 = y.m_set.begin(); + while (true){ + bool end0 = iter0 == x.m_set.end(); + bool end1 = iter1 == y.m_set.end(); + if (end0 && end1){ + return false; + } + if (end0){ + return true; + } + if (end1){ + return false; + } + int cmp = strcmp(iter0->c_str(), iter1->c_str()); + if (cmp < 0){ + return true; + } + if (cmp > 0){ + return false; + } + + ++iter0; + ++iter1; + } +} +std::string PokemonEncounterSet::dump() const{ + if (m_set.empty()){ + return "None - Unable to detect"; + } + if (m_set.size() == 1){ + return *m_set.begin(); + } + if (m_set.size() <= 5){ + std::string str = "Ambiguous ("; + bool first = true; + for (const std::string& token : m_set){ + if (!first){ + str += ", "; + } + first = false; + str += token; + } + str += ")"; + return str; + } + return "Ambiguous (" + std::to_string(m_set.size()) + " candidates)"; +} + + + +void PokemonEncounterStats::operator+=(const PokemonEncounterSet& set){ + m_encounter_map[set]++; +} + +std::multimap> +PokemonEncounterStats::to_sorted_map() const{ + MapType ret; + for (const auto& item : m_encounter_map){ + ret.emplace(item.second, &item.first); + } + return ret; +} +std::string PokemonEncounterStats::dump_sorted_map() const{ + MapType map = to_sorted_map(); + std::string str = "Encounter Stats:\n"; + for (const auto& item : map){ + str += tostr_u_commas(item.first); + str += " : "; + str += item.second->dump(); + str += "\n"; + } + return str; +} + + + +} +} + diff --git a/SerialPrograms/Source/Pokemon/Pokemon_EncounterStats.h b/SerialPrograms/Source/Pokemon/Pokemon_EncounterStats.h new file mode 100644 index 0000000000..9030c0c147 --- /dev/null +++ b/SerialPrograms/Source/Pokemon/Pokemon_EncounterStats.h @@ -0,0 +1,56 @@ +/* Pokemon Encounter Stats + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_Pokemon_EncounterStats_H +#define PokemonAutomation_Pokemon_EncounterStats_H + +#include +#include +#include + +namespace PokemonAutomation{ +namespace Pokemon{ + + +class PokemonEncounterSet{ +public: + PokemonEncounterSet() = default; + PokemonEncounterSet(const std::set& set) + : m_set(set) + {} + PokemonEncounterSet(std::set&& set) + : m_set(std::move(set)) + {} + + friend bool operator<(const PokemonEncounterSet& x, const PokemonEncounterSet& y); + + std::string dump() const; + + +private: + std::set m_set; +}; + + +class PokemonEncounterStats{ + +public: + void operator+=(const PokemonEncounterSet& set); + + std::string dump_sorted_map() const; + +public: + using MapType = std::multimap>; + MapType to_sorted_map() const; + +private: + std::map m_encounter_map; +}; + + +} +} +#endif diff --git a/SerialPrograms/Source/Pokemon/Pokemon_NameReader.cpp b/SerialPrograms/Source/Pokemon/Pokemon_NameReader.cpp new file mode 100644 index 0000000000..5019f9f236 --- /dev/null +++ b/SerialPrograms/Source/Pokemon/Pokemon_NameReader.cpp @@ -0,0 +1,37 @@ +/* Pokemon Name Reader + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "CommonFramework/OCR/RawOCR.h" +#include "Pokemon_NameReader.h" + +namespace PokemonAutomation{ +namespace Pokemon{ + + +PokemonNameReader::PokemonNameReader() + : LargeDictionaryMatcher("Pokemon/PokemonNameOCR/PokemonOCR-") +{} + +OCR::MatchResult PokemonNameReader::read_exact( + Language language, + const QImage& image +) const{ + QString text = OCR::ocr_read(language, image); + return match_substring(language, text); +} +OCR::MatchResult PokemonNameReader::read_exact( + Language language, + const std::string& expected, + const QImage& image +) const{ + QString text = OCR::ocr_read(language, image); + return match_substring(language, expected, text); +} + + +} +} + diff --git a/SerialPrograms/Source/Pokemon/Pokemon_NameReader.h b/SerialPrograms/Source/Pokemon/Pokemon_NameReader.h new file mode 100644 index 0000000000..91a56ce4b7 --- /dev/null +++ b/SerialPrograms/Source/Pokemon/Pokemon_NameReader.h @@ -0,0 +1,35 @@ +/* Pokemon Name Reader + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_Pokemon_PokemonNameReader_H +#define PokemonAutomation_Pokemon_PokemonNameReader_H + +#include +#include "CommonFramework/OCR/LargeDictionaryMatcher.h" + +namespace PokemonAutomation{ +namespace Pokemon{ + + +class PokemonNameReader : public OCR::LargeDictionaryMatcher{ +public: + PokemonNameReader(); + + OCR::MatchResult read_exact( + Language language, + const QImage& image + ) const; + OCR::MatchResult read_exact( + Language language, + const std::string& expected, + const QImage& image + ) const; +}; + + +} +} +#endif diff --git a/SerialPrograms/Source/Pokemon/Pokemon_TrainIVCheckerOCR.cpp b/SerialPrograms/Source/Pokemon/Pokemon_TrainIVCheckerOCR.cpp new file mode 100644 index 0000000000..3b7b56c2df --- /dev/null +++ b/SerialPrograms/Source/Pokemon/Pokemon_TrainIVCheckerOCR.cpp @@ -0,0 +1,77 @@ +/* Train IV Checker OCR Data + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include "Common/Cpp/PrettyPrint.h" +#include "Common/Cpp/ParallelTaskRunner.h" +#include "CommonFramework/PersistentSettings.h" +#include "CommonFramework/Language.h" +#include "CommonFramework/OCR/RawOCR.h" +#include "CommonFramework/OCR/Filtering.h" +#include "CommonFramework/OCR/TextMatcher.h" +#include "CommonFramework/OCR/TrainingTools.h" +#include "Pokemon_TrainIVCheckerOCR.h" + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ +namespace Pokemon{ + + +TrainIVCheckerOCR_Descriptor::TrainIVCheckerOCR_Descriptor() + : RunnableComputerProgramDescriptor( + "PokemonSwSh:TrainIVCheckerOCR", + "Train IV Checker OCR", + "", + "Train IV Checker OCR" + ) +{} + + + +TrainIVCheckerOCR::TrainIVCheckerOCR(const TrainIVCheckerOCR_Descriptor& descriptor) + : RunnableComputerProgramInstance(descriptor) + , DIRECTORY( + "Training Data Directory: (Relative to \"TrainingData/\")", + "IVCheckerOCR/" + ) + , MODE( + "Mode:", + { + "Start Fresh: Use only baseline strings. (1st candidate of each entry in above path)", + "Incremental: Build off of the existing training data in the above path.", + }, + 0 + ) + , THREADS( + "Worker Threads:", + std::thread::hardware_concurrency() + ) +{ + m_options.emplace_back(&DIRECTORY, "DIRECTORY"); + m_options.emplace_back(&MODE, "MODE"); + m_options.emplace_back(&THREADS, "THREADS"); +} + + + +void TrainIVCheckerOCR::program(ProgramEnvironment& env){ + OCR::TrainingSession session(env, DIRECTORY); + session.generate_small_dictionary( + env, + "PokemonSwSh/IVCheckerOCR.json", + "IVCheckerOCR.json", + MODE != 0, + THREADS + ); +} + + + +} +} diff --git a/SerialPrograms/Source/Pokemon/Pokemon_TrainIVCheckerOCR.h b/SerialPrograms/Source/Pokemon/Pokemon_TrainIVCheckerOCR.h new file mode 100644 index 0000000000..a26034041f --- /dev/null +++ b/SerialPrograms/Source/Pokemon/Pokemon_TrainIVCheckerOCR.h @@ -0,0 +1,43 @@ +/* Train IV Checker OCR Data + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PokemonSwSh_TrainIVCheckerOCR_H +#define PokemonAutomation_PokemonSwSh_TrainIVCheckerOCR_H + +#include "CommonFramework/Options/SimpleInteger.h" +#include "CommonFramework/Options/String.h" +#include "CommonFramework/Options/EnumDropdown.h" +#include "CommonFramework/Panels/RunnableComputerProgram.h" + +namespace PokemonAutomation{ +namespace Pokemon{ + + +class TrainIVCheckerOCR_Descriptor : public RunnableComputerProgramDescriptor{ +public: + TrainIVCheckerOCR_Descriptor(); +}; + + + +class TrainIVCheckerOCR : public RunnableComputerProgramInstance{ +public: + TrainIVCheckerOCR(const TrainIVCheckerOCR_Descriptor& descriptor); + + virtual void program(ProgramEnvironment& env) override; + +private: + String DIRECTORY; + EnumDropdown MODE; + SimpleInteger THREADS; + +}; + + + +} +} +#endif diff --git a/SerialPrograms/Source/Pokemon/Pokemon_TrainPokemonOCR.cpp b/SerialPrograms/Source/Pokemon/Pokemon_TrainPokemonOCR.cpp new file mode 100644 index 0000000000..d2d42d4018 --- /dev/null +++ b/SerialPrograms/Source/Pokemon/Pokemon_TrainPokemonOCR.cpp @@ -0,0 +1,76 @@ +/* Train Pokemon Name OCR + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include "Common/Cpp/PrettyPrint.h" +#include "Common/Cpp/ParallelTaskRunner.h" +#include "CommonFramework/PersistentSettings.h" +#include "CommonFramework/Language.h" +#include "CommonFramework/OCR/RawOCR.h" +#include "CommonFramework/OCR/Filtering.h" +#include "CommonFramework/OCR/LargeDictionaryMatcher.h" +#include "CommonFramework/OCR/TrainingTools.h" +#include "Pokemon_TrainPokemonOCR.h" + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ +namespace Pokemon{ + + +TrainPokemonOCR_Descriptor::TrainPokemonOCR_Descriptor() + : RunnableComputerProgramDescriptor( + "PokemonSwSh:TrainPokemonNameOCR", + "Train " + STRING_POKEMON + " Name OCR", + "", + "Train " + STRING_POKEMON + " Name OCR" + ) +{} + + + +TrainPokemonOCR::TrainPokemonOCR(const TrainPokemonOCR_Descriptor& descriptor) + : RunnableComputerProgramInstance(descriptor) + , DIRECTORY( + "Training Data Directory: (Relative to \"TrainingData/\")", + "PokemonNameOCR/" + ) + , MODE( + "Mode:", + { + "Start Fresh: Use only baseline strings. (1st candidate of each entry in above path)", + "Incremental: Build off of the existing training data in the above path.", + }, + 0 + ) + , THREADS( + "Worker Threads:", + std::thread::hardware_concurrency() + ) +{ + m_options.emplace_back(&DIRECTORY, "DIRECTORY"); + m_options.emplace_back(&MODE, "MODE"); + m_options.emplace_back(&THREADS, "THREADS"); +} + + +void TrainPokemonOCR::program(ProgramEnvironment& env){ + OCR::TrainingSession session(env, DIRECTORY); + session.generate_large_dictionary( + env, + "Pokemon/PokemonNameOCR/", + "PokemonOCR-", + MODE != 0, + THREADS + ); +} + + +} +} + diff --git a/SerialPrograms/Source/Pokemon/Pokemon_TrainPokemonOCR.h b/SerialPrograms/Source/Pokemon/Pokemon_TrainPokemonOCR.h new file mode 100644 index 0000000000..bf9798de74 --- /dev/null +++ b/SerialPrograms/Source/Pokemon/Pokemon_TrainPokemonOCR.h @@ -0,0 +1,43 @@ +/* Train Pokemon Name OCR + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_Pokemon_TrainPokemonOCR_H +#define PokemonAutomation_Pokemon_TrainPokemonOCR_H + +#include "CommonFramework/Options/SimpleInteger.h" +#include "CommonFramework/Options/String.h" +#include "CommonFramework/Options/EnumDropdown.h" +#include "CommonFramework/Panels/RunnableComputerProgram.h" + +namespace PokemonAutomation{ +namespace Pokemon{ + + +class TrainPokemonOCR_Descriptor : public RunnableComputerProgramDescriptor{ +public: + TrainPokemonOCR_Descriptor(); +}; + + + +class TrainPokemonOCR : public RunnableComputerProgramInstance{ +public: + TrainPokemonOCR(const TrainPokemonOCR_Descriptor& descriptor); + + virtual void program(ProgramEnvironment& env) override; + +private: + String DIRECTORY; + EnumDropdown MODE; + SimpleInteger THREADS; + +}; + + + +} +} +#endif diff --git a/SerialPrograms/Source/PokemonBDSP/Panels_PokemonBDSP.cpp b/SerialPrograms/Source/PokemonBDSP/Panels_PokemonBDSP.cpp new file mode 100644 index 0000000000..02e17d5935 --- /dev/null +++ b/SerialPrograms/Source/PokemonBDSP/Panels_PokemonBDSP.cpp @@ -0,0 +1,32 @@ +/* Pokemon BD/SP Panels + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "Common/Qt/QtJsonTools.h" +#include "CommonFramework/PersistentSettings.h" +#include "CommonFramework/Windows/MainWindow.h" +#include "Panels_PokemonBDSP.h" + + + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonBDSP{ + + +Panels::Panels(QTabWidget& parent, PanelListener& listener) + : PanelList(parent, "BD/SP", listener) +{ + PersistentSettings& settings = PERSISTENT_SETTINGS(); + + + finish_panel_setup(); +} + + + +} +} +} diff --git a/SerialPrograms/Source/PokemonBDSP/Panels_PokemonBDSP.h b/SerialPrograms/Source/PokemonBDSP/Panels_PokemonBDSP.h new file mode 100644 index 0000000000..e079435e96 --- /dev/null +++ b/SerialPrograms/Source/PokemonBDSP/Panels_PokemonBDSP.h @@ -0,0 +1,27 @@ +/* Pokemon BD/SP Panels + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PokemonBDSPPanels_H +#define PokemonAutomation_PokemonBDSPPanels_H + +#include "CommonFramework/Panels/PanelList.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonBDSP{ + + +class Panels : public PanelList{ +public: + Panels(QTabWidget& parent, PanelListener& listener); +}; + + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_BattleMenuDetector.cpp b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_BattleMenuDetector.cpp index 4ea83a668f..425124e358 100644 --- a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_BattleMenuDetector.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_BattleMenuDetector.cpp @@ -7,6 +7,7 @@ * */ +#include "Common/Compiler.h" #include "CommonFramework/Inference/ImageTools.h" #include "CommonFramework/Inference/ColorClustering.h" #include "PokemonSwSh_BattleMenuDetector.h" @@ -32,6 +33,12 @@ StandardBattleMenuDetector::StandardBattleMenuDetector(VideoFeed& feed) , m_text_bag (feed, 0.830, 0.576 + 2 * 0.1075, 0.08, 0.080) , m_text_run (feed, 0.830, 0.576 + 3 * 0.1075, 0.08, 0.080) {} +bool StandardBattleMenuDetector::on_frame( + const QImage& frame, + std::chrono::system_clock::time_point timestamp +){ + return detect(frame); +} bool StandardBattleMenuDetector::detect(const QImage& image) const{ bool fight; diff --git a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_BattleMenuDetector.h b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_BattleMenuDetector.h index f987fb867d..a367964fc8 100644 --- a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_BattleMenuDetector.h +++ b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_BattleMenuDetector.h @@ -11,17 +11,23 @@ #define PokemonAutomation_PokemonSwSh_BattleMenuDetector_H #include "CommonFramework/Tools/VideoFeed.h" +#include "CommonFramework/Inference/VisualInferenceCallback.h" namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class StandardBattleMenuDetector{ +class StandardBattleMenuDetector : public VisualInferenceCallbackWithCommandStop{ public: StandardBattleMenuDetector(VideoFeed& feed); bool detect(const QImage& image) const; + virtual bool on_frame( + const QImage& frame, + std::chrono::system_clock::time_point timestamp + ) override final; + private: InferenceBoxScope m_icon_fight; diff --git a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_BeamSetter.cpp b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_BeamSetter.cpp index 5e08521983..ecae7cd510 100644 --- a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_BeamSetter.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_BeamSetter.cpp @@ -7,11 +7,17 @@ * */ +#include "Common/Compiler.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "CommonFramework/Inference/ImageTools.h" #include "CommonFramework/Inference/InferenceThrottler.h" +#include "CommonFramework/Inference/StatAccumulator.h" +#include "CommonFramework/Inference/TimeWindowStatTracker.h" #include "PokemonSwSh_BeamSetter.h" +//#include "CommonFramework/Inference/FillGeometry.h" + #include using std::cout; using std::endl; @@ -25,16 +31,83 @@ BeamSetter::BeamSetter(VideoFeed& feed, Logger& logger) : m_feed(feed) , m_logger(logger) , m_text_box(feed, Qt::red, 0.400, 0.825, 0.05, 0.05) - , m_box(feed, Qt::red, 0.10, 0.2, 0.8, 0.275) + , m_box(feed, Qt::red, 0.10, 0.005, 0.8, 0.470) { for (size_t c = 0; c < 32; c++){ - m_boxes.emplace_back(0.10 + 0.025*c, 0.2, 0.025, 0.275); + m_boxes.emplace_back(0.10 + 0.025*c, 0.005, 0.025, 0.470); } } + + +struct PurpleDetectionEntry{ +#if 0 + double stddev; + double brightness; + double euclidean_delta; +#endif +}; +struct PurpleDetectionAccumulator{ + using StatObject = PurpleDetectionEntry; + +#if 0 + PurpleDetectionEntry oldest; + PurpleDetectionEntry newest; + + double delta_stddev () const{ return newest.stddev - oldest.stddev; } + double delta_brightness () const{ return newest.brightness - oldest.brightness; } + double delta_euclidean () const{ return newest.euclidean_delta - oldest.euclidean_delta; } + + double brightness_ratio () const{ return (768 - newest.brightness) / (768 - oldest.brightness); } +#endif +}; + +//struct ImageDelta{ +// double average_euclidean; +//}; +//struct ImageDeltaAccumulator{ +// +//}; + + + +#if 0 +struct PurpleBeamFilter{ + size_t count = 0; + + void operator()(FillMatrix::ObjectID& cell, const QImage& image, int x, int y){ + QRgb pixel = image.pixel(x, y); + int set = (pixel & 0x00c0c0c0) == 0x00c0c0c0 ? 1 : 0; + cell = set; + count += set; + } +}; + +struct PurpleBeamFilterDebug{ + size_t count = 0; + + void operator()(FillMatrix::ObjectID& cell, QImage& image, int x, int y){ + QRgb pixel = image.pixel(x, y); + int set = (pixel & 0x00c0c0c0) == 0x00c0c0c0 ? 1 : 0; + cell = set; + if (cell == 0){ + image.setPixel(x, y, 0); + } + count += set; + } +}; +#endif + + + BeamSetter::Detection BeamSetter::run( ProgramEnvironment& env, BotBase& botbase, - double detection_threshold, uint16_t timeout_ticks + bool save_screenshot, + uint16_t timeout_ticks, + double min_brightness, + double min_euclidean, + double min_delta_ratio, + double min_sigma_ratio ){ // Grab baseline image. QImage baseline_image = m_feed.snapshot(); @@ -45,9 +118,11 @@ BeamSetter::Detection BeamSetter::run( // baseline_image.save("f:/test0.jpg"); // cout << "=======================" << endl; + std::vector baseline_values(m_boxes.size()); std::vector baseline_ratios(m_boxes.size()); for (size_t c = 0; c < m_boxes.size(); c++){ - baseline_ratios[c] = pixel_average_normalized(extract_box(baseline_image, m_boxes[c])); + baseline_values[c] = pixel_average(extract_box(baseline_image, m_boxes[c])); + baseline_ratios[c] = baseline_values[c] / baseline_values[c].sum(); } // Drop the wishing piece. @@ -55,110 +130,166 @@ BeamSetter::Detection BeamSetter::run( botbase.wait_for_all_requests(); // Set up detection history. - std::map red_detections; - std::map purple_detections; +// std::map red_detections; +// std::map purple_detections; bool low_stddev_flag = false; - std::vector current_values(m_boxes.size()); - std::vector current_ratio_diffs(m_boxes.size()); +// std::vector current_values(m_boxes.size()); +// std::vector current_ratio_diffs(m_boxes.size()); + +// static size_t c = 0; + +// std::vector> trackers; + std::vector> trackers; + for (size_t c = 0; c < m_boxes.size(); c++){ + trackers.emplace_back(std::chrono::milliseconds(1000)); + } + +// std::vector large_sigmas(m_boxes.size()); + + InferenceThrottler throttler( + std::chrono::milliseconds((uint64_t)timeout_ticks * 1000 / TICKS_PER_SECOND), + std::chrono::milliseconds(50) + ); - InferenceThrottler throttler(std::chrono::milliseconds((uint64_t)timeout_ticks * 1000 / TICKS_PER_SECOND)); +// static size_t count = 0; + + QImage last_screenshot = baseline_image; do{ // Take screenshot. - QImage current = m_feed.snapshot(); - if (current.isNull()){ + QImage current_screenshot = m_feed.snapshot(); + if (current_screenshot.isNull()){ m_logger.log("BeamSetter(): Screenshot failed.", "purple"); return Detection::NO_DETECTION; } // current.save("f:/test1.jpg"); // Text detection. - double text_stddev = pixel_stddev(extract_box(current, m_text_box)).sum(); + double text_stddev = pixel_stddev(extract_box(current_screenshot, m_text_box)).sum(); if (text_stddev < 10){ low_stddev_flag = true; } - // Compute ratios. - FloatPixel average_diff; - for (size_t c = 0; c < m_boxes.size(); c++){ - current_values[c] = pixel_average(extract_box(current, m_boxes[c])); - FloatPixel ratio = current_values[c] / current_values[c].sum(); - current_ratio_diffs[c] = ratio - baseline_ratios[c]; -// cout << c << " - " << current_ratio_diffs[c] << endl; - average_diff += current_ratio_diffs[c]; - } - average_diff /= m_boxes.size(); +// FillMatrix matrix(current_screenshot); +// PurpleBeamFilterDebug filter; +// matrix.apply_filter(current_screenshot, filter); + +// current_screenshot.save("test-" + QString::number(count++) + ".png"); + + +#if 1 + QImage baseline_diff = image_diff_greyscale(baseline_image, current_screenshot); +// baseline_diff.save("diff-" + QString::number(c++) + ".png"); + auto now = std::chrono::system_clock::now(); - // Detect all columns. - double max_red_diff = -1.0; - size_t max_red_diff_index = 0; - double min_stddev = 255; - size_t min_stddev_index = 0; + bool purple = false; + size_t best_index = 0; + double best_euclidean = 0; + double best_stddev = 0; + double best_brightness = 0; +// PurpleDetectionAccumulator max_diff_delta; +// FloatStatAccumulator max_diff_delta; + double best_delta = 0; + double best_sigma = 0; for (size_t c = 0; c < m_boxes.size(); c++){ - FloatPixel diff = current_ratio_diffs[c] - average_diff; -// cout << "current_values[" << c << "] = " << current_values[c] << ", " << diff << endl; - double stddev = current_values[c].stddev(); - if (max_red_diff < diff.r){ - max_red_diff = diff.r; - max_red_diff_index = c; - } - if (min_stddev > stddev){ - min_stddev = stddev; - min_stddev_index = c; - } -// cout << c << " : stddev = " << stddev << ", sum = " << current_values[c].sum() << endl; - if (stddev < 50 && current_values[c].sum() > 500){ - size_t& count = purple_detections[c]; - count++; + FloatStatAccumulator stats = trackers[c].accumulate_all(); + + QImage previous_box = extract_box(last_screenshot, m_boxes[c]); + QImage current_box = extract_box(current_screenshot, m_boxes[c]); + + FloatPixel current_average = pixel_average(current_box); + double delta = image_diff_total(current_box, previous_box); + + double sigma = 0; + if (stats.count() >= 5){ + sigma = stats.diff_metric(delta); +// cout << sigma << endl; } - if (diff.r > detection_threshold){ - size_t& count = red_detections[c]; - count++; + + double stddev = current_average.stddev(); + double brightness = current_average.sum(); + double average_euclidean_diff = pixel_average(extract_box(baseline_diff, m_boxes[c])).r; + +#if 0 + trackers[c].push( + PurpleDetectionEntry{ + stddev, + brightness, + average_euclidean_diff + }, + now + ); +// PurpleDetectionAccumulator delta = trackers[c].accumulate_all(); + const PurpleDetectionEntry& oldest = trackers[c].oldest(); + const PurpleDetectionEntry& newest = trackers[c].newest(); + PurpleDetectionAccumulator delta{oldest, newest}; +#endif + + if (best_sigma <= sigma){ + best_index = c; + best_euclidean = average_euclidean_diff; + best_stddev = stddev; + best_brightness = brightness; +// max_diff_delta = delta; + best_delta = delta; + best_sigma = sigma; } - } - QString str = - "BeamReader(): r[" + QString::number(max_red_diff_index) + "] = " + - QString::number(current_ratio_diffs[max_red_diff_index].r - average_diff.r) + - ", b[" + QString::number(min_stddev_index) + "] = " + QString::number(min_stddev) + - ", t = " + QString::number(text_stddev); - m_logger.log(str, "purple"); - - if (!red_detections.empty()){ - str = "BeamReader(): Red = "; - size_t count = 0; - for (const auto& column : red_detections){ - count = std::max(count, column.second); - str += "[" + QString::number(column.second) + " x " + - QString::number(column.first) + "-" + - QString::number(current_ratio_diffs[column.first].r - average_diff.r) + "]"; + bool required = true; +// required &= stddev < absolute_stddev; + required &= brightness >= min_brightness; + required &= average_euclidean_diff >= min_euclidean; + + required &= delta / stddev >= min_delta_ratio; + required &= sigma / stddev >= min_sigma_ratio; + + if (required){ + purple = true; +// break; + }else{ + trackers[c].push(delta, now); } - m_logger.log(str, "purple"); - if (count >= 5){ - m_logger.log("BeamReader(): 5 positive red reads. Red beam found.", "blue"); - return Detection::RED_DETECTED; + + if (best_sigma <= sigma && required == purple){ + best_index = c; + best_euclidean = average_euclidean_diff; + best_stddev = stddev; + best_brightness = brightness; +// max_diff_delta = delta; + best_delta = delta; + best_sigma = sigma; } } - if (!purple_detections.empty()){ - str = "BeamReader(): Purple = "; - size_t count = 0; - for (const auto& column : purple_detections){ - count = std::max(count, column.second); - str += "[" + QString::number(column.second) + " x " + - QString::number(column.first) + "-" + - current_values[column.first].to_string() + "]"; + + QString str = "BeamReader: column = " + QString::number(best_index); +// str += ", stddev = " + QString::number(max_diff_stddev) + " (" + QString::number(max_diff_delta.delta_stddev()) + ")"; +// str += ", brightness = " + QString::number(max_diff_brightness) + " (" + QString::number(max_diff_delta.brightness_ratio()) + ")"; +// str += ", euclidean = " + QString::number(max_diff) + " (" + QString::number(max_diff_delta.delta_euclidean()) + ")"; + + str += ", stddev = " + QString::number(best_stddev); + str += ", brightness = " + QString::number(best_brightness); + str += ", euclidean = " + QString::number(best_euclidean); + str += ", delta = " + QString::number(best_delta); + str += ", sigma = " + QString::number(best_sigma); + + if (purple){ + m_logger.log(str, "blue"); + m_logger.log("BeamReader(): Purple beam found!", "blue"); + if (save_screenshot){ + current_screenshot.save(QString("PurpleBeam-") + now_to_filestring().c_str() + ".png"); } + return Detection::PURPLE; + }else{ m_logger.log(str, "purple"); - if (count >= 1){ - m_logger.log("BeamReader(): Purple beam found!", "blue"); - return Detection::PURPLE; - } } + if (low_stddev_flag && text_stddev > 100){ m_logger.log("BeamReader(): No beam detected with text. Resetting.", "blue"); return Detection::RED_ASSUMED; } +#endif + last_screenshot = std::move(current_screenshot); }while (!throttler.end_iteration(env)); return Detection::NO_DETECTION; diff --git a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_BeamSetter.h b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_BeamSetter.h index c1904b9d9f..3bdb9a2a96 100644 --- a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_BeamSetter.h +++ b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_BeamSetter.h @@ -34,7 +34,12 @@ class BeamSetter{ Detection run( ProgramEnvironment& env, BotBase& botbase, - double detection_threshold, uint16_t timeout_ticks + bool save_screenshot, + uint16_t timeout_ticks, + double min_brightness, + double min_euclidean, + double min_delta_ratio, + double min_sigma_ratio ); diff --git a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_FishingDetector.cpp b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_FishingDetector.cpp index a2bd4625ed..e498422c60 100644 --- a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_FishingDetector.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_FishingDetector.cpp @@ -18,7 +18,7 @@ FishingDetector::FishingDetector( VideoFeed& feed ) : m_feed(feed) - , m_hook_box(feed, 0.4, 0.15, 0.2, 0.4) + , m_hook_box(feed, 0.1, 0.15, 0.8, 0.4) , m_miss_box(feed, 0.3, 0.9, 0.4, 0.05) , m_battle_menu(feed) {} @@ -40,6 +40,14 @@ FishingDetector::Detection FishingDetector::detect_now(){ std::vector exclamation_marks; find_marks(hook_image, &exclamation_marks, nullptr); + for (const PixelBox& mark : exclamation_marks){ + InferenceBox box = translate_to_parent(screen, m_hook_box, mark); + box.color = Qt::yellow; + box.x -= box.width * 1.5; + box.width *= 4; + box.height *= 1.5; + m_marks.emplace_back(m_feed, box); + } return exclamation_marks.empty() ? Detection::NO_DETECTION diff --git a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_FishingDetector.h b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_FishingDetector.h index 5cc4dc61e0..b362efd99e 100644 --- a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_FishingDetector.h +++ b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_FishingDetector.h @@ -45,6 +45,7 @@ class FishingDetector{ InferenceBoxScope m_hook_box; InferenceBoxScope m_miss_box; StandardBattleMenuDetector m_battle_menu; + std::deque m_marks; }; diff --git a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_IVCheckerReader.cpp b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_IVCheckerReader.cpp new file mode 100644 index 0000000000..516a8eff8e --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_IVCheckerReader.cpp @@ -0,0 +1,121 @@ +/* IV Checker Reader + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "Common/Cpp/Exception.h" +#include "Common/Qt/QtJsonTools.h" +#include "CommonFramework/Inference/ImageTools.h" +#include "CommonFramework/OCR/RawOCR.h" +#include "CommonFramework/OCR/Filtering.h" +#include "PokemonSwSh_IVCheckerReader.h" + +#include +using std::cout; +using std::endl; + + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +const std::map IVCheckerReader::m_token_to_enum{ + {"No Good", NoGood}, + {"Decent", Decent}, + {"Pretty Good", PrettyGood}, + {"Very Good", VeryGood}, + {"Fantastic", Fantastic}, + {"Best", Best}, + {"Hyper trained!", HyperTrained}, +}; +const std::map IVCheckerReader::m_enum_to_token{ + {UnableToDetect, "Unable to Detect"}, + {NoGood, "No Good"}, + {Decent, "Decent"}, + {PrettyGood, "Pretty Good"}, + {VeryGood, "Very Good"}, + {Fantastic, "Fantastic"}, + {Best, "Best"}, + {HyperTrained, "Hyper trained!"}, +}; + + + +IVCheckerReader::IVCheckerReader() + : SmallDictionaryMatcher("PokemonSwSh/IVCheckerOCR.json") +{} + +IVCheckerReader::Result IVCheckerReader::token_to_enum(const std::string& token){ + auto iter = m_token_to_enum.find(token); + if (iter == m_token_to_enum.end()){ + return Result::UnableToDetect; + } + return iter->second; +} +const std::string& IVCheckerReader::enum_to_token(Result result){ + auto iter = m_enum_to_token.find(result); + if (iter == m_enum_to_token.end()){ + PA_THROW_StringException("Invalid IV result enum."); + } + return iter->second; +} + + + + +IVCheckerReaderScope::IVCheckerReaderScope(const IVCheckerReader& reader, VideoFeed& feed, Language language) + : m_reader(reader) + , m_language(language) + , m_box0(feed, InferenceBox(0.777, 0.198 + 0 * 0.0515, 0.2, 0.0515)) + , m_box1(feed, InferenceBox(0.777, 0.198 + 1 * 0.0515, 0.2, 0.0515)) + , m_box2(feed, InferenceBox(0.777, 0.198 + 2 * 0.0515, 0.2, 0.0515)) + , m_box3(feed, InferenceBox(0.777, 0.198 + 3 * 0.0515, 0.2, 0.0515)) + , m_box4(feed, InferenceBox(0.777, 0.198 + 4 * 0.0515, 0.2, 0.0515)) + , m_box5(feed, InferenceBox(0.777, 0.198 + 5 * 0.0515, 0.2, 0.0515)) +{} + + +IVCheckerReader::Result IVCheckerReaderScope::read(Logger* logger, const QImage& frame, const InferenceBoxScope& box){ + QImage image = extract_box(frame, box); + OCR::make_OCR_filter(image).apply(image); +// image.save("test.png"); + + QString text = OCR::ocr_read(m_language, image); + + OCR::MatchResult result = m_reader.match_substring(m_language, text); + result.log(logger); + if (!result.matched || result.tokens.size() != 1){ + return IVCheckerReader::Result::UnableToDetect; + } + return IVCheckerReader::token_to_enum(*result.tokens.begin()); +} +IVCheckerReader::Results IVCheckerReaderScope::read(Logger* logger, const QImage& frame){ + IVCheckerReader::Results results; + results.hp = read(logger, frame, m_box0); + results.attack = read(logger, frame, m_box1); + results.defense = read(logger, frame, m_box2); + results.spatk = read(logger, frame, m_box3); + results.spdef = read(logger, frame, m_box4); + results.speed = read(logger, frame, m_box5); + return results; +} + +std::vector IVCheckerReaderScope::dump_images(const QImage& frame){ + std::vector images; + images.emplace_back(extract_box(frame, m_box0)); + images.emplace_back(extract_box(frame, m_box1)); + images.emplace_back(extract_box(frame, m_box2)); + images.emplace_back(extract_box(frame, m_box3)); + images.emplace_back(extract_box(frame, m_box4)); + images.emplace_back(extract_box(frame, m_box5)); + return images; +} + + + +} +} +} + diff --git a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_IVCheckerReader.h b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_IVCheckerReader.h new file mode 100644 index 0000000000..d5f0785c5e --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_IVCheckerReader.h @@ -0,0 +1,83 @@ +/* IV Checker Reader + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PokemonSwSh_IVCheckerReader_H +#define PokemonAutomation_PokemonSwSh_IVCheckerReader_H + +#include "CommonFramework/Language.h" +#include "CommonFramework/Tools/VideoFeed.h" +#include "CommonFramework/Tools/ProgramEnvironment.h" +#include "CommonFramework/OCR/SmallDictionaryMatcher.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +class IVCheckerReader : public OCR::SmallDictionaryMatcher{ +public: + enum Result{ + UnableToDetect, + NoGood, + Decent, + PrettyGood, + VeryGood, + Fantastic, + Best, + HyperTrained, + }; + + struct Results{ + Result hp; + Result attack; + Result defense; + Result spatk; + Result spdef; + Result speed; + }; + +public: + IVCheckerReader(); + +public: + static Result token_to_enum(const std::string& token); + static const std::string& enum_to_token(Result result); + +private: + static const std::map m_token_to_enum; + static const std::map m_enum_to_token; +}; + + +class IVCheckerReaderScope{ +public: + IVCheckerReaderScope(const IVCheckerReader& reader, VideoFeed& feed, Language language); + + IVCheckerReader::Results read(Logger* logger, const QImage& frame); + + std::vector dump_images(const QImage& frame); + +private: + IVCheckerReader::Result read(Logger* logger, const QImage& frame, const InferenceBoxScope& box); + +private: + const IVCheckerReader& m_reader; + Language m_language; + InferenceBoxScope m_box0; + InferenceBoxScope m_box1; + InferenceBoxScope m_box2; + InferenceBoxScope m_box3; + InferenceBoxScope m_box4; + InferenceBoxScope m_box5; +}; + + + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_RaidLobbyReader.h b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_RaidLobbyReader.h index 410103a1db..be0629ffdf 100644 --- a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_RaidLobbyReader.h +++ b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_RaidLobbyReader.h @@ -44,6 +44,14 @@ struct RaidLobbyState{ player2 != RaidLobbySlot::NOT_READY && player3 != RaidLobbySlot::NOT_READY; } + + size_t raiders() const{ + size_t count = 0; + if (player1 != RaidLobbySlot::EMPTY) count++; + if (player2 != RaidLobbySlot::EMPTY) count++; + if (player3 != RaidLobbySlot::EMPTY) count++; + return count; + } }; diff --git a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_ReceivePokemonDetector.cpp b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_ReceivePokemonDetector.cpp new file mode 100644 index 0000000000..e1a1a2391e --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_ReceivePokemonDetector.cpp @@ -0,0 +1,84 @@ +/* Receive Pokemon (Orange Background) Detector + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "Common/Compiler.h" +#include "CommonFramework/Inference/ImageTools.h" +#include "PokemonSwSh_ReceivePokemonDetector.h" + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +ReceivePokemonDetector::ReceivePokemonDetector( + VideoFeed& feed +) + : m_box(feed, 0.2, 0.1, 0.6, 0.1) + , m_has_been_orange(false) +{} +ReceivePokemonDetector::ReceivePokemonDetector( + VideoFeed& feed, + const InferenceBox& box +) + : m_box(feed, box) + , m_has_been_orange(false) +{} + + +bool ReceivePokemonDetector::on_frame( + const QImage& frame, + std::chrono::system_clock::time_point timestamp +){ + return receive_is_over(frame); +} +bool ReceivePokemonDetector::receive_is_over(const QImage& frame){ + QImage image = extract_box(frame, m_box); +// QImage image = m_feed.snapshot(); +// if (image.isNull()){ +// m_logger.log("BlackScreenDetector(): Screenshot failed.", "purple"); +// return false; +// } + +// ImageStats stats = pixel_stats(image); +// double average = stats.average.sum(); +// double stddev = stats.stddev.sum(); +// cout << stats.average << endl; +// m_logger.log("BlackScreenDetector(): a = " + QString::number(average) + ", s = " + QString::number(stddev), "purple"); +// if (average < 100 && stddev < 10){ + + + ImageStats stats = pixel_stats(image); + FloatPixel expected(193, 78, 56); + FloatPixel actual = stats.average; + + expected /= expected.sum(); + actual /= actual.sum(); + + double distance = euclidean_distance(expected, actual); + +// cout << "average = " << stats.average << ", stddev = " << stats.stddev << ", distance = " << distance << endl; +// cout << "m_has_been_orange = " << m_has_been_orange << endl; + +// double average = stats.average.sum(); +// double stddev = stats.stddev.sum(); +// return average <= max_rgb_sum && stddev <= max_stddev_sum; + + + if (stats.stddev.sum() < 10 && distance < 0.2){ + m_has_been_orange = true; + return false; + } + return m_has_been_orange; +} + + +} +} +} diff --git a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_ReceivePokemonDetector.h b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_ReceivePokemonDetector.h new file mode 100644 index 0000000000..d1c6943a0d --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_ReceivePokemonDetector.h @@ -0,0 +1,43 @@ +/* Receive Pokemon (Orange Background) Detector + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + * + * Returns true after a orange background has been detected + * and has ended. + * + */ + +#ifndef PokemonAutomation_CommonFramework_ReceivePokemonDetector_H +#define PokemonAutomation_CommonFramework_ReceivePokemonDetector_H + +#include "CommonFramework/Tools/VideoFeed.h" +#include "CommonFramework/Tools/Logger.h" +#include "CommonFramework/Inference/VisualInferenceCallback.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +class ReceivePokemonDetector : public VisualInferenceCallbackWithCommandStop{ +public: + ReceivePokemonDetector(VideoFeed& feed); + ReceivePokemonDetector(VideoFeed& feed, const InferenceBox& box); + + bool receive_is_over(const QImage& frame); + virtual bool on_frame( + const QImage& frame, + std::chrono::system_clock::time_point timestamp + ) override; + +private: + InferenceBoxScope m_box; + bool m_has_been_orange; +}; + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_StartBattleDetector.cpp b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_StartBattleDetector.cpp index c3387b2135..bb07a1a05a 100644 --- a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_StartBattleDetector.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_StartBattleDetector.cpp @@ -4,8 +4,10 @@ * */ +#include "Common/Compiler.h" #include "CommonFramework/Inference/ImageTools.h" #include "CommonFramework/Inference/InferenceThrottler.h" +#include "CommonFramework/Inference/VisualInferenceWait.h" #include "PokemonSwSh_StartBattleDetector.h" #include @@ -39,7 +41,61 @@ bool is_dialog_grey(const QImage& image){ -StartBattleDetector::StartBattleDetector( +StartBattleDetector::StartBattleDetector(VideoFeed& feed) + : m_screen_box(feed, 0.2, 0.2, 0.6, 0.6) + , m_dialog_box(feed, 0.50, 0.89, 0.40, 0.07) +{} +bool StartBattleDetector::on_frame( + const QImage& frame, + std::chrono::system_clock::time_point timestamp +){ + return detect(frame); +} + +bool StartBattleDetector::detect(const QImage& frame){ + QImage image0 = extract_box(frame, m_screen_box); + QImage image1 = extract_box(frame, m_dialog_box); + + ImageStats stats0 = pixel_stats(image0); + ImageStats stats1 = pixel_stats(image1); +// cout << "mean = " << stats.average << ", stddev = " << stats.stddev << endl; +// return stats.stddev.sum() < 10; + + // White screen. + if ( + stats0.average.sum() > 600 && stats0.stddev.sum() < 10 && + stats1.average.sum() > 600 && stats1.stddev.sum() < 10 + ){ + return true; + } + + // Grey text box. + bool dialog = stats0.stddev.sum() > 50 && is_dialog_grey(stats1); + if (dialog){ +// cout << stats0.stddev.sum() << endl; + } + return dialog; +} + + + + +bool wait_for_start_battle( + ProgramEnvironment& env, + VideoFeed& feed, + std::chrono::milliseconds timeout +){ + VisualInferenceWait inference(env, feed, timeout); + StartBattleDetector detector(feed); + inference += detector; + return inference.run(); +} + + + +#if 1 + +TimedStartBattleDetector::TimedStartBattleDetector( VideoFeed& feed, std::chrono::milliseconds timeout ) @@ -50,10 +106,10 @@ StartBattleDetector::StartBattleDetector( , m_start_time(std::chrono::system_clock::now()) {} -bool StartBattleDetector::has_timed_out() const{ +bool TimedStartBattleDetector::has_timed_out() const{ return std::chrono::system_clock::now() - m_start_time > m_timeout; } -bool StartBattleDetector::detect(const QImage& screen){ +bool TimedStartBattleDetector::detect(const QImage& screen){ QImage image0 = extract_box(screen, m_screen_box); QImage image1 = extract_box(screen, m_dialog_box); @@ -77,7 +133,7 @@ bool StartBattleDetector::detect(const QImage& screen){ } return dialog; } -bool StartBattleDetector::wait(ProgramEnvironment& env){ +bool TimedStartBattleDetector::wait(ProgramEnvironment& env){ InferenceThrottler throttler(m_timeout, std::chrono::milliseconds(50)); while (true){ env.check_stopping(); @@ -98,7 +154,7 @@ bool StartBattleDetector::wait(ProgramEnvironment& env){ AsyncStartBattleDetector::AsyncStartBattleDetector(ProgramEnvironment& env, VideoFeed& feed) - : StartBattleDetector(feed, std::chrono::milliseconds(0)) + : TimedStartBattleDetector(feed, std::chrono::milliseconds(0)) , m_stopping(false) , m_detected(false) , m_thread(&AsyncStartBattleDetector::thread_loop, this, std::ref(env)) @@ -114,21 +170,21 @@ bool AsyncStartBattleDetector::detected() const{ void AsyncStartBattleDetector::thread_loop(ProgramEnvironment& env){ InferenceThrottler throttler(m_timeout, std::chrono::milliseconds(50)); - while (!m_stopping.load(std::memory_order_acquire) && !detected()){ - env.check_stopping(); + try{ + while (!m_stopping.load(std::memory_order_acquire) && !detected()){ + env.check_stopping(); - QImage screen = m_feed.snapshot(); - if (detect(screen)){ - m_detected.store(true, std::memory_order_release); - } + QImage screen = m_feed.snapshot(); + if (detect(screen)){ + m_detected.store(true, std::memory_order_release); + } - if (throttler.end_iteration(env)){ - env.log("StartBattleDetector: Timed out.", "red"); - return; + throttler.end_iteration(env); } - } + }catch (CancelledException&){} } +#endif diff --git a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_StartBattleDetector.h b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_StartBattleDetector.h index e12e9f3ecb..bd35ac2797 100644 --- a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_StartBattleDetector.h +++ b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_StartBattleDetector.h @@ -7,10 +7,13 @@ #ifndef PokemonAutomation_PokemonSwSh_StartBattleDetector_H #define PokemonAutomation_PokemonSwSh_StartBattleDetector_H +#include #include +#include #include "CommonFramework/Tools/Logger.h" #include "CommonFramework/Tools/VideoFeed.h" #include "CommonFramework/Tools/ProgramEnvironment.h" +#include "CommonFramework/Inference/VisualInferenceCallback.h" namespace PokemonAutomation{ namespace NintendoSwitch{ @@ -21,9 +24,41 @@ namespace PokemonSwSh{ bool is_dialog_grey(const QImage& image); -class StartBattleDetector{ +// Return false if timed out. +bool wait_for_start_battle( + ProgramEnvironment& env, + VideoFeed& feed, + std::chrono::milliseconds timeout +); + + + +class StartBattleDetector : public VisualInferenceCallbackWithCommandStop{ +public: + StartBattleDetector(VideoFeed& feed); + + bool detect(const QImage& frame); + + virtual bool on_frame( + const QImage& frame, + std::chrono::system_clock::time_point timestamp + ) override final; + +private: + InferenceBoxScope m_screen_box; + InferenceBoxScope m_dialog_box; +}; + + + + + +#if 1 +// Deprecated + +class TimedStartBattleDetector{ public: - StartBattleDetector( + TimedStartBattleDetector( VideoFeed& feed, std::chrono::milliseconds timeout ); @@ -41,7 +76,10 @@ class StartBattleDetector{ }; -class AsyncStartBattleDetector : public StartBattleDetector{ + + + +class AsyncStartBattleDetector : public TimedStartBattleDetector{ public: AsyncStartBattleDetector(ProgramEnvironment& env, VideoFeed& feed); ~AsyncStartBattleDetector(); @@ -59,7 +97,7 @@ class AsyncStartBattleDetector : public StartBattleDetector{ std::atomic m_detected; std::thread m_thread; }; - +#endif } diff --git a/SerialPrograms/Source/PokemonSwSh/InferenceTraining/PokemonSwSh_GenerateIVCheckerOCR.cpp b/SerialPrograms/Source/PokemonSwSh/InferenceTraining/PokemonSwSh_GenerateIVCheckerOCR.cpp new file mode 100644 index 0000000000..04ffd94b49 --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/InferenceTraining/PokemonSwSh_GenerateIVCheckerOCR.cpp @@ -0,0 +1,93 @@ +/* Generate IV Checker OCR Data + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include "Common/Cpp/PrettyPrint.h" +#include "PokemonSwSh_GenerateIVCheckerOCR.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +const std::string IVCheckerOptionOCR::TOKENS[]{ + "No Good", + "Decent", + "Pretty Good", + "Very Good", + "Fantastic", + "Best", + "Hyper trained!", +}; + + + +GenerateIVCheckerOCR_Descriptor::GenerateIVCheckerOCR_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:GenerateIVCheckerOCR", + "Generate IV Checker OCR Data", + "", + "Generate IV Checker OCR Data", + FeedbackType::REQUIRED, + PABotBaseLevel::PABOTBASE_12KB + ) +{} + + + +GenerateIVCheckerOCR::GenerateIVCheckerOCR(const GenerateIVCheckerOCR_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) + , LANGUAGE( + "Game Language:", + m_reader.languages() + ) + , HP("HP:") + , ATTACK("Attack:") + , DEFENSE("Defense:") + , SPATK("Sp. Atk:") + , SPDEF("Sp. Def:") + , SPEED("Speed:") +{ + m_options.emplace_back(&LANGUAGE, "LANGUAGE"); + m_options.emplace_back(&HP, "HP"); + m_options.emplace_back(&ATTACK, "ATTACK"); + m_options.emplace_back(&DEFENSE, "DEFENSE"); + m_options.emplace_back(&SPATK, "SPATK"); + m_options.emplace_back(&SPDEF, "SPDEF"); + m_options.emplace_back(&SPEED, "SPEED"); +} + + +void GenerateIVCheckerOCR::program(SingleSwitchProgramEnvironment& env){ + IVCheckerReaderScope reader(m_reader, env.console, LANGUAGE); + + QString path = "IVCheckerOCR/"; + path += language_data(LANGUAGE).code.c_str(); + + QDir dir(path); + if (!dir.exists()){ + dir.mkpath("."); + } + path += "/"; + + std::vector images = reader.dump_images(env.console.video().snapshot()); + + QString now = now_to_filestring().c_str(); + images[0].save(path + IVCheckerOptionOCR::TOKENS[HP].c_str() + "-" + now + "a.png"); + images[1].save(path + IVCheckerOptionOCR::TOKENS[ATTACK].c_str() + "-" + now + "b.png"); + images[2].save(path + IVCheckerOptionOCR::TOKENS[DEFENSE].c_str() + "-" + now + "c.png"); + images[3].save(path + IVCheckerOptionOCR::TOKENS[SPATK].c_str() + "-" + now + "d.png"); + images[4].save(path + IVCheckerOptionOCR::TOKENS[SPDEF].c_str() + "-" + now + "e.png"); + images[5].save(path + IVCheckerOptionOCR::TOKENS[SPEED].c_str() + "-" + now + "f.png"); + +} + + + +} +} +} + diff --git a/SerialPrograms/Source/PokemonSwSh/InferenceTraining/PokemonSwSh_GenerateIVCheckerOCR.h b/SerialPrograms/Source/PokemonSwSh/InferenceTraining/PokemonSwSh_GenerateIVCheckerOCR.h new file mode 100644 index 0000000000..c56d74268f --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/InferenceTraining/PokemonSwSh_GenerateIVCheckerOCR.h @@ -0,0 +1,92 @@ +/* Generate IV Checker OCR Data + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PokemonSwSh_GenerateIVCheckerOCR_H +#define PokemonAutomation_PokemonSwSh_GenerateIVCheckerOCR_H + +#include "CommonFramework/Options/EnumDropdown.h" +#include "CommonFramework/Options/LanguageOCR.h" +#include "PokemonSwSh/Inference/PokemonSwSh_IVCheckerReader.h" +#include "NintendoSwitch/Framework/SingleSwitchProgram.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +class IVCheckerOptionOCR : public EnumDropdown{ +public: + static const std::string TOKENS[]; + +public: + IVCheckerOptionOCR(QString label, size_t default_index = 0) + : EnumDropdown( + std::move(label), + { + "No Good (0)", + "Decent (0-15)", + "Pretty Good (16-25)", + "Very Good (26-29)", + "Fantastic (30)", + "Best (31)", + "Hyper trained!", + }, + default_index + ) + {} +}; + + + +class GenerateIVCheckerOCR_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + GenerateIVCheckerOCR_Descriptor(); +}; + + + +class GenerateIVCheckerOCR : public SingleSwitchProgramInstance{ +public: + enum Mode{ + READ_AND_SAVE, + GENERATE_TRAINING_DATA, + }; + +public: + GenerateIVCheckerOCR(const GenerateIVCheckerOCR_Descriptor& descriptor); + + virtual void program(SingleSwitchProgramEnvironment& env) override; + +private: + void read( + QJsonArray& output, + Logger* logger, + QImage image + ) const; + void dump_images( + const std::vector& expected, + size_t index, + QImage image + ) const; + +private: + IVCheckerReader m_reader; + + LanguageOCR LANGUAGE; + IVCheckerOptionOCR HP; + IVCheckerOptionOCR ATTACK; + IVCheckerOptionOCR DEFENSE; + IVCheckerOptionOCR SPATK; + IVCheckerOptionOCR SPDEF; + IVCheckerOptionOCR SPEED; +}; + + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonSwSh/InferenceTraining/PokemonSwSh_GenerateNameOCRPokedex.cpp b/SerialPrograms/Source/PokemonSwSh/InferenceTraining/PokemonSwSh_GenerateNameOCRPokedex.cpp new file mode 100644 index 0000000000..6b4b91a6f4 --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/InferenceTraining/PokemonSwSh_GenerateNameOCRPokedex.cpp @@ -0,0 +1,208 @@ +/* Generate Pokemon Name OCR Data (Pokedex) + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include +#include "Common/Cpp/PrettyPrint.h" +#include "Common/Qt/QtJsonTools.h" +#include "Common/SwitchFramework/Switch_PushButtons.h" +#include "Common/PokemonSwSh/PokemonSettings.h" +#include "Common/PokemonSwSh/PokemonSwShGameEntry.h" +#include "CommonFramework/PersistentSettings.h" +#include "CommonFramework/Inference/ImageTools.h" +#include "CommonFramework/OCR/RawOCR.h" +#include "CommonFramework/OCR/Filtering.h" +#include "PokemonSwSh_GenerateNameOCRPokedex.h" + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +GenerateNameOCRDataPokedex_Descriptor::GenerateNameOCRDataPokedex_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:GenerateNameOCRPokedex", + "Generate " + STRING_POKEMON + " Name OCR Data", + "", + "Generate " + STRING_POKEMON + " Name OCR data by iterating the " + STRING_POKEDEX + ".", + FeedbackType::REQUIRED, + PABotBaseLevel::PABOTBASE_12KB + ) +{} + + + +GenerateNameOCRDataPokedex::GenerateNameOCRDataPokedex(const GenerateNameOCRDataPokedex_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) + , LANGUAGE( + "Game Language:", + m_reader.languages() + ) + , POKEDEX( + "" + STRING_POKEDEX + ":", + { + "Galar", + "Isle of Armor", + "Crown Tundra", + }, + 0 + ) + , MODE( + "Mode:", + { + "Read names and save to JSON.", + "Generate training data.", + }, + 1 + ) +{ + m_options.emplace_back(&LANGUAGE, "LANGUAGE"); + m_options.emplace_back(&POKEDEX, "POKEDEX"); + m_options.emplace_back(&MODE, "MODE"); +} + +void GenerateNameOCRDataPokedex::read( + QJsonArray& output, + Logger* logger, + QImage image +) const{ + OCR::make_OCR_filter(image).apply(image); + image.save("test.png"); + + OCR::MatchResult result = m_reader.read_exact(LANGUAGE, image); + result.log(logger); + if (result.tokens.empty()){ + output.append(""); + }else{ + output.append(result.tokens.begin()->c_str()); + } +} + +void GenerateNameOCRDataPokedex::dump_images( + const std::vector& expected, + size_t index, + QImage image +) const{ + if (index >= expected.size()){ + return; + } + + QString path = "PokemonNameOCR/"; + path += language_data(LANGUAGE).code.c_str(); + + QDir dir(path); + if (!dir.exists()){ + dir.mkpath("."); + } + + path += "/"; + path += expected[index].c_str(); + path += "-"; + path += now_to_filestring().c_str(); + path += ".png"; + image.save(path); + + OCR::make_OCR_filter(image).apply(image); +} + +void GenerateNameOCRDataPokedex::program(SingleSwitchProgramEnvironment& env){ + + QString dex_name; + size_t dex_size = 0; + switch (POKEDEX){ + case 0: + dex_name = "Galar"; + dex_size = 400; + break; + case 1: + dex_name = "IsleOfArmor"; + dex_size = 211; + break; + case 2: + dex_name = "CrownTundra"; + dex_size = 210; + break; + } + + InferenceBoxScope box0(env.console, Qt::blue, 0.75, 0.146 + 0 * 0.1115, 0.18, 0.059); + InferenceBoxScope box1(env.console, Qt::blue, 0.75, 0.146 + 1 * 0.1115, 0.18, 0.059); + InferenceBoxScope box2(env.console, Qt::blue, 0.75, 0.146 + 2 * 0.1115, 0.18, 0.059); + InferenceBoxScope box3(env.console, Qt::blue, 0.75, 0.146 + 3 * 0.1115, 0.18, 0.059); + InferenceBoxScope box4(env.console, Qt::blue, 0.75, 0.146 + 4 * 0.1115, 0.18, 0.059); + InferenceBoxScope box5(env.console, Qt::blue, 0.75, 0.146 + 5 * 0.1115, 0.18, 0.059); + InferenceBoxScope box6(env.console, Qt::blue, 0.75, 0.146 + 6 * 0.1115, 0.18, 0.059); + + std::vector expected; + QJsonArray actual; +// OCR::DictionaryOCR& dictionary = m_reader.dictionary(LANGUAGE); + + if (MODE == Mode::GENERATE_TRAINING_DATA){ + QJsonArray array = read_json_file( + PERSISTENT_SETTINGS().resource_path + "Pokemon/Pokedex/Pokedex-" + dex_name + ".json" + ).array(); + for (const auto& item : array){ + expected.emplace_back(item.toString().toUtf8().data()); + } + } + + for (size_t c = 1; c <= dex_size; c += 7){ + env.console.botbase().wait_for_all_requests(); + + if (c + 6 > dex_size){ + c = dex_size - 6; + } +// cout << "dex: " << c << endl; + + QImage frame = env.console.video().snapshot(); + QImage image0 = extract_box(frame, box0); + QImage image1 = extract_box(frame, box1); + QImage image2 = extract_box(frame, box2); + QImage image3 = extract_box(frame, box3); + QImage image4 = extract_box(frame, box4); + QImage image5 = extract_box(frame, box5); + QImage image6 = extract_box(frame, box6); + +// image1.save("test.png"); + + switch (MODE){ + case Mode::READ_AND_SAVE: + read(actual, &env.logger(), std::move(image0)); + read(actual, &env.logger(), std::move(image1)); + read(actual, &env.logger(), std::move(image2)); + read(actual, &env.logger(), std::move(image3)); + read(actual, &env.logger(), std::move(image4)); + read(actual, &env.logger(), std::move(image5)); + read(actual, &env.logger(), std::move(image6)); + break; + case Mode::GENERATE_TRAINING_DATA: + dump_images(expected, c - 1 + 0, std::move(image0)); + dump_images(expected, c - 1 + 1, std::move(image1)); + dump_images(expected, c - 1 + 2, std::move(image2)); + dump_images(expected, c - 1 + 3, std::move(image3)); + dump_images(expected, c - 1 + 4, std::move(image4)); + dump_images(expected, c - 1 + 5, std::move(image5)); + dump_images(expected, c - 1 + 6, std::move(image6)); + break; + } + + pbf_press_dpad(env.console, DPAD_RIGHT, 10, TICKS_PER_SECOND); + } + + if (MODE == Mode::READ_AND_SAVE){ + write_json_file("PokedexReadData.json", QJsonDocument(actual)); + } + +} + + + +} +} +} diff --git a/SerialPrograms/Source/PokemonSwSh/InferenceTraining/PokemonSwSh_GenerateNameOCRPokedex.h b/SerialPrograms/Source/PokemonSwSh/InferenceTraining/PokemonSwSh_GenerateNameOCRPokedex.h new file mode 100644 index 0000000000..62d9652b97 --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/InferenceTraining/PokemonSwSh_GenerateNameOCRPokedex.h @@ -0,0 +1,65 @@ +/* Generate Pokemon Name OCR Data (Pokedex) + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PokemonSwSh_GenerateNameOCRData_H +#define PokemonAutomation_PokemonSwSh_GenerateNameOCRData_H + +#include "CommonFramework/Options/EnumDropdown.h" +#include "CommonFramework/Options/LanguageOCR.h" +#include "Pokemon/Pokemon_NameReader.h" +#include "NintendoSwitch/Framework/SingleSwitchProgram.h" + + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +class GenerateNameOCRDataPokedex_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + GenerateNameOCRDataPokedex_Descriptor(); +}; + + + +class GenerateNameOCRDataPokedex : public SingleSwitchProgramInstance{ +public: + enum Mode{ + READ_AND_SAVE, + GENERATE_TRAINING_DATA, + }; + +public: + GenerateNameOCRDataPokedex(const GenerateNameOCRDataPokedex_Descriptor& descriptor); + + virtual void program(SingleSwitchProgramEnvironment& env) override; + +private: + void read( + QJsonArray& output, + Logger* logger, + QImage image + ) const; + void dump_images( + const std::vector& expected, + size_t index, + QImage image + ) const; + +private: + Pokemon::PokemonNameReader m_reader; + + LanguageOCR LANGUAGE; + EnumDropdown POKEDEX; + EnumDropdown MODE; +}; + + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonSwSh/Options/EggStepCount.cpp b/SerialPrograms/Source/PokemonSwSh/Options/EggStepCount.cpp index 962166a7ef..cbafff25a5 100644 --- a/SerialPrograms/Source/PokemonSwSh/Options/EggStepCount.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Options/EggStepCount.cpp @@ -6,7 +6,7 @@ #include #include -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "EggStepCount.h" namespace PokemonAutomation{ diff --git a/SerialPrograms/Source/PokemonSwSh/Panels_PokemonSwSh.cpp b/SerialPrograms/Source/PokemonSwSh/Panels_PokemonSwSh.cpp new file mode 100644 index 0000000000..d714147e6a --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Panels_PokemonSwSh.cpp @@ -0,0 +1,171 @@ +/* Pokemon Sword/Shield Panels + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "Common/Qt/QtJsonTools.h" +#include "CommonFramework/PersistentSettings.h" +#include "CommonFramework/Windows/MainWindow.h" +#include "Panels_PokemonSwSh.h" + +#include "PokemonSwSh_SettingsPanel.h" + +#include "Programs/QoLMacros/PokemonSwSh_FastCodeEntry.h" +#include "Programs/QoLMacros/PokemonSwSh_FriendSearchDisconnect.h" + +#include "Programs/BasicPrograms/PokemonSwSh_TurboA.h" +#include "Programs/BasicPrograms/PokemonSwSh_MassRelease.h" +#include "Programs/BasicPrograms/PokemonSwSh_SurpriseTrade.h" +#include "Programs/BasicPrograms/PokemonSwSh_TradeBot.h" +#include "Programs/BasicPrograms/PokemonSwSh_ClothingBuyer.h" +#include "Programs/BasicPrograms/PokemonSwSh_BallThrower.h" +#include "Programs/BasicPrograms/PokemonSwSh_DexRecFinder.h" +#include "Programs/PokemonSwSh_StatsReset.h" + +#include "Programs/DateSpamFarmers/PokemonSwSh_DateSpam-WattFarmer.h" +#include "Programs/DateSpamFarmers/PokemonSwSh_DateSpam-BerryFarmer.h" +#include "Programs/DateSpamFarmers/PokemonSwSh_DateSpam-LotoFarmer.h" +#include "Programs/DateSpamFarmers/PokemonSwSh_DateSpam-StowOnSideFarmer.h" +#include "Programs/DateSpamFarmers/PokemonSwSh_DateSpam-DailyHighlightFarmer.h" + +#include "Programs/DenHunting/PokemonSwSh_BeamReset.h" +#include "Programs/DenHunting/PokemonSwSh_PurpleBeamFinder.h" +#include "Programs/DenHunting/PokemonSwSh_EventBeamFinder.h" +#include "Programs/DenHunting/PokemonSwSh_DaySkipperJPN.h" +#include "Programs/DenHunting/PokemonSwSh_DaySkipperEU.h" +#include "Programs/DenHunting/PokemonSwSh_DaySkipperUS.h" +#include "Programs/DenHunting/PokemonSwSh_DaySkipperJPN-7.8k.h" + +#include "Programs/Hosting/PokemonSwSh_DenRoller.h" +#include "Programs/Hosting/PokemonSwSh_AutoHost-Rolling.h" +#include "Programs/Hosting/PokemonSwSh_AutoHost-MultiGame.h" + +#include "Programs/ShinyHunting/PokemonSwSh_MultiGameFossil.h" +#include "Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regi.h" +#include "Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-SwordsOfJustice.h" +#include "Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-StrongSpawn.h" +#include "Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regigigas2.h" +#include "Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-IoATrade.h" + +#include "Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regi.h" +#include "Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-SwordsOfJustice.h" +#include "Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-StrongSpawn.h" +#include "Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regigigas2.h" +#include "Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-IoATrade.h" +#include "Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-BerryTree.h" +#include "Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Whistling.h" +#include "Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Fishing.h" +#include "Programs/OverworldBot/PokemonSwSh_ShinyHuntAutonomous-Overworld.h" + +#include "Programs/EggPrograms/PokemonSwSh_EggFetcher2.h" +#include "Programs/EggPrograms/PokemonSwSh_EggHatcher.h" +#include "Programs/EggPrograms/PokemonSwSh_EggCombined2.h" +#include "Programs/EggPrograms/PokemonSwSh_EggSuperCombined2.h" +#include "Programs/EggPrograms/PokemonSwSh_GodEggDuplication.h" +#include "Programs/EggPrograms/PokemonSwSh_GodEggItemDupe.h" + +#include "Programs/PokemonSwSh_SynchronizedSpinning.h" +#include "Programs/PokemonSwSh_RaidItemFarmerOKHO.h" + +#include "InferenceTraining/PokemonSwSh_GenerateIVCheckerOCR.h" +#include "InferenceTraining/PokemonSwSh_GenerateNameOCRPokedex.h" + + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +Panels::Panels(QTabWidget& parent, PanelListener& listener) + : PanelList(parent, "Sword/Shield", listener) +{ + PersistentSettings& settings = PERSISTENT_SETTINGS(); + + add_divider("---- Settings ----"); + add_settings(); + + add_divider("---- QoL Macros ----"); + add_program(); + add_program(); + + add_divider("---- General ----"); + add_program(); + add_program(); + add_program(); + add_program(); + add_program(); + add_program(); + add_program(); + add_program(); + + add_divider("---- Date-Spam Farmers ----"); + add_program(); + add_program(); + add_program(); + add_program(); + add_program(); + + add_divider("---- Den Hunting ----"); + add_program(); + add_program(); + add_program(); + add_program(); + add_program(); + add_program(); + add_program(); + + add_divider("---- Hosting ----"); + add_program(); + add_program(); + add_program(); + + add_divider("---- Unattended Shiny Hunting ----"); + add_program(); + add_program(); + add_program(); + add_program(); + add_program(); + add_program(); + + add_divider("---- Autonomous Shiny Hunting ----"); + add_program(); + add_program(); + add_program(); + add_program(); + add_program(); + add_program(); + add_program(); + add_program(); + add_program(); + + add_divider("---- Eggs ----"); + add_program(); + add_program(); + add_program(); + add_program(); + add_program(); + if (settings.naughty_mode){ + add_program(); + } + + add_divider("---- Multi-Switch Programs ----"); + add_program(); + add_program(); + + if (settings.developer_mode){ + add_divider("---- Developer Tools ----"); + add_program(); + add_program(); + } + + + finish_panel_setup(); +} + + + + +} +} +} diff --git a/SerialPrograms/Source/PokemonSwSh/Panels_PokemonSwSh.h b/SerialPrograms/Source/PokemonSwSh/Panels_PokemonSwSh.h new file mode 100644 index 0000000000..692c245be0 --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Panels_PokemonSwSh.h @@ -0,0 +1,27 @@ +/* Pokemon Sword/Shield Panels + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PokemonSwordShieldPanels_H +#define PokemonAutomation_PokemonSwordShieldPanels_H + +#include "CommonFramework/Panels/PanelList.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +class Panels : public PanelList{ +public: + Panels(QTabWidget& parent, PanelListener& listener); +}; + + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonSwSh/PokemonSwSh_SettingsPanel.cpp b/SerialPrograms/Source/PokemonSwSh/PokemonSwSh_SettingsPanel.cpp index 403d3b6675..5059fb1c30 100644 --- a/SerialPrograms/Source/PokemonSwSh/PokemonSwSh_SettingsPanel.cpp +++ b/SerialPrograms/Source/PokemonSwSh/PokemonSwSh_SettingsPanel.cpp @@ -15,13 +15,21 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -PokemonSettings::PokemonSettings() - : SettingsPanel( + +PokemonSettings_Descriptor::PokemonSettings_Descriptor() + : PanelDescriptor( QColor(), + "PokemonSwSh:GlobalSettings", STRING_POKEMON + " Settings", "", "Global " + STRING_POKEMON + " Settings" ) +{} + + + +PokemonSettings::PokemonSettings(const PokemonSettings_Descriptor& descriptor) + : SettingsPanelInstance(descriptor) { m_options.emplace_back( "", @@ -143,14 +151,6 @@ PokemonSettings::PokemonSettings() "", new SectionDivider("Start Game Timings:") ); - m_options.emplace_back( - "START_GAME_INTERNET_CHECK_DELAY", - new TimeExpression( - START_GAME_INTERNET_CHECK_DELAY, - "Start Game Internet Check Delay:
If starting the game requires checking the internet, wait this long for it.", - "3 * TICKS_PER_SECOND" - ) - ); m_options.emplace_back( "START_GAME_MASH", new TimeExpression( @@ -321,12 +321,6 @@ PokemonSettings::PokemonSettings() ); } -PokemonSettings::PokemonSettings(const QJsonValue& json) - : PokemonSettings() -{ - from_json(json); -} - diff --git a/SerialPrograms/Source/PokemonSwSh/PokemonSwSh_SettingsPanel.h b/SerialPrograms/Source/PokemonSwSh/PokemonSwSh_SettingsPanel.h index e3ed5c91c9..865df81a57 100644 --- a/SerialPrograms/Source/PokemonSwSh/PokemonSwSh_SettingsPanel.h +++ b/SerialPrograms/Source/PokemonSwSh/PokemonSwSh_SettingsPanel.h @@ -14,10 +14,15 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ -class PokemonSettings : public SettingsPanel{ +class PokemonSettings_Descriptor : public PanelDescriptor{ public: - PokemonSettings(); - PokemonSettings(const QJsonValue& json); + PokemonSettings_Descriptor(); +}; + + +class PokemonSettings : public SettingsPanelInstance{ +public: + PokemonSettings(const PokemonSettings_Descriptor& descriptor); }; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_BallThrower.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_BallThrower.cpp index 2ca3171a45..557e420934 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_BallThrower.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_BallThrower.cpp @@ -13,28 +13,37 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -BallThrower::BallThrower() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, + +BallThrower_Descriptor::BallThrower_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:BallThrower", "Ball Thrower", "NativePrograms/BallThrower.md", - "Blindly throw balls at the opposing " + STRING_POKEMON + " until it catches." + "Blindly throw balls at the opposing " + STRING_POKEMON + " until it catches.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) {} -void BallThrower::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); - pbf_press_button(BUTTON_HOME, 10, HOME_TO_GAME_DELAY); + + +BallThrower::BallThrower(const BallThrower_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) +{} + +void BallThrower::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + pbf_press_button(env.console, BUTTON_HOME, 10, HOME_TO_GAME_DELAY); while (true){ - pbf_press_button(BUTTON_X, 50, 50); - pbf_press_button(BUTTON_A, 50, 50); - pbf_mash_button(BUTTON_B, 100); + pbf_press_button(env.console, BUTTON_X, 50, 50); + pbf_press_button(env.console, BUTTON_A, 50, 50); + pbf_mash_button(env.console, BUTTON_B, 100); } - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - end_program_callback(); - end_program_loop(); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_BallThrower.h b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_BallThrower.h index 4f3558897f..d4c5af129e 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_BallThrower.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_BallThrower.h @@ -13,11 +13,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class BallThrower : public SingleSwitchProgram{ + +class BallThrower_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + BallThrower_Descriptor(); +}; + + + +class BallThrower : public SingleSwitchProgramInstance{ public: - BallThrower(); + BallThrower(const BallThrower_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; }; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_ClothingBuyer.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_ClothingBuyer.cpp index 48dbb6713a..ca3e257ff5 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_ClothingBuyer.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_ClothingBuyer.cpp @@ -14,13 +14,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -ClothingBuyer::ClothingBuyer() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, + +ClothingBuyer_Descriptor::ClothingBuyer_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:ClothingBuyer", "Clothing Buyer", "NativePrograms/ClothingBuyer.md", - "Buy out all the clothing in a store." + "Buy out all the clothing in a store.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +ClothingBuyer::ClothingBuyer(const ClothingBuyer_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , CATEGORY_ROTATION( "Rotate Categories:
This slows down the program, but ensures it will cover all categories.", true @@ -29,18 +38,18 @@ ClothingBuyer::ClothingBuyer() m_options.emplace_back(&CATEGORY_ROTATION, "CATEGORY_ROTATION"); } -void ClothingBuyer::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); - resume_game_no_interact(TOLERATE_SYSTEM_UPDATE_MENU_FAST); +void ClothingBuyer::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + resume_game_no_interact(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST); while (true){ - pbf_press_button(BUTTON_A, 10, 90); + pbf_press_button(env.console, BUTTON_A, 10, 90); if (CATEGORY_ROTATION){ - pbf_press_dpad(DPAD_RIGHT, 10, 40); + pbf_press_dpad(env.console, DPAD_RIGHT, 10, 40); } - pbf_press_button(BUTTON_A, 10, 90); - pbf_press_button(BUTTON_A, 10, 90); - pbf_press_dpad(DPAD_DOWN, 10, 40); + pbf_press_button(env.console, BUTTON_A, 10, 90); + pbf_press_button(env.console, BUTTON_A, 10, 90); + pbf_press_dpad(env.console, DPAD_DOWN, 10, 40); } } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_ClothingBuyer.h b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_ClothingBuyer.h index 1026c4c365..6b63f7b87f 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_ClothingBuyer.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_ClothingBuyer.h @@ -14,11 +14,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class ClothingBuyer : public SingleSwitchProgram{ + +class ClothingBuyer_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + ClothingBuyer_Descriptor(); +}; + + + +class ClothingBuyer : public SingleSwitchProgramInstance{ public: - ClothingBuyer(); + ClothingBuyer(const ClothingBuyer_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: BooleanCheckBox CATEGORY_ROTATION; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_DexRecFinder.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_DexRecFinder.cpp new file mode 100644 index 0000000000..ffce9e8693 --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_DexRecFinder.cpp @@ -0,0 +1,192 @@ +/* Pokedex Recommendation Finder + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "Common/SwitchFramework/Switch_PushButtons.h" +#include "Common/PokemonSwSh/PokemonSettings.h" +#include "Common/PokemonSwSh/PokemonSwShGameEntry.h" +#include "Common/PokemonSwSh/PokemonSwShDateSpam.h" +#include "CommonFramework/Inference/ImageTools.h" +#include "CommonFramework/OCR/RawOCR.h" +#include "CommonFramework/OCR/Filtering.h" +#include "PokemonSwSh_DexRecFinder.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +DexRecFinder_Descriptor::DexRecFinder_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:DexRecFinder", + "Dex Rec Finder", + "SerialPrograms/DexRecFinder.md", + "Search for a " + STRING_POKEDEX + " recommendation by date-spamming.", + FeedbackType::OPTIONAL_, + PABotBaseLevel::PABOTBASE_12KB + ) +{} + + + +DexRecFinder::DexRecFinder(const DexRecFinder_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) + , GO_HOME_WHEN_DONE( + "Go Home when Done:
After finding a match, go to the Switch Home menu to idle. (turn this off for unattended streaming)", + false + ) + , LANGUAGE( + "Game Language:", + m_name_reader.languages(), false + ) + , DESIRED( + "Desired " + STRING_POKEMON + ":
Stop when it finds this " + STRING_POKEMON + ". Requires the language be set.", + "Pokemon/Pokedex/Pokedex-National.json" + ) + , VIEW_TIME( + "View Time:
View the " + STRING_POKEDEX + " for this long before continuing.", + "2 * TICKS_PER_SECOND" + ) + , m_advanced_options( + "Advanced Options: You should not need to touch anything below here." + ) + , ENTER_POKEDEX_TIME( + "Enter " + STRING_POKEDEX + " Time:
Wait this long for the " + STRING_POKEDEX + " to open.", + "3 * TICKS_PER_SECOND" + ) + , BACK_OUT_TIME( + "Back Out Time:
Mash B for this long to return to the overworld.", + "3 * TICKS_PER_SECOND" + ) +{ + m_options.emplace_back(&GO_HOME_WHEN_DONE, "GO_HOME_WHEN_DONE"); + m_options.emplace_back(&LANGUAGE, "LANGUAGE"); + m_options.emplace_back(&DESIRED, "DESIRED"); + m_options.emplace_back(&VIEW_TIME, "VIEW_TIME"); + m_options.emplace_back(&m_advanced_options, ""); + m_options.emplace_back(&ENTER_POKEDEX_TIME, "ENTER_POKEDEX_TIME"); + m_options.emplace_back(&BACK_OUT_TIME, "BACK_OUT_TIME"); +} + + +struct DexRecFinder::Stats : public StatsTracker{ + Stats() + : attempts(m_stats["Attempts"]) + , errors(m_stats["Read Errors"]) + , matches(m_stats["Matches"]) + { + m_display_order.emplace_back(Stat("Attempts")); + m_display_order.emplace_back(Stat("Read Errors")); + m_display_order.emplace_back(Stat("Matches")); + } + + uint64_t& attempts; + uint64_t& errors; + uint64_t& matches; +}; +std::unique_ptr DexRecFinder::make_stats() const{ + return std::unique_ptr(new Stats()); +} + + +void DexRecFinder::read_line( + bool& found, + bool& bad_read, + Logger& logger, + const QImage& frame, + const InferenceBox& box, + const std::set& desired +){ + QImage image = extract_box(frame, box); + OCR::make_OCR_filter(image).apply(image); + + OCR::MatchResult result = m_name_reader.read_exact(LANGUAGE, image); + result.log(&logger); + + if (!result.matched || result.tokens.empty()){ + bad_read = true; + return; + } + for (const std::string& hit : result.tokens){ + if (desired.find(hit) != desired.end()){ + found = true; + } + } +} + +void DexRecFinder::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + + std::set desired; + desired.insert(DESIRED.token()); + + Stats& stats = env.stats(); + + while (true){ + home_to_date_time(env.console, true, true); + neutral_date_skip(env.console); + settings_to_enter_game(env.console, true); + pbf_mash_button(env.console, BUTTON_B, 90); + pbf_press_button(env.console, BUTTON_X, 20, OVERWORLD_TO_MENU_DELAY - 20); + + if (LANGUAGE){ + env.console.botbase().wait_for_all_requests(); + InferenceBoxScope box0(env.console, InferenceBox(0.75, 0.531 + 0 * 0.1115, 0.18, 0.059)); + InferenceBoxScope box1(env.console, InferenceBox(0.75, 0.531 + 1 * 0.1115, 0.18, 0.059)); + InferenceBoxScope box2(env.console, InferenceBox(0.75, 0.531 + 2 * 0.1115, 0.18, 0.059)); + InferenceBoxScope box3(env.console, InferenceBox(0.75, 0.531 + 3 * 0.1115, 0.18, 0.059)); + pbf_press_button(env.console, BUTTON_A, 10, ENTER_POKEDEX_TIME); + env.console.botbase().wait_for_all_requests(); + + QImage frame = env.console.video().snapshot(); + bool found = false; + bool bad_read = false; + if (!frame.isNull()){ + read_line(found, bad_read, env.logger(), frame, box0, desired); + read_line(found, bad_read, env.logger(), frame, box1, desired); + read_line(found, bad_read, env.logger(), frame, box2, desired); + read_line(found, bad_read, env.logger(), frame, box3, desired); + }else{ + bad_read = true; + } + + stats.attempts++; + if (found){ + env.log("Found a match!", Qt::blue); + stats.matches++; + break; + } + if (bad_read){ + env.log("Read Errors. Pausing for user to see.", Qt::red); + stats.errors++; + pbf_wait(env.console, VIEW_TIME); + } + }else{ + stats.attempts++; + stats.errors++; + pbf_press_button(env.console, BUTTON_A, 10, ENTER_POKEDEX_TIME); + pbf_wait(env.console, VIEW_TIME); + } + env.update_stats(); + + pbf_mash_button(env.console, BUTTON_B, BACK_OUT_TIME); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + } + + env.update_stats(); + + if (GO_HOME_WHEN_DONE){ + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + } + + end_program_callback(env.console); + end_program_loop(env.console); +} + + + +} +} +} diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_DexRecFinder.h b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_DexRecFinder.h new file mode 100644 index 0000000000..18e955fb46 --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_DexRecFinder.h @@ -0,0 +1,70 @@ +/* Pokedex Recommendation Finder + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PokemonSwSh_DexRecFinder_H +#define PokemonAutomation_PokemonSwSh_DexRecFinder_H + +#include "CommonFramework/Options/SectionDivider.h" +#include "CommonFramework/Options/BooleanCheckBox.h" +#include "CommonFramework/Options/LanguageOCR.h" +#include "Pokemon/Options/Pokemon_NameSelect.h" +#include "Pokemon/Pokemon_NameReader.h" +#include "NintendoSwitch/Options/TimeExpression.h" +#include "NintendoSwitch/Framework/SingleSwitchProgram.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +class DexRecFinder_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + DexRecFinder_Descriptor(); +}; + + + +class DexRecFinder : public SingleSwitchProgramInstance{ +public: + DexRecFinder(const DexRecFinder_Descriptor& descriptor); + + virtual std::unique_ptr make_stats() const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; + +private: + void read_line( + bool& found, + bool& bad_read, + Logger& logger, + const QImage& frame, + const InferenceBox& box, + const std::set& desired + ); + +private: + struct Stats; + +private: + Pokemon::PokemonNameReader m_name_reader; + + BooleanCheckBox GO_HOME_WHEN_DONE; + + LanguageOCR LANGUAGE; + Pokemon::PokemonNameSelect DESIRED; + TimeExpression VIEW_TIME; + + SectionDivider m_advanced_options; + TimeExpression ENTER_POKEDEX_TIME; + TimeExpression BACK_OUT_TIME; +}; + +} +} +} +#endif + + + diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_MassRelease.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_MassRelease.cpp index f85fa2c318..36e08ff7f1 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_MassRelease.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_MassRelease.cpp @@ -14,13 +14,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -MassRelease::MassRelease() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, + +MassRelease_Descriptor::MassRelease_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:MassRelease", "Mass Release", "NativePrograms/MassRelease.md", - "Mass release boxes of " + STRING_POKEMON + "." + "Mass release boxes of " + STRING_POKEMON + ".", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +MassRelease::MassRelease(const MassRelease_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , BOXES_TO_RELEASE( "Number of Boxes to Release:", 2, 0, 32 @@ -34,15 +43,15 @@ MassRelease::MassRelease() m_options.emplace_back(&DODGE_SYSTEM_UPDATE_WINDOW, "DODGE_SYSTEM_UPDATE_WINDOW"); } -void MassRelease::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); - resume_game_no_interact(DODGE_SYSTEM_UPDATE_WINDOW); +void MassRelease::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + resume_game_no_interact(env.console, DODGE_SYSTEM_UPDATE_WINDOW); - release_boxes(BOXES_TO_RELEASE, BOX_SCROLL_DELAY, BOX_CHANGE_DELAY); - pbf_press_button(BUTTON_HOME, 10, HOME_TO_GAME_DELAY); + release_boxes(env.console, BOXES_TO_RELEASE, BOX_SCROLL_DELAY, BOX_CHANGE_DELAY); + pbf_press_button(env.console, BUTTON_HOME, 10, HOME_TO_GAME_DELAY); - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_MassRelease.h b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_MassRelease.h index b3d73b35cc..5e7053a41b 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_MassRelease.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_MassRelease.h @@ -15,11 +15,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class MassRelease : public SingleSwitchProgram{ + +class MassRelease_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + MassRelease_Descriptor(); +}; + + + +class MassRelease : public SingleSwitchProgramInstance{ public: - MassRelease(); + MassRelease(const MassRelease_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger BOXES_TO_RELEASE; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_SurpriseTrade.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_SurpriseTrade.cpp index 3d2f0ef5f1..5a4f00ad00 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_SurpriseTrade.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_SurpriseTrade.cpp @@ -15,13 +15,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -SurpriseTrade::SurpriseTrade() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, + +SurpriseTrade_Descriptor::SurpriseTrade_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:SurpriseTrade", "Surprise Trade", "NativePrograms/SurpriseTrade.md", - "Surprise trade away boxes of " + STRING_POKEMON + "Surprise trade away boxes of " + STRING_POKEMON, + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +SurpriseTrade::SurpriseTrade(const SurpriseTrade_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , BOXES_TO_TRADE( "Number of Boxes to Trade:", 2 @@ -50,52 +59,52 @@ SurpriseTrade::SurpriseTrade() } -void SurpriseTrade::trade_slot(uint8_t slot, bool next_box) const{ - ssf_press_button2(BUTTON_Y, OPEN_YCOMM_DELAY, 50); - ssf_press_dpad1(DPAD_DOWN, 10); - ssf_press_button2(BUTTON_A, 280, 20); +void SurpriseTrade::trade_slot(const BotBaseContext& context, uint8_t slot, bool next_box) const{ + ssf_press_button2(context, BUTTON_Y, OPEN_YCOMM_DELAY, 50); + ssf_press_dpad1(context, DPAD_DOWN, 10); + ssf_press_button2(context, BUTTON_A, 280, 20); if (next_box){ - ssf_press_button1(BUTTON_R, BOX_CHANGE_DELAY); + ssf_press_button1(context, BUTTON_R, BOX_CHANGE_DELAY); } // Move to slot while (slot >= 6){ - ssf_press_dpad1(DPAD_DOWN, BOX_SCROLL_DELAY); + ssf_press_dpad1(context, DPAD_DOWN, BOX_SCROLL_DELAY); slot -= 6; } while (slot > 0){ - ssf_press_dpad1(DPAD_RIGHT, BOX_SCROLL_DELAY); + ssf_press_dpad1(context, DPAD_RIGHT, BOX_SCROLL_DELAY); slot--; } - ssf_press_button1(BUTTON_A, 50); - ssf_press_button1(BUTTON_A, 500); - ssf_press_button1(BUTTON_A, 100); - ssf_press_button1(BUTTON_A, 100); + ssf_press_button1(context, BUTTON_A, 50); + ssf_press_button1(context, BUTTON_A, 500); + ssf_press_button1(context, BUTTON_A, 100); + ssf_press_button1(context, BUTTON_A, 100); - pbf_mash_button(BUTTON_B, INITIAL_WAIT); + pbf_mash_button(context, BUTTON_B, INITIAL_WAIT); // This is a state-merging operation. // If we just finished a trade, this will start the animation for it. // If we failed the previous trade and are stuck in the wrong parity, this // is a no-op that will correct the parity and setup the next trade. - ssf_press_button1(BUTTON_Y, OPEN_YCOMM_DELAY); - pbf_mash_button(BUTTON_B, TRADE_ANIMATION); + ssf_press_button1(context, BUTTON_Y, OPEN_YCOMM_DELAY); + pbf_mash_button(context, BUTTON_B, TRADE_ANIMATION); } -void SurpriseTrade::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); - resume_game_no_interact(TOLERATE_SYSTEM_UPDATE_MENU_FAST); +void SurpriseTrade::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + resume_game_no_interact(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST); for (uint8_t box = 0; box < BOXES_TO_TRADE; box++){ // At this point, we MUST be in the overworld with no pending trade. // Otherwise the box transition will fail. Therefore we add a cleanup // stage after each box to make sure we are in this state. - trade_slot(0, box != 0); + trade_slot(env.console, 0, box != 0); for (uint8_t c = 1; c < 30; c++){ - trade_slot(c, false); + trade_slot(env.console, c, false); } // If the previous trade isn't done, either wait to finish or cancel it. @@ -107,23 +116,23 @@ void SurpriseTrade::program(SingleSwitchProgramEnvironment& env) const{ // because the trade is in progress. The 2nd iteration finishes it. // 4. No partner was ever found. The 1st iteration will cancel the trade. for (uint8_t c = 0; c < 2; c++){ - ssf_press_button1(BUTTON_Y, 250); - ssf_press_dpad1(DPAD_DOWN, 20); - ssf_press_button1(BUTTON_A, 280); - ssf_press_button1(BUTTON_B, 280); - ssf_press_button1(BUTTON_B, 200); - ssf_press_button1(BUTTON_A, 100); - pbf_mash_button(BUTTON_B, TRADE_ANIMATION); + ssf_press_button1(env.console, BUTTON_Y, 250); + ssf_press_dpad1(env.console, DPAD_DOWN, 20); + ssf_press_button1(env.console, BUTTON_A, 280); + ssf_press_button1(env.console, BUTTON_B, 280); + ssf_press_button1(env.console, BUTTON_B, 200); + ssf_press_button1(env.console, BUTTON_A, 100); + pbf_mash_button(env.console, BUTTON_B, TRADE_ANIMATION); } // Wait out any new pokedex entries or trade evolutions. - pbf_mash_button(BUTTON_B, EVOLVE_DELAY); + pbf_mash_button(env.console, BUTTON_B, EVOLVE_DELAY); } - ssf_press_button2(BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); + ssf_press_button2(env.console, BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_SurpriseTrade.h b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_SurpriseTrade.h index 8f92708307..76531dc08c 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_SurpriseTrade.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_SurpriseTrade.h @@ -16,14 +16,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class SurpriseTrade : public SingleSwitchProgram{ + +class SurpriseTrade_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + SurpriseTrade_Descriptor(); +}; + + + +class SurpriseTrade : public SingleSwitchProgramInstance{ public: - SurpriseTrade(); + SurpriseTrade(const SurpriseTrade_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: - void trade_slot(uint8_t slot, bool next_box) const; + void trade_slot(const BotBaseContext& context, uint8_t slot, bool next_box) const; private: SimpleInteger BOXES_TO_TRADE; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TradeBot.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TradeBot.cpp index 794068594b..78b2e50a84 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TradeBot.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TradeBot.cpp @@ -17,13 +17,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -TradeBot::TradeBot() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, + +TradeBot_Descriptor::TradeBot_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:TradeBot", "Trade Bot", "NativePrograms/TradeBot.md", - "Surprise trade with a code for hosting giveaways." + "Surprise trade with a code for hosting giveaways.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +TradeBot::TradeBot(const TradeBot_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , TRADE_CODE( "Trade Code:", 8, @@ -78,67 +87,67 @@ TradeBot::TradeBot() } -void TradeBot::trade_slot(const uint8_t code[8], uint8_t slot) const{ - ssf_press_button2(BUTTON_Y, OPEN_YCOMM_DELAY, 50); - ssf_press_button2(BUTTON_A, 150, 20); - ssf_press_dpad1(DPAD_DOWN, 10); - ssf_press_button2(BUTTON_A, 200, 20); +void TradeBot::trade_slot(const BotBaseContext& context, const uint8_t code[8], uint8_t slot) const{ + ssf_press_button2(context, BUTTON_Y, OPEN_YCOMM_DELAY, 50); + ssf_press_button2(context, BUTTON_A, 150, 20); + ssf_press_dpad1(context, DPAD_DOWN, 10); + ssf_press_button2(context, BUTTON_A, 200, 20); if (LINK_TRADE_EXTRA_LINE){ - ssf_press_button2(BUTTON_B, 50, 20); + ssf_press_button2(context, BUTTON_B, 50, 20); } - ssf_press_button2(BUTTON_B, 200, 20); - ssf_press_dpad1(DPAD_UP, 10); - ssf_press_button1(BUTTON_A, 5); - ssf_press_button1(BUTTON_B, 5); + ssf_press_button2(context, BUTTON_B, 200, 20); + ssf_press_dpad1(context, DPAD_UP, 10); + ssf_press_button1(context, BUTTON_A, 5); + ssf_press_button1(context, BUTTON_B, 5); - enter_digits(8, code); - ssf_press_button1(BUTTON_PLUS, 200); - ssf_press_button2(BUTTON_B, 125, 10); - ssf_press_button2(BUTTON_A, 50, 10); - pbf_mash_button(BUTTON_B, 400); + enter_digits(context, 8, code); + ssf_press_button1(context, BUTTON_PLUS, 200); + ssf_press_button2(context, BUTTON_B, 125, 10); + ssf_press_button2(context, BUTTON_A, 50, 10); + pbf_mash_button(context, BUTTON_B, 400); - pbf_wait(SEARCH_DELAY); + pbf_wait(context, SEARCH_DELAY); // If we're not in a trade, enter Y-COMM to avoid a connection at this point. - ssf_press_button2(BUTTON_Y, OPEN_YCOMM_DELAY, 50); - ssf_press_button2(BUTTON_A, 200, 20); - ssf_press_button2(BUTTON_B, 80, 10); + ssf_press_button2(context, BUTTON_Y, OPEN_YCOMM_DELAY, 50); + ssf_press_button2(context, BUTTON_A, 200, 20); + ssf_press_button2(context, BUTTON_B, 80, 10); // Move to slot while (slot >= 6){ - ssf_press_dpad1(DPAD_DOWN, BOX_SCROLL_DELAY); + ssf_press_dpad1(context, DPAD_DOWN, BOX_SCROLL_DELAY); slot -= 6; } while (slot > 0){ - ssf_press_dpad1(DPAD_RIGHT, BOX_SCROLL_DELAY); + ssf_press_dpad1(context, DPAD_RIGHT, BOX_SCROLL_DELAY); slot--; } // Select Pokemon - ssf_press_button1(BUTTON_A, 100); - ssf_press_button1(BUTTON_A, CONFIRM_DELAY); + ssf_press_button1(context, BUTTON_A, 100); + ssf_press_button1(context, BUTTON_A, CONFIRM_DELAY); // Start Trade - ssf_press_button1(BUTTON_A, TRADE_START); + ssf_press_button1(context, BUTTON_A, TRADE_START); // Cancel out for (uint16_t c = 0; c < TRADE_COMMUNICATION + TRADE_ANIMATION; c += 300){ - ssf_press_button1(BUTTON_B, 100); - ssf_press_button1(BUTTON_B, 100); - ssf_press_button1(BUTTON_A, 100); + ssf_press_button1(context, BUTTON_B, 100); + ssf_press_button1(context, BUTTON_B, 100); + ssf_press_button1(context, BUTTON_A, 100); } } -void TradeBot::program(SingleSwitchProgramEnvironment& env) const{ +void TradeBot::program(SingleSwitchProgramEnvironment& env){ uint8_t code[8]; TRADE_CODE.to_str(code); - grip_menu_connect_go_home(); - resume_game_no_interact(TOLERATE_SYSTEM_UPDATE_MENU_FAST); + grip_menu_connect_go_home(env.console); + resume_game_no_interact(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST); for (uint8_t box = 0; box < BOXES_TO_TRADE; box++){ for (uint8_t c = 0; c < 30; c++){ - trade_slot(code, c); + trade_slot(env.console, code, c); } // If the previous trade isn't done, either wait to finish or cancel it. @@ -150,29 +159,29 @@ void TradeBot::program(SingleSwitchProgramEnvironment& env) const{ // because the trade is in progress. The 2nd iteration finishes it. // 4. No partner was ever found. The 1st iteration will cancel the trade. for (uint8_t c = 0; c < 2; c++){ - ssf_press_button1(BUTTON_Y, 250); - ssf_press_button1(BUTTON_A, 280); - ssf_press_button1(BUTTON_B, 280); - ssf_press_button1(BUTTON_B, 200); - ssf_press_button1(BUTTON_A, 100); - pbf_mash_button(BUTTON_B, TRADE_ANIMATION); + ssf_press_button1(env.console, BUTTON_Y, 250); + ssf_press_button1(env.console, BUTTON_A, 280); + ssf_press_button1(env.console, BUTTON_B, 280); + ssf_press_button1(env.console, BUTTON_B, 200); + ssf_press_button1(env.console, BUTTON_A, 100); + pbf_mash_button(env.console, BUTTON_B, TRADE_ANIMATION); } // Wait out any new pokedex entries or trade evolutions. - pbf_mash_button(BUTTON_B, EVOLVE_DELAY); + pbf_mash_button(env.console, BUTTON_B, EVOLVE_DELAY); // Change boxes. - ssf_press_button2(BUTTON_X, OVERWORLD_TO_MENU_DELAY, 20); - ssf_press_button2(BUTTON_A, MENU_TO_POKEMON_DELAY, 10); - ssf_press_button2(BUTTON_R, POKEMON_TO_BOX_DELAY, 10); - ssf_press_button2(BUTTON_R, BOX_CHANGE_DELAY, 10); - pbf_mash_button(BUTTON_B, BOX_TO_POKEMON_DELAY + POKEMON_TO_MENU_DELAY + OVERWORLD_TO_MENU_DELAY); + ssf_press_button2(env.console, BUTTON_X, OVERWORLD_TO_MENU_DELAY, 20); + ssf_press_button2(env.console, BUTTON_A, MENU_TO_POKEMON_DELAY, 10); + ssf_press_button2(env.console, BUTTON_R, POKEMON_TO_BOX_DELAY, 10); + ssf_press_button2(env.console, BUTTON_R, BOX_CHANGE_DELAY, 10); + pbf_mash_button(env.console, BUTTON_B, BOX_TO_POKEMON_DELAY + POKEMON_TO_MENU_DELAY + OVERWORLD_TO_MENU_DELAY); } - ssf_press_button2(BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); + ssf_press_button2(env.console, BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TradeBot.h b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TradeBot.h index 057749d2cd..a55f6709c9 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TradeBot.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TradeBot.h @@ -18,14 +18,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class TradeBot : public SingleSwitchProgram{ + +class TradeBot_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + TradeBot_Descriptor(); +}; + + + +class TradeBot : public SingleSwitchProgramInstance{ public: - TradeBot(); + TradeBot(const TradeBot_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: - void trade_slot(const uint8_t code[8], uint8_t slot) const; + void trade_slot(const BotBaseContext& context, const uint8_t code[8], uint8_t slot) const; private: FixedCode TRADE_CODE; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TurboA.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TurboA.cpp index 73f671ac9e..023b7e9ee7 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TurboA.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TurboA.cpp @@ -13,20 +13,29 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -TurboA::TurboA() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, + +TurboA_Descriptor::TurboA_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:TurboA", "Turbo A", "NativePrograms/TurboA.md", - "Endlessly mash A." + "Endlessly mash A.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) {} -void TurboA::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); - resume_game_back_out(TOLERATE_SYSTEM_UPDATE_MENU_FAST, 200); + + +TurboA::TurboA(const TurboA_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) +{} + +void TurboA::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + resume_game_back_out(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST, 200); while (true){ - pbf_press_button(BUTTON_A, 5, 5); + pbf_press_button(env.console, BUTTON_A, 5, 5); } } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TurboA.h b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TurboA.h index bd85a6c5a1..5b2033887f 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TurboA.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/BasicPrograms/PokemonSwSh_TurboA.h @@ -13,11 +13,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class TurboA : public SingleSwitchProgram{ + +class TurboA_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + TurboA_Descriptor(); +}; + + + +class TurboA : public SingleSwitchProgramInstance{ public: - TurboA(); + TurboA(const TurboA_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; }; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-BerryFarmer.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-BerryFarmer.cpp index 9973a4e687..814c3a36c9 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-BerryFarmer.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-BerryFarmer.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSettings.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" @@ -15,13 +15,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -BerryFarmer::BerryFarmer() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, + +BerryFarmer_Descriptor::BerryFarmer_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:BerryFarmer", "Date Spam: Berry Farmer", "NativePrograms/DateSpam-BerryFarmer.md", - "Farm berries." + "Farm berries.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +BerryFarmer::BerryFarmer(const BerryFarmer_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , SKIPS( "Number of Fetch Attempts:", 100000 @@ -35,40 +44,40 @@ BerryFarmer::BerryFarmer() m_options.emplace_back(&SAVE_ITERATIONS, "SAVE_ITERATIONS"); } -void BerryFarmer::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); +void BerryFarmer::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); uint8_t year = MAX_YEAR; uint16_t save_count = 0; for (uint32_t c = 0; c < SKIPS; c++){ env.log("Fetch Attempts: " + tostr_u_commas(c)); - home_roll_date_enter_game_autorollback(&year); - pbf_mash_button(BUTTON_B, 90); + home_roll_date_enter_game_autorollback(env.console, &year); + pbf_mash_button(env.console, BUTTON_B, 90); - pbf_press_button(BUTTON_A, 10, 10); - pbf_mash_button(BUTTON_ZL, 385); - pbf_mash_button(BUTTON_B, 600); + pbf_press_button(env.console, BUTTON_A, 10, 10); + pbf_mash_button(env.console, BUTTON_ZL, 385); + pbf_mash_button(env.console, BUTTON_B, 600); if (SAVE_ITERATIONS != 0){ save_count++; if (save_count >= SAVE_ITERATIONS){ save_count = 0; - pbf_mash_button(BUTTON_B, 2 * TICKS_PER_SECOND); - pbf_press_button(BUTTON_X, 20, OVERWORLD_TO_MENU_DELAY); - pbf_press_button(BUTTON_R, 20, 2 * TICKS_PER_SECOND); - pbf_press_button(BUTTON_ZL, 20, 3 * TICKS_PER_SECOND); + pbf_mash_button(env.console, BUTTON_B, 2 * TICKS_PER_SECOND); + pbf_press_button(env.console, BUTTON_X, 20, OVERWORLD_TO_MENU_DELAY); + pbf_press_button(env.console, BUTTON_R, 20, 2 * TICKS_PER_SECOND); + pbf_press_button(env.console, BUTTON_ZL, 20, 3 * TICKS_PER_SECOND); } } // Tap HOME and quickly spam B. The B spamming ensures that we don't // accidentally update the system if the system update window pops up. - pbf_press_button(BUTTON_HOME, 10, 5); - pbf_mash_button(BUTTON_B, GAME_TO_HOME_DELAY_FAST - 15); + pbf_press_button(env.console, BUTTON_HOME, 10, 5); + pbf_mash_button(env.console, BUTTON_B, GAME_TO_HOME_DELAY_FAST - 15); } - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-BerryFarmer.h b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-BerryFarmer.h index 458ece1450..c7ffea6cca 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-BerryFarmer.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-BerryFarmer.h @@ -14,11 +14,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class BerryFarmer : public SingleSwitchProgram{ + +class BerryFarmer_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + BerryFarmer_Descriptor(); +}; + + + +class BerryFarmer : public SingleSwitchProgramInstance{ public: - BerryFarmer(); + BerryFarmer(const BerryFarmer_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger SKIPS; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-DailyHighlightFarmer.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-DailyHighlightFarmer.cpp index a320b693f9..0a4ccfd732 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-DailyHighlightFarmer.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-DailyHighlightFarmer.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSettings.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" @@ -15,13 +15,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -DailyHighlightFarmer::DailyHighlightFarmer() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, + +DailyHighlightFarmer_Descriptor::DailyHighlightFarmer_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:DailyHighlightFarmer", "Date Spam: Daily Highlight Farmer", "NativePrograms/DateSpam-DailyHighlightFarmer.md", - "Farm the daily highlight watt trader in Crown Tundra." + "Farm the daily highlight watt trader in Crown Tundra.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +DailyHighlightFarmer::DailyHighlightFarmer(const DailyHighlightFarmer_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , SKIPS( "Number of Purchase Attempts:", 100000 @@ -35,41 +44,41 @@ DailyHighlightFarmer::DailyHighlightFarmer() m_options.emplace_back(&SAVE_ITERATIONS, "SAVE_ITERATIONS"); } -void DailyHighlightFarmer::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); +void DailyHighlightFarmer::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); uint8_t year = MAX_YEAR; uint16_t save_count = 0; for (uint32_t c = 0; c < SKIPS; c++){ env.log("Fetch Attempts: " + tostr_u_commas(c)); - home_roll_date_enter_game_autorollback(&year); - pbf_mash_button(BUTTON_B, 90); + home_roll_date_enter_game_autorollback(env.console, &year); + pbf_mash_button(env.console, BUTTON_B, 90); - pbf_press_button(BUTTON_A, 10, 110); - pbf_press_button(BUTTON_ZL, 10, 40); - pbf_press_dpad(DPAD_DOWN, 10, 10); - pbf_mash_button(BUTTON_ZL, 400); - pbf_mash_button(BUTTON_B, 700); + pbf_press_button(env.console, BUTTON_A, 10, 110); + pbf_press_button(env.console, BUTTON_ZL, 10, 40); + pbf_press_dpad(env.console, DPAD_DOWN, 10, 10); + pbf_mash_button(env.console, BUTTON_ZL, 400); + pbf_mash_button(env.console, BUTTON_B, 700); if (SAVE_ITERATIONS != 0){ save_count++; if (save_count >= SAVE_ITERATIONS){ save_count = 0; - pbf_mash_button(BUTTON_B, 2 * TICKS_PER_SECOND); - pbf_press_button(BUTTON_X, 20, OVERWORLD_TO_MENU_DELAY); - pbf_press_button(BUTTON_R, 20, 2 * TICKS_PER_SECOND); - pbf_press_button(BUTTON_ZL, 20, 3 * TICKS_PER_SECOND); + pbf_mash_button(env.console, BUTTON_B, 2 * TICKS_PER_SECOND); + pbf_press_button(env.console, BUTTON_X, 20, OVERWORLD_TO_MENU_DELAY); + pbf_press_button(env.console, BUTTON_R, 20, 2 * TICKS_PER_SECOND); + pbf_press_button(env.console, BUTTON_ZL, 20, 3 * TICKS_PER_SECOND); } } // Tap HOME and quickly spam B. The B spamming ensures that we don't // accidentally update the system if the system update window pops up. - pbf_press_button(BUTTON_HOME, 10, 5); - pbf_mash_button(BUTTON_B, GAME_TO_HOME_DELAY_FAST - 15); + pbf_press_button(env.console, BUTTON_HOME, 10, 5); + pbf_mash_button(env.console, BUTTON_B, GAME_TO_HOME_DELAY_FAST - 15); } - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-DailyHighlightFarmer.h b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-DailyHighlightFarmer.h index e8c894a057..efb2921f6d 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-DailyHighlightFarmer.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-DailyHighlightFarmer.h @@ -14,11 +14,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class DailyHighlightFarmer : public SingleSwitchProgram{ + +class DailyHighlightFarmer_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + DailyHighlightFarmer_Descriptor(); +}; + + + +class DailyHighlightFarmer : public SingleSwitchProgramInstance{ public: - DailyHighlightFarmer(); + DailyHighlightFarmer(const DailyHighlightFarmer_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger SKIPS; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-LotoFarmer.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-LotoFarmer.cpp index 1a3c805832..9024a57f13 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-LotoFarmer.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-LotoFarmer.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSettings.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" @@ -15,49 +15,58 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -LotoFarmer::LotoFarmer() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, + +LotoFarmer_Descriptor::LotoFarmer_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:LotoFarmer", "Date Spam: Loto Farmer", "NativePrograms/DateSpam-LotoFarmer.md", - "Farm the Loto ID." + "Farm the Loto ID.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +LotoFarmer::LotoFarmer(const LotoFarmer_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , SKIPS( "Number of Loto Attempts:", 100000 ) , MASH_B_DURATION( "Mash B for this long to exit the dialog:
(Some languages like German need to increase this.)", - "8 * TICKS_PER_SECOND" + "9 * TICKS_PER_SECOND" ) { m_options.emplace_back(&SKIPS, "SKIPS"); m_options.emplace_back(&MASH_B_DURATION, "MASH_B_DURATION"); } -void LotoFarmer::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); +void LotoFarmer::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); uint8_t year = MAX_YEAR; for (uint32_t c = 0; c < SKIPS; c++){ env.log("Fetch Attempts: " + tostr_u_commas(c)); - home_roll_date_enter_game_autorollback(&year); - pbf_mash_button(BUTTON_B, 90); + home_roll_date_enter_game_autorollback(env.console, &year); + pbf_mash_button(env.console, BUTTON_B, 90); - pbf_press_button(BUTTON_A, 10, 70); - pbf_press_button(BUTTON_B, 10, 70); - pbf_press_dpad(DPAD_DOWN, 10, 5); - pbf_mash_button(BUTTON_ZL, 490); - pbf_mash_button(BUTTON_B, MASH_B_DURATION); + pbf_press_button(env.console, BUTTON_A, 10, 70); + pbf_press_button(env.console, BUTTON_B, 10, 70); + pbf_press_dpad(env.console, DPAD_DOWN, 10, 5); + pbf_mash_button(env.console, BUTTON_ZL, 490); + pbf_mash_button(env.console, BUTTON_B, MASH_B_DURATION); // Tap HOME and quickly spam B. The B spamming ensures that we don't // accidentally update the system if the system update window pops up. - pbf_press_button(BUTTON_HOME, 10, 5); - pbf_mash_button(BUTTON_B, GAME_TO_HOME_DELAY_FAST - 15); + pbf_press_button(env.console, BUTTON_HOME, 10, 5); + pbf_mash_button(env.console, BUTTON_B, GAME_TO_HOME_DELAY_FAST - 15); } - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-LotoFarmer.h b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-LotoFarmer.h index 3c1110dcc8..e9f55bb9e3 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-LotoFarmer.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-LotoFarmer.h @@ -15,11 +15,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class LotoFarmer : public SingleSwitchProgram{ + +class LotoFarmer_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + LotoFarmer_Descriptor(); +}; + + + +class LotoFarmer : public SingleSwitchProgramInstance{ public: - LotoFarmer(); + LotoFarmer(const LotoFarmer_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger SKIPS; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-StowOnSideFarmer.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-StowOnSideFarmer.cpp index 768379ca7a..79708e56ef 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-StowOnSideFarmer.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-StowOnSideFarmer.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSettings.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" @@ -15,13 +15,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -StowOnSideFarmer::StowOnSideFarmer() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, + +StowOnSideFarmer_Descriptor::StowOnSideFarmer_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:StowOnSideFarmer", "Date Spam: Stow-On-Side Farmer", "NativePrograms/DateSpam-StowOnSideFarmer.md", - "Farm the Stow-on-Side items dealer." + "Farm the Stow-on-Side items dealer.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +StowOnSideFarmer::StowOnSideFarmer(const StowOnSideFarmer_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , SKIPS( "Number of Purchase Attempts:", 100000 @@ -35,39 +44,39 @@ StowOnSideFarmer::StowOnSideFarmer() m_options.emplace_back(&SAVE_ITERATIONS, "SAVE_ITERATIONS"); } -void StowOnSideFarmer::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); +void StowOnSideFarmer::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); uint8_t year = MAX_YEAR; uint16_t save_count = 0; for (uint32_t c = 0; c < SKIPS; c++){ env.log("Fetch Attempts: " + tostr_u_commas(c)); - home_roll_date_enter_game_autorollback(&year); - pbf_mash_button(BUTTON_B, 90); + home_roll_date_enter_game_autorollback(env.console, &year); + pbf_mash_button(env.console, BUTTON_B, 90); - pbf_press_button(BUTTON_A, 10, 10); - pbf_mash_button(BUTTON_ZL, 385); - pbf_mash_button(BUTTON_B, 700); + pbf_press_button(env.console, BUTTON_A, 10, 10); + pbf_mash_button(env.console, BUTTON_ZL, 385); + pbf_mash_button(env.console, BUTTON_B, 700); if (SAVE_ITERATIONS != 0){ save_count++; if (save_count >= SAVE_ITERATIONS){ save_count = 0; - pbf_mash_button(BUTTON_B, 2 * TICKS_PER_SECOND); - pbf_press_button(BUTTON_X, 20, OVERWORLD_TO_MENU_DELAY); - pbf_press_button(BUTTON_R, 20, 2 * TICKS_PER_SECOND); - pbf_press_button(BUTTON_ZL, 20, 3 * TICKS_PER_SECOND); + pbf_mash_button(env.console, BUTTON_B, 2 * TICKS_PER_SECOND); + pbf_press_button(env.console, BUTTON_X, 20, OVERWORLD_TO_MENU_DELAY); + pbf_press_button(env.console, BUTTON_R, 20, 2 * TICKS_PER_SECOND); + pbf_press_button(env.console, BUTTON_ZL, 20, 3 * TICKS_PER_SECOND); } } // Tap HOME and quickly spam B. The B spamming ensures that we don't // accidentally update the system if the system update window pops up. - pbf_press_button(BUTTON_HOME, 10, 5); - pbf_mash_button(BUTTON_B, GAME_TO_HOME_DELAY_FAST - 15); + pbf_press_button(env.console, BUTTON_HOME, 10, 5); + pbf_mash_button(env.console, BUTTON_B, GAME_TO_HOME_DELAY_FAST - 15); } - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-StowOnSideFarmer.h b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-StowOnSideFarmer.h index 7fc4a11ded..b84a774922 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-StowOnSideFarmer.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-StowOnSideFarmer.h @@ -14,11 +14,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class StowOnSideFarmer : public SingleSwitchProgram{ + +class StowOnSideFarmer_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + StowOnSideFarmer_Descriptor(); +}; + + + +class StowOnSideFarmer : public SingleSwitchProgramInstance{ public: - StowOnSideFarmer(); + StowOnSideFarmer(const StowOnSideFarmer_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger SKIPS; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-WattFarmer.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-WattFarmer.cpp index d763728690..b94bdafcb4 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-WattFarmer.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-WattFarmer.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSettings.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" @@ -15,13 +15,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -WattFarmer::WattFarmer() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, + +WattFarmer_Descriptor::WattFarmer_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:WattFarmer", "Date Spam: Watt Farmer", "NativePrograms/DateSpam-WattFarmer.md", - "Farm watts. (6.9 seconds/fetch, 1 million watts/hour)" + "Farm watts. (6.9 seconds/fetch, 1 million watts/hour)", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +WattFarmer::WattFarmer(const WattFarmer_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , SKIPS( "Number of Fetch Attempts:", 33334 @@ -35,39 +44,39 @@ WattFarmer::WattFarmer() m_options.emplace_back(&SAVE_ITERATIONS, "SAVE_ITERATIONS"); } -void WattFarmer::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); +void WattFarmer::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); uint8_t year = MAX_YEAR; uint16_t save_count = 0; for (uint32_t c = 0; c < SKIPS; c++){ env.log("Fetch Attempts: " + tostr_u_commas(c)); - home_roll_date_enter_game_autorollback(&year); - pbf_mash_button(BUTTON_B, 90); + home_roll_date_enter_game_autorollback(env.console, &year); + pbf_mash_button(env.console, BUTTON_B, 90); - pbf_press_button(BUTTON_A, 5, 5); - pbf_mash_button(BUTTON_B, 215); + pbf_press_button(env.console, BUTTON_A, 5, 5); + pbf_mash_button(env.console, BUTTON_B, 215); if (SAVE_ITERATIONS != 0){ save_count++; if (save_count >= SAVE_ITERATIONS){ save_count = 0; - pbf_mash_button(BUTTON_B, 2 * TICKS_PER_SECOND); - pbf_press_button(BUTTON_X, 20, OVERWORLD_TO_MENU_DELAY); - pbf_press_button(BUTTON_R, 20, 2 * TICKS_PER_SECOND); - pbf_press_button(BUTTON_ZL, 20, 3 * TICKS_PER_SECOND); + pbf_mash_button(env.console, BUTTON_B, 2 * TICKS_PER_SECOND); + pbf_press_button(env.console, BUTTON_X, 20, OVERWORLD_TO_MENU_DELAY); + pbf_press_button(env.console, BUTTON_R, 20, 2 * TICKS_PER_SECOND); + pbf_press_button(env.console, BUTTON_ZL, 20, 3 * TICKS_PER_SECOND); } } // Tap HOME and quickly spam B. The B spamming ensures that we don't // accidentally update the system if the system update window pops up. - pbf_press_button(BUTTON_HOME, 10, 5); - pbf_mash_button(BUTTON_B, GAME_TO_HOME_DELAY_FAST - 15); + pbf_press_button(env.console, BUTTON_HOME, 10, 5); + pbf_mash_button(env.console, BUTTON_B, GAME_TO_HOME_DELAY_FAST - 15); } - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-WattFarmer.h b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-WattFarmer.h index 2be1dff2c3..271d630299 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-WattFarmer.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DateSpamFarmers/PokemonSwSh_DateSpam-WattFarmer.h @@ -14,11 +14,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class WattFarmer : public SingleSwitchProgram{ + +class WattFarmer_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + WattFarmer_Descriptor(); +}; + + + +class WattFarmer : public SingleSwitchProgramInstance{ public: - WattFarmer(); + WattFarmer(const WattFarmer_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger SKIPS; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_BeamReset.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_BeamReset.cpp index 5bb760ec56..a8ea6ca402 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_BeamReset.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_BeamReset.cpp @@ -14,13 +14,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -BeamReset::BeamReset() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, + +BeamReset_Descriptor::BeamReset_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:BeamReset", "Beam Reset", "NativePrograms/BeamReset.md", - "Reset a beam until you see a purple beam." + "Reset a beam until you see a purple beam.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +BeamReset::BeamReset(const BeamReset_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , DELAY_BEFORE_RESET( "Delay before Reset:", "5 * TICKS_PER_SECOND" @@ -34,31 +43,31 @@ BeamReset::BeamReset() m_options.emplace_back(&EXTRA_LINE, "EXTRA_LINE"); } -void BeamReset::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); +void BeamReset::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); - resume_game_front_of_den_nowatts(TOLERATE_SYSTEM_UPDATE_MENU_SLOW); - pbf_mash_button(BUTTON_B, 100); + resume_game_front_of_den_nowatts(env.console, TOLERATE_SYSTEM_UPDATE_MENU_SLOW); + pbf_mash_button(env.console, BUTTON_B, 100); while (true){ // Talk to den. - pbf_press_button(BUTTON_A, 10, 450); + pbf_press_button(env.console, BUTTON_A, 10, 450); if (EXTRA_LINE){ - pbf_press_button(BUTTON_A, 10, 300); + pbf_press_button(env.console, BUTTON_A, 10, 300); } - pbf_press_button(BUTTON_A, 10, 300); + pbf_press_button(env.console, BUTTON_A, 10, 300); // Drop wishing piece. - pbf_press_button(BUTTON_A, 10, 70); - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_FAST); + pbf_press_button(env.console, BUTTON_A, 10, 70); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_FAST); for (uint16_t c = 0; c < 4; c++){ - pbf_press_button(BUTTON_HOME, 10, 10); - pbf_press_button(BUTTON_HOME, 10, 220); + pbf_press_button(env.console, BUTTON_HOME, 10, 10); + pbf_press_button(env.console, BUTTON_HOME, 10, 220); } - pbf_wait(DELAY_BEFORE_RESET); + pbf_wait(env.console, DELAY_BEFORE_RESET); - reset_game_from_home(TOLERATE_SYSTEM_UPDATE_MENU_SLOW); + reset_game_from_home(env.console, TOLERATE_SYSTEM_UPDATE_MENU_SLOW); } } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_BeamReset.h b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_BeamReset.h index a02c72a97b..35ee343b42 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_BeamReset.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_BeamReset.h @@ -15,11 +15,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class BeamReset : public SingleSwitchProgram{ + +class BeamReset_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + BeamReset_Descriptor(); +}; + + + +class BeamReset : public SingleSwitchProgramInstance{ public: - BeamReset(); + BeamReset(const BeamReset_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: TimeExpression DELAY_BEFORE_RESET; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperEU.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperEU.cpp index 4ebc131fbb..d01d5e10b5 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperEU.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperEU.cpp @@ -4,24 +4,34 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" #include "Common/PokemonSwSh/PokemonSwShDaySkippers.h" #include "NintendoSwitch/FixedInterval.h" +#include "PokemonSwSh_DaySkipperStats.h" #include "PokemonSwSh_DaySkipperEU.h" namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -DaySkipperEU::DaySkipperEU() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_31KB, + +DaySkipperEU_Descriptor::DaySkipperEU_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:DaySkipperEU", "Day Skipper (EU)", "NativePrograms/DaySkipperEU.md", - "A day skipper for EU date format that. (~7500 skips/hour)" + "A day skipper for EU date format that. (~7500 skips/hour)", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_31KB ) +{} + + + +DaySkipperEU::DaySkipperEU(const DaySkipperEU_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , SKIPS( "Number of Frame Skips:", 10 @@ -44,7 +54,14 @@ DaySkipperEU::DaySkipperEU() m_options.emplace_back(&CORRECTION_SKIPS, "CORRECTION_SKIPS"); } -void DaySkipperEU::program(SingleSwitchProgramEnvironment& env) const{ +std::unique_ptr DaySkipperEU::make_stats() const{ + return std::unique_ptr(new SkipperStats()); +} + +void DaySkipperEU::program(SingleSwitchProgramEnvironment& env){ + SkipperStats& stats = env.stats(); + stats.runs++; + // Setup globals. uint8_t real_life_year = (uint8_t)( REAL_LIFE_YEAR < 2000 ? 0 : @@ -54,42 +71,44 @@ void DaySkipperEU::program(SingleSwitchProgramEnvironment& env) const{ uint32_t remaining_skips = SKIPS; // Connect - pbf_press_button(BUTTON_ZR, 5, 5); + pbf_press_button(env.console, BUTTON_ZR, 5, 5); // Setup starting state. - skipper_init_view(); - skipper_rollback_year_full(false); + skipper_init_view(env.console); + skipper_rollback_year_full(env.console, false); year = 0; uint16_t correct_count = 0; while (remaining_skips > 0){ - skipper_increment_day(false); + skipper_increment_day(env.console, false); correct_count++; year++; remaining_skips--; - env.log("Skips Remaining: " + tostr_u_commas(remaining_skips)); + stats.issued++; +// env.log("Skips Remaining: " + tostr_u_commas(remaining_skips)); + env.update_stats(stats.to_str_current(remaining_skips)); if (year >= 60){ if (real_life_year <= 36){ - skipper_rollback_year_sync(); + skipper_rollback_year_sync(env.console); year = real_life_year; }else{ - skipper_rollback_year_full(false); + skipper_rollback_year_full(env.console, false); year = 0; } } if (CORRECTION_SKIPS != 0 && correct_count == CORRECTION_SKIPS){ correct_count = 0; - skipper_auto_recovery(); + skipper_auto_recovery(env.console); } } // Prevent the Switch from sleeping and the time from advancing. - end_program_callback(); - pbf_wait(15 * TICKS_PER_SECOND); + end_program_callback(env.console); + pbf_wait(env.console, 15 * TICKS_PER_SECOND); while (true){ - ssf_press_button1(BUTTON_A, 15 * TICKS_PER_SECOND); + ssf_press_button1(env.console, BUTTON_A, 15 * TICKS_PER_SECOND); } } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperEU.h b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperEU.h index 1565c717dd..9b3beba9f6 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperEU.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperEU.h @@ -15,11 +15,20 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class DaySkipperEU : public SingleSwitchProgram{ + +class DaySkipperEU_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + DaySkipperEU_Descriptor(); +}; + + + +class DaySkipperEU : public SingleSwitchProgramInstance{ public: - DaySkipperEU(); + DaySkipperEU(const DaySkipperEU_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual std::unique_ptr make_stats() const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger SKIPS; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperJPN-7.8k.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperJPN-7.8k.cpp index 83d10f1c0a..eab57d82ce 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperJPN-7.8k.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperJPN-7.8k.cpp @@ -4,23 +4,33 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" #include "Common/PokemonSwSh/PokemonSwShDaySkippers.h" #include "NintendoSwitch/FixedInterval.h" +#include "PokemonSwSh_DaySkipperStats.h" #include "PokemonSwSh_DaySkipperJPN-7.8k.h" namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -DaySkipperJPN7p8k::DaySkipperJPN7p8k() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_31KB, + +DaySkipperJPN7p8k_Descriptor::DaySkipperJPN7p8k_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:DaySkipperJPN7p8k", "Day Skipper (JPN) - 7.8k", "NativePrograms/DaySkipperJPN-7.8k.md", - "A faster, but less reliable Japanese date skipper. (7800 skips/hour)" + "A faster, but less reliable Japanese date skipper. (7800 skips/hour)", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_31KB ) +{} + + + +DaySkipperJPN7p8k::DaySkipperJPN7p8k(const DaySkipperJPN7p8k_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , SKIPS( "Number of Frame Skips:", 10 @@ -43,6 +53,10 @@ DaySkipperJPN7p8k::DaySkipperJPN7p8k() m_options.emplace_back(&CORRECTION_SKIPS, "CORRECTION_SKIPS"); } +std::unique_ptr DaySkipperJPN7p8k::make_stats() const{ + return std::unique_ptr(new SkipperStats()); +} + const uint8_t DAYS_PER_MONTH[] = { 31, // January 28, // February @@ -71,11 +85,11 @@ typedef struct{ bool is_start(const DateSmall* date){ return date->year != 0 || date->month != 1 || date->day != 1; } -bool date_increment_day(DateSmall* date, bool press){ +bool date_increment_day(const BotBaseContext& context, DateSmall* date, bool press){ uint8_t days = days_in_month(date->year, date->month); if (date->day != days){ if (press){ - skipper_increment_day(false); + skipper_increment_day(context, false); } date->day++; return true; @@ -96,25 +110,28 @@ bool date_increment_day(DateSmall* date, bool press){ } if (date->month != 1){ - skipper_increment_month(DAYS_PER_MONTH[date->month - 1]); + skipper_increment_month(context, DAYS_PER_MONTH[date->month - 1]); return true; } if (date->year != 0){ - skipper_increment_all(); + skipper_increment_all(context); return true; } - skipper_increment_all_rollback(); + skipper_increment_all_rollback(context); return false; } -void DaySkipperJPN7p8k::program(SingleSwitchProgramEnvironment& env) const{ +void DaySkipperJPN7p8k::program(SingleSwitchProgramEnvironment& env){ + SkipperStats& stats = env.stats(); + stats.runs++; + // Setup globals. uint32_t remaining_skips = SKIPS; // Connect - pbf_press_button(BUTTON_ZL, 5, 5); + pbf_press_button(env.console, BUTTON_ZL, 5, 5); // Sanitize starting date. uint16_t year = (uint16_t)((QDate)START_DATE).year(); @@ -134,27 +151,30 @@ void DaySkipperJPN7p8k::program(SingleSwitchProgramEnvironment& env) const{ } // Setup starting state. - skipper_init_view(); + skipper_init_view(env.console); uint16_t correct_count = 0; while (remaining_skips > 0){ - if (date_increment_day(&date, true)){ - remaining_skips--; + if (date_increment_day(env.console, &date, true)){ correct_count++; + remaining_skips--; + stats.issued++; env.log("Expected Date: " + QDate(date.year + 2000, date.month, date.day).toString("yyyy/MM/dd")); - env.log("Skips Remaining: " + tostr_u_commas(remaining_skips)); +// env.log("Skips Remaining: " + tostr_u_commas(remaining_skips)); + env.update_stats(stats.to_str_current(remaining_skips)); } if (CORRECTION_SKIPS != 0 && correct_count == CORRECTION_SKIPS){ correct_count = 0; - skipper_auto_recovery(); + skipper_auto_recovery(env.console); } + } // Prevent the Switch from sleeping and the time from advancing. - end_program_callback(); - pbf_wait(15 * TICKS_PER_SECOND); + end_program_callback(env.console); + pbf_wait(env.console, 15 * TICKS_PER_SECOND); while (true){ - ssf_press_button1(BUTTON_A, 15 * TICKS_PER_SECOND); + ssf_press_button1(env.console, BUTTON_A, 15 * TICKS_PER_SECOND); } } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperJPN-7.8k.h b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperJPN-7.8k.h index dd27910376..190a8a19bb 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperJPN-7.8k.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperJPN-7.8k.h @@ -17,11 +17,20 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class DaySkipperJPN7p8k : public SingleSwitchProgram{ + +class DaySkipperJPN7p8k_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + DaySkipperJPN7p8k_Descriptor(); +}; + + + +class DaySkipperJPN7p8k : public SingleSwitchProgramInstance{ public: - DaySkipperJPN7p8k(); + DaySkipperJPN7p8k(const DaySkipperJPN7p8k_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual std::unique_ptr make_stats() const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger SKIPS; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperJPN.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperJPN.cpp index 3fcd63f814..733ee7df4b 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperJPN.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperJPN.cpp @@ -4,24 +4,34 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" #include "Common/PokemonSwSh/PokemonSwShDaySkippers.h" #include "NintendoSwitch/FixedInterval.h" +#include "PokemonSwSh_DaySkipperStats.h" #include "PokemonSwSh_DaySkipperJPN.h" namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -DaySkipperJPN::DaySkipperJPN() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_31KB, + +DaySkipperJPN_Descriptor::DaySkipperJPN_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:DaySkipperJPN", "Day Skipper (JPN)", "NativePrograms/DaySkipperJPN.md", - "A day skipper for Japanese date format. (7600 skips/hour)" + "A day skipper for Japanese date format. (7600 skips/hour)", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_31KB ) +{} + + + +DaySkipperJPN::DaySkipperJPN(const DaySkipperJPN_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , SKIPS( "Number of Frame Skips:", 10 @@ -39,20 +49,27 @@ DaySkipperJPN::DaySkipperJPN() m_options.emplace_back(&CORRECTION_SKIPS, "CORRECTION_SKIPS"); } -void DaySkipperJPN::program(SingleSwitchProgramEnvironment& env) const{ +std::unique_ptr DaySkipperJPN::make_stats() const{ + return std::unique_ptr(new SkipperStats()); +} + +void DaySkipperJPN::program(SingleSwitchProgramEnvironment& env){ + SkipperStats& stats = env.stats(); + stats.runs++; + // Setup globals. uint32_t remaining_skips = SKIPS; // Connect - pbf_press_button(BUTTON_ZR, 5, 5); + pbf_press_button(env.console, BUTTON_ZR, 5, 5); // Setup starting state. - skipper_init_view(); + skipper_init_view(env.console); uint8_t day = 1; uint16_t correct_count = 0; while (remaining_skips > 0){ - skipper_increment_day(false); + skipper_increment_day(env.console, false); if (day == 31){ day = 1; @@ -60,19 +77,22 @@ void DaySkipperJPN::program(SingleSwitchProgramEnvironment& env) const{ correct_count++; day++; remaining_skips--; - env.log("Skips Remaining: " + tostr_u_commas(remaining_skips)); + stats.issued++; +// env.log("Skips Remaining: " + tostr_u_commas(remaining_skips)); + env.update_stats(stats.to_str_current(remaining_skips)); } if (CORRECTION_SKIPS != 0 && correct_count == CORRECTION_SKIPS){ correct_count = 0; - skipper_auto_recovery(); + skipper_auto_recovery(env.console); } + } // Prevent the Switch from sleeping and the time from advancing. - end_program_callback(); - pbf_wait(15 * TICKS_PER_SECOND); + end_program_callback(env.console); + pbf_wait(env.console, 15 * TICKS_PER_SECOND); while (true){ - ssf_press_button1(BUTTON_A, 15 * TICKS_PER_SECOND); + ssf_press_button1(env.console, BUTTON_A, 15 * TICKS_PER_SECOND); } } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperJPN.h b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperJPN.h index 6278141181..786b1e6d36 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperJPN.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperJPN.h @@ -15,11 +15,20 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class DaySkipperJPN : public SingleSwitchProgram{ + +class DaySkipperJPN_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + DaySkipperJPN_Descriptor(); +}; + + + +class DaySkipperJPN : public SingleSwitchProgramInstance{ public: - DaySkipperJPN(); + DaySkipperJPN(const DaySkipperJPN_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual std::unique_ptr make_stats() const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger SKIPS; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperStats.h b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperStats.h new file mode 100644 index 0000000000..48e152f472 --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperStats.h @@ -0,0 +1,42 @@ +/* Day Skipper Stats + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PokemonSwSh_DaySkipperStats_H +#define PokemonAutomation_PokemonSwSh_DaySkipperStats_H + +#include "Common/Cpp/PrettyPrint.h" +#include "CommonFramework/Tools/StatsTracking.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +class SkipperStats : public StatsTracker{ +public: + SkipperStats() + : runs(m_stats["Runs"]) + , issued(m_stats["Skips Issued"]) + { + m_display_order.emplace_back(Stat("Runs")); + m_display_order.emplace_back(Stat("Skips Issued")); + } + + std::string to_str_current(uint64_t skips_remaining) const{ + return + "Skips Issued: " + std::to_string(issued) + + " - Skips Remaining: " + tostr_u_commas(skips_remaining); + } + + uint64_t& runs; + uint64_t& issued; +}; + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperUS.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperUS.cpp index 49068715e6..cfba665c8d 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperUS.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperUS.cpp @@ -4,24 +4,34 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" #include "Common/PokemonSwSh/PokemonSwShDaySkippers.h" #include "NintendoSwitch/FixedInterval.h" +#include "PokemonSwSh_DaySkipperStats.h" #include "PokemonSwSh_DaySkipperUS.h" namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -DaySkipperUS::DaySkipperUS() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_31KB, + +DaySkipperUS_Descriptor::DaySkipperUS_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:DaySkipperUS", "Day Skipper (US)", "NativePrograms/DaySkipperUS.md", - "A day skipper for US date format that. (~7500 skips/hour)" + "A day skipper for US date format that. (~7500 skips/hour)", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_31KB ) +{} + + + +DaySkipperUS::DaySkipperUS(const DaySkipperUS_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , SKIPS( "Number of Frame Skips:", 10 @@ -44,7 +54,14 @@ DaySkipperUS::DaySkipperUS() m_options.emplace_back(&CORRECTION_SKIPS, "CORRECTION_SKIPS"); } -void DaySkipperUS::program(SingleSwitchProgramEnvironment& env) const{ +std::unique_ptr DaySkipperUS::make_stats() const{ + return std::unique_ptr(new SkipperStats()); +} + +void DaySkipperUS::program(SingleSwitchProgramEnvironment& env){ + SkipperStats& stats = env.stats(); + stats.runs++; + // Setup globals. uint8_t real_life_year = (uint8_t)( REAL_LIFE_YEAR < 2000 ? 0 : @@ -54,42 +71,44 @@ void DaySkipperUS::program(SingleSwitchProgramEnvironment& env) const{ uint32_t remaining_skips = SKIPS; // Connect - pbf_press_button(BUTTON_ZR, 5, 5); + pbf_press_button(env.console, BUTTON_ZR, 5, 5); // Setup starting state. - skipper_init_view(); - skipper_rollback_year_full(true); + skipper_init_view(env.console); + skipper_rollback_year_full(env.console, true); year = 0; uint16_t correct_count = 0; while (remaining_skips > 0){ - skipper_increment_day(true); + skipper_increment_day(env.console, true); correct_count++; year++; remaining_skips--; - env.log("Skips Remaining: " + tostr_u_commas(remaining_skips)); + stats.issued++; +// env.log("Skips Remaining: " + tostr_u_commas(remaining_skips)); + env.update_stats(stats.to_str_current(remaining_skips)); if (year >= 60){ if (real_life_year <= 36){ - skipper_rollback_year_sync(); + skipper_rollback_year_sync(env.console); year = real_life_year; }else{ - skipper_rollback_year_full(true); + skipper_rollback_year_full(env.console, true); year = 0; } } if (CORRECTION_SKIPS != 0 && correct_count == CORRECTION_SKIPS){ correct_count = 0; - skipper_auto_recovery(); + skipper_auto_recovery(env.console); } } // Prevent the Switch from sleeping and the time from advancing. - end_program_callback(); - pbf_wait(15 * TICKS_PER_SECOND); + end_program_callback(env.console); + pbf_wait(env.console, 15 * TICKS_PER_SECOND); while (true){ - ssf_press_button1(BUTTON_A, 15 * TICKS_PER_SECOND); + ssf_press_button1(env.console, BUTTON_A, 15 * TICKS_PER_SECOND); } } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperUS.h b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperUS.h index 8dc7c2ca71..eb7a48703f 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperUS.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_DaySkipperUS.h @@ -15,11 +15,20 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class DaySkipperUS : public SingleSwitchProgram{ + +class DaySkipperUS_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + DaySkipperUS_Descriptor(); +}; + + + +class DaySkipperUS : public SingleSwitchProgramInstance{ public: - DaySkipperUS(); + DaySkipperUS(const DaySkipperUS_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual std::unique_ptr make_stats() const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger SKIPS; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_EventBeamFinder.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_EventBeamFinder.cpp index 1983cd842f..2c9d529b26 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_EventBeamFinder.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_EventBeamFinder.cpp @@ -15,13 +15,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -EventBeamFinder::EventBeamFinder() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, + +EventBeamFinder_Descriptor::EventBeamFinder_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:EventBeamFinder", "Event Beam Finder", "NativePrograms/EventBeamFinder.md", - "Drop wishing pieces until you find an event den." + "Drop wishing pieces until you find an event den.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +EventBeamFinder::EventBeamFinder(const EventBeamFinder_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , WAIT_TIME_IN_DEN( "Wait time in Den:", "5 * TICKS_PER_SECOND" @@ -31,58 +40,58 @@ EventBeamFinder::EventBeamFinder() } -void EventBeamFinder::goto_near_den(void) const{ - ssf_hold_joystick1(true, STICK_CENTER, STICK_MIN, 375); - pbf_wait(50); - ssf_press_button1(BUTTON_PLUS, 100); - ssf_press_joystick2(true, STICK_MAX, STICK_CENTER, 100, 5); - ssf_press_button1(BUTTON_L, 100); - ssf_press_button1(BUTTON_PLUS, 100); - ssf_hold_joystick1(true, STICK_CENTER, STICK_MIN, 370); +void EventBeamFinder::goto_near_den(const BotBaseContext& context) const{ + ssf_hold_joystick1(context, true, STICK_CENTER, STICK_MIN, 375); + pbf_wait(context, 50); + ssf_press_button1(context, BUTTON_PLUS, 100); + ssf_press_joystick2(context, true, STICK_MAX, STICK_CENTER, 100, 5); + ssf_press_button1(context, BUTTON_L, 100); + ssf_press_button1(context, BUTTON_PLUS, 100); + ssf_hold_joystick1(context, true, STICK_CENTER, STICK_MIN, 370); } -void EventBeamFinder::goto_far_den(void) const{ - ssf_hold_joystick1(true, STICK_CENTER, STICK_MIN, 992); - pbf_wait(50); - ssf_press_button1(BUTTON_PLUS, 100); - ssf_press_joystick2(true, STICK_MIN, STICK_CENTER, 100, 5); - ssf_press_button1(BUTTON_L, 100); - ssf_press_button1(BUTTON_PLUS, 100); - ssf_hold_joystick1(true, STICK_CENTER, STICK_MIN, 300); +void EventBeamFinder::goto_far_den(const BotBaseContext& context) const{ + ssf_hold_joystick1(context, true, STICK_CENTER, STICK_MIN, 992); + pbf_wait(context, 50); + ssf_press_button1(context, BUTTON_PLUS, 100); + ssf_press_joystick2(context, true, STICK_MIN, STICK_CENTER, 100, 5); + ssf_press_button1(context, BUTTON_L, 100); + ssf_press_button1(context, BUTTON_PLUS, 100); + ssf_hold_joystick1(context, true, STICK_CENTER, STICK_MIN, 300); } -void EventBeamFinder::drop_wishing_piece(void) const{ - ssf_press_button2(BUTTON_A, 200, 10); - ssf_press_button2(BUTTON_A, 150, 10); - ssf_press_button1(BUTTON_A, 5); - pbf_mash_button(BUTTON_B, 500); - ssf_press_button2(BUTTON_A, WAIT_TIME_IN_DEN + 100, 10); - pbf_mash_button(BUTTON_B, 600); +void EventBeamFinder::drop_wishing_piece(const BotBaseContext& context) const{ + ssf_press_button2(context, BUTTON_A, 200, 10); + ssf_press_button2(context, BUTTON_A, 150, 10); + ssf_press_button1(context, BUTTON_A, 5); + pbf_mash_button(context, BUTTON_B, 500); + ssf_press_button2(context, BUTTON_A, WAIT_TIME_IN_DEN + 100, 10); + pbf_mash_button(context, BUTTON_B, 600); } -void EventBeamFinder::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); +void EventBeamFinder::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); - resume_game_no_interact(TOLERATE_SYSTEM_UPDATE_MENU_FAST); - pbf_mash_button(BUTTON_B, 700); + resume_game_no_interact(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST); + pbf_mash_button(env.console, BUTTON_B, 700); bool parity = false; while (true){ // Fly back to daycare. - ssf_press_button2(BUTTON_X, OVERWORLD_TO_MENU_DELAY, 20); - pbf_mash_button(BUTTON_A, 700); + ssf_press_button2(env.console, BUTTON_X, OVERWORLD_TO_MENU_DELAY, 20); + pbf_mash_button(env.console, BUTTON_A, 700); // Goto den. if (parity){ - goto_far_den(); + goto_far_den(env.console); }else{ - goto_near_den(); + goto_near_den(env.console); } parity = !parity; // Drop wishing piece and see what you get. - drop_wishing_piece(); + drop_wishing_piece(env.console); } - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_EventBeamFinder.h b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_EventBeamFinder.h index 9df43cd3db..b4081e63cc 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_EventBeamFinder.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_EventBeamFinder.h @@ -14,15 +14,23 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class EventBeamFinder : public SingleSwitchProgram{ + +class EventBeamFinder_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + EventBeamFinder_Descriptor(); +}; + + + +class EventBeamFinder : public SingleSwitchProgramInstance{ public: - EventBeamFinder(); + EventBeamFinder(const EventBeamFinder_Descriptor& descriptor); - void goto_near_den(void) const; - void goto_far_den(void) const; - void drop_wishing_piece(void) const; - virtual void program(SingleSwitchProgramEnvironment& env) const override; + void goto_near_den(const BotBaseContext& context) const; + void goto_far_den(const BotBaseContext& context) const; + void drop_wishing_piece(const BotBaseContext& context) const; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: TimeExpression WAIT_TIME_IN_DEN; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_PurpleBeamFinder.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_PurpleBeamFinder.cpp index e29eeb3cdb..f48ba7f2a3 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_PurpleBeamFinder.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_PurpleBeamFinder.cpp @@ -4,9 +4,10 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/FrameworkSettings.h" #include "Common/SwitchFramework/Switch_PushButtons.h" +#include "CommonFramework/PersistentSettings.h" #include "Common/PokemonSwSh/PokemonSettings.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" #include "CommonFramework/Tools/StatsTracking.h" @@ -19,29 +20,67 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ -PurpleBeamFinder::PurpleBeamFinder() - : SingleSwitchProgram( - FeedbackType::REQUIRED, PABotBaseLevel::PABOTBASE_12KB, +PurpleBeamFinder_Descriptor::PurpleBeamFinder_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:PurpleBeamFinder", "Purple Beam Finder", "SerialPrograms/PurpleBeamFinder.md", - "Automatically reset for a purple beam." + "Automatically reset for a purple beam.", + FeedbackType::REQUIRED, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +PurpleBeamFinder::PurpleBeamFinder(const PurpleBeamFinder_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , EXTRA_LINE( "Extra Line:
(German has an extra line of text.)", false ) - , DETECTION_THRESHOLD( - "Red Beam Detection Threshold:", - 0.02, 0.0, 1.0 + , m_advanced_options( + "Advanced Options: Don't adjust these unless you're having problems." + ) + , SAVE_SCREENSHOT( + "Screenshot Purple Beams: (for debugging purposes)", + false ) , TIMEOUT_DELAY( "Timeout Delay:
Reset if no beam is detected after this long.", "2 * TICKS_PER_SECOND" ) +// , MAX_STDDEV( +// "Maximum Standard Deviation:
Range: 0 - 768", +// 10, 0, 768 +// ) + , MIN_BRIGHTNESS( + "Minimum Brightness:
Range: 0 - 768", + 500, 0, 768 + ) + , MIN_EUCLIDEAN( + "Minimum Euclidean Distance:
Range: 0 - 443", + 15, 0, 443 + ) + , MIN_DELTA_STDDEV_RATIO( + "Minimum Delta/Stddev Ratio:", + 5.0, 0 + ) + , MIN_SIGMA_STDDEV_RATIO( + "Minimum Sigma/Stddev Ratio:", + 5.0, 0 + ) { m_options.emplace_back(&EXTRA_LINE, "EXTRA_LINE"); - m_options.emplace_back(&DETECTION_THRESHOLD, "DETECTION_THRESHOLD"); - m_options.emplace_back(&TIMEOUT_DELAY, "TIMEOUT_DELAY"); + if (PERSISTENT_SETTINGS().developer_mode){ + m_options.emplace_back(&m_advanced_options, ""); + m_options.emplace_back(&SAVE_SCREENSHOT, "SAVE_SCREENSHOT"); + m_options.emplace_back(&TIMEOUT_DELAY, "TIMEOUT_DELAY"); + m_options.emplace_back(&MIN_BRIGHTNESS, "MIN_BRIGHTNESS"); + m_options.emplace_back(&MIN_EUCLIDEAN, "MIN_EUCLIDEAN"); + m_options.emplace_back(&MIN_DELTA_STDDEV_RATIO, "MIN_DELTA_STDDEV_RATIO"); + m_options.emplace_back(&MIN_SIGMA_STDDEV_RATIO, "MIN_SIGMA_STDDEV_RATIO"); + } } @@ -53,18 +92,23 @@ struct PurpleBeamFinder::Stats : public StatsTracker{ , timeouts(m_stats["Timeouts"]) , red_detected(m_stats["Red Detected"]) , red_presumed(m_stats["Red Presumed"]) + , red(m_stats["Red"]) , purple(m_stats["Purple"]) { m_display_order.emplace_back(Stat("Attempts")); m_display_order.emplace_back(Stat("Timeouts")); - m_display_order.emplace_back(Stat("Red Detected")); - m_display_order.emplace_back(Stat("Red Presumed")); +// m_display_order.emplace_back(Stat("Red Detected")); +// m_display_order.emplace_back(Stat("Red Presumed")); + m_display_order.emplace_back(Stat("Red")); m_display_order.emplace_back(Stat("Purple")); + m_aliases["Red Detected"] = "Red"; + m_aliases["Red Presumed"] = "Red"; } uint64_t& attempts; uint64_t& timeouts; uint64_t& red_detected; uint64_t& red_presumed; + uint64_t& red; uint64_t& purple; }; std::unique_ptr PurpleBeamFinder::make_stats() const{ @@ -73,11 +117,12 @@ std::unique_ptr PurpleBeamFinder::make_stats() const{ -void PurpleBeamFinder::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); - resume_game_front_of_den_nowatts(TOLERATE_SYSTEM_UPDATE_MENU_SLOW); - pbf_mash_button(BUTTON_B, 100); +void PurpleBeamFinder::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + + resume_game_front_of_den_nowatts(env.console, TOLERATE_SYSTEM_UPDATE_MENU_SLOW); + pbf_mash_button(env.console, BUTTON_B, 100); env.console.botbase().wait_for_all_requests(); @@ -87,17 +132,25 @@ void PurpleBeamFinder::program(SingleSwitchProgramEnvironment& env) const{ bool exit = false; while (true){ // Talk to den. - pbf_press_button(BUTTON_A, 10, 450); + pbf_press_button(env.console, BUTTON_A, 10, 450); if (EXTRA_LINE){ - pbf_press_button(BUTTON_A, 10, 300); + pbf_press_button(env.console, BUTTON_A, 10, 300); } - pbf_press_button(BUTTON_A, 10, 300); + pbf_press_button(env.console, BUTTON_A, 10, 300); env.console.botbase().wait_for_all_requests(); BeamSetter::Detection detection; { BeamSetter setter(env.console, env.logger()); - detection = setter.run(env, env.console, DETECTION_THRESHOLD, TIMEOUT_DELAY); + detection = setter.run( + env, env.console, + SAVE_SCREENSHOT, + TIMEOUT_DELAY, + MIN_BRIGHTNESS, + MIN_EUCLIDEAN, + MIN_DELTA_STDDEV_RATIO, + MIN_SIGMA_STDDEV_RATIO + ); stats.attempts++; } switch (detection){ @@ -120,7 +173,7 @@ void PurpleBeamFinder::program(SingleSwitchProgramEnvironment& env) const{ break; } - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); reset_game_from_home_with_inference( env, env.console, TOLERATE_SYSTEM_UPDATE_MENU_SLOW @@ -129,8 +182,8 @@ void PurpleBeamFinder::program(SingleSwitchProgramEnvironment& env) const{ while (true){ - pbf_press_button(BUTTON_B, 20, 20); - pbf_press_button(BUTTON_LCLICK, 20, 20); + pbf_press_button(env.console, BUTTON_B, 20, 20); + pbf_press_button(env.console, BUTTON_LCLICK, 20, 20); } } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_PurpleBeamFinder.h b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_PurpleBeamFinder.h index 8e77f6925a..1ab58da153 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_PurpleBeamFinder.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/DenHunting/PokemonSwSh_PurpleBeamFinder.h @@ -7,6 +7,7 @@ #ifndef PokemonAutomation_PokemonSwSh_PurpleBeamFinder_H #define PokemonAutomation_PokemonSwSh_PurpleBeamFinder_H +#include "CommonFramework/Options/SectionDivider.h" #include "CommonFramework/Options/BooleanCheckBox.h" #include "CommonFramework/Options/FloatingPoint.h" #include "NintendoSwitch/Options/TimeExpression.h" @@ -16,19 +17,34 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class PurpleBeamFinder : public SingleSwitchProgram{ + +class PurpleBeamFinder_Descriptor : public RunnableSwitchProgramDescriptor{ public: - PurpleBeamFinder(); + PurpleBeamFinder_Descriptor(); +}; + + + +class PurpleBeamFinder : public SingleSwitchProgramInstance{ +public: + PurpleBeamFinder(const PurpleBeamFinder_Descriptor& descriptor); virtual std::unique_ptr make_stats() const override; - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: struct Stats; BooleanCheckBox EXTRA_LINE; - FloatingPoint DETECTION_THRESHOLD; + + SectionDivider m_advanced_options; + BooleanCheckBox SAVE_SCREENSHOT; TimeExpression TIMEOUT_DELAY; +// FloatingPoint MAX_STDDEV; + FloatingPoint MIN_BRIGHTNESS; + FloatingPoint MIN_EUCLIDEAN; + FloatingPoint MIN_DELTA_STDDEV_RATIO; + FloatingPoint MIN_SIGMA_STDDEV_RATIO; }; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggCombined2.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggCombined2.cpp index f8785bef3c..3095239d97 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggCombined2.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggCombined2.cpp @@ -13,13 +13,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -EggCombined2::EggCombined2() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_31KB, + +EggCombined2_Descriptor::EggCombined2_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:EggCombined2", "Egg Combined 2", "NativePrograms/EggCombined2.md", - "Fetch and hatch eggs at the same time. (Fastest - 1700 eggs/day for 5120-step)" + "Fetch and hatch eggs at the same time. (Fastest - 1700 eggs/day for 5120-step)", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_31KB ) +{} + + + +EggCombined2::EggCombined2(const EggCombined2_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , BOXES_TO_HATCH( "Boxes to Hatch:", 32, 0, 32 @@ -58,7 +67,7 @@ EggCombined2::EggCombined2() m_options.emplace_back(&HATCH_DELAY, "HATCH_DELAY"); } -void EggCombined2::program(SingleSwitchProgramEnvironment& env) const{ +void EggCombined2::program(SingleSwitchProgramEnvironment& env){ EggCombinedSession session{ .BOXES_TO_HATCH = BOXES_TO_HATCH, .STEPS_TO_HATCH = STEPS_TO_HATCH, @@ -69,13 +78,13 @@ void EggCombined2::program(SingleSwitchProgramEnvironment& env) const{ .TOUCH_DATE_INTERVAL = TOUCH_DATE_INTERVAL, }; - grip_menu_connect_go_home(); - resume_game_back_out(TOLERATE_SYSTEM_UPDATE_MENU_FAST, 400); + grip_menu_connect_go_home(env.console); + resume_game_back_out(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST, 400); session.eggcombined2_body(env); - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggCombined2.h b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggCombined2.h index 8da0e8584c..d76d25805b 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggCombined2.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggCombined2.h @@ -19,11 +19,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class EggCombined2 : public SingleSwitchProgram{ + +class EggCombined2_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + EggCombined2_Descriptor(); +}; + + + +class EggCombined2 : public SingleSwitchProgramInstance{ public: - EggCombined2(); + EggCombined2(const EggCombined2_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger BOXES_TO_HATCH; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggCombinedShared.h b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggCombinedShared.h index f0bd142f70..7b7432540c 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggCombinedShared.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggCombinedShared.h @@ -65,52 +65,52 @@ struct EggCombinedSession{ return block; } - void withdraw_column_shiftR(uint8_t column){ - menu_to_box(false); - party_to_column(column); - pickup_column(false); - ssf_press_button2(BUTTON_R, BOX_CHANGE_DELAY, EGG_BUTTON_HOLD_DELAY); - column_to_party(column); - ssf_press_button2(BUTTON_A, BOX_PICKUP_DROP_DELAY, EGG_BUTTON_HOLD_DELAY); - box_to_menu(); + void withdraw_column_shiftR(const BotBaseContext& context, uint8_t column){ + menu_to_box(context, false); + party_to_column(context, column); + pickup_column(context, false); + ssf_press_button2(context, BUTTON_R, BOX_CHANGE_DELAY, EGG_BUTTON_HOLD_DELAY); + column_to_party(context, column); + ssf_press_button2(context, BUTTON_A, BOX_PICKUP_DROP_DELAY, EGG_BUTTON_HOLD_DELAY); + box_to_menu(context); } - void deposit_column_shiftL(uint8_t column){ - menu_to_box(true); - pickup_column(true); - party_to_column(column); - ssf_press_button2(BUTTON_L, BOX_CHANGE_DELAY, EGG_BUTTON_HOLD_DELAY); - ssf_press_button2(BUTTON_A, BOX_PICKUP_DROP_DELAY, EGG_BUTTON_HOLD_DELAY); - box_to_menu(); + void deposit_column_shiftL(const BotBaseContext& context, uint8_t column){ + menu_to_box(context, true); + pickup_column(context, true); + party_to_column(context, column); + ssf_press_button2(context, BUTTON_L, BOX_CHANGE_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_button2(context, BUTTON_A, BOX_PICKUP_DROP_DELAY, EGG_BUTTON_HOLD_DELAY); + box_to_menu(context); } - uint8_t swap_party_shift(uint8_t column){ - menu_to_box(true); - pickup_column(true); + uint8_t swap_party_shift(const BotBaseContext& context, uint8_t column){ + menu_to_box(context, true); + pickup_column(context, true); // Move to column. - party_to_column(column); - ssf_press_button2(BUTTON_L, BOX_CHANGE_DELAY, EGG_BUTTON_HOLD_DELAY); - ssf_press_button2(BUTTON_A, BOX_PICKUP_DROP_DELAY, EGG_BUTTON_HOLD_DELAY); + party_to_column(context, column); + ssf_press_button2(context, BUTTON_L, BOX_CHANGE_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_button2(context, BUTTON_A, BOX_PICKUP_DROP_DELAY, EGG_BUTTON_HOLD_DELAY); // Move to next column. column++; if (column < 6){ - ssf_press_dpad2(DPAD_RIGHT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_dpad2(context, DPAD_RIGHT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); }else{ column = 0; - ssf_press_button2(BUTTON_R, BOX_CHANGE_DELAY, EGG_BUTTON_HOLD_DELAY); - ssf_press_dpad2(DPAD_RIGHT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); - ssf_press_dpad2(DPAD_RIGHT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_button2(context, BUTTON_R, BOX_CHANGE_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_dpad2(context, DPAD_RIGHT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_dpad2(context, DPAD_RIGHT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); } - pickup_column(false); + pickup_column(context, false); // Move to party. - ssf_press_button2(BUTTON_R, BOX_CHANGE_DELAY, EGG_BUTTON_HOLD_DELAY); - column_to_party(column); - ssf_press_button2(BUTTON_A, BOX_PICKUP_DROP_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_button2(context, BUTTON_R, BOX_CHANGE_DELAY, EGG_BUTTON_HOLD_DELAY); + column_to_party(context, column); + ssf_press_button2(context, BUTTON_A, BOX_PICKUP_DROP_DELAY, EGG_BUTTON_HOLD_DELAY); // Return to menu. - box_to_menu(); + box_to_menu(context); return column; } @@ -120,6 +120,7 @@ struct EggCombinedSession{ #define TRAVEL_BACK_TO_LADY_DURATION (30 + 260 + (620) + 120 + 120 * 0) void eggcombined2_run_batch( + const BotBaseContext& context, uint16_t INCUBATION_DELAY_LOWER, uint16_t remaining_travel_duration, uint8_t column, @@ -142,12 +143,12 @@ struct EggCombinedSession{ spin *= 128; } - collect_egg(); - collect_egg_mash_out(AUTO_DEPOSIT); + collect_egg(context); + collect_egg_mash_out(context, AUTO_DEPOSIT); - travel_to_spin_location(); - spin_and_mash_A(spin); - travel_back_to_lady(); + travel_to_spin_location(context); + spin_and_mash_A(context, spin); + travel_back_to_lady(context); fetches--; loop_incubation -= MIN_TRAVEL_TIME + spin; @@ -156,54 +157,54 @@ struct EggCombinedSession{ // Last fetch. if (fetches > 0){ - collect_egg(); - collect_egg_mash_out(AUTO_DEPOSIT); + collect_egg(context); + collect_egg_mash_out(context, AUTO_DEPOSIT); fetches--; } - travel_to_spin_location(); + travel_to_spin_location(context); // Hatch eggs. if (remaining_travel_duration >= END_BATCH_MASH_B_DURATION){ - spin_and_mash_A(remaining_travel_duration - END_BATCH_MASH_B_DURATION); - pbf_mash_button(BUTTON_B, END_BATCH_MASH_B_DURATION); + spin_and_mash_A(context, remaining_travel_duration - END_BATCH_MASH_B_DURATION); + pbf_mash_button(context, BUTTON_B, END_BATCH_MASH_B_DURATION); }else{ - spin_and_mash_A(remaining_travel_duration); + spin_and_mash_A(context, remaining_travel_duration); } if (fetches == 0){ // Swap party. - ssf_press_button2(BUTTON_X, OVERWORLD_TO_MENU_DELAY, 20); + ssf_press_button2(context, BUTTON_X, OVERWORLD_TO_MENU_DELAY, 20); if (last_batch){ - deposit_column_shiftL(column); - ssf_press_button2(BUTTON_B, MENU_TO_OVERWORLD_DELAY, 20); + deposit_column_shiftL(context, column); + ssf_press_button2(context, BUTTON_B, MENU_TO_OVERWORLD_DELAY, 20); }else{ - swap_party_shift(column); - fly_home_goto_lady(false); + swap_party_shift(context, column); + fly_home_goto_lady(context, false); } return; } // Additional fetches. - fly_home_goto_lady(true); + fly_home_goto_lady(context, true); while (fetches-- > 0){ - collect_egg(); - collect_egg_mash_out(AUTO_DEPOSIT); - eggfetcher_loop(); + collect_egg(context); + collect_egg_mash_out(context, AUTO_DEPOSIT); + eggfetcher_loop(context); } // Swap party. - ssf_press_button2(BUTTON_X, OVERWORLD_TO_MENU_DELAY, 20); + ssf_press_button2(context, BUTTON_X, OVERWORLD_TO_MENU_DELAY, 20); if (last_batch){ - deposit_column_shiftL(column); + deposit_column_shiftL(context, column); }else{ - swap_party_shift(column); + swap_party_shift(context, column); } - ssf_press_button2(BUTTON_B, MENU_TO_OVERWORLD_DELAY, 20); + ssf_press_button2(context, BUTTON_B, MENU_TO_OVERWORLD_DELAY, 20); } void eggcombined2_body(SingleSwitchProgramEnvironment& env){ if (BOXES_TO_HATCH == 0){ - ssf_press_button2(BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); + ssf_press_button2(env.console, BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); return; } @@ -223,25 +224,26 @@ struct EggCombinedSession{ float fetch_residual = 0; // Withdraw party. - ssf_press_button2(BUTTON_X, OVERWORLD_TO_MENU_DELAY, 20); - withdraw_column_shiftR(0); - fly_home_goto_lady(false); + ssf_press_button2(env.console, BUTTON_X, OVERWORLD_TO_MENU_DELAY, 20); + withdraw_column_shiftR(env.console, 0); + fly_home_goto_lady(env.console, false); - uint32_t last_touch = system_clock() - TOUCH_DATE_INTERVAL; + uint32_t last_touch = system_clock(env.console) - TOUCH_DATE_INTERVAL; for (uint8_t box = 0; box < BOXES_TO_HATCH; box++){ for (uint8_t column = 0; column < 6; column++){ // Touch the date. - if (TOUCH_DATE_INTERVAL > 0 && system_clock() - last_touch >= TOUCH_DATE_INTERVAL){ + if (TOUCH_DATE_INTERVAL > 0 && system_clock(env.console) - last_touch >= TOUCH_DATE_INTERVAL){ env.log("Touching date to prevent rollover."); - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - touch_date_from_home(SETTINGS_TO_HOME_DELAY); - resume_game_no_interact(TOLERATE_SYSTEM_UPDATE_MENU_FAST); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + touch_date_from_home(env.console, SETTINGS_TO_HOME_DELAY); + resume_game_no_interact(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST); last_touch += TOUCH_DATE_INTERVAL; } fetch_residual += fetches_per_batch; uint8_t fetches = (uint8_t)fetch_residual; eggcombined2_run_batch( + env.console, INCUBATION_DELAY_LOWER, INCUBATION_DELAY_UPPER + FINISH_DELAY, column, @@ -253,7 +255,7 @@ struct EggCombinedSession{ } // Finish - ssf_press_button2(BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); + ssf_press_button2(env.console, BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); } }; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggFetcher2.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggFetcher2.cpp index c55129f8c8..f3f5335e86 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggFetcher2.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggFetcher2.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/FrameworkSettings.h" #include "Common/PokemonSwSh/PokemonSettings.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" @@ -15,13 +15,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -EggFetcher2::EggFetcher2() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_31KB, + +EggFetcher2_Descriptor::EggFetcher2_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:EggFetcher2", "Egg Fetcher 2", "NativePrograms/EggFetcher2.md", - "Fetch eggs without hatching them." + "Fetch eggs without hatching them.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_31KB ) +{} + + + +EggFetcher2::EggFetcher2(const EggFetcher2_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , MAX_FETCH_ATTEMPTS( "Fetch this many times:
This puts a limit on how many eggs you can get so you don't make a mess of your boxes for fetching too many.", 2000 @@ -31,7 +40,11 @@ EggFetcher2::EggFetcher2() } -void EggFetcher2::run_eggfetcher(SingleSwitchProgramEnvironment& env, bool deposit_automatically, uint16_t attempts) const{ +void EggFetcher2::run_eggfetcher( + SingleSwitchProgramEnvironment& env, + bool deposit_automatically, + uint16_t attempts +) const{ if (attempts == 0){ return; } @@ -41,8 +54,8 @@ void EggFetcher2::run_eggfetcher(SingleSwitchProgramEnvironment& env, bool depos // 1st Fetch: Get into position. { env.log("Fetch Attempts: " + tostr_u_commas(c)); - fly_home_collect_egg(true); - collect_egg_mash_out(deposit_automatically); + fly_home_collect_egg(env.console, true); + collect_egg_mash_out(env.console, deposit_automatically); c++; if (c >= attempts){ @@ -53,21 +66,21 @@ void EggFetcher2::run_eggfetcher(SingleSwitchProgramEnvironment& env, bool depos // Now we are in steady state. for (; c < attempts; c++){ env.log("Fetch Attempts: " + tostr_u_commas(c)); - eggfetcher_loop(); - collect_egg(); - collect_egg_mash_out(deposit_automatically); + eggfetcher_loop(env.console); + collect_egg(env.console); + collect_egg_mash_out(env.console, deposit_automatically); } } -void EggFetcher2::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); - resume_game_back_out(TOLERATE_SYSTEM_UPDATE_MENU_FAST, 400); +void EggFetcher2::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + resume_game_back_out(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST, 400); run_eggfetcher(env, AUTO_DEPOSIT, MAX_FETCH_ATTEMPTS); - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - end_program_callback(); - end_program_loop(); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggFetcher2.h b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggFetcher2.h index a620e37cc1..ee8afad0da 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggFetcher2.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggFetcher2.h @@ -15,12 +15,20 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class EggFetcher2 : public SingleSwitchProgram{ + +class EggFetcher2_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + EggFetcher2_Descriptor(); +}; + + + +class EggFetcher2 : public SingleSwitchProgramInstance{ public: - EggFetcher2(); + EggFetcher2(const EggFetcher2_Descriptor& descriptor); void run_eggfetcher(SingleSwitchProgramEnvironment& env, bool deposit_automatically, uint16_t attempts) const; - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger MAX_FETCH_ATTEMPTS; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggHatcher.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggHatcher.cpp index 002003071a..14e199bf4e 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggHatcher.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggHatcher.cpp @@ -15,60 +15,69 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -void withdraw_column(uint8_t column){ - menu_to_box(false); - party_to_column(column); - pickup_column(false); - column_to_party(column); - ssf_press_button1(BUTTON_A, BOX_PICKUP_DROP_DELAY); - box_to_menu(); + +EggHatcher_Descriptor::EggHatcher_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:EggHatcher", + "Egg Hatcher", + "NativePrograms/EggHatcher.md", + "Fetch eggs without hatching them.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_31KB + ) +{} + + + +void withdraw_column(const BotBaseContext& context, uint8_t column){ + menu_to_box(context, false); + party_to_column(context, column); + pickup_column(context, false); + column_to_party(context, column); + ssf_press_button1(context, BUTTON_A, BOX_PICKUP_DROP_DELAY); + box_to_menu(context); } -void deposit_column(uint8_t column){ - menu_to_box(true); - pickup_column(true); - party_to_column(column); - ssf_press_button1(BUTTON_A, BOX_PICKUP_DROP_DELAY); - box_to_menu(); +void deposit_column(const BotBaseContext& context, uint8_t column){ + menu_to_box(context, true); + pickup_column(context, true); + party_to_column(context, column); + ssf_press_button1(context, BUTTON_A, BOX_PICKUP_DROP_DELAY); + box_to_menu(context); } -uint8_t swap_party(uint8_t column){ - menu_to_box(true); - pickup_column(true); +uint8_t swap_party(const BotBaseContext& context, uint8_t column){ + menu_to_box(context, true); + pickup_column(context, true); // Move to column. - party_to_column(column); - ssf_press_button1(BUTTON_A, BOX_PICKUP_DROP_DELAY); + party_to_column(context, column); + ssf_press_button1(context, BUTTON_A, BOX_PICKUP_DROP_DELAY); // Move to next column. column++; if (column < 6){ - ssf_press_dpad1(DPAD_RIGHT, BOX_SCROLL_DELAY); + ssf_press_dpad1(context, DPAD_RIGHT, BOX_SCROLL_DELAY); }else{ column = 0; - ssf_press_button1(BUTTON_R, BOX_CHANGE_DELAY); - ssf_press_dpad1(DPAD_RIGHT, BOX_SCROLL_DELAY); - ssf_press_dpad1(DPAD_RIGHT, BOX_SCROLL_DELAY); + ssf_press_button1(context, BUTTON_R, BOX_CHANGE_DELAY); + ssf_press_dpad1(context, DPAD_RIGHT, BOX_SCROLL_DELAY); + ssf_press_dpad1(context, DPAD_RIGHT, BOX_SCROLL_DELAY); } - pickup_column(false); + pickup_column(context, false); // Move to party. - column_to_party(column); - ssf_press_button1(BUTTON_A, BOX_PICKUP_DROP_DELAY); + column_to_party(context, column); + ssf_press_button1(context, BUTTON_A, BOX_PICKUP_DROP_DELAY); // Return to menu. - box_to_menu(); + box_to_menu(context); return column; } -EggHatcher::EggHatcher() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_31KB, - "Egg Hatcher", - "NativePrograms/EggHatcher.md", - "Fetch eggs without hatching them." - ) +EggHatcher::EggHatcher(const EggHatcher_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , BOXES_TO_HATCH( "Boxes to Hatch:", 3 @@ -91,57 +100,57 @@ EggHatcher::EggHatcher() m_options.emplace_back(&SAFETY_TIME, "SAFETY_TIME"); m_options.emplace_back(&HATCH_DELAY, "HATCH_DELAY"); } -void EggHatcher::program(SingleSwitchProgramEnvironment& env) const{ +void EggHatcher::program(SingleSwitchProgramEnvironment& env){ // Calculate upper bounds for incubation time. uint16_t INCUBATION_DELAY_UPPER = (uint16_t)((uint32_t)STEPS_TO_HATCH * (uint32_t)103180 >> 16); uint16_t TOTAL_DELAY = INCUBATION_DELAY_UPPER + HATCH_DELAY + SAFETY_TIME - TRAVEL_RIGHT_DURATION; - grip_menu_connect_go_home(); - resume_game_back_out(TOLERATE_SYSTEM_UPDATE_MENU_FAST, 400); + grip_menu_connect_go_home(env.console); + resume_game_back_out(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST, 400); bool party_is_empty = true; for (uint8_t box = 0; box < BOXES_TO_HATCH; box++){ for (uint8_t column = 0; column < 6; column++){ // Get eggs from box. - pbf_press_button(BUTTON_X, 20, OVERWORLD_TO_MENU_DELAY - 20); + pbf_press_button(env.console, BUTTON_X, 20, OVERWORLD_TO_MENU_DELAY - 20); if (party_is_empty){ - withdraw_column(column); + withdraw_column(env.console, column); party_is_empty = false; }else if (column == 0){ - swap_party(5); + swap_party(env.console, 5); }else{ - swap_party(column - 1); + swap_party(env.console, column - 1); } - fly_home(false); + fly_home(env.console, false); // Travel to spin location. - pbf_move_left_joystick(STICK_MAX, STICK_CENTER, TRAVEL_RIGHT_DURATION, 0); + pbf_move_left_joystick(env.console, STICK_MAX, STICK_CENTER, TRAVEL_RIGHT_DURATION, 0); // Spin #if 0 spin_and_mash_A(TOTAL_DELAY); #else if (TOTAL_DELAY >= END_BATCH_MASH_B_DURATION){ - spin_and_mash_A(TOTAL_DELAY - END_BATCH_MASH_B_DURATION); - pbf_mash_button(BUTTON_B, END_BATCH_MASH_B_DURATION); + spin_and_mash_A(env.console, TOTAL_DELAY - END_BATCH_MASH_B_DURATION); + pbf_mash_button(env.console, BUTTON_B, END_BATCH_MASH_B_DURATION); }else{ - spin_and_mash_A(TOTAL_DELAY); + spin_and_mash_A(env.console, TOTAL_DELAY); } #endif } } if (!party_is_empty){ - pbf_press_button(BUTTON_X, 20, OVERWORLD_TO_MENU_DELAY - 20); - deposit_column(5); - pbf_press_button(BUTTON_X, 20, OVERWORLD_TO_MENU_DELAY - 20); + pbf_press_button(env.console, BUTTON_X, 20, OVERWORLD_TO_MENU_DELAY - 20); + deposit_column(env.console, 5); + pbf_press_button(env.console, BUTTON_X, 20, OVERWORLD_TO_MENU_DELAY - 20); } - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE - 10); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE - 10); - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggHatcher.h b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggHatcher.h index 8bbd2a6851..e037870105 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggHatcher.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggHatcher.h @@ -19,11 +19,18 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ -class EggHatcher : public SingleSwitchProgram{ +class EggHatcher_Descriptor : public RunnableSwitchProgramDescriptor{ public: - EggHatcher(); + EggHatcher_Descriptor(); +}; + + + +class EggHatcher : public SingleSwitchProgramInstance{ +public: + EggHatcher(const EggHatcher_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggHelpers.h b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggHelpers.h index 5611a2c992..47be1c4bf8 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggHelpers.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggHelpers.h @@ -22,15 +22,16 @@ namespace PokemonSwSh{ // Collect egg. -static void collect_egg(void){ - ssf_press_button1(BUTTON_A, 120); +static void collect_egg(const BotBaseContext& context){ + ssf_press_button1(context, BUTTON_A, 120); if (EGG_FETCH_EXTRA_LINE){ - ssf_press_button1(BUTTON_A, 120); + ssf_press_button1(context, BUTTON_A, 120); } - ssf_press_button1(BUTTON_A, 10); + ssf_press_button1(context, BUTTON_A, 10); } -static void collect_egg_mash_out(bool deposit_automatically){ +static void collect_egg_mash_out(const BotBaseContext& context, bool deposit_automatically){ pbf_mash_button( + context, BUTTON_B, deposit_automatically ? FETCH_EGG_MASH_DELAY @@ -40,25 +41,25 @@ static void collect_egg_mash_out(bool deposit_automatically){ // Fly Home: Used by everything. -static void fly_home(char from_overworld){ +static void fly_home(const BotBaseContext& context, char from_overworld){ if (from_overworld){ - ssf_press_button2(BUTTON_X, OVERWORLD_TO_MENU_DELAY, 20); + ssf_press_button2(context, BUTTON_X, OVERWORLD_TO_MENU_DELAY, 20); } - ssf_press_button2(BUTTON_A, 350, 10); - ssf_press_dpad2(DPAD_UP_RIGHT, 25, 5); - pbf_mash_button(BUTTON_A, 480); + ssf_press_button2(context, BUTTON_A, 350, 10); + ssf_press_dpad2(context, DPAD_UP_RIGHT, 25, 5); + pbf_mash_button(context, BUTTON_A, 480); } -static void fly_home_goto_lady(char from_overworld){ - fly_home(from_overworld); +static void fly_home_goto_lady(const BotBaseContext& context, char from_overworld){ + fly_home(context, from_overworld); // Go to lady. // If you change this, you MUST update "GO_TO_LADY_DURATION". - ssf_press_joystick2(true, STICK_MIN, STICK_CENTER, 16, 6); - ssf_press_joystick2(true, STICK_CENTER, STICK_MIN, 90, 45); + ssf_press_joystick2(context, true, STICK_MIN, STICK_CENTER, 16, 6); + ssf_press_joystick2(context, true, STICK_CENTER, STICK_MIN, 90, 45); } -static void fly_home_collect_egg(char from_overworld){ - fly_home_goto_lady(from_overworld); - collect_egg(); +static void fly_home_collect_egg(const BotBaseContext& context, char from_overworld){ + fly_home_goto_lady(context, from_overworld); + collect_egg(context); } @@ -67,19 +68,19 @@ static void fly_home_collect_egg(char from_overworld){ #define EGG_BUTTON_HOLD_DELAY 10 -static void menu_to_box(bool from_map){ +static void menu_to_box(const BotBaseContext& context, bool from_map){ if (from_map){ - ssf_press_dpad2(DPAD_UP, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); - ssf_press_dpad2(DPAD_RIGHT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_dpad2(context, DPAD_UP, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_dpad2(context, DPAD_RIGHT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); } - ssf_press_button2(BUTTON_A, MENU_TO_POKEMON_DELAY, EGG_BUTTON_HOLD_DELAY); - ssf_press_button2(BUTTON_R, POKEMON_TO_BOX_DELAY, EGG_BUTTON_HOLD_DELAY); - ssf_press_dpad2(DPAD_LEFT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); - ssf_press_dpad2(DPAD_DOWN, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); - ssf_press_button2(BUTTON_Y, 30, EGG_BUTTON_HOLD_DELAY); - ssf_press_button2(BUTTON_Y, 30, EGG_BUTTON_HOLD_DELAY); + ssf_press_button2(context, BUTTON_A, MENU_TO_POKEMON_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_button2(context, BUTTON_R, POKEMON_TO_BOX_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_dpad2(context, DPAD_LEFT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_dpad2(context, DPAD_DOWN, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_button2(context, BUTTON_Y, 30, EGG_BUTTON_HOLD_DELAY); + ssf_press_button2(context, BUTTON_Y, 30, EGG_BUTTON_HOLD_DELAY); } -static void box_to_menu(void){ +static void box_to_menu(const BotBaseContext& context){ // There are two states here which need to be merged: // 1. The depositing column was empty. The party has been swapped and // it's sitting in the box with no held pokemon. @@ -91,50 +92,50 @@ static void box_to_menu(void){ // be swallowed by the animation. // In state (2): The 1st B will drop the party pokemon. The 2nd B will // back out of the box. - ssf_press_button2(BUTTON_B, 20, EGG_BUTTON_HOLD_DELAY); - ssf_press_button2(BUTTON_B, BOX_TO_POKEMON_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_button2(context, BUTTON_B, 20, EGG_BUTTON_HOLD_DELAY); + ssf_press_button2(context, BUTTON_B, BOX_TO_POKEMON_DELAY, EGG_BUTTON_HOLD_DELAY); // Back out to menu. - ssf_press_button2(BUTTON_B, POKEMON_TO_MENU_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_button2(context, BUTTON_B, POKEMON_TO_MENU_DELAY, EGG_BUTTON_HOLD_DELAY); - ssf_press_dpad2(DPAD_LEFT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); - ssf_press_dpad2(DPAD_DOWN, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_dpad2(context, DPAD_LEFT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_dpad2(context, DPAD_DOWN, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); } -static void party_to_column(uint8_t column){ - ssf_press_dpad2(DPAD_UP, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); +static void party_to_column(const BotBaseContext& context, uint8_t column){ + ssf_press_dpad2(context, DPAD_UP, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); column++; if (column <= 3){ for (uint8_t c = 0; c != column; c++){ - ssf_press_dpad2(DPAD_RIGHT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_dpad2(context, DPAD_RIGHT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); } }else{ for (uint8_t c = 7; c != column; c--){ - ssf_press_dpad2(DPAD_LEFT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_dpad2(context, DPAD_LEFT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); } } } -static void column_to_party(uint8_t column){ +static void column_to_party(const BotBaseContext& context, uint8_t column){ column++; if (column <= 3){ for (uint8_t c = column; c != 0; c--){ - ssf_press_dpad2(DPAD_LEFT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_dpad2(context, DPAD_LEFT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); } }else{ for (uint8_t c = column; c != 7; c++){ - ssf_press_dpad2(DPAD_RIGHT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_dpad2(context, DPAD_RIGHT, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); } } - ssf_press_dpad2(DPAD_DOWN, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_dpad2(context, DPAD_DOWN, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); } -static void pickup_column(char party){ - ssf_press_button2(BUTTON_A, 20, EGG_BUTTON_HOLD_DELAY); +static void pickup_column(const BotBaseContext& context, char party){ + ssf_press_button2(context, BUTTON_A, 20, EGG_BUTTON_HOLD_DELAY); if (party){ - ssf_press_dpad2(DPAD_UP, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_dpad2(context, DPAD_UP, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); } - ssf_press_dpad2(DPAD_UP, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); - ssf_press_button2(BUTTON_A, BOX_PICKUP_DROP_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_dpad2(context, DPAD_UP, BOX_SCROLL_DELAY, EGG_BUTTON_HOLD_DELAY); + ssf_press_button2(context, BUTTON_A, BOX_PICKUP_DROP_DELAY, EGG_BUTTON_HOLD_DELAY); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggSuperCombined2.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggSuperCombined2.cpp index 8d75f86a02..40ca39bb02 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggSuperCombined2.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggSuperCombined2.cpp @@ -14,13 +14,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -EggSuperCombined2::EggSuperCombined2() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_31KB, + +EggSuperCombined2_Descriptor::EggSuperCombined2_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:EggSuperCombined2", "Egg Super-Combined 2", "NativePrograms/EggSuperCombined2.md", - "Fetch and hatch eggs at the same time. (Fastest - 1700 eggs/day for 5120-step)" + "Fetch and hatch eggs at the same time. (Fastest - 1700 eggs/day for 5120-step)", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_31KB ) +{} + + + +EggSuperCombined2::EggSuperCombined2(const EggSuperCombined2_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , BOXES_TO_RELEASE( "Boxes to Release:
Start by releasing this many boxes.", 2, 0, 32 @@ -69,7 +78,7 @@ EggSuperCombined2::EggSuperCombined2() m_options.emplace_back(&HATCH_DELAY, "HATCH_DELAY"); } -void EggSuperCombined2::program(SingleSwitchProgramEnvironment& env) const{ +void EggSuperCombined2::program(SingleSwitchProgramEnvironment& env){ EggCombinedSession session{ .BOXES_TO_HATCH = BOXES_TO_HATCH, .STEPS_TO_HATCH = STEPS_TO_HATCH, @@ -80,25 +89,25 @@ void EggSuperCombined2::program(SingleSwitchProgramEnvironment& env) const{ .TOUCH_DATE_INTERVAL = TOUCH_DATE_INTERVAL, }; - grip_menu_connect_go_home(); - resume_game_back_out(TOLERATE_SYSTEM_UPDATE_MENU_FAST, 400); + grip_menu_connect_go_home(env.console); + resume_game_back_out(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST, 400); // Mass Release - ssf_press_button2(BUTTON_X, OVERWORLD_TO_MENU_DELAY, 20); - ssf_press_button1(BUTTON_A, 200); - ssf_press_button1(BUTTON_R, 250); - release_boxes(BOXES_TO_RELEASE, BOX_SCROLL_DELAY, BOX_CHANGE_DELAY); + ssf_press_button2(env.console, BUTTON_X, OVERWORLD_TO_MENU_DELAY, 20); + ssf_press_button1(env.console, BUTTON_A, 200); + ssf_press_button1(env.console, BUTTON_R, 250); + release_boxes(env.console, BOXES_TO_RELEASE, BOX_SCROLL_DELAY, BOX_CHANGE_DELAY); // Skip Boxes for (uint8_t c = 0; c <= BOXES_TO_SKIP; c++){ - ssf_press_button1(BUTTON_R, 60); + ssf_press_button1(env.console, BUTTON_R, 60); } - pbf_mash_button(BUTTON_B, 600); + pbf_mash_button(env.console, BUTTON_B, 600); session.eggcombined2_body(env); - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggSuperCombined2.h b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggSuperCombined2.h index 11ebd43e7a..4ae50aebce 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggSuperCombined2.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggSuperCombined2.h @@ -19,11 +19,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class EggSuperCombined2 : public SingleSwitchProgram{ + +class EggSuperCombined2_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + EggSuperCombined2_Descriptor(); +}; + + + +class EggSuperCombined2 : public SingleSwitchProgramInstance{ public: - EggSuperCombined2(); + EggSuperCombined2(const EggSuperCombined2_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger BOXES_TO_RELEASE; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_GodEggDuplication.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_GodEggDuplication.cpp index a8cabc5736..93a359c27a 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_GodEggDuplication.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_GodEggDuplication.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/FrameworkSettings.h" #include "Common/PokemonSwSh/PokemonSettings.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" @@ -15,13 +15,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -GodEggDuplication::GodEggDuplication() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_31KB, + +GodEggDuplication_Descriptor::GodEggDuplication_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:GodEggDuplication", "God Egg Duplication", "NativePrograms/GodEggDuplication.md", - "Mass duplicate " + STRING_POKEMON + " with the God Egg." + "Mass duplicate " + STRING_POKEMON + " with the God Egg.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_31KB ) +{} + + + +GodEggDuplication::GodEggDuplication(const GodEggDuplication_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , MAX_FETCH_ATTEMPTS( "Fetch this many times:
This puts a limit on how many eggs you can get so you don't make a mess of your boxes for fetching too many.", 2000 @@ -36,30 +45,30 @@ GodEggDuplication::GodEggDuplication() } -void GodEggDuplication::collect_godegg(uint8_t party_slot) const{ - pbf_wait(50); - ssf_press_button1(BUTTON_B, 100); - ssf_press_button1(BUTTON_B, 100); - pbf_wait(225); +void GodEggDuplication::collect_godegg(const BotBaseContext& context, uint8_t party_slot) const{ + pbf_wait(context, 50); + ssf_press_button1(context, BUTTON_B, 100); + ssf_press_button1(context, BUTTON_B, 100); + pbf_wait(context, 225); // "You received an Egg from the Nursery worker!" - ssf_press_button1(BUTTON_B, 300); + ssf_press_button1(context, BUTTON_B, 300); // "Where do you want to send the Egg to?" - ssf_press_button1(BUTTON_A, 100); + ssf_press_button1(context, BUTTON_A, 100); // (extra line of text for French) - ssf_press_button1(BUTTON_B, 100); + ssf_press_button1(context, BUTTON_B, 100); // "Please select a Pokemon to swap from your party." - ssf_press_button1(BUTTON_B, MENU_TO_POKEMON_DELAY); + ssf_press_button1(context, BUTTON_B, MENU_TO_POKEMON_DELAY); // Select the party member. for (uint8_t c = 0; c < party_slot; c++){ - ssf_press_dpad1(DPAD_DOWN, 10); + ssf_press_dpad1(context, DPAD_DOWN, 10); } - ssf_press_button1(BUTTON_A, 300); - pbf_mash_button(BUTTON_B, 500); + ssf_press_button1(context, BUTTON_A, 300); + pbf_mash_button(context, BUTTON_B, 500); } void GodEggDuplication::run_program(SingleSwitchProgramEnvironment& env, uint16_t attempts) const{ if (attempts == 0){ @@ -74,8 +83,8 @@ void GodEggDuplication::run_program(SingleSwitchProgramEnvironment& env, uint16_ // 1st Fetch: Get into position. { env.log("Fetch Attempts: " + tostr_u_commas(c)); - fly_home_collect_egg(true); - collect_godegg(party_slot++); + fly_home_collect_egg(env.console, true); + collect_godegg(env.console, party_slot++); if (party_slot >= items){ party_slot = 0; } @@ -89,24 +98,24 @@ void GodEggDuplication::run_program(SingleSwitchProgramEnvironment& env, uint16_ // Now we are in steady state. for (; c < attempts; c++){ env.log("Fetch Attempts: " + tostr_u_commas(c)); - eggfetcher_loop(); - collect_egg(); - collect_godegg(party_slot++); + eggfetcher_loop(env.console); + collect_egg(env.console); + collect_godegg(env.console, party_slot++); if (party_slot >= items){ party_slot = 0; } } } -void GodEggDuplication::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); - resume_game_back_out(TOLERATE_SYSTEM_UPDATE_MENU_FAST, 400); +void GodEggDuplication::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + resume_game_back_out(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST, 400); run_program(env, MAX_FETCH_ATTEMPTS); - ssf_press_button2(BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); + ssf_press_button2(env.console, BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_GodEggDuplication.h b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_GodEggDuplication.h index 48bde9a9b3..19581814cf 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_GodEggDuplication.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_GodEggDuplication.h @@ -16,13 +16,21 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class GodEggDuplication : public SingleSwitchProgram{ + +class GodEggDuplication_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + GodEggDuplication_Descriptor(); +}; + + + +class GodEggDuplication : public SingleSwitchProgramInstance{ public: - GodEggDuplication(); + GodEggDuplication(const GodEggDuplication_Descriptor& descriptor); - void collect_godegg(uint8_t party_slot) const; + void collect_godegg(const BotBaseContext& context, uint8_t party_slot) const; void run_program(SingleSwitchProgramEnvironment& env, uint16_t attempts) const; - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger MAX_FETCH_ATTEMPTS; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_GodEggItemDupe.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_GodEggItemDupe.cpp index c4f6d7128d..f8ca47e8f8 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_GodEggItemDupe.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_GodEggItemDupe.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/FrameworkSettings.h" #include "Common/PokemonSwSh/PokemonSettings.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" @@ -16,13 +16,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -GodEggItemDupe::GodEggItemDupe() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_31KB, + +GodEggItemDupe_Descriptor::GodEggItemDupe_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:GodEggItemDupe", "God Egg Item Duplication", "NativePrograms/GodEggItemDupe.md", - "Mass duplicate items with the God Egg." + "Mass duplicate items with the God Egg.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_31KB ) +{} + + + +GodEggItemDupe::GodEggItemDupe(const GodEggItemDupe_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , MAX_FETCH_ATTEMPTS( "Fetch this many times:
This puts a limit on how many eggs you can get so you don't make a mess of your boxes for fetching too many.", 2000 @@ -42,69 +51,74 @@ GodEggItemDupe::GodEggItemDupe() } -void GodEggItemDupe::collect_godegg(uint8_t party_slot, bool map_to_pokemon, bool pokemon_to_map) const{ - pbf_wait(50); - ssf_press_button1(BUTTON_B, 100); - ssf_press_button1(BUTTON_B, 100); - pbf_wait(225); +void GodEggItemDupe::collect_godegg( + const BotBaseContext& context, + uint8_t party_slot, + bool map_to_pokemon, + bool pokemon_to_map +) const{ + pbf_wait(context, 50); + ssf_press_button1(context, BUTTON_B, 100); + ssf_press_button1(context, BUTTON_B, 100); + pbf_wait(context, 225); // "You received an Egg from the Nursery worker!" - ssf_press_button1(BUTTON_B, 300); + ssf_press_button1(context, BUTTON_B, 300); // "Where do you want to send the Egg to?" - ssf_press_button1(BUTTON_A, 100); + ssf_press_button1(context, BUTTON_A, 100); // (extra line of text for French) - ssf_press_button1(BUTTON_B, 100); + ssf_press_button1(context, BUTTON_B, 100); // "Please select a Pokemon to swap from your party." - ssf_press_button1(BUTTON_B, MENU_TO_POKEMON_DELAY); + ssf_press_button1(context, BUTTON_B, MENU_TO_POKEMON_DELAY); // Select the party member. for (uint8_t c = 0; c < party_slot; c++){ - ssf_press_dpad1(DPAD_DOWN, 10); + ssf_press_dpad1(context, DPAD_DOWN, 10); } - ssf_press_button1(BUTTON_A, 300); - pbf_mash_button(BUTTON_B, 500); + ssf_press_button1(context, BUTTON_A, 300); + pbf_mash_button(context, BUTTON_B, 500); // Enter box - ssf_press_button2(BUTTON_X, OVERWORLD_TO_MENU_DELAY, 20); + ssf_press_button2(context, BUTTON_X, OVERWORLD_TO_MENU_DELAY, 20); if (map_to_pokemon){ - ssf_press_dpad2(DPAD_UP, 20, 10); - ssf_press_dpad2(DPAD_RIGHT, 20, 10); + ssf_press_dpad2(context, DPAD_UP, 20, 10); + ssf_press_dpad2(context, DPAD_RIGHT, 20, 10); } - ssf_press_button2(BUTTON_A, MENU_TO_POKEMON_DELAY, 10); - ssf_press_button2(BUTTON_R, POKEMON_TO_BOX_DELAY, 10); + ssf_press_button2(context, BUTTON_A, MENU_TO_POKEMON_DELAY, 10); + ssf_press_button2(context, BUTTON_R, POKEMON_TO_BOX_DELAY, 10); if (DETACH_BEFORE_RELEASE){ // Detach item - ssf_press_button2(BUTTON_A, 50, 10); - ssf_press_dpad1(DPAD_DOWN, 10); - ssf_press_dpad1(DPAD_DOWN, 10); - ssf_press_button2(BUTTON_A, 150, 10); - ssf_press_button2(BUTTON_A, 150, 10); - ssf_press_button2(BUTTON_A, 100, 10); + ssf_press_button2(context, BUTTON_A, 50, 10); + ssf_press_dpad1(context, DPAD_DOWN, 10); + ssf_press_dpad1(context, DPAD_DOWN, 10); + ssf_press_button2(context, BUTTON_A, 150, 10); + ssf_press_button2(context, BUTTON_A, 150, 10); + ssf_press_button2(context, BUTTON_A, 100, 10); // Release - release(); + release(context); }else{ // Release (item detaches automatically) - ssf_press_button2(BUTTON_A, 60, 10); - ssf_press_dpad1(DPAD_DOWN, 15); - ssf_press_dpad1(DPAD_DOWN, 15); - ssf_press_dpad1(DPAD_DOWN, 15); - ssf_press_dpad1(DPAD_DOWN, 15); - ssf_press_button2(BUTTON_A, 125, 10); - ssf_press_dpad1(DPAD_UP, 10); - mash_A(180); + ssf_press_button2(context, BUTTON_A, 60, 10); + ssf_press_dpad1(context, DPAD_DOWN, 15); + ssf_press_dpad1(context, DPAD_DOWN, 15); + ssf_press_dpad1(context, DPAD_DOWN, 15); + ssf_press_dpad1(context, DPAD_DOWN, 15); + ssf_press_button2(context, BUTTON_A, 125, 10); + ssf_press_dpad1(context, DPAD_UP, 10); + mash_A(context, 180); } // Back out to menu. if (pokemon_to_map){ - box_to_menu(); - ssf_press_button1(BUTTON_B, 250); + box_to_menu(context); + ssf_press_button1(context, BUTTON_B, 250); }else{ - pbf_mash_button(BUTTON_B, 700); + pbf_mash_button(context, BUTTON_B, 700); } } void GodEggItemDupe::run_program(SingleSwitchProgramEnvironment& env, uint16_t attempts) const{ @@ -120,8 +134,8 @@ void GodEggItemDupe::run_program(SingleSwitchProgramEnvironment& env, uint16_t a // 1st Fetch: Get into position. { env.log("Fetch Attempts: " + tostr_u_commas(c)); - fly_home_collect_egg(true); - collect_godegg(party_slot++, true, false); + fly_home_collect_egg(env.console, true); + collect_godegg(env.console, party_slot++, true, false); if (party_slot >= items){ party_slot = 0; } @@ -135,24 +149,24 @@ void GodEggItemDupe::run_program(SingleSwitchProgramEnvironment& env, uint16_t a // Now we are in steady state. for (; c < attempts; c++){ env.log("Fetch Attempts: " + tostr_u_commas(c)); - eggfetcher_loop(); - collect_egg(); - collect_godegg(party_slot++, false, false); + eggfetcher_loop(env.console); + collect_egg(env.console); + collect_godegg(env.console, party_slot++, false, false); if (party_slot >= items){ party_slot = 0; } } } -void GodEggItemDupe::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); - resume_game_back_out(TOLERATE_SYSTEM_UPDATE_MENU_FAST, 400); +void GodEggItemDupe::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + resume_game_back_out(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST, 400); run_program(env, MAX_FETCH_ATTEMPTS); - ssf_press_button2(BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); + ssf_press_button2(env.console, BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_GodEggItemDupe.h b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_GodEggItemDupe.h index 06297d549d..1f2467b13e 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_GodEggItemDupe.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_GodEggItemDupe.h @@ -16,13 +16,21 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class GodEggItemDupe : public SingleSwitchProgram{ + +class GodEggItemDupe_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + GodEggItemDupe_Descriptor(); +}; + + + +class GodEggItemDupe : public SingleSwitchProgramInstance{ public: - GodEggItemDupe(); + GodEggItemDupe(const GodEggItemDupe_Descriptor& descriptor); - void collect_godegg(uint8_t party_slot, bool map_to_pokemon, bool pokemon_to_map) const; + void collect_godegg(const BotBaseContext& context, uint8_t party_slot, bool map_to_pokemon, bool pokemon_to_map) const; void run_program(SingleSwitchProgramEnvironment& env, uint16_t attempts) const; - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger MAX_FETCH_ATTEMPTS; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHost-MultiGame.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHost-MultiGame.cpp index 19057cd537..a4c707fa3a 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHost-MultiGame.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHost-MultiGame.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/FrameworkSettings.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/SwitchRoutines/SwitchDigitEntry.h" @@ -16,19 +16,29 @@ #include "PokemonSwSh/Programs/PokemonSwSh_StartGame.h" #include "PokemonSwSh_DenTools.h" #include "PokemonSwSh_LobbyWait.h" +#include "PokemonSwSh_AutoHostStats.h" #include "PokemonSwSh_AutoHost-MultiGame.h" namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -AutoHostMultiGame::AutoHostMultiGame() - : SingleSwitchProgram( - FeedbackType::OPTIONAL_, PABotBaseLevel::PABOTBASE_12KB, + +AutoHostMultiGame_Descriptor::AutoHostMultiGame_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:AutoHostMultiGame", "Auto-Host Multi-Game", "NativePrograms/AutoHost-MultiGame.md", - "Run AutoHost-Rolling across multiple game saves. (Up to 16 dens!)" + "Run AutoHost-Rolling across multiple game saves. (Up to 16 dens!)", + FeedbackType::OPTIONAL_, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +AutoHostMultiGame::AutoHostMultiGame(const AutoHostMultiGame_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , HOST_ONLINE("Host Online:", true) , LOBBY_WAIT_DELAY( "Lobby Wait Delay:
Wait this long before starting raid. Start time is 3 minutes minus this number.", @@ -81,6 +91,10 @@ AutoHostMultiGame::AutoHostMultiGame() } +std::unique_ptr AutoHostMultiGame::make_stats() const{ + return std::unique_ptr(new AutoHostStats()); +} + void AutoHostMultiGame::run_autohost( SingleSwitchProgramEnvironment& env, @@ -89,12 +103,14 @@ void AutoHostMultiGame::run_autohost( uint16_t lobby_wait_delay, Catchability catchability ) const{ - roll_den(ENTER_ONLINE_DEN_DELAY, OPEN_ONLINE_DEN_LOBBY_DELAY, game.skips, catchability); + AutoHostStats& stats = env.stats(); + + roll_den(env.console, ENTER_ONLINE_DEN_DELAY, OPEN_ONLINE_DEN_LOBBY_DELAY, game.skips, catchability); if (HOST_ONLINE){ - connect_to_internet(OPEN_YCOMM_DELAY, CONNECT_TO_INTERNET_DELAY); + connect_to_internet(env.console, OPEN_YCOMM_DELAY, CONNECT_TO_INTERNET_DELAY); } - enter_den(ENTER_ONLINE_DEN_DELAY, game.skips != 0, HOST_ONLINE); + enter_den(env.console, ENTER_ONLINE_DEN_DELAY, game.skips != 0, HOST_ONLINE); uint8_t code[8]; if (RAID_CODE.get_code(code)){ @@ -103,15 +119,15 @@ void AutoHostMultiGame::run_autohost( str[c] = code[c] + '0'; } env.log("Next Raid Code: " + std::string(str, sizeof(str))); - pbf_press_button(BUTTON_PLUS, 5, 145); - enter_digits(8, code); - pbf_wait(180); - pbf_press_button(BUTTON_A, 5, 95); + pbf_press_button(env.console, BUTTON_PLUS, 5, 145); + enter_digits(env.console, 8, code); + pbf_wait(env.console, 180); + pbf_press_button(env.console, BUTTON_A, 5, 95); } - enter_lobby(OPEN_ONLINE_DEN_LOBBY_DELAY, HOST_ONLINE, catchability); + enter_lobby(env.console, OPEN_ONLINE_DEN_LOBBY_DELAY, HOST_ONLINE, catchability); // Accept friend requests while we wait. - raid_lobby_wait( + RaidLobbyState raid_state = raid_lobby_wait( env.console, env.logger(), HOST_ONLINE, accept_FR_slot, @@ -119,49 +135,54 @@ void AutoHostMultiGame::run_autohost( ); // Start Raid - pbf_press_dpad(DPAD_UP, 5, 45); + pbf_press_dpad(env.console, DPAD_UP, 5, 45); // Mash A until it's time to close the game. #if 1 { env.console.botbase().wait_for_all_requests(); - uint32_t start = system_clock(); - pbf_mash_button(BUTTON_A, 3 * TICKS_PER_SECOND); + uint32_t start = system_clock(env.console); + pbf_mash_button(env.console, BUTTON_A, 3 * TICKS_PER_SECOND); env.console.botbase().wait_for_all_requests(); - BlackScreenDetector black_screen(env.console, env.logger()); + BlackScreenDetector black_screen(env.console); uint32_t now = start; - while (now - start < RAID_START_TO_EXIT_DELAY){ - if (black_screen.black_is_over()){ + while (true){ + if (black_screen.black_is_over(env.console.video().snapshot())){ env.log("Raid has Started!", "blue"); + stats.add_raid(raid_state.raiders()); break; } - pbf_mash_button(BUTTON_A, TICKS_PER_SECOND); + if (now - start >= RAID_START_TO_EXIT_DELAY){ + stats.add_timeout(); + break; + } + pbf_mash_button(env.console, BUTTON_A, TICKS_PER_SECOND); env.console.botbase().wait_for_all_requests(); - now = system_clock(); + now = system_clock(env.console); } } #else - pbf_mash_button(BUTTON_A, RAID_START_TO_EXIT_DELAY); + pbf_mash_button(env.console, BUTTON_A, RAID_START_TO_EXIT_DELAY); #endif // Select a move. if (game.move_slot > 0){ - pbf_wait(DELAY_TO_SELECT_MOVE); - pbf_press_button(BUTTON_A, 20, 80); + pbf_wait(env.console, DELAY_TO_SELECT_MOVE); + pbf_press_button(env.console, BUTTON_A, 20, 80); if (game.dynamax){ - pbf_press_dpad(DPAD_LEFT, 20, 30); - pbf_press_button(BUTTON_A, 20, 60); + pbf_press_dpad(env.console, DPAD_LEFT, 20, 30); + pbf_press_button(env.console, BUTTON_A, 20, 60); } for (uint8_t c = 1; c < game.move_slot; c++){ - pbf_press_dpad(DPAD_DOWN, 20, 30); + pbf_press_dpad(env.console, DPAD_DOWN, 20, 30); } - pbf_press_button(BUTTON_A, 20, 80); - pbf_press_button(BUTTON_A, 20, 980); + pbf_press_button(env.console, BUTTON_A, 20, 80); + pbf_press_button(env.console, BUTTON_A, 20, 980); } } -void AutoHostMultiGame::program(SingleSwitchProgramEnvironment& env) const{ +void AutoHostMultiGame::program(SingleSwitchProgramEnvironment& env){ uint16_t start_raid_delay = HOST_ONLINE ? OPEN_ONLINE_DEN_LOBBY_DELAY : OPEN_LOCAL_DEN_LOBBY_DELAY; @@ -182,12 +203,12 @@ void AutoHostMultiGame::program(SingleSwitchProgramEnvironment& env) const{ } } - grip_menu_connect_go_home(); + grip_menu_connect_go_home(env.console); uint32_t last_touch = 0; if (enable_touch && TOUCH_DATE_INTERVAL > 0){ - touch_date_from_home(SETTINGS_TO_HOME_DELAY); - last_touch = system_clock(); + touch_date_from_home(env.console, SETTINGS_TO_HOME_DELAY); + last_touch = system_clock(env.console); } uint32_t raids = 0; @@ -195,6 +216,8 @@ void AutoHostMultiGame::program(SingleSwitchProgramEnvironment& env) const{ while (true){ env.log("Beginning from start of game list."); for (uint8_t index = 0; index < GAME_LIST.size(); index++){ + env.update_stats(); + const MultiHostTable::GameSlot& game = GAME_LIST[index]; // if (game.user_slot == 0){ // break; @@ -203,7 +226,7 @@ void AutoHostMultiGame::program(SingleSwitchProgramEnvironment& env) const{ env.log("Raids Completed: " + tostr_u_commas(raids++)); // Start game. - rollback_date_from_home(game.skips); + rollback_date_from_home(env.console, game.skips); // Sanitize game slot. uint8_t game_slot = game.game_slot; @@ -237,7 +260,7 @@ void AutoHostMultiGame::program(SingleSwitchProgramEnvironment& env) const{ size_t FR_index = index; for (uint8_t c = 0; c < FR_FORWARD_ACCEPT; c++){ FR_index++; - if (GAME_LIST[FR_index].user_slot == 0){ + if (FR_index >= GAME_LIST.size()){ FR_index = 0; } } @@ -253,22 +276,22 @@ void AutoHostMultiGame::program(SingleSwitchProgramEnvironment& env) const{ ); // Exit game. - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - close_game(); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + close_game(env.console); // Post-raid delay. - pbf_wait(parse_ticks_i32(game.post_raid_delay)); + pbf_wait(env.console, parse_ticks_i32(game.post_raid_delay)); // Touch the date. - if (enable_touch && TOUCH_DATE_INTERVAL > 0 && system_clock() - last_touch >= TOUCH_DATE_INTERVAL){ - touch_date_from_home(SETTINGS_TO_HOME_DELAY); + if (enable_touch && TOUCH_DATE_INTERVAL > 0 && system_clock(env.console) - last_touch >= TOUCH_DATE_INTERVAL){ + touch_date_from_home(env.console, SETTINGS_TO_HOME_DELAY); last_touch += TOUCH_DATE_INTERVAL; } } } - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHost-MultiGame.h b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHost-MultiGame.h index 2593241177..3c8c2f4ed6 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHost-MultiGame.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHost-MultiGame.h @@ -20,11 +20,20 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class AutoHostMultiGame : public SingleSwitchProgram{ + +class AutoHostMultiGame_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + AutoHostMultiGame_Descriptor(); +}; + + + +class AutoHostMultiGame : public SingleSwitchProgramInstance{ public: - AutoHostMultiGame(); + AutoHostMultiGame(const AutoHostMultiGame_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual std::unique_ptr make_stats() const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: void run_autohost( diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHost-Rolling.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHost-Rolling.cpp index e1805697b6..c1fe6af40c 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHost-Rolling.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHost-Rolling.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/FrameworkSettings.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/SwitchRoutines/SwitchDigitEntry.h" @@ -14,19 +14,29 @@ #include "PokemonSwSh/Programs/PokemonSwSh_StartGame.h" #include "PokemonSwSh_DenTools.h" #include "PokemonSwSh_LobbyWait.h" +#include "PokemonSwSh_AutoHostStats.h" #include "PokemonSwSh_AutoHost-Rolling.h" namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -AutoHostRolling::AutoHostRolling() - : SingleSwitchProgram( - FeedbackType::OPTIONAL_, PABotBaseLevel::PABOTBASE_12KB, + +AutoHostRolling_Descriptor::AutoHostRolling_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:AutoHostRolling", "Auto-Host Rolling", "NativePrograms/AutoHost-Rolling.md", - "Roll N days, host, SR and repeat. Also supports hard-locks and soft-locks." + "Roll N days, host, SR and repeat. Also supports hard-locks and soft-locks.", + FeedbackType::OPTIONAL_, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +AutoHostRolling::AutoHostRolling(const AutoHostRolling_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , SKIPS("Day Skips:", 3) , BACKUP_SAVE("Load Backup Save:
For backup save soft-locking method.", false) , HOST_ONLINE("Host Online:", true) @@ -107,7 +117,16 @@ AutoHostRolling::AutoHostRolling() m_options.emplace_back(&DELAY_TO_SELECT_MOVE, "DELAY_TO_SELECT_MOVE"); } -void AutoHostRolling::program(SingleSwitchProgramEnvironment& env) const{ + + +std::unique_ptr AutoHostRolling::make_stats() const{ + return std::unique_ptr(new AutoHostStats()); +} + + +void AutoHostRolling::program(SingleSwitchProgramEnvironment& env){ + AutoHostStats& stats = env.stats(); + uint16_t start_raid_delay = HOST_ONLINE ? OPEN_ONLINE_DEN_LOBBY_DELAY : OPEN_LOCAL_DEN_LOBBY_DELAY; @@ -115,32 +134,39 @@ void AutoHostRolling::program(SingleSwitchProgramEnvironment& env) const{ ? 0 : LOBBY_WAIT_DELAY - start_raid_delay; - grip_menu_connect_go_home(); + grip_menu_connect_go_home(env.console); uint32_t last_touch = 0; if (SKIPS == 0 && TOUCH_DATE_INTERVAL > 0){ - touch_date_from_home(SETTINGS_TO_HOME_DELAY); - last_touch = system_clock(); + touch_date_from_home(env.console, SETTINGS_TO_HOME_DELAY); + last_touch = system_clock(env.console); } - rollback_date_from_home(SKIPS); - resume_game_front_of_den_nowatts(TOLERATE_SYSTEM_UPDATE_MENU_SLOW); + rollback_date_from_home(env.console, SKIPS); + resume_game_front_of_den_nowatts(env.console, TOLERATE_SYSTEM_UPDATE_MENU_SLOW); char first = true; for (uint32_t raids = 0;; raids++){ env.log("Raids Completed: " + tostr_u_commas(raids)); - - roll_den(ENTER_ONLINE_DEN_DELAY, OPEN_ONLINE_DEN_LOBBY_DELAY, SKIPS, CATCHABILITY); + env.update_stats(); + + roll_den( + env.console, + ENTER_ONLINE_DEN_DELAY, + OPEN_ONLINE_DEN_LOBBY_DELAY, + SKIPS, + CATCHABILITY + ); if (HOST_ONLINE){ - connect_to_internet(OPEN_YCOMM_DELAY, CONNECT_TO_INTERNET_DELAY); + connect_to_internet(env.console, OPEN_YCOMM_DELAY, CONNECT_TO_INTERNET_DELAY); } - enter_den(ENTER_ONLINE_DEN_DELAY, SKIPS != 0, HOST_ONLINE); + enter_den(env.console, ENTER_ONLINE_DEN_DELAY, SKIPS != 0, HOST_ONLINE); // Don't delay if it's the first iteration. if (first){ first = false; }else{ - pbf_wait(EXTRA_DELAY_BETWEEN_RAIDS); + pbf_wait(env.console, EXTRA_DELAY_BETWEEN_RAIDS); } uint8_t code[8]; @@ -150,15 +176,15 @@ void AutoHostRolling::program(SingleSwitchProgramEnvironment& env) const{ str[c] = code[c] + '0'; } env.log("Next Raid Code: " + std::string(str, sizeof(str))); - pbf_press_button(BUTTON_PLUS, 5, 145); - enter_digits(8, code); - pbf_wait(180); - pbf_press_button(BUTTON_A, 5, 95); + pbf_press_button(env.console, BUTTON_PLUS, 5, 145); + enter_digits(env.console, 8, code); + pbf_wait(env.console, 180); + pbf_press_button(env.console, BUTTON_A, 5, 95); } - enter_lobby(OPEN_ONLINE_DEN_LOBBY_DELAY, HOST_ONLINE, CATCHABILITY); + enter_lobby(env.console, OPEN_ONLINE_DEN_LOBBY_DELAY, HOST_ONLINE, CATCHABILITY); // Accept friend requests while we wait. - raid_lobby_wait( + RaidLobbyState raid_state = raid_lobby_wait( env.console, env.logger(), HOST_ONLINE, FRIEND_ACCEPT_USER_SLOT, @@ -166,26 +192,31 @@ void AutoHostRolling::program(SingleSwitchProgramEnvironment& env) const{ ); // Start Raid - pbf_press_dpad(DPAD_UP, 5, 45); + pbf_press_dpad(env.console, DPAD_UP, 5, 45); // Mash A until it's time to close the game. #if 1 { env.console.botbase().wait_for_all_requests(); - uint32_t start = system_clock(); - pbf_mash_button(BUTTON_A, 3 * TICKS_PER_SECOND); + uint32_t start = system_clock(env.console); + pbf_mash_button(env.console, BUTTON_A, 3 * TICKS_PER_SECOND); env.console.botbase().wait_for_all_requests(); - BlackScreenDetector black_screen(env.console, env.logger()); + BlackScreenDetector black_screen(env.console); uint32_t now = start; - while (now - start < RAID_START_TO_EXIT_DELAY){ - if (black_screen.black_is_over()){ + while (true){ + if (black_screen.black_is_over(env.console.video().snapshot())){ env.log("Raid has Started!", "blue"); + stats.add_raid(raid_state.raiders()); + break; + } + if (now - start >= RAID_START_TO_EXIT_DELAY){ + stats.add_timeout(); break; } - pbf_mash_button(BUTTON_A, TICKS_PER_SECOND); + pbf_mash_button(env.console, BUTTON_A, TICKS_PER_SECOND); env.console.botbase().wait_for_all_requests(); - now = system_clock(); + now = system_clock(env.console); } } #else @@ -194,39 +225,39 @@ void AutoHostRolling::program(SingleSwitchProgramEnvironment& env) const{ // Select a move. if (MOVE_SLOT > 0){ - pbf_wait(DELAY_TO_SELECT_MOVE); - pbf_press_button(BUTTON_A, 20, 80); + pbf_wait(env.console, DELAY_TO_SELECT_MOVE); + pbf_press_button(env.console, BUTTON_A, 20, 80); if (DYNAMAX){ - pbf_press_dpad(DPAD_LEFT, 20, 30); - pbf_press_button(BUTTON_A, 20, 60); + pbf_press_dpad(env.console, DPAD_LEFT, 20, 30); + pbf_press_button(env.console, BUTTON_A, 20, 60); } for (uint8_t c = 1; c < MOVE_SLOT; c++){ - pbf_press_dpad(DPAD_DOWN, 20, 30); + pbf_press_dpad(env.console, DPAD_DOWN, 20, 30); } - pbf_press_button(BUTTON_A, 20, 80); + pbf_press_button(env.console, BUTTON_A, 20, 80); // Disable the troll hosting option if the dynamax is set to TRUE. if (!DYNAMAX && TROLL_HOSTING > 0){ - pbf_press_dpad(DPAD_DOWN, 20, 80); + pbf_press_dpad(env.console, DPAD_DOWN, 20, 80); for (uint8_t c = 0; c < TROLL_HOSTING; c++){ - pbf_press_dpad(DPAD_RIGHT, 20, 80); + pbf_press_dpad(env.console, DPAD_RIGHT, 20, 80); } } - pbf_press_button(BUTTON_A, 20, 980); + pbf_press_button(env.console, BUTTON_A, 20, 980); } // Add a little extra wait time since correctness matters here. - ssf_press_button2(BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); + ssf_press_button2(env.console, BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); - close_game(); + close_game(env.console); // Touch the date. - if (SKIPS == 0 && TOUCH_DATE_INTERVAL > 0 && system_clock() - last_touch >= TOUCH_DATE_INTERVAL){ - touch_date_from_home(SETTINGS_TO_HOME_DELAY); + if (SKIPS == 0 && TOUCH_DATE_INTERVAL > 0 && system_clock(env.console) - last_touch >= TOUCH_DATE_INTERVAL){ + touch_date_from_home(env.console, SETTINGS_TO_HOME_DELAY); last_touch += TOUCH_DATE_INTERVAL; } - rollback_date_from_home(SKIPS); + rollback_date_from_home(env.console, SKIPS); start_game_from_home_with_inference( env, env.console, @@ -236,8 +267,8 @@ void AutoHostRolling::program(SingleSwitchProgramEnvironment& env) const{ ); } - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHost-Rolling.h b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHost-Rolling.h index cfb530b846..873f40ac6d 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHost-Rolling.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHost-Rolling.h @@ -19,11 +19,20 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class AutoHostRolling : public SingleSwitchProgram{ + +class AutoHostRolling_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + AutoHostRolling_Descriptor(); +}; + + + +class AutoHostRolling : public SingleSwitchProgramInstance{ public: - AutoHostRolling(); + AutoHostRolling(const AutoHostRolling_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual std::unique_ptr make_stats() const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: RandomCode RAID_CODE; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHostStats.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHostStats.cpp new file mode 100644 index 0000000000..ed30cf0456 --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHostStats.cpp @@ -0,0 +1,48 @@ +/* Auto-Hosting Stats + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "PokemonSwSh_AutoHostStats.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + + +AutoHostStats::AutoHostStats() + : m_raids(m_stats["Raids"]) + , m_timeouts(m_stats["Timeouts"]) + , m_empty(m_stats["Empty Raids"]) + , m_full(m_stats["Full Raids"]) + , m_total(m_stats["Total Raiders"]) +{ + m_display_order.emplace_back("Raids"); + m_display_order.emplace_back("Timeouts"); + m_display_order.emplace_back("Empty Raids"); + m_display_order.emplace_back("Full Raids"); + m_display_order.emplace_back("Total Raiders"); +} + +void AutoHostStats::add_raid(size_t raiders){ + m_raids++; + m_total += raiders; + if (raiders == 0){ + m_empty++; + } + if (raiders == 3){ + m_full++; + } +} +void AutoHostStats::add_timeout(){ + m_timeouts++; +} + + + +} +} +} + diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHostStats.h b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHostStats.h new file mode 100644 index 0000000000..19417ca326 --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_AutoHostStats.h @@ -0,0 +1,36 @@ +/* Auto-Hosting Stats + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PokemonSwSh_AutoHostStats_H +#define PokemonAutomation_PokemonSwSh_AutoHostStats_H + +#include "CommonFramework/Tools/StatsTracking.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +class AutoHostStats : public StatsTracker{ +public: + AutoHostStats(); + + void add_raid(size_t raiders); + void add_timeout(); + +private: + uint64_t& m_raids; + uint64_t& m_timeouts; + uint64_t& m_empty; + uint64_t& m_full; + uint64_t& m_total; +}; + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_DenRoller.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_DenRoller.cpp index 98e19f4ba0..051c206da2 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_DenRoller.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_DenRoller.cpp @@ -12,13 +12,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -DenRoller::DenRoller() - : SingleSwitchProgram( - FeedbackType::OPTIONAL_, PABotBaseLevel::PABOTBASE_12KB, + +DenRoller_Descriptor::DenRoller_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:DenRoller", "Den Roller", "NativePrograms/DenRoller.md", - "Roll den to the N'th day, SR and repeat." + "Roll den to the N'th day, SR and repeat.", + FeedbackType::OPTIONAL_, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +DenRoller::DenRoller(const DenRoller_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , SKIPS( "Number of Skips:", 3, 0, 60 @@ -34,32 +43,32 @@ DenRoller::DenRoller() } -void DenRoller::ring_bell(int count) const{ +void DenRoller::ring_bell(const BotBaseContext& context, int count) const{ for (int c = 0; c < count; c++){ - pbf_press_button(BUTTON_LCLICK, 5, 10); + pbf_press_button(context, BUTTON_LCLICK, 5, 10); } - pbf_wait(200); + pbf_wait(context, 200); } -void DenRoller::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); +void DenRoller::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); - rollback_date_from_home(SKIPS); - resume_game_front_of_den_nowatts(TOLERATE_SYSTEM_UPDATE_MENU_SLOW); + rollback_date_from_home(env.console, SKIPS); + resume_game_front_of_den_nowatts(env.console, TOLERATE_SYSTEM_UPDATE_MENU_SLOW); while (true){ - roll_den(0, 0, SKIPS, CATCHABILITY); + roll_den(env.console, 0, 0, SKIPS, CATCHABILITY); - ring_bell(20); - enter_den(0, SKIPS != 0, false); + ring_bell(env.console, 20); + enter_den(env.console, 0, SKIPS != 0, false); // Give user time to look at the mon. - pbf_wait(VIEW_TIME); + pbf_wait(env.console, VIEW_TIME); // Add a little extra wait time since correctness matters here. - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE - 10); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE - 10); - rollback_date_from_home(SKIPS); + rollback_date_from_home(env.console, SKIPS); // reset_game_from_home(TOLERATE_SYSTEM_UPDATE_MENU_SLOW); reset_game_from_home_with_inference( env, env.console, @@ -67,8 +76,8 @@ void DenRoller::program(SingleSwitchProgramEnvironment& env) const{ ); } - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_DenRoller.h b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_DenRoller.h index ad294e1424..8abf7386a2 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_DenRoller.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_DenRoller.h @@ -17,12 +17,19 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ -class DenRoller : public SingleSwitchProgram{ +class DenRoller_Descriptor : public RunnableSwitchProgramDescriptor{ public: - DenRoller(); + DenRoller_Descriptor(); +}; + + + +class DenRoller : public SingleSwitchProgramInstance{ +public: + DenRoller(const DenRoller_Descriptor& descriptor); - void ring_bell(int count) const; - virtual void program(SingleSwitchProgramEnvironment& env) const override; + void ring_bell(const BotBaseContext& context, int count) const; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger SKIPS; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_DenTools.h b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_DenTools.h index 9ab3b88883..a029390ff5 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_DenTools.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_DenTools.h @@ -21,75 +21,70 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ -static void enter_den(BotBase& device, uint16_t ENTER_ONLINE_DEN_DELAY, bool watts, bool online){ +static void enter_den(const BotBaseContext& context, uint16_t ENTER_ONLINE_DEN_DELAY, bool watts, bool online){ if (!online){ if (!watts){ - ssf_press_button2(device, BUTTON_A, ENTER_OFFLINE_DEN_DELAY, 10); + ssf_press_button2(context, BUTTON_A, ENTER_OFFLINE_DEN_DELAY, 10); }else{ // This is the critical den-rolling path. It needs to be fast. - mash_A(device, COLLECT_WATTS_OFFLINE_DELAY); - pbf_wait(device, ENTER_OFFLINE_DEN_DELAY); + mash_A(context, COLLECT_WATTS_OFFLINE_DELAY); + pbf_wait(context, ENTER_OFFLINE_DEN_DELAY); } }else{ if (!watts){ - ssf_press_button2(device, BUTTON_A, ENTER_ONLINE_DEN_DELAY, 50); + ssf_press_button2(context, BUTTON_A, ENTER_ONLINE_DEN_DELAY, 50); }else{ - ssf_press_button2(device, BUTTON_A, COLLECT_WATTS_ONLINE_DELAY, 50); - ssf_press_button2(device, BUTTON_B, 100, 50); - ssf_press_button2(device, BUTTON_B, ENTER_ONLINE_DEN_DELAY, 50); + ssf_press_button2(context, BUTTON_A, COLLECT_WATTS_ONLINE_DELAY, 50); + ssf_press_button2(context, BUTTON_B, 100, 50); + ssf_press_button2(context, BUTTON_B, ENTER_ONLINE_DEN_DELAY, 50); } } } -static void enter_den(uint16_t ENTER_ONLINE_DEN_DELAY, bool watts, bool online){ - enter_den(*global_connection, ENTER_ONLINE_DEN_DELAY, watts, online); -} -static void enter_lobby(BotBase& device, uint16_t OPEN_ONLINE_DEN_LOBBY_DELAY, bool online, Catchability catchability){ +static void enter_lobby(const BotBaseContext& context, uint16_t OPEN_ONLINE_DEN_LOBBY_DELAY, bool online, Catchability catchability){ if (online){ switch (catchability){ case ALWAYS_CATCHABLE: - ssf_press_button1(device, BUTTON_A, OPEN_ONLINE_DEN_LOBBY_DELAY); + ssf_press_button1(context, BUTTON_A, OPEN_ONLINE_DEN_LOBBY_DELAY); return; case MAYBE_UNCATCHABLE: case ALWAYS_UNCATCHABLE: - ssf_press_button1(device, BUTTON_A, UNCATCHABLE_PROMPT_DELAY); - ssf_press_button1(device, BUTTON_A, OPEN_ONLINE_DEN_LOBBY_DELAY); + ssf_press_button1(context, BUTTON_A, UNCATCHABLE_PROMPT_DELAY); + ssf_press_button1(context, BUTTON_A, OPEN_ONLINE_DEN_LOBBY_DELAY); return; } } switch (catchability){ case ALWAYS_CATCHABLE: - ssf_press_button1(device, BUTTON_A, OPEN_LOCAL_DEN_LOBBY_DELAY); + ssf_press_button1(context, BUTTON_A, OPEN_LOCAL_DEN_LOBBY_DELAY); return; case MAYBE_UNCATCHABLE: - ssf_press_button1(device, BUTTON_A, UNCATCHABLE_PROMPT_DELAY); - ssf_press_button1(device, BUTTON_A, OPEN_LOCAL_DEN_LOBBY_DELAY); + ssf_press_button1(context, BUTTON_A, UNCATCHABLE_PROMPT_DELAY); + ssf_press_button1(context, BUTTON_A, OPEN_LOCAL_DEN_LOBBY_DELAY); if (!DODGE_UNCATCHABLE_PROMPT_FAST){ // lobby-switch switch-box - ssf_press_dpad1(device, DPAD_LEFT, 10); + ssf_press_dpad1(context, DPAD_LEFT, 10); // lobby-switch switch-party-red - ssf_press_button1(device, BUTTON_A, ENTER_SWITCH_POKEMON); + ssf_press_button1(context, BUTTON_A, ENTER_SWITCH_POKEMON); // switch-box switch-confirm - ssf_press_button1(device, BUTTON_Y, 10); - ssf_press_dpad1(device, DPAD_LEFT, 10); + ssf_press_button1(context, BUTTON_Y, 10); + ssf_press_dpad1(context, DPAD_LEFT, 10); // switch-party-blue switch-confirm - ssf_press_button1(device, BUTTON_A, EXIT_SWITCH_POKEMON); + ssf_press_button1(context, BUTTON_A, EXIT_SWITCH_POKEMON); // lobby-switch lobby-switch } return; case ALWAYS_UNCATCHABLE: - ssf_press_button1(device, BUTTON_A, UNCATCHABLE_PROMPT_DELAY); - ssf_press_button1(device, BUTTON_A, OPEN_LOCAL_DEN_LOBBY_DELAY); + ssf_press_button1(context, BUTTON_A, UNCATCHABLE_PROMPT_DELAY); + ssf_press_button1(context, BUTTON_A, OPEN_LOCAL_DEN_LOBBY_DELAY); return; } } -static void enter_lobby(uint16_t OPEN_ONLINE_DEN_LOBBY_DELAY, bool online, Catchability catchability){ - enter_lobby(*global_connection, OPEN_ONLINE_DEN_LOBBY_DELAY, online, catchability); -} static void roll_den( + const BotBaseContext& context, uint16_t ENTER_ONLINE_DEN_DELAY, uint16_t OPEN_ONLINE_DEN_LOBBY_DELAY, uint8_t skips, Catchability catchability @@ -98,37 +93,41 @@ static void roll_den( skips = 60; } for (uint8_t c = 0; c < skips; c++){ - enter_den(ENTER_ONLINE_DEN_DELAY, c != 0, false); - enter_lobby(OPEN_ONLINE_DEN_LOBBY_DELAY, false, catchability); + enter_den(context, ENTER_ONLINE_DEN_DELAY, c != 0, false); + enter_lobby(context, OPEN_ONLINE_DEN_LOBBY_DELAY, false, catchability); // Skip forward. - ssf_press_button2(BUTTON_HOME, GAME_TO_HOME_DELAY_FAST, 10); - home_to_date_time(true, false); - roll_date_forward_1(false); + ssf_press_button2(context, BUTTON_HOME, GAME_TO_HOME_DELAY_FAST, 10); + home_to_date_time(context, true, false); + roll_date_forward_1(context, false); // Enter game - settings_to_enter_game_den_lobby(TOLERATE_SYSTEM_UPDATE_MENU_SLOW, true); + settings_to_enter_game_den_lobby( + context, + TOLERATE_SYSTEM_UPDATE_MENU_SLOW, true, + ENTER_SWITCH_POKEMON, EXIT_SWITCH_POKEMON + ); // Exit Raid - ssf_press_button2(BUTTON_B, 120, 50); - ssf_press_button2(BUTTON_A, REENTER_DEN_DELAY, 50); + ssf_press_button2(context, BUTTON_B, 120, 50); + ssf_press_button2(context, BUTTON_A, REENTER_DEN_DELAY, 50); } } -static void rollback_date_from_home(uint8_t skips){ +static void rollback_date_from_home(const BotBaseContext& context, uint8_t skips){ if (skips == 0){ return; } if (skips > 60){ skips = 60; } - home_to_date_time(true, false); - roll_date_backward_N(skips, false); + home_to_date_time(context, true, false); + roll_date_backward_N(context, skips, false); // pbf_wait(5); // Note that it is possible for this return animation to run longer than // "SETTINGS_TO_HOME_DELAY" and swallow a subsequent button press. // Therefore the caller needs to be able to tolerate this. - ssf_press_button2(BUTTON_HOME, SETTINGS_TO_HOME_DELAY, 10); + ssf_press_button2(context, BUTTON_HOME, SETTINGS_TO_HOME_DELAY, 10); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_LobbyWait.h b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_LobbyWait.h index 8eb510edb3..9997a2874b 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_LobbyWait.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/Hosting/PokemonSwSh_LobbyWait.h @@ -23,55 +23,40 @@ namespace PokemonSwSh{ //using std::cout; //using std::endl; -static void raid_lobby_wait( +static RaidLobbyState raid_lobby_wait( ConsoleHandle& console, Logger& logger, bool HOST_ONLINE, uint8_t accept_FR_slot, uint16_t lobby_wait_delay ){ -#if 0 - if (!settings.developer_mode){ - if (HOST_ONLINE && accept_FR_slot > 0){ - accept_FRs_while_waiting( - accept_FR_slot - 1, - lobby_wait_delay, - GAME_TO_HOME_DELAY_SAFE, - AUTO_FR_DURATION, - TOLERATE_SYSTEM_UPDATE_MENU_SLOW - ); - }else{ - pbf_wait(lobby_wait_delay); - } - return; - } -#endif - console.botbase().wait_for_all_requests(); - uint32_t start = system_clock(); + uint32_t start = system_clock(console); RaidLobbyReader inference(console, logger); RaidLobbyState state; if (HOST_ONLINE && accept_FR_slot > 0){ accept_FRs( + console, accept_FR_slot - 1, true, GAME_TO_HOME_DELAY_SAFE, AUTO_FR_DURATION, TOLERATE_SYSTEM_UPDATE_MENU_SLOW ); console.botbase().wait_for_all_requests(); - uint32_t time_elapsed = system_clock() - start; + uint32_t time_elapsed = system_clock(console) - start; uint32_t delay = time_elapsed; while (true){ state = inference.read(); if (state.valid && state.raid_is_full() && state.raiders_are_ready()){ - return; + return state; } - time_elapsed = system_clock() - start; + time_elapsed = system_clock(console) - start; if (time_elapsed + delay >= lobby_wait_delay){ break; } accept_FRs( + console, accept_FR_slot - 1, false, GAME_TO_HOME_DELAY_SAFE, AUTO_FR_DURATION, @@ -84,13 +69,19 @@ static void raid_lobby_wait( while (true){ state = inference.read(); if (state.valid && state.raid_is_full() && state.raiders_are_ready()){ - return; + return state; } - uint32_t time_elapsed = system_clock() - start; + uint32_t time_elapsed = system_clock(console) - start; if (time_elapsed >= lobby_wait_delay){ break; } - pbf_wait(std::min(lobby_wait_delay - time_elapsed, (uint32_t)TICKS_PER_SECOND)); + pbf_wait( + console, + std::min( + lobby_wait_delay - time_elapsed, + (uint32_t)TICKS_PER_SECOND + ) + ); console.botbase().wait_for_all_requests(); } @@ -98,13 +89,19 @@ static void raid_lobby_wait( while (true){ if (!state.valid || state.raiders_are_ready()){ - return; + return state; } - uint32_t time_elapsed = system_clock() - start; + uint32_t time_elapsed = system_clock(console) - start; if (time_elapsed > FULL_LOBBY_TIMER){ - return; + return state; } - pbf_wait(std::min(FULL_LOBBY_TIMER - time_elapsed, (uint32_t)TICKS_PER_SECOND)); + pbf_wait( + console, + std::min( + FULL_LOBBY_TIMER - time_elapsed, + (uint32_t)TICKS_PER_SECOND + ) + ); console.botbase().wait_for_all_requests(); state = inference.read(); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldMovement.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldMovement.cpp new file mode 100644 index 0000000000..90c7527d59 --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldMovement.cpp @@ -0,0 +1,97 @@ +/* Overworld Movement + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "Common/SwitchFramework/Switch_PushButtons.h" +#include "PokemonSwSh_OverworldMovement.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +void move_in_circle_up(const BotBaseContext& context, bool counter_clockwise){ +// cout << "up" << endl; + if (counter_clockwise){ + pbf_move_left_joystick(context, 255, 128, 16, 0); + pbf_move_left_joystick(context, 255, 0, 16, 0); + pbf_move_left_joystick(context, 128, 0, 16, 0); + pbf_move_left_joystick(context, 0, 0, 16, 0); + pbf_move_left_joystick(context, 0, 128, 16, 0); + pbf_move_left_joystick(context, 0, 255, 16, 0); + pbf_move_left_joystick(context, 128, 255, 16, 0); + pbf_move_left_joystick(context, 255, 255, 16, 0); + }else{ + pbf_move_left_joystick(context, 0, 128, 16, 0); + pbf_move_left_joystick(context, 0, 0, 16, 0); + pbf_move_left_joystick(context, 128, 0, 16, 0); + pbf_move_left_joystick(context, 255, 0, 16, 0); + pbf_move_left_joystick(context, 255, 128, 16, 0); + pbf_move_left_joystick(context, 255, 255, 16, 0); + pbf_move_left_joystick(context, 128, 255, 16, 0); + pbf_move_left_joystick(context, 0, 255, 16, 0); + } +} +void move_in_circle_down(const BotBaseContext& context, bool counter_clockwise){ + if (counter_clockwise){ + pbf_move_left_joystick(context, 0, 128, 16, 0); + pbf_move_left_joystick(context, 0, 255, 16, 0); + pbf_move_left_joystick(context, 128, 255, 16, 0); + pbf_move_left_joystick(context, 255, 255, 16, 0); + pbf_move_left_joystick(context, 255, 128, 16, 0); + pbf_move_left_joystick(context, 255, 0, 24, 0); + pbf_move_left_joystick(context, 128, 0, 24, 0); + pbf_move_left_joystick(context, 0, 0, 24, 0); + }else{ + pbf_move_left_joystick(context, 255, 128, 16, 0); + pbf_move_left_joystick(context, 255, 255, 16, 0); + pbf_move_left_joystick(context, 128, 255, 16, 0); + pbf_move_left_joystick(context, 0, 255, 16, 0); + pbf_move_left_joystick(context, 0, 128, 16, 0); + pbf_move_left_joystick(context, 0, 0, 24, 0); + pbf_move_left_joystick(context, 128, 0, 24, 0); + pbf_move_left_joystick(context, 255, 0, 24, 0); + } +} +void circle_in_place(const BotBaseContext& context, bool counter_clockwise){ + if (counter_clockwise){ + pbf_move_left_joystick(context, 0, 128, 64, 0); // Correct for bias. + pbf_move_left_joystick(context, 128, 255, 32, 0); + pbf_move_left_joystick(context, 255, 255, 32, 0); + pbf_move_left_joystick(context, 255, 128, 32, 0); + pbf_move_left_joystick(context, 255, 0, 32, 0); + pbf_move_left_joystick(context, 128, 0, 32, 0); + pbf_move_left_joystick(context, 0, 0, 32, 0); + pbf_move_left_joystick(context, 0, 128, 32, 0); + pbf_move_left_joystick(context, 0, 255, 32, 0); + pbf_move_left_joystick(context, 255, 128, 16, 0); // Correct for bias. + }else{ + pbf_move_left_joystick(context, 255, 128, 64, 0); // Correct for bias. + pbf_move_left_joystick(context, 128, 255, 32, 0); + pbf_move_left_joystick(context, 0, 255, 32, 0); + pbf_move_left_joystick(context, 0, 128, 32, 0); + pbf_move_left_joystick(context, 0, 0, 32, 0); + pbf_move_left_joystick(context, 128, 0, 32, 0); + pbf_move_left_joystick(context, 255, 0, 32, 0); + pbf_move_left_joystick(context, 255, 128, 32, 0); + pbf_move_left_joystick(context, 255, 255, 32, 0); + pbf_move_left_joystick(context, 0, 128, 16, 0); // Correct for bias. + } +} +void move_in_line(const BotBaseContext& context, bool horizontal){ + if (horizontal){ + pbf_move_left_joystick(context, 0, 128, 128, 32); + pbf_move_left_joystick(context, 255, 128, 128, 32); + }else{ + pbf_move_left_joystick(context, 128, 255, 128, 32); + pbf_move_left_joystick(context, 128, 0, 128, 32); + } +} + + +} +} +} + diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldMovement.h b/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldMovement.h new file mode 100644 index 0000000000..7b6f87db68 --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldMovement.h @@ -0,0 +1,25 @@ +/* Overworld Movement + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PokemonSwSh_OverworldMovement_H +#define PokemonAutomation_PokemonSwSh_OverworldMovement_H + +#include "ClientSource/Connection/BotBase.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +void move_in_circle_up(const BotBaseContext& context, bool counter_clockwise); +void move_in_circle_down(const BotBaseContext& context, bool counter_clockwise); +void circle_in_place(const BotBaseContext& context, bool counter_clockwise); +void move_in_line(const BotBaseContext& context, bool horizontal); + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTargetTracker.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTargetTracker.cpp new file mode 100644 index 0000000000..06fcda37fa --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTargetTracker.cpp @@ -0,0 +1,284 @@ +/* Overworld Mark Tracker + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "CommonFramework/Inference/ImageTools.h" +#include "PokemonSwSh/Inference/PokemonSwSh_MarkFinder.h" +#include "PokemonSwSh_OverworldTargetTracker.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +const std::vector MARK_PRIORITY_STRINGS{ + "Exclamation Marks Only (Ignore Question Marks)", + "Prioritize Exclamation Marks", + "No Preference", + "Prioritize Question Marks", + "Question Marks Only (Ignore Exclamation Marks)", +}; + + + +const double OverworldTargetTracker::OVERWORLD_CENTER_X = 0.50; +const double OverworldTargetTracker::OVERWORLD_CENTER_Y = 0.70; + + +OverworldTargetTracker::OverworldTargetTracker( + Logger& logger, VideoFeed& feed, + std::chrono::milliseconds window, + double mark_offset, + MarkPriority mark_priority, + double max_alpha +) + : m_logger(logger) + , m_feed(feed) + , m_window(window) + , m_mark_offset(mark_offset) + , m_mark_priority(mark_priority) + , m_max_alpha(max_alpha) + , m_search_area(feed, 0.0, 0.2, 1.0, 0.8) + , m_stop_on_target(false) +{ + m_best_target.first = -1; +} + +void OverworldTargetTracker::set_stop_on_target(bool stop){ + m_stop_on_target.store(stop, std::memory_order_release); +} +void OverworldTargetTracker::clear_detections(){ + SpinLockGuard lg(m_lock, "OverworldTargetTracker::clear_detections()"); + m_best_target.first = -1; + m_exclamations.clear(); + m_questions.clear(); +} +std::pair OverworldTargetTracker::best_target(){ + SpinLockGuard lg(m_lock, "OverworldTargetTracker::best_target()"); + return m_best_target; +} + + +void OverworldTargetTracker::populate_targets( + std::multimap& scored_targets, + const std::vector& targets +){ +#if 0 + cout << "Targets:" << endl; + for (const auto& item : targets){ + cout << " " << item.box.x << " - " << item.box.x + item.box.width + << " x " << item.box.y << " - " << item.box.y + item.box.height << endl; + } +#endif + +// cout << "Candidates:" << endl; + for (size_t c = 0; c < targets.size(); c++){ + double overlap = 0; + const InferenceBox& box0 = targets[c].box; + for (size_t i = 0; i < targets.size(); i++){ + const InferenceBox& box1 = targets[i].box; + double min_x = std::max(box0.x, box1.x); + double max_x = std::min(box0.x + box0.width, box1.x + box1.width); + if (min_x >= max_x){ + continue; + } + double min_y = std::max(box0.y, box1.y); + double max_y = std::min(box0.y + box0.height, box1.y + box1.height); + if (min_y >= max_y){ + continue; + } + overlap += (max_x - min_x) * (max_y - min_y); + } + double score = targets[c].trajectory.distance_in_ticks / overlap; + scored_targets.emplace(score, targets[c]); +// cout << " " << score << " = " +// << (int)targets[c].trajectory.joystick_x << ", " +// << (int)targets[c].trajectory.joystick_y << endl; + } +} + +void OverworldTargetTracker::populate_targets( + std::multimap& scored_targets, + const std::deque& marks, + OverworldMark mark +){ + std::vector targets; + for (const Mark& item : marks){ + const InferenceBox& box = item.box; + double delta_x = box.x + box.width / 2 - OVERWORLD_CENTER_X; + double delta_y = box.y + box.height * (1.0 + m_mark_offset) - OVERWORLD_CENTER_Y; + Trajectory trajectory = get_trajectory_float(delta_x, delta_y); + targets.emplace_back(OverworldTarget{mark, box, trajectory, delta_x, delta_y}); + } + populate_targets(scored_targets, targets); +} + +bool OverworldTargetTracker::save_target(std::multimap::iterator target){ +#if 0 + m_logger.log( + QString("Best Target: ") + + (target->second.mark == OverworldMark::EXCLAMATION_MARK ? "Exclamation" : "Question") + + " at [" + + QString::number(target->second.delta_x) + " , " + + QString::number(-target->second.delta_y) + "], alpha = " + + QString::number(target->first), + "purple" + ); +#endif +// SpinLockGuard lg(m_lock, "OverworldTargetTracker::save_target()"); + m_best_target = *target; + return target->first <= m_max_alpha && m_stop_on_target.load(std::memory_order_acquire); +} + +bool OverworldTargetTracker::on_frame( + const QImage& frame, + std::chrono::system_clock::time_point timestamp +){ + QImage image = extract_box(frame, m_search_area); + + std::vector exclamation_marks; + std::vector question_marks; + find_marks( + image, + &exclamation_marks, + &question_marks + ); + + + SpinLockGuard lg(m_lock, "OverworldTargetTracker::on_frame()"); + + // Clear out old detections. + auto oldest = timestamp - m_window; + while (!m_exclamations.empty() && m_exclamations[0].timestamp < oldest){ + m_exclamations.pop_front(); + } + while (!m_questions.empty() && m_questions[0].timestamp < oldest){ + m_questions.pop_front(); + } + + + m_detection_boxes.clear(); + for (const PixelBox& mark : exclamation_marks){ + InferenceBox box = translate_to_parent(frame, m_search_area, mark); + box.color = Qt::magenta; + box.x -= box.width * 1.5; + box.width *= 4; + box.height *= 1.5; + m_exclamations.emplace_back(Mark{timestamp, box}); + m_detection_boxes.emplace_back(m_feed, box); +// cout << "asdf = " << exclamations.size() << endl; + } + for (const PixelBox& mark : question_marks){ + InferenceBox box = translate_to_parent(frame, m_search_area, mark); + box.color = Qt::magenta; + box.x -= box.width * 0.5; + box.width *= 2; + box.height *= 1.5; + m_questions.emplace_back(Mark{timestamp, box}); + m_detection_boxes.emplace_back(m_feed, box); +// cout << "qwer = " << questions.size() << endl; + } + + + // Build targets. + + switch (m_mark_priority){ + case MarkPriority::EXCLAMATION_ONLY:{ + std::multimap targets; + populate_targets(targets, m_exclamations, OverworldMark::EXCLAMATION_MARK); + if (!targets.empty()){ + return save_target(targets.begin()); + } + break; + } + case MarkPriority::PRIORITIZE_EXCLAMATION:{ + std::multimap exclamation_targets; + std::multimap question_targets; + populate_targets(exclamation_targets, m_exclamations, OverworldMark::EXCLAMATION_MARK); + populate_targets(question_targets, m_questions, OverworldMark::QUESTION_MARK); + + auto target0 = exclamation_targets.begin(); + auto target1 = question_targets.begin(); + + // See if we have any good target. + if (!exclamation_targets.empty() && target0->first <= m_max_alpha){ + return save_target(target0); + } + if (!question_targets.empty() && target1->first <= m_max_alpha){ + return save_target(target1); + } + + // No good targets. Pick the next best one for logging purposes. + std::multimap targets; + if (!exclamation_targets.empty()){ + targets.emplace(target0->first, target0->second); + } + if (!question_targets.empty()){ + targets.emplace(target1->first, target1->second); + } + if (!targets.empty()){ + return save_target(targets.begin()); + } + break; + } + case MarkPriority::NO_PREFERENCE:{ + std::multimap targets; + populate_targets(targets, m_exclamations, OverworldMark::EXCLAMATION_MARK); + populate_targets(targets, m_questions, OverworldMark::QUESTION_MARK); + if (!targets.empty()){ + return save_target(targets.begin()); + } + break; + } + case MarkPriority::PRIORITIZE_QUESTION:{ + std::multimap exclamation_targets; + std::multimap question_targets; + populate_targets(exclamation_targets, m_exclamations, OverworldMark::EXCLAMATION_MARK); + populate_targets(question_targets, m_questions, OverworldMark::QUESTION_MARK); + + auto target0 = exclamation_targets.begin(); + auto target1 = question_targets.begin(); + + // See if we have any good target. + if (!question_targets.empty() && target1->first <= m_max_alpha){ + return save_target(target1); + } + if (!exclamation_targets.empty() && target0->first <= m_max_alpha){ + return save_target(target0); + } + + // No good targets. Pick the next best one for logging purposes. + std::multimap targets; + if (!question_targets.empty()){ + targets.emplace(target1->first, target1->second); + } + if (!exclamation_targets.empty()){ + targets.emplace(target0->first, target0->second); + } + if (!targets.empty()){ + return save_target(targets.begin()); + } + break; + } + case MarkPriority::QUESTION_ONLY:{ + std::multimap targets; + populate_targets(targets, m_questions, OverworldMark::QUESTION_MARK); + if (!targets.empty()){ + return save_target(targets.begin()); + } + break; + } + } + + m_best_target.first = -1; + return false; +} + + + +} +} +} + diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTargetTracker.h b/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTargetTracker.h new file mode 100644 index 0000000000..52380d2fc2 --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTargetTracker.h @@ -0,0 +1,122 @@ +/* Overworld Target Tracker + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PokemonSwSh_OverworldTargetTracker_H +#define PokemonAutomation_PokemonSwSh_OverworldTargetTracker_H + +#include +#include "Common/Cpp/SpinLock.h" +#include "CommonFramework/Tools/Logger.h" +#include "CommonFramework/Tools/VideoFeed.h" +#include "CommonFramework/Inference/VisualInferenceCallback.h" +#include "PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTrajectory.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + + +enum class OverworldMark{ + EXCLAMATION_MARK, + QUESTION_MARK, +}; + +enum class MarkPriority{ + EXCLAMATION_ONLY, + PRIORITIZE_EXCLAMATION, + NO_PREFERENCE, + PRIORITIZE_QUESTION, + QUESTION_ONLY, +}; +extern const std::vector MARK_PRIORITY_STRINGS; + +struct OverworldTarget{ + OverworldMark mark; + InferenceBox box; + Trajectory trajectory; + double delta_x; + double delta_y; +}; + + +class OverworldTargetTracker : public VisualInferenceCallbackWithCommandStop{ +public: + static const double OVERWORLD_CENTER_X; + static const double OVERWORLD_CENTER_Y; + +public: + OverworldTargetTracker( + Logger& logger, VideoFeed& feed, + std::chrono::milliseconds window, + double mark_offset, + MarkPriority mark_priority, + double max_alpha + ); + + // If set to true, this inference object will not return true on + // "on_frame()" callbacks. + void set_stop_on_target(bool stop); + + void clear_detections(); + + // Get the best target as of right now. + // The return value is only valid if the first element is non-negative. + std::pair best_target(); + + virtual bool on_frame( + const QImage& frame, + std::chrono::system_clock::time_point timestamp + ) override final; + + +private: + struct Mark{ + std::chrono::system_clock::time_point timestamp; + InferenceBox box; + }; + + static void populate_targets( + std::multimap& scored_targets, + const std::vector& targets + ); + void populate_targets( + std::multimap& scored_targets, + const std::deque& marks, + OverworldMark mark + ); + + bool save_target(std::multimap::iterator target); + + +private: + Logger& m_logger; + VideoFeed& m_feed; + std::chrono::milliseconds m_window; + double m_mark_offset; + MarkPriority m_mark_priority; + double m_max_alpha; + + InferenceBoxScope m_search_area; + std::deque m_detection_boxes; + + // Sliding window of detections. + std::deque m_exclamations; + std::deque m_questions; + + std::atomic m_stop_on_target; + SpinLock m_lock; + std::pair m_best_target; +}; + + + + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_OverworldTrajectory.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTrajectory.cpp similarity index 100% rename from SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_OverworldTrajectory.cpp rename to SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTrajectory.cpp diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_OverworldTrajectory.h b/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTrajectory.h similarity index 100% rename from SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_OverworldTrajectory.h rename to SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTrajectory.h diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTrigger.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTrigger.cpp new file mode 100644 index 0000000000..60fa3e57b6 --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTrigger.cpp @@ -0,0 +1,101 @@ +/* Overworld Trigger + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "Common/SwitchFramework/Switch_PushButtons.h" +#include "PokemonSwSh_OverworldMovement.h" +#include "PokemonSwSh_OverworldTrigger.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +OverworldTrigger::OverworldTrigger(ProgramEnvironment& env) + : m_env(env) +{} +void OverworldTrigger::whistle(const BotBaseContext& context, bool rotate){ + if (rotate){ + pbf_move_right_joystick(context, 192, 255, 50, 70); + } + pbf_press_button(context, BUTTON_LCLICK, 5, 0); + pbf_mash_button(context, BUTTON_B, 120); +} + + +void OverworldTrigger_Whistle::run( + InterruptableCommandSession& session, + OverworldTargetTracker& target_tracker +){ +// m_env.log("Whistle and wait."); + session.run([=](const BotBaseContext& context){ + whistle(context, !m_first_after_battle); + context.botbase().wait_for_all_requests(); + }); + m_first_after_battle = false; +} + + +OverworldTrigger_WhistleStaticAction::OverworldTrigger_WhistleStaticAction( + ProgramEnvironment& env, + bool whistle_first, + size_t whistle_count, + size_t action_count +) + : OverworldTrigger(env) + , m_whistle_first(whistle_first) + , m_whistle_count(whistle_count) + , m_action_count(action_count) +{} +void OverworldTrigger_WhistleStaticAction::run( + InterruptableCommandSession& session, + OverworldTargetTracker& target_tracker +){ + target_tracker.set_stop_on_target(true); + if (m_whistle_first){ + session.run([=](const BotBaseContext& context){ + for (size_t c = 0; c < m_whistle_count; c++){ + whistle(context, !m_first_after_battle); + m_first_after_battle = false; + } + for (size_t c = 0; c < m_action_count; c++){ + action(context); + } + context.botbase().wait_for_all_requests(); + }); + }else{ + session.run([=](const BotBaseContext& context){ + for (size_t c = 0; c < m_action_count; c++){ + action(context); + } + for (size_t c = 0; c < m_whistle_count; c++){ + whistle(context, true); + } + context.botbase().wait_for_all_requests(); + }); + + } + target_tracker.set_stop_on_target(false); +} + + +void OverworldTrigger_WhistleCircle::action(const BotBaseContext& context){ + circle_in_place(context, rand() % 2); +} +void OverworldTrigger_WhistleHorizontal::action(const BotBaseContext& context){ + move_in_line(context, true); +} +void OverworldTrigger_WhistleVertical::action(const BotBaseContext& context){ + move_in_line(context, false); +} + + + +} +} +} + + + diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTrigger.h b/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTrigger.h new file mode 100644 index 0000000000..d28c4d22b4 --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_OverworldTrigger.h @@ -0,0 +1,99 @@ +/* Overworld Trigger + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PokemonSwSh_OverworldTrigger_H +#define PokemonAutomation_PokemonSwSh_OverworldTrigger_H + +#include "CommonFramework/Tools/ProgramEnvironment.h" +#include "CommonFramework/Tools/InterruptableCommands.h" +#include "PokemonSwSh_OverworldTargetTracker.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +class OverworldTrigger{ +public: + OverworldTrigger(ProgramEnvironment& env); + + virtual void run( + InterruptableCommandSession& session, + OverworldTargetTracker& target_tracker + ) = 0; + +protected: + static void whistle(const BotBaseContext& context, bool rotate); + +protected: + ProgramEnvironment& m_env; +}; + + + +class OverworldTrigger_Whistle : public OverworldTrigger{ +public: + using OverworldTrigger::OverworldTrigger; + virtual void run( + InterruptableCommandSession& session, + OverworldTargetTracker& target_tracker + ) override; + +private: + bool m_first_after_battle = true; +}; + + +class OverworldTrigger_WhistleStaticAction : public OverworldTrigger{ +public: + OverworldTrigger_WhistleStaticAction( + ProgramEnvironment& env, + bool whistle_first, + size_t whistle_count, + size_t action_count + ); + virtual void run( + InterruptableCommandSession& session, + OverworldTargetTracker& target_tracker + ) override; + +protected: + virtual void action(const BotBaseContext& context) = 0; + +private: + bool m_whistle_first; + size_t m_whistle_count; + size_t m_action_count; + bool m_first_after_battle = true; +}; + + +class OverworldTrigger_WhistleCircle : public OverworldTrigger_WhistleStaticAction{ +public: + using OverworldTrigger_WhistleStaticAction::OverworldTrigger_WhistleStaticAction; + virtual void action(const BotBaseContext& context) override; +}; + + +class OverworldTrigger_WhistleHorizontal : public OverworldTrigger_WhistleStaticAction{ +public: + using OverworldTrigger_WhistleStaticAction::OverworldTrigger_WhistleStaticAction; + virtual void action(const BotBaseContext& context) override; +}; + + +class OverworldTrigger_WhistleVertical : public OverworldTrigger_WhistleStaticAction{ +public: + using OverworldTrigger_WhistleStaticAction::OverworldTrigger_WhistleStaticAction; + virtual void action(const BotBaseContext& context) override; +}; + + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_ShinyHuntAutonomous-Overworld.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_ShinyHuntAutonomous-Overworld.cpp new file mode 100644 index 0000000000..4cc7c4d2f1 --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_ShinyHuntAutonomous-Overworld.cpp @@ -0,0 +1,422 @@ +/* Shiny Hunt Autonomous - Overworld + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include "Common/Cpp/PrettyPrint.h" +#include "Common/SwitchFramework/FrameworkSettings.h" +#include "Common/SwitchFramework/Switch_PushButtons.h" +#include "Common/PokemonSwSh/PokemonSettings.h" +#include "Common/PokemonSwSh/PokemonSwShGameEntry.h" +#include "Common/PokemonSwSh/PokemonSwShDateSpam.h" +#include "CommonFramework/PersistentSettings.h" +#include "CommonFramework/Tools/InterruptableCommands.h" +#include "CommonFramework/Inference/ImageTools.h" +#include "CommonFramework/Inference/InferenceThrottler.h" +#include "CommonFramework/Inference/VisualInferenceSession.h" +#include "CommonFramework/OCR/Filtering.h" +#include "PokemonSwSh/ShinyHuntTracker.h" +#include "PokemonSwSh/Inference/PokemonSwSh_MarkFinder.h" +#include "PokemonSwSh/Inference/PokemonSwSh_StartBattleDetector.h" +#include "PokemonSwSh/Inference/PokemonSwSh_BattleMenuDetector.h" +#include "PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_ShinyEncounterDetector.h" +#include "PokemonSwSh/Programs/PokemonSwSh_StartGame.h" +#include "PokemonSwSh_OverworldMovement.h" +#include "PokemonSwSh_OverworldTargetTracker.h" +#include "PokemonSwSh_OverworldTrajectory.h" +#include "PokemonSwSh_OverworldTrigger.h" +#include "PokemonSwSh_ShinyHuntAutonomous-Overworld.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +ShinyHuntAutonomousOverworld_Descriptor::ShinyHuntAutonomousOverworld_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:ShinyHuntAutonomousOverworld", + "Shiny Hunt Autonomous - Overworld", + "SerialPrograms/ShinyHuntAutonomous-Overworld.md", + "Automatically shiny hunt overworld " + STRING_POKEMON + " with video feedback.", + FeedbackType::REQUIRED, + PABotBaseLevel::PABOTBASE_12KB + ) +{} + + + +ShinyHuntAutonomousOverworld::ShinyHuntAutonomousOverworld(const ShinyHuntAutonomousOverworld_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) + , GO_HOME_WHEN_DONE( + "Go Home when Done:
After finding a shiny, go to the Switch Home menu to idle. (turn this off for unattended streaming)", + false + ) + , LANGUAGE( + "Game Language:
Attempt to read and log the encountered " + STRING_POKEMON + " in this language.
Set to \"None\" to disable this feature.", + m_name_reader.languages(), false + ) + , MARK_OFFSET( + "Mark Offset:
Aim this far below the bottom of the exclamation/question mark. 1.0 is the height of the mark. " + "Increase this value when the " + STRING_POKEMON + " are large.", + 0.5, 0, 20 + ) + , MARK_PRIORITY( + "Mark Priority:
Favor exclamation marks or question marks?", + MARK_PRIORITY_STRINGS, 1 + ) + , TRIGGER_METHOD( + "Trigger Method:
How to trigger an overworld reaction mark?", + { + "Whistle Only", + "Whistle 3 times, then circle once.", + "Circle 3 times, then whistle 3 times.", + "Circle Only", + "Horizontal Line Only", + "Whistle 3 times, then do horizontal line once.", + "Do horizontal line 3 times, then whistle 3 times.", + "Vertical Line Only", + "Whistle 3 times, then do vertical line once.", + "Do vertical line 3 times, then whistle 3 times.", + }, 1 + ) + , MAX_MOVE_DURATION( + "Maximum Move Duration:
Do not move in the same direction for more than this long." + " If you set this too high, you may wander too far from the grassy area.", + "200" + ) + , WATCHDOG_TIMER( + "Watchdog Timer:
Reset the game if you go this long without any encounters.", + "60 * TICKS_PER_SECOND" + ) + , TIME_ROLLBACK_HOURS( + "Time Rollback (in hours):
Periodically roll back the time to keep the weather the same. If set to zero, this feature is disabled.", + 1, 0, 11 + ) + , m_advanced_options( + "Advanced Options: You should not need to touch anything below here." + ) + , EXIT_BATTLE_TIMEOUT( + "Exit Battle Timeout:
After running, wait this long to return to overworld.", + "10 * TICKS_PER_SECOND" + ) + , TARGET_CIRCLING( + "Target Circling:
After moving towards a " + STRING_POKEMON + ", make a circle." + " This increases the chance of encountering the " + STRING_POKEMON + " if it has moved or if the trajectory missed.", + true + ) + , MAX_TARGET_ALPHA( + "Max Target Alpha:
Ignore all targets with alpha larger than this.", + 70000, 0 + ) + , VIDEO_ON_SHINY( + "Video Capture:
Take a video of the encounter if it is shiny.", + true + ) + , RUN_FROM_EVERYTHING( + "Run from Everything:
Run from everything - even if it is shiny. (For testing only.)", + false + ) +{ + m_options.emplace_back(&GO_HOME_WHEN_DONE, "GO_HOME_WHEN_DONE"); + m_options.emplace_back(&LANGUAGE, "LANGUAGE"); + m_options.emplace_back(&MARK_OFFSET, "MARK_OFFSET"); + m_options.emplace_back(&MARK_PRIORITY, "MARK_PRIORITY"); + m_options.emplace_back(&TRIGGER_METHOD, "TRIGGER_METHOD"); + m_options.emplace_back(&MAX_MOVE_DURATION, "MAX_MOVE_DURATION"); + m_options.emplace_back(&WATCHDOG_TIMER, "WATCHDOG_TIMER"); + m_options.emplace_back(&TIME_ROLLBACK_HOURS, "TIME_ROLLBACK_HOURS"); + m_options.emplace_back(&m_advanced_options, ""); + m_options.emplace_back(&EXIT_BATTLE_TIMEOUT, "EXIT_BATTLE_TIMEOUT"); + m_options.emplace_back(&TARGET_CIRCLING, "ENABLE_CIRCLING"); + m_options.emplace_back(&MAX_TARGET_ALPHA, "MAX_TARGET_ALPHA"); + if (PERSISTENT_SETTINGS().developer_mode){ + m_options.emplace_back(&VIDEO_ON_SHINY, "VIDEO_ON_SHINY"); + m_options.emplace_back(&RUN_FROM_EVERYTHING, "RUN_FROM_EVERYTHING"); + } +} + + + +struct ShinyHuntAutonomousOverworld::Stats : public ShinyHuntTracker{ + Stats() + : ShinyHuntTracker(true) + , m_errors(m_stats["Errors"]) + , m_resets(m_stats["Resets"]) + { + m_display_order.insert(m_display_order.begin() + 1, Stat("Errors")); + m_display_order.insert(m_display_order.begin() + 2, Stat("Resets")); + m_aliases["Timeouts"] = "Errors"; + m_aliases["Unexpected Battles"] = "Errors"; + } + uint64_t& m_errors; + uint64_t& m_resets; +}; +std::unique_ptr ShinyHuntAutonomousOverworld::make_stats() const{ + return std::unique_ptr(new Stats()); +} + + + +bool ShinyHuntAutonomousOverworld::find_encounter( + SingleSwitchProgramEnvironment& env, + Stats& stats, + StandardEncounterTracker& tracker, + std::chrono::system_clock::time_point expiration +) const{ + InferenceBoxScope self( + env.console, Qt::cyan, + OverworldTargetTracker::OVERWORLD_CENTER_X - 0.02, + OverworldTargetTracker::OVERWORLD_CENTER_Y - 0.05, + 0.04, 0.1 + ); + + std::unique_ptr trigger; + switch ((size_t)TRIGGER_METHOD){ + case 0: + trigger.reset(new OverworldTrigger_Whistle(env)); + break; + case 1: + trigger.reset(new OverworldTrigger_WhistleCircle(env, true, 3, 1)); + break; + case 2: + trigger.reset(new OverworldTrigger_WhistleCircle(env, false, 3, 3)); + break; + case 3: + trigger.reset(new OverworldTrigger_WhistleCircle(env, false, 0, 1)); + break; + case 4: + trigger.reset(new OverworldTrigger_WhistleHorizontal(env, false, 0, 1)); + break; + case 5: + trigger.reset(new OverworldTrigger_WhistleHorizontal(env, true, 3, 1)); + break; + case 6: + trigger.reset(new OverworldTrigger_WhistleHorizontal(env, false, 3, 3)); + break; + case 7: + trigger.reset(new OverworldTrigger_WhistleVertical(env, false, 0, 1)); + break; + case 8: + trigger.reset(new OverworldTrigger_WhistleVertical(env, true, 3, 1)); + break; + case 9: + trigger.reset(new OverworldTrigger_WhistleVertical(env, false, 3, 3)); + break; + } + + InterruptableCommandSession commands(env.console); + + StandardBattleMenuDetector battle_menu_detector(env.console); + battle_menu_detector.register_command_stop(commands); + + StartBattleDetector start_battle_detector(env.console); + start_battle_detector.register_command_stop(commands); + + OverworldTargetTracker target_tracker( + env.logger(), env.console, + std::chrono::milliseconds(1000), + MARK_OFFSET, + (MarkPriority)(size_t)MARK_PRIORITY, + MAX_TARGET_ALPHA + ); + target_tracker.register_command_stop(commands); + + size_t loops = 0; + while (true){ + loops++; + + // Time expired. + if (std::chrono::system_clock::now() > expiration){ + return false; + } + + if (battle_menu_detector.triggered()){ + env.log("Unexpected Battle.", "red"); + stats.m_errors++; + tracker.run_away(false); + return false; + } + if (start_battle_detector.triggered()){ + env.log("Battle started!"); + return true; + } + + std::pair target = target_tracker.best_target(); + + target_tracker.clear_detections(); + AsyncVisualInferenceSession inference(env, env.console); + inference += battle_menu_detector; + inference += start_battle_detector; + inference += target_tracker; + + // No target found. + if (target.first < 0 || target.first > MAX_TARGET_ALPHA){ + if (target.first < 0){ + if (loops > 1){ + env.log("No targets found.", "orange"); +// pbf_press_button(env.console, BUTTON_B, 5, 0); + } + }else{ + env.log( + QString("Target too Weak: ") + + (target.second.mark == OverworldMark::EXCLAMATION_MARK ? "Exclamation" : "Question") + + " at [" + + QString::number(target.second.delta_x) + " , " + + QString::number(-target.second.delta_y) + "], alpha = " + + QString::number(target.first), + "orange" + ); + } + trigger->run(commands, target_tracker); + continue; + } + + + // Target Found + target.second.box.color = Qt::yellow; + InferenceBoxScope target_box(env.console, target.second.box); + env.log( + QString("Best Target: ") + + (target.second.mark == OverworldMark::EXCLAMATION_MARK ? "Exclamation" : "Question") + + " at [" + + QString::number(target.second.delta_x) + " , " + + QString::number(-target.second.delta_y) + "], alpha = " + + QString::number(target.first), + "purple" + ); + + const Trajectory& trajectory = target.second.trajectory; + double angle = std::atan2( + (double)trajectory.joystick_y - 128, + (double)trajectory.joystick_x - 128 + ) * 57.295779513082320877; + env.log( + "Trajectory: Distance = " + QString::number(trajectory.distance_in_ticks) + + ", Direction = " + QString::number(-angle) + " degrees" + ); + + int duration = trajectory.distance_in_ticks + 16; + if (duration > (int)MAX_MOVE_DURATION){ + duration = MAX_MOVE_DURATION; + } + + commands.run([=](const BotBaseContext& context){ + // Move to target. + pbf_move_left_joystick( + context, + trajectory.joystick_x, + trajectory.joystick_y, + (uint16_t)duration, 0 + ); + + // Circle Maneuver + if (TARGET_CIRCLING){ + if ( + trajectory.joystick_y < 64 && + 64 <= trajectory.joystick_x && trajectory.joystick_x <= 192 + ){ + move_in_circle_up(context, trajectory.joystick_x > 128); + }else{ + move_in_circle_down(context, trajectory.joystick_x <= 128); + } + } + context.botbase().wait_for_all_requests(); + }); + + + } +} + +void ShinyHuntAutonomousOverworld::program(SingleSwitchProgramEnvironment& env){ + srand(time(nullptr)); + + grip_menu_connect_go_home(env.console); + resume_game_back_out(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST, 200); + pbf_move_right_joystick(env.console, 128, 255, TICKS_PER_SECOND, 0); + + const std::chrono::milliseconds TIMEOUT((uint64_t)WATCHDOG_TIMER * 1000 / TICKS_PER_SECOND); + const uint32_t PERIOD = (uint32_t)TIME_ROLLBACK_HOURS * 3600 * TICKS_PER_SECOND; + uint32_t last_touch = system_clock(env.console); + + Stats& stats = env.stats(); + StandardEncounterTracker tracker( + stats, env, env.console, + &m_name_reader, LANGUAGE, + false, + EXIT_BATTLE_TIMEOUT, + VIDEO_ON_SHINY, + RUN_FROM_EVERYTHING + ); + + // Encounter Loop +// size_t consecutive_failures = 0; + auto last = std::chrono::system_clock::now(); + while (true){ + env.update_stats(); + + // Touch the date. + if (TIME_ROLLBACK_HOURS > 0 && system_clock(env.console) - last_touch >= PERIOD){ + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + rollback_hours_from_home(env.console, TIME_ROLLBACK_HOURS, SETTINGS_TO_HOME_DELAY); + resume_game_no_interact(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST); + last_touch += PERIOD; + } + +// cout << "TOLERATE_SYSTEM_UPDATE_MENU_FAST = " << TOLERATE_SYSTEM_UPDATE_MENU_FAST << endl; + + auto now = std::chrono::system_clock::now(); + if (now - last > TIMEOUT){ + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + reset_game_from_home_with_inference( + env, env.console, + TOLERATE_SYSTEM_UPDATE_MENU_FAST + ); + stats.m_resets++; + last = std::chrono::system_clock::now(); + continue; + } + + env.console.botbase().wait_for_all_requests(); + + bool battle = find_encounter(env, stats, tracker, last + TIMEOUT); + if (!battle){ + continue; + } + + // Detect shiny. + ShinyDetection detection = detect_shiny_battle( + env, env.console, + SHINY_BATTLE_REGULAR, + std::chrono::seconds(30) + ); + + if (tracker.process_result(detection)){ + break; + } + if (detection == ShinyDetection::NO_BATTLE_MENU){ + stats.m_errors++; + pbf_mash_button(env.console, BUTTON_B, TICKS_PER_SECOND); + tracker.run_away(false); + }else{ + last = std::chrono::system_clock::now(); + } + } + + env.update_stats(); + + if (GO_HOME_WHEN_DONE){ + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + } + + end_program_callback(env.console); + end_program_loop(env.console); +} + + + +} +} +} + diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Overworld.h b/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_ShinyHuntAutonomous-Overworld.h similarity index 52% rename from SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Overworld.h rename to SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_ShinyHuntAutonomous-Overworld.h index c4e70744a6..40230fc39a 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Overworld.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/OverworldBot/PokemonSwSh_ShinyHuntAutonomous-Overworld.h @@ -10,60 +10,61 @@ #include "CommonFramework/Options/SectionDivider.h" #include "CommonFramework/Options/BooleanCheckBox.h" #include "CommonFramework/Options/SimpleInteger.h" +#include "CommonFramework/Options/FloatingPoint.h" +#include "CommonFramework/Options/EnumDropdown.h" +#include "CommonFramework/Options/LanguageOCR.h" +#include "Pokemon/Pokemon_NameReader.h" #include "NintendoSwitch/Options/TimeExpression.h" #include "NintendoSwitch/Framework/SingleSwitchProgram.h" -#include "PokemonSwSh_EncounterTracker.h" +#include "PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_EncounterTracker.h" namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class ShinyHuntAutonomousOverworld : public SingleSwitchProgram{ + +class ShinyHuntAutonomousOverworld_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + ShinyHuntAutonomousOverworld_Descriptor(); +}; + + + +class ShinyHuntAutonomousOverworld : public SingleSwitchProgramInstance{ public: - ShinyHuntAutonomousOverworld(); + ShinyHuntAutonomousOverworld(const ShinyHuntAutonomousOverworld_Descriptor& descriptor); virtual std::unique_ptr make_stats() const override; - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: struct Stats; - void move_in_circle( - SingleSwitchProgramEnvironment& env, - uint8_t size_ticks, - uint8_t current_direction_x, - uint8_t current_direction_y - ) const; - - enum WatchResult{ - TIMEOUT, - BATTLE_START, - BATTLE_MENU, - }; - WatchResult whistle_and_watch( - SingleSwitchProgramEnvironment& env, - std::vector& exclamations, - std::vector& questions - ) const; - bool find_encounter( SingleSwitchProgramEnvironment& env, Stats& stats, - StandardEncounterTracker& tracker + StandardEncounterTracker& tracker, + std::chrono::system_clock::time_point expiration ) const; private: BooleanCheckBox GO_HOME_WHEN_DONE; - BooleanCheckBox PRIORITIZE_EXCLAMATION_POINTS; - BooleanCheckBox TARGET_CIRCLING; - SimpleInteger LOCAL_CIRCLING; + + Pokemon::PokemonNameReader m_name_reader; + LanguageOCR LANGUAGE; + + FloatingPoint MARK_OFFSET; + EnumDropdown MARK_PRIORITY; + EnumDropdown TRIGGER_METHOD; TimeExpression MAX_MOVE_DURATION; TimeExpression WATCHDOG_TIMER; SimpleInteger TIME_ROLLBACK_HOURS; SectionDivider m_advanced_options; - TimeExpression EXIT_BATTLE_MASH_TIME; + TimeExpression EXIT_BATTLE_TIMEOUT; + BooleanCheckBox TARGET_CIRCLING; + FloatingPoint MAX_TARGET_ALPHA; BooleanCheckBox VIDEO_ON_SHINY; BooleanCheckBox RUN_FROM_EVERYTHING; }; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_RaidItemFarmerOKHO.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_RaidItemFarmerOKHO.cpp index ea54c6c291..e48da3b337 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_RaidItemFarmerOKHO.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_RaidItemFarmerOKHO.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "PokemonSwSh/Programs/Hosting/PokemonSwSh_DenTools.h" #include "PokemonSwSh_RaidItemFarmerOKHO.h" @@ -14,14 +14,22 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ -RaidItemFarmerOHKO::RaidItemFarmerOHKO() - : MultiSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, +RaidItemFarmerOHKO_Descriptor::RaidItemFarmerOHKO_Descriptor() + : MultiSwitchProgramDescriptor( + "PokemonSwSh:RaidItemFarmerOHKO", "Raid Item Farmer (OHKO)", "SerialPrograms/RaidItemFarmerOHKO.md", "Farm items from raids that can be OHKO'ed. (requires multiple Switches)", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB, 2, 4, 2 ) +{} + + + +RaidItemFarmerOHKO::RaidItemFarmerOHKO(const RaidItemFarmerOHKO_Descriptor& descriptor) + : MultiSwitchProgramInstance(descriptor) , BACKUP_SAVE("Load Backup Save:
For backup save soft-locking method.", false) // , m_advanced_options( // "Advanced Options: You should not need to touch anything below here." @@ -68,7 +76,7 @@ RaidItemFarmerOHKO::RaidItemFarmerOHKO() m_options.emplace_back(&TOUCH_DATE_INTERVAL, "TOUCH_DATE_INTERVAL"); } -void RaidItemFarmerOHKO::program(MultiSwitchProgramEnvironment& env) const{ +void RaidItemFarmerOHKO::program(MultiSwitchProgramEnvironment& env){ BotBase& host = env.consoles[0]; size_t switches = env.consoles.size(); diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_RaidItemFarmerOKHO.h b/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_RaidItemFarmerOKHO.h index 3ad05f41d9..aa2712a3d4 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_RaidItemFarmerOKHO.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_RaidItemFarmerOKHO.h @@ -16,11 +16,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class RaidItemFarmerOHKO : public MultiSwitchProgram{ + +class RaidItemFarmerOHKO_Descriptor : public MultiSwitchProgramDescriptor{ +public: + RaidItemFarmerOHKO_Descriptor(); +}; + + + +class RaidItemFarmerOHKO : public MultiSwitchProgramInstance{ public: - RaidItemFarmerOHKO(); + RaidItemFarmerOHKO(const RaidItemFarmerOHKO_Descriptor& descriptor); - virtual void program(MultiSwitchProgramEnvironment& env) const override; + virtual void program(MultiSwitchProgramEnvironment& env) override; private: BooleanCheckBox BACKUP_SAVE; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_StartGame.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_StartGame.cpp index d3f464fd61..bff5d97b1b 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_StartGame.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_StartGame.cpp @@ -61,7 +61,7 @@ void enter_loading_game( } env.log("enter_loading_game(): Game Loaded. Entering game...", "purple"); - enter_game(backup_save, ENTER_GAME_MASH, 0); + enter_game(console, backup_save, ENTER_GAME_MASH, 0); console.botbase().wait_for_all_requests(); // Wait to enter game. @@ -101,7 +101,7 @@ void enter_loading_game( env.log("start_game_with_inference(): Game started.", "purple"); if (post_wait_time != 0){ - pbf_wait(post_wait_time); + pbf_wait(console, post_wait_time); } } @@ -114,6 +114,10 @@ void start_game_from_home_with_inference( bool backup_save, uint16_t post_wait_time ){ +// cout << "tolerate_update_menu = " << tolerate_update_menu << endl; +// cout << "TOLERATE_SYSTEM_UPDATE_MENU_FAST = " << TOLERATE_SYSTEM_UPDATE_MENU_FAST << endl; +// cout << "TOLERATE_SYSTEM_UPDATE_MENU_FAST = " << &TOLERATE_SYSTEM_UPDATE_MENU_FAST << endl; + if (game_slot != 0){ pbf_press_button(console, BUTTON_HOME, 10, SETTINGS_TO_HOME_DELAY - 10); for (uint8_t c = 1; c < game_slot; c++){ @@ -128,6 +132,7 @@ void start_game_from_home_with_inference( pbf_press_dpad(console, DPAD_UP, 5, 0); // Skip the update window. } +// cout << "START_GAME_REQUIRES_INTERNET = " << START_GAME_REQUIRES_INTERNET << endl; if (!START_GAME_REQUIRES_INTERNET && user_slot == 0){ // Mash your way into the game. pbf_mash_button(console, BUTTON_A, START_GAME_MASH); @@ -167,7 +172,7 @@ void reset_game_from_home_with_inference( uint16_t post_wait_time ){ if (START_GAME_REQUIRES_INTERNET || tolerate_update_menu){ - close_game(); + close_game(console); start_game_from_home_with_inference( env, console, tolerate_update_menu, 0, 0, false, post_wait_time ); diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_StatsReset.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_StatsReset.cpp new file mode 100644 index 0000000000..de81a43393 --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_StatsReset.cpp @@ -0,0 +1,190 @@ +/* Stats Reset + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "Common/SwitchFramework/FrameworkSettings.h" +#include "Common/SwitchFramework/Switch_PushButtons.h" +#include "Common/PokemonSwSh/PokemonSettings.h" +#include "Common/PokemonSwSh/PokemonSwShGameEntry.h" +#include "CommonFramework/Tools/InterruptableCommands.h" +#include "CommonFramework/Tools/StatsTracking.h" +#include "CommonFramework/Inference/BlackScreenDetector.h" +#include "CommonFramework/Inference/VisualInferenceSession.h" +#include "NintendoSwitch/FixedInterval.h" +//#include "PokemonSwSh/Inference/PokemonSwSh_ReceivePokemonDetector.h" +#include "PokemonSwSh/Programs/PokemonSwSh_StartGame.h" +#include "PokemonSwSh_StatsReset.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +StatsReset_Descriptor::StatsReset_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:StatsReset", + "Stats Reset", + "SerialPrograms/StatsReset.md", + "Repeatedly receive gift " + STRING_POKEMON + " until you get the stats you want.", + FeedbackType::REQUIRED, + PABotBaseLevel::PABOTBASE_12KB + ) +{} + + + +StatsReset::StatsReset(const StatsReset_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) + , GO_HOME_WHEN_DONE( + "Go Home when Done:
After finding a match, go to the Switch Home menu to idle. (turn this off for unattended streaming)", + false + ) + , LANGUAGE( + "Game Language:", + m_iv_checker_reader.languages() + ) + , POKEMON( + "Gift " + STRING_POKEMON + ":", + { + "Type: Null", + "Cosmog", + "Poipole", + }, + 0 + ) + , HP("HP:") + , ATTACK("Attack:", 1) + , DEFENSE("Defense:") + , SPATK("Sp. Atk:") + , SPDEF("Sp. Def:") + , SPEED("Speed:") +{ + m_options.emplace_back(&GO_HOME_WHEN_DONE, "GO_HOME_WHEN_DONE"); + m_options.emplace_back(&LANGUAGE, "LANGUAGE"); + m_options.emplace_back(&POKEMON, "POKEMON"); + m_options.emplace_back(&HP, "HP"); + m_options.emplace_back(&ATTACK, "ATTACK"); + m_options.emplace_back(&DEFENSE, "DEFENSE"); + m_options.emplace_back(&SPATK, "SPATK"); + m_options.emplace_back(&SPDEF, "SPDEF"); + m_options.emplace_back(&SPEED, "SPEED"); +} + + + +struct StatsReset::Stats : public StatsTracker{ + Stats() + : attempts(m_stats["Attempts"]) + , errors(m_stats["Errors"]) + , matches(m_stats["Matches"]) + { + m_display_order.emplace_back(Stat("Attempts")); + m_display_order.emplace_back(Stat("Errors")); + m_display_order.emplace_back(Stat("Matches")); + } + + uint64_t& attempts; + uint64_t& errors; + uint64_t& matches; +}; +std::unique_ptr StatsReset::make_stats() const{ + return std::unique_ptr(new Stats()); +} + + + +void StatsReset::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + resume_game_back_out(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST, 200); + + Stats& stats = env.stats(); + + while (true){ + env.update_stats(); + + env.console.botbase().wait_for_all_requests(); + { + InterruptableCommandSession commands(env.console); + + BlackScreenDetector detector(env.console); + detector.register_command_stop(commands); + +// ReceivePokemonDetector detector(env.console); +// detector.register_command_stop(commands); + + AsyncVisualInferenceSession inference(env, env.console); + inference += detector; + + commands.run([=](const BotBaseContext& context){ + + if (POKEMON == 2){ + pbf_mash_button(context, BUTTON_A, 10 * TICKS_PER_SECOND); + }else{ + pbf_mash_button(context, BUTTON_A, 5 * TICKS_PER_SECOND); + } + + pbf_mash_button(context, BUTTON_B, 20 * TICKS_PER_SECOND); + context->wait_for_all_requests(); + }); + + if (detector.triggered()){ + env.log(STRING_POKEMON + " receive menu detected.", "purple"); + }else{ + env.log(STRING_POKEMON + " receive menu timed out.", Qt::red); + } + } + stats.attempts++; + + pbf_mash_button(env.console, BUTTON_B, 1 * TICKS_PER_SECOND); + + pbf_press_button(env.console, BUTTON_X, 10, OVERWORLD_TO_MENU_DELAY); + ssf_press_dpad2(env.console, DPAD_RIGHT, BOX_SCROLL_DELAY, 10); + ssf_press_button2(env.console, BUTTON_A, MENU_TO_POKEMON_DELAY, 10); + ssf_press_button2(env.console, BUTTON_R, POKEMON_TO_BOX_DELAY, 10); + env.console.botbase().wait_for_all_requests(); + + { + IVCheckerReaderScope reader(m_iv_checker_reader, env.console, LANGUAGE); + IVCheckerReader::Results results = reader.read(&env.logger(), env.console.video().snapshot()); + bool ok = true; + ok &= HP.matches(stats.errors, results.hp); + ok &= ATTACK.matches(stats.errors, results.attack); + ok &= DEFENSE.matches(stats.errors, results.defense); + ok &= SPATK.matches(stats.errors, results.spatk); + ok &= SPDEF.matches(stats.errors, results.spdef); + ok &= SPEED.matches(stats.errors, results.speed); + if (ok){ + break; + } + } + + // Add a little extra wait time since correctness matters here. + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + + reset_game_from_home_with_inference( + env, env.console, + TOLERATE_SYSTEM_UPDATE_MENU_SLOW + ); + } + + stats.matches++; + env.update_stats(); + env.log("Result Found!", Qt::blue); + + pbf_wait(env.console, 5 * TICKS_PER_SECOND); + pbf_press_button(env.console, BUTTON_CAPTURE, 2 * TICKS_PER_SECOND, 5 * TICKS_PER_SECOND); + + if (GO_HOME_WHEN_DONE){ + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + } + + end_program_callback(env.console); + end_program_loop(env.console); +} + + +} +} +} diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_StatsReset.h b/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_StatsReset.h new file mode 100644 index 0000000000..3b8913b389 --- /dev/null +++ b/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_StatsReset.h @@ -0,0 +1,91 @@ +/* Stats Reset + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PokemonSwSh_StatsReset_H +#define PokemonAutomation_PokemonSwSh_StatsReset_H + +#include "CommonFramework/Options/BooleanCheckBox.h" +#include "CommonFramework/Options/EnumDropdown.h" +#include "CommonFramework/Options/LanguageOCR.h" +#include "PokemonSwSh/Inference/PokemonSwSh_IVCheckerReader.h" +#include "NintendoSwitch/Framework/SingleSwitchProgram.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSwSh{ + + +class IVCheckerOption : public EnumDropdown{ +public: + IVCheckerOption(QString label, size_t default_index = 0) + : EnumDropdown( + std::move(label), + { + "Don't Care (0-31)", + "No Good (0)", + "Decent (0-15)", + "Pretty Good (16-25)", + "Very Good (26-29)", + "Fantastic (30)", + "Best (31)", + }, + default_index + ) + {} + + bool matches(uint64_t& errors, IVCheckerReader::Result result) const{ + if (result == IVCheckerReader::Result::UnableToDetect){ + errors++; + } + size_t desired = (size_t)*this; + if (desired == 0){ + return true; + } + if (desired == (size_t)result){ + return true; + } + return false; + } +}; + + + +class StatsReset_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + StatsReset_Descriptor(); +}; + + + +class StatsReset : public SingleSwitchProgramInstance{ +public: + StatsReset(const StatsReset_Descriptor& descriptor); + + virtual std::unique_ptr make_stats() const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; + +private: + struct Stats; + +private: + IVCheckerReader m_iv_checker_reader; + + BooleanCheckBox GO_HOME_WHEN_DONE; + LanguageOCR LANGUAGE; + EnumDropdown POKEMON; + IVCheckerOption HP; + IVCheckerOption ATTACK; + IVCheckerOption DEFENSE; + IVCheckerOption SPATK; + IVCheckerOption SPDEF; + IVCheckerOption SPEED; +}; + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_SynchronizedSpinning.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_SynchronizedSpinning.cpp index aea5eb08ce..8280ef8afb 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_SynchronizedSpinning.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_SynchronizedSpinning.cpp @@ -12,16 +12,24 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ -SynchronizedSpinning::SynchronizedSpinning() - : MultiSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, +SynchronizedSpinning_Descriptor::SynchronizedSpinning_Descriptor() + : MultiSwitchProgramDescriptor( + "PokemonSwSh:SynchronizedSpinning", "Synchronized Spinning", "", "Don't ask... seriously, don't ask...", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB, 1, 4, 1 ) {} -void SynchronizedSpinning::program(MultiSwitchProgramEnvironment& env) const{ + + +SynchronizedSpinning::SynchronizedSpinning(const SynchronizedSpinning_Descriptor& description) + : MultiSwitchProgramInstance(description) +{} + +void SynchronizedSpinning::program(MultiSwitchProgramEnvironment& env){ env.run_in_parallel( [&](ConsoleHandle& console){ pbf_move_left_joystick(console, 128, 255, 5, 20); diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_SynchronizedSpinning.h b/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_SynchronizedSpinning.h index 466bccad6c..ab2082249f 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_SynchronizedSpinning.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/PokemonSwSh_SynchronizedSpinning.h @@ -13,11 +13,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class SynchronizedSpinning : public MultiSwitchProgram{ + +class SynchronizedSpinning_Descriptor : public MultiSwitchProgramDescriptor{ +public: + SynchronizedSpinning_Descriptor(); +}; + + + +class SynchronizedSpinning : public MultiSwitchProgramInstance{ public: - SynchronizedSpinning(); + SynchronizedSpinning(const SynchronizedSpinning_Descriptor& description); - virtual void program(MultiSwitchProgramEnvironment& env) const override; + virtual void program(MultiSwitchProgramEnvironment& env) override; }; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FastCodeEntry.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FastCodeEntry.cpp index 6568613f3a..3ce11f0d96 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FastCodeEntry.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FastCodeEntry.cpp @@ -13,13 +13,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -FastCodeEntry::FastCodeEntry() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, + +FastCodeEntry_Descriptor::FastCodeEntry_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:FastCodeEntry", "Fast Code Entry (FCE)", "NativePrograms/FastCodeEntry.md", - "Force your way into raids by entering 8-digit codes in under 1 second." + "Force your way into raids by entering 8-digit codes in under 1 second.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +FastCodeEntry::FastCodeEntry(const FastCodeEntry_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , RAID_CODE( "Raid Code:", 8, @@ -34,22 +43,23 @@ FastCodeEntry::FastCodeEntry() m_options.emplace_back(&INITIAL_DELAY, "INITIAL_DELAY"); } -void FastCodeEntry::program(SingleSwitchProgramEnvironment& env) const{ +void FastCodeEntry::program(SingleSwitchProgramEnvironment& env){ uint8_t code[8]; RAID_CODE.to_str(code); if (INITIAL_DELAY != 0){ - start_program_flash(INITIAL_DELAY); + start_program_flash(env.console, INITIAL_DELAY); } - pbf_press_button(BUTTON_PLUS, 5, 5); - pbf_press_button(BUTTON_PLUS, 5, 5); - enter_digits(8, code); + pbf_press_button(env.console, BUTTON_PLUS, 5, 5); + pbf_press_button(env.console, BUTTON_PLUS, 5, 5); + enter_digits(env.console, 8, code); - end_program_callback(); + end_program_callback(env.console); } + } } } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FastCodeEntry.h b/SerialPrograms/Source/PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FastCodeEntry.h index 8bb1233418..5ec421ee71 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FastCodeEntry.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FastCodeEntry.h @@ -15,11 +15,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class FastCodeEntry : public SingleSwitchProgram{ + +class FastCodeEntry_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + FastCodeEntry_Descriptor(); +}; + + + +class FastCodeEntry : public SingleSwitchProgramInstance{ public: - FastCodeEntry(); + FastCodeEntry(const FastCodeEntry_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: FixedCode RAID_CODE; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FriendSearchDisconnect.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FriendSearchDisconnect.cpp index 91f7e7849e..76df330a3b 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FriendSearchDisconnect.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FriendSearchDisconnect.cpp @@ -15,13 +15,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -FriendSearchDisconnect::FriendSearchDisconnect() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, + +FriendSearchDisconnect_Descriptor::FriendSearchDisconnect_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:FriendSearchDisconnect", "Friend Search Disconnect", "SerialPrograms/FriendSearchDisconnect.md", - "Disconnect from the internet using the friend search method." + "Disconnect from the internet using the friend search method.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +FriendSearchDisconnect::FriendSearchDisconnect(const FriendSearchDisconnect_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , USER_SLOT( "User Slot:
Use this profile to disconnect.", 1, 1, 8 @@ -30,14 +39,14 @@ FriendSearchDisconnect::FriendSearchDisconnect() m_options.emplace_back(&USER_SLOT, "USER_SLOT"); } -void FriendSearchDisconnect::program(SingleSwitchProgramEnvironment& env) const{ - ssf_press_button2(BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); +void FriendSearchDisconnect::program(SingleSwitchProgramEnvironment& env) { + ssf_press_button2(env.console, BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); - home_to_add_friends(USER_SLOT - 1, 1, true); + home_to_add_friends(env.console, USER_SLOT - 1, 1, true); // Enter friend search. - pbf_mash_button(BUTTON_A, 100); - settings_to_enter_game(true); + pbf_mash_button(env.console, BUTTON_A, 100); + settings_to_enter_game(env.console, true); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FriendSearchDisconnect.h b/SerialPrograms/Source/PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FriendSearchDisconnect.h index 3a4cebd10e..fc45d049f7 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FriendSearchDisconnect.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/QoLMacros/PokemonSwSh_FriendSearchDisconnect.h @@ -14,11 +14,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class FriendSearchDisconnect : public SingleSwitchProgram{ + +class FriendSearchDisconnect_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + FriendSearchDisconnect_Descriptor(); +}; + + + +class FriendSearchDisconnect : public SingleSwitchProgramInstance{ public: - FriendSearchDisconnect(); + FriendSearchDisconnect(const FriendSearchDisconnect_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger USER_SLOT; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ReleaseHelpers.h b/SerialPrograms/Source/PokemonSwSh/Programs/ReleaseHelpers.h index 8eda8472ff..c07b746e31 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ReleaseHelpers.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ReleaseHelpers.h @@ -15,44 +15,49 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -static void release(void){ - ssf_press_button2(BUTTON_A, 60, 10); - ssf_press_dpad1(DPAD_UP, 15); - ssf_press_dpad1(DPAD_UP, 15); - ssf_press_button2(BUTTON_A, 125, 10); - ssf_press_dpad1(DPAD_DOWN, 10); -// ssf_press_button1(BUTTON_A, 150); -// ssf_press_button1(BUTTON_A, 40); - mash_A(180); +static void release(const BotBaseContext& context){ + ssf_press_button2(context, BUTTON_A, 60, 10); + ssf_press_dpad1(context, DPAD_UP, 15); + ssf_press_dpad1(context, DPAD_UP, 15); + ssf_press_button2(context, BUTTON_A, 125, 10); + ssf_press_dpad1(context, DPAD_DOWN, 10); +// ssf_press_button1(context, BUTTON_A, 150); +// ssf_press_button1(context, BUTTON_A, 40); + mash_A(context, 180); } -static void release_box(uint16_t box_scroll_delay){ +static void release_box(const BotBaseContext& context, uint16_t box_scroll_delay){ for (uint8_t row = 0; row < 5; row++){ if (row != 0){ - ssf_press_dpad1(DPAD_DOWN, box_scroll_delay); - ssf_press_dpad1(DPAD_RIGHT, box_scroll_delay); - ssf_press_dpad1(DPAD_RIGHT, box_scroll_delay); + ssf_press_dpad1(context, DPAD_DOWN, box_scroll_delay); + ssf_press_dpad1(context, DPAD_RIGHT, box_scroll_delay); + ssf_press_dpad1(context, DPAD_RIGHT, box_scroll_delay); } for (uint8_t col = 0; col < 6; col++){ if (col != 0){ - ssf_press_dpad1(DPAD_RIGHT, box_scroll_delay); + ssf_press_dpad1(context, DPAD_RIGHT, box_scroll_delay); } - release(); + release(context); } } } -static void release_boxes(uint8_t boxes, uint16_t box_scroll_delay, uint16_t box_change_delay){ +static void release_boxes( + const BotBaseContext& context, + uint8_t boxes, + uint16_t box_scroll_delay, + uint16_t box_change_delay +){ if (boxes == 0){ return; } - release_box(box_scroll_delay); + release_box(context, box_scroll_delay); for (uint8_t box = 1; box < boxes; box++){ - ssf_press_dpad1(DPAD_DOWN, box_scroll_delay); - ssf_press_dpad1(DPAD_DOWN, box_scroll_delay); - ssf_press_dpad1(DPAD_DOWN, box_scroll_delay); - ssf_press_dpad1(DPAD_RIGHT, box_scroll_delay); - ssf_press_dpad1(DPAD_RIGHT, box_scroll_delay); - ssf_press_button1(BUTTON_R, box_change_delay); - release_box(box_scroll_delay); + ssf_press_dpad1(context, DPAD_DOWN, box_scroll_delay); + ssf_press_dpad1(context, DPAD_DOWN, box_scroll_delay); + ssf_press_dpad1(context, DPAD_DOWN, box_scroll_delay); + ssf_press_dpad1(context, DPAD_RIGHT, box_scroll_delay); + ssf_press_dpad1(context, DPAD_RIGHT, box_scroll_delay); + ssf_press_button1(context, BUTTON_R, box_change_delay); + release_box(context, box_scroll_delay); } } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_EncounterTracker.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_EncounterTracker.cpp index 0309e05305..04c835b13a 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_EncounterTracker.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_EncounterTracker.cpp @@ -5,6 +5,12 @@ */ #include "Common/SwitchFramework/Switch_PushButtons.h" +#include "CommonFramework/Globals.h" +#include "CommonFramework/Tools/InterruptableCommands.h" +#include "CommonFramework/Inference/ImageTools.h" +#include "CommonFramework/Inference/VisualInferenceSession.h" +#include "CommonFramework/Inference/BlackScreenDetector.h" +#include "CommonFramework/Inference/VisualInferenceSession.h" #include "PokemonSwSh_EncounterTracker.h" namespace PokemonAutomation{ @@ -12,35 +18,92 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ + + StandardEncounterTracker::StandardEncounterTracker( ShinyHuntTracker& stats, + ProgramEnvironment& env, ConsoleHandle& console, + Pokemon::PokemonNameReader* name_reader, Language language, bool require_square, uint16_t exit_battle_time, bool take_video, bool run_from_everything ) - : m_stats(stats) + : m_shiny_stats_tracker(stats) + , m_env(env) , m_console(console) + , m_name_reader(name_reader) + , m_language(language) , m_require_square(require_square) , m_exit_battle_time(exit_battle_time) , m_take_video(take_video) , m_run_from_everything(run_from_everything) {} -bool StandardEncounterTracker::run_away(){ - pbf_press_dpad(DPAD_UP, 10, 10); - pbf_press_button(BUTTON_A, 10, 10); - pbf_mash_button(BUTTON_B, m_exit_battle_time); +bool StandardEncounterTracker::run_away(bool confirmed_encounter){ + // Initiate the run-away. + pbf_press_dpad(m_console, DPAD_UP, 10, 40); + pbf_mash_button(m_console, BUTTON_A, 20); + m_console.botbase().wait_for_all_requests(); + + // While we are running away, read the name. We do this in parallel + // to avoid slowing down the program. + if (confirmed_encounter){ + read_name(); + } + + InterruptableCommandSession commands(m_console); + + BlackScreenDetector black_screen_detector(m_console); + black_screen_detector.register_command_stop(commands); + + AsyncVisualInferenceSession inference(m_env, m_console); + inference += black_screen_detector; + + commands.run([=](const BotBaseContext& context){ + pbf_mash_button(context, BUTTON_A, TICKS_PER_SECOND); + if (m_exit_battle_time > TICKS_PER_SECOND){ + pbf_mash_button(context, BUTTON_B, m_exit_battle_time - TICKS_PER_SECOND); + } + context.botbase().wait_for_all_requests(); + }); return true; } void StandardEncounterTracker::take_video(){ if (m_take_video){ - pbf_wait(m_console, 5 * TICKS_PER_SECOND); + pbf_wait(m_console, 1 * TICKS_PER_SECOND); + m_console.botbase().wait_for_all_requests(); + read_name(); + pbf_wait(m_console, 4 * TICKS_PER_SECOND); pbf_press_button(m_console, BUTTON_CAPTURE, 2 * TICKS_PER_SECOND, 5 * TICKS_PER_SECOND); } } +void StandardEncounterTracker::read_name(){ + if (m_name_reader == nullptr || m_language == Language::None){ + return; + } + +// m_env.wait(std::chrono::milliseconds(100)); + + InferenceBoxScope box(m_console, InferenceBox(0.76, 0.04, 0.15, 0.044)); + QImage frame = m_console.video().snapshot(); + frame = extract_box(frame, box); +// OCR::binary_filter_black_text(frame); + + OCR::MatchResult result = m_name_reader->read_exact(m_language, frame); + result.log(&m_env.logger()); + + if (result.matched){ + m_encounter_stats += std::move(result.tokens); + }else{ + m_encounter_stats += std::set(); + } + + m_env.log(m_encounter_stats.dump_sorted_map()); +} + bool StandardEncounterTracker::process_result(ShinyDetection detection){ bool stop = false; @@ -49,23 +112,23 @@ bool StandardEncounterTracker::process_result(ShinyDetection detection){ return false; case ShinyDetection::NOT_SHINY: - m_stats.add_non_shiny(); + m_shiny_stats_tracker.add_non_shiny(); break; case ShinyDetection::STAR_SHINY: - m_stats.add_star_shiny(); + m_shiny_stats_tracker.add_star_shiny(); take_video(); stop = !m_require_square; break; case ShinyDetection::SQUARE_SHINY: - m_stats.add_square_shiny(); + m_shiny_stats_tracker.add_square_shiny(); take_video(); stop = true; break; case ShinyDetection::UNKNOWN_SHINY: - m_stats.add_unknown_shiny(); + m_shiny_stats_tracker.add_unknown_shiny(); take_video(); stop = true; break; @@ -77,7 +140,7 @@ bool StandardEncounterTracker::process_result(ShinyDetection detection){ } if (!stop){ - run_away(); + run_away(true); } return stop; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_EncounterTracker.h b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_EncounterTracker.h index f518c07e3d..c4b7ddb7ec 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_EncounterTracker.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_EncounterTracker.h @@ -7,7 +7,11 @@ #ifndef PokemonAutomation_PokemonSwSh_EncounterTracker_H #define PokemonAutomation_PokemonSwSh_EncounterTracker_H +#include "CommonFramework/Language.h" #include "CommonFramework/Tools/ConsoleHandle.h" +#include "CommonFramework/Tools/ProgramEnvironment.h" +#include "Pokemon/Pokemon_NameReader.h" +#include "Pokemon/Pokemon_EncounterStats.h" #include "PokemonSwSh/ShinyHuntTracker.h" #include "PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_ShinyEncounterDetector.h" @@ -20,27 +24,35 @@ class StandardEncounterTracker{ public: StandardEncounterTracker( ShinyHuntTracker& stats, + ProgramEnvironment& env, ConsoleHandle& console, + Pokemon::PokemonNameReader* name_reader, Language language, bool require_square, uint16_t exit_battle_time, bool take_video, bool run_from_everything ); - virtual bool run_away(); + virtual bool run_away(bool confirmed_encounter); bool process_result(ShinyDetection detection); private: void take_video(); + void read_name(); protected: - ShinyHuntTracker& m_stats; + ShinyHuntTracker& m_shiny_stats_tracker; + ProgramEnvironment& m_env; ConsoleHandle& m_console; + Pokemon::PokemonNameReader* m_name_reader; + Language m_language; bool m_require_square; uint16_t m_exit_battle_time; bool m_take_video; bool m_run_from_everything; + + Pokemon::PokemonEncounterStats m_encounter_stats; }; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_MultiGameFossil.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_MultiGameFossil.cpp index 144be655b8..348477e43d 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_MultiGameFossil.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_MultiGameFossil.cpp @@ -17,18 +17,31 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ -MultiGameFossil::MultiGameFossil() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, +MultiGameFossil_Descriptor::MultiGameFossil_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:MultiGameFossil", "Multi-Game Fossil Revive", "NativePrograms/MultiGameFossil.md", - "Revive fossils. Supports multiple saves so you can go afk for longer than 5 hours." + "Revive fossils. Supports multiple saves so you can go afk for longer than 5 hours.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +MultiGameFossil::MultiGameFossil(const MultiGameFossil_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) { m_options.emplace_back(&GAME_LIST, "GAME_LIST"); } -void run_fossil_batch(const FossilTable::GameSlot* batch, bool* game_slot_flipped, bool save_and_exit){ +void run_fossil_batch( + const BotBaseContext& context, + const FossilTable::GameSlot* batch, + bool* game_slot_flipped, + bool save_and_exit +){ // Sanitize Slots uint8_t game_slot = batch->game_slot; uint8_t user_slot = batch->user_slot; @@ -48,7 +61,13 @@ void run_fossil_batch(const FossilTable::GameSlot* batch, bool* game_slot_flippe break; } - start_game_from_home(TOLERATE_SYSTEM_UPDATE_MENU_FAST, game_slot, user_slot, false); + start_game_from_home( + context, + TOLERATE_SYSTEM_UPDATE_MENU_FAST, + game_slot, + user_slot, + false + ); if (game_slot == 2){ *game_slot_flipped = !*game_slot_flipped; } @@ -57,27 +76,28 @@ void run_fossil_batch(const FossilTable::GameSlot* batch, bool* game_slot_flippe #if 1 for (uint16_t c = 0; c < batch->revives; c++){ #if 1 - mash_A(170); - pbf_wait(65); + mash_A(context, 170); + pbf_wait(context, 65); #else - mash_A(50); - pbf_wait(140); - ssf_press_button1(BUTTON_A, 160); + mash_A(context, 50); + pbf_wait(context, 140); + ssf_press_button1(context, BUTTON_A, 160); #endif if (batch->fossil & 2){ - ssf_press_dpad1(DPAD_DOWN, 5); + ssf_press_dpad1(context, DPAD_DOWN, 5); } - ssf_press_button1(BUTTON_A, 160); + ssf_press_button1(context, BUTTON_A, 160); if (batch->fossil & 1){ - ssf_press_dpad1(DPAD_DOWN, 5); + ssf_press_dpad1(context, DPAD_DOWN, 5); } - mash_A(400); + mash_A(context, 400); pbf_mash_button( + context, BUTTON_B, AUTO_DEPOSIT ? 1400 : 1520 ); } - pbf_wait(100); + pbf_wait(context, 100); #endif if (!save_and_exit){ @@ -86,18 +106,18 @@ void run_fossil_batch(const FossilTable::GameSlot* batch, bool* game_slot_flippe } // Save game. - ssf_press_button2(BUTTON_X, OVERWORLD_TO_MENU_DELAY, 20); - ssf_press_button2(BUTTON_R, 150, 20); - ssf_press_button2(BUTTON_A, 500, 10); + ssf_press_button2(context, BUTTON_X, OVERWORLD_TO_MENU_DELAY, 20); + ssf_press_button2(context, BUTTON_R, 150, 20); + ssf_press_button2(context, BUTTON_A, 500, 10); // Exit game. - ssf_press_button2(BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); - close_game(); + ssf_press_button2(context, BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); + close_game(context); } -void MultiGameFossil::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); +void MultiGameFossil::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); FossilTable::GameSlot batch; @@ -106,13 +126,13 @@ void MultiGameFossil::program(SingleSwitchProgramEnvironment& env) const{ bool game_slot_flipped = false; for (size_t c = 0; c < games; c++){ batch = GAME_LIST[c]; - run_fossil_batch(&batch, &game_slot_flipped, c + 1 < games); + run_fossil_batch(env.console, &batch, &game_slot_flipped, c + 1 < games); } - ssf_press_button2(BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); + ssf_press_button2(env.console, BUTTON_HOME, GAME_TO_HOME_DELAY_SAFE, 10); - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_MultiGameFossil.h b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_MultiGameFossil.h index c218c8f964..61ee5ad7cd 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_MultiGameFossil.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_MultiGameFossil.h @@ -15,11 +15,18 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ -class MultiGameFossil : public SingleSwitchProgram{ +class MultiGameFossil_Descriptor : public RunnableSwitchProgramDescriptor{ public: - MultiGameFossil(); + MultiGameFossil_Descriptor(); +}; + + + +class MultiGameFossil : public SingleSwitchProgramInstance{ +public: + MultiGameFossil(const MultiGameFossil_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: FossilTable GAME_LIST; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHunt-Regi.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHunt-Regi.cpp index 5890469323..07e46d639a 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHunt-Regi.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHunt-Regi.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "PokemonSwSh_ShinyHunt-Regi.h" diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-BerryTree.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-BerryTree.cpp index a1662e934a..7db3f56111 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-BerryTree.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-BerryTree.cpp @@ -4,14 +4,17 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/FrameworkSettings.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSettings.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" #include "Common/PokemonSwSh/PokemonSwShDateSpam.h" #include "CommonFramework/PersistentSettings.h" +#include "CommonFramework/Tools/InterruptableCommands.h" +#include "CommonFramework/Inference/VisualInferenceSession.h" #include "PokemonSwSh/Inference/PokemonSwSh_StartBattleDetector.h" +#include "PokemonSwSh/Inference/PokemonSwSh_BattleMenuDetector.h" #include "PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_ShinyEncounterDetector.h" #include "PokemonSwSh_EncounterTracker.h" #include "PokemonSwSh_ShinyHuntAutonomous-BerryTree.h" @@ -21,17 +24,29 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ -ShinyHuntAutonomousBerryTree::ShinyHuntAutonomousBerryTree() - : SingleSwitchProgram( - FeedbackType::REQUIRED, PABotBaseLevel::PABOTBASE_12KB, +ShinyHuntAutonomousBerryTree_Descriptor::ShinyHuntAutonomousBerryTree_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:ShinyHuntAutonomousBerryTree", "Shiny Hunt Autonomous - Berry Tree", "SerialPrograms/ShinyHuntAutonomous-BerryTree.md", - "Automatically hunt for shiny berry tree " + STRING_POKEMON + " using video feedback." + "Automatically hunt for shiny berry tree " + STRING_POKEMON + " using video feedback.", + FeedbackType::REQUIRED, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +ShinyHuntAutonomousBerryTree::ShinyHuntAutonomousBerryTree(const ShinyHuntAutonomousBerryTree_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , GO_HOME_WHEN_DONE( "Go Home when Done:
After finding a shiny, go to the Switch Home menu to idle. (turn this off for unattended streaming)", false ) + , LANGUAGE( + "Game Language:
Attempt to read and log the encountered " + STRING_POKEMON + " in this language.
Set to \"None\" to disable this feature.", + m_name_reader.languages(), false + ) , REQUIRE_SQUARE( "Require Square:
Stop only for a square shiny. Run from star shinies.", false @@ -39,9 +54,9 @@ ShinyHuntAutonomousBerryTree::ShinyHuntAutonomousBerryTree() , m_advanced_options( "Advanced Options: You should not need to touch anything below here." ) - , EXIT_BATTLE_MASH_TIME( - "Exit Battle Time:
After running, wait this long to return to overworld.", - "6 * TICKS_PER_SECOND" + , EXIT_BATTLE_TIMEOUT( + "Exit Battle Timeout:
After running, wait this long to return to overworld.", + "10 * TICKS_PER_SECOND" ) , VIDEO_ON_SHINY( "Video Capture:
Take a video of the encounter if it is shiny.", @@ -53,10 +68,11 @@ ShinyHuntAutonomousBerryTree::ShinyHuntAutonomousBerryTree() ) { m_options.emplace_back(&GO_HOME_WHEN_DONE, "GO_HOME_WHEN_DONE"); + m_options.emplace_back(&LANGUAGE, "LANGUAGE"); m_options.emplace_back(&REQUIRE_SQUARE, "REQUIRE_SQUARE"); m_options.emplace_back(&m_advanced_options, ""); - m_options.emplace_back(&EXIT_BATTLE_MASH_TIME, "EXIT_BATTLE_MASH_TIME"); - if (settings.developer_mode){ + m_options.emplace_back(&EXIT_BATTLE_TIMEOUT, "EXIT_BATTLE_TIMEOUT"); + if (PERSISTENT_SETTINGS().developer_mode){ m_options.emplace_back(&VIDEO_ON_SHINY, "VIDEO_ON_SHINY"); m_options.emplace_back(&RUN_FROM_EVERYTHING, "RUN_FROM_EVERYTHING"); } @@ -67,11 +83,11 @@ ShinyHuntAutonomousBerryTree::ShinyHuntAutonomousBerryTree() struct ShinyHuntAutonomousBerryTree::Stats : public ShinyHuntTracker{ Stats() : ShinyHuntTracker(true) - , m_timeouts(m_stats["Timeouts"]) + , m_errors(m_stats["Errors"]) { - m_display_order.insert(m_display_order.begin() + 1, Stat("Timeouts")); + m_display_order.insert(m_display_order.begin() + 1, Stat("Errors")); } - uint64_t& m_timeouts; + uint64_t& m_errors; }; std::unique_ptr ShinyHuntAutonomousBerryTree::make_stats() const{ return std::unique_ptr(new Stats()); @@ -80,14 +96,16 @@ std::unique_ptr ShinyHuntAutonomousBerryTree::make_stats() const{ -void ShinyHuntAutonomousBerryTree::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); +void ShinyHuntAutonomousBerryTree::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + resume_game_no_interact(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST); Stats& stats = env.stats(); StandardEncounterTracker tracker( - stats, env.console, + stats, env, env.console, + &m_name_reader, LANGUAGE, REQUIRE_SQUARE, - EXIT_BATTLE_MASH_TIME, + EXIT_BATTLE_TIMEOUT, VIDEO_ON_SHINY, RUN_FROM_EVERYTHING ); @@ -96,12 +114,47 @@ void ShinyHuntAutonomousBerryTree::program(SingleSwitchProgramEnvironment& env) while (true){ env.update_stats(); - home_roll_date_enter_game_autorollback(&year); - pbf_mash_button(BUTTON_B, 90); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_FAST); + home_roll_date_enter_game_autorollback(env.console, &year); + pbf_mash_button(env.console, BUTTON_B, 90); env.console.botbase().wait_for_all_requests(); { - StartBattleDetector detector(env.console, std::chrono::seconds(60)); + InterruptableCommandSession commands(env.console); + + StandardBattleMenuDetector battle_menu_detector(env.console); + battle_menu_detector.register_command_stop(commands); + + StartBattleDetector start_battle_detector(env.console); + start_battle_detector.register_command_stop(commands); + + AsyncVisualInferenceSession inference(env, env.console); + inference += battle_menu_detector; + inference += start_battle_detector; + + commands.run([](const BotBaseContext& context){ + pbf_mash_button(context, BUTTON_A, 60 * TICKS_PER_SECOND); + context.botbase().wait_for_all_requests(); + }); + + if (battle_menu_detector.triggered()){ + env.log("Unexpected battle menu.", Qt::red); + stats.m_errors++; + pbf_mash_button(env.console, BUTTON_B, TICKS_PER_SECOND); + tracker.run_away(false); + continue; + } + if (start_battle_detector.triggered()){ + env.log("Battle started!"); + }else{ + stats.m_errors++; + env.log("Timed out."); + continue; + } + } +#if 0 + if (false){ + TimedStartBattleDetector detector(env.console, std::chrono::seconds(60)); // Detect start of battle. bool timed_out = false; @@ -112,16 +165,17 @@ void ShinyHuntAutonomousBerryTree::program(SingleSwitchProgramEnvironment& env) timed_out = true; break; } - pbf_mash_button(BUTTON_A, 10); + pbf_mash_button(env.console, BUTTON_A, 10); env.console.botbase().wait_for_all_requests(); }while (!detector.detect(env.console.video().snapshot())); - pbf_mash_button(BUTTON_B, 5 * TICKS_PER_SECOND); + pbf_mash_button(env.console, BUTTON_B, 5 * TICKS_PER_SECOND); if (timed_out){ - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_FAST); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_FAST); continue; } } +#endif // Detect shiny. ShinyDetection detection = detect_shiny_battle( @@ -134,29 +188,29 @@ void ShinyHuntAutonomousBerryTree::program(SingleSwitchProgramEnvironment& env) break; } if (detection == ShinyDetection::NO_BATTLE_MENU){ - stats.m_timeouts++; - pbf_mash_button(BUTTON_B, TICKS_PER_SECOND); - tracker.run_away(); + stats.m_errors++; + pbf_mash_button(env.console, BUTTON_B, TICKS_PER_SECOND); + tracker.run_away(false); } - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_FAST); +// pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_FAST); } env.update_stats(); - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - home_to_date_time(false, false); - pbf_press_button(BUTTON_A, 5, 5); - pbf_press_button(BUTTON_A, 5, 10); - pbf_press_button(BUTTON_HOME, 10, SETTINGS_TO_HOME_DELAY); + home_to_date_time(env.console, false, false); + pbf_press_button(env.console, BUTTON_A, 5, 5); + pbf_press_button(env.console, BUTTON_A, 5, 10); + pbf_press_button(env.console, BUTTON_HOME, 10, SETTINGS_TO_HOME_DELAY); if (!GO_HOME_WHEN_DONE){ - pbf_press_button(BUTTON_HOME, 10, HOME_TO_GAME_DELAY); + pbf_press_button(env.console, BUTTON_HOME, 10, HOME_TO_GAME_DELAY); } - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-BerryTree.h b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-BerryTree.h index 068c593af0..0c58e14173 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-BerryTree.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-BerryTree.h @@ -9,27 +9,41 @@ #include "CommonFramework/Options/SectionDivider.h" #include "CommonFramework/Options/BooleanCheckBox.h" +#include "CommonFramework/Options/LanguageOCR.h" #include "NintendoSwitch/Options/TimeExpression.h" #include "NintendoSwitch/Framework/SingleSwitchProgram.h" +#include "Pokemon/Pokemon_NameReader.h" namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class ShinyHuntAutonomousBerryTree : public SingleSwitchProgram{ + +class ShinyHuntAutonomousBerryTree_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + ShinyHuntAutonomousBerryTree_Descriptor(); +}; + + + +class ShinyHuntAutonomousBerryTree : public SingleSwitchProgramInstance{ public: - ShinyHuntAutonomousBerryTree(); + ShinyHuntAutonomousBerryTree(const ShinyHuntAutonomousBerryTree_Descriptor& descriptor); virtual std::unique_ptr make_stats() const override; - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: struct Stats; BooleanCheckBox GO_HOME_WHEN_DONE; + + Pokemon::PokemonNameReader m_name_reader; + LanguageOCR LANGUAGE; + BooleanCheckBox REQUIRE_SQUARE; SectionDivider m_advanced_options; - TimeExpression EXIT_BATTLE_MASH_TIME; + TimeExpression EXIT_BATTLE_TIMEOUT; BooleanCheckBox VIDEO_ON_SHINY; BooleanCheckBox RUN_FROM_EVERYTHING; }; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Fishing.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Fishing.cpp index bfc9b079ea..2d4a85cb6e 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Fishing.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Fishing.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/FrameworkSettings.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSettings.h" @@ -22,17 +22,29 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ -ShinyHuntAutonomousFishing::ShinyHuntAutonomousFishing() - : SingleSwitchProgram( - FeedbackType::REQUIRED, PABotBaseLevel::PABOTBASE_12KB, +ShinyHuntAutonomousFishing_Descriptor::ShinyHuntAutonomousFishing_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:ShinyHuntAutonomousFishing", "Shiny Hunt Autonomous - Fishing", "SerialPrograms/ShinyHuntAutonomous-Fishing.md", - "Automatically hunt for shiny fishing " + STRING_POKEMON + " using video feedback." + "Automatically hunt for shiny fishing " + STRING_POKEMON + " using video feedback.", + FeedbackType::REQUIRED, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +ShinyHuntAutonomousFishing::ShinyHuntAutonomousFishing(const ShinyHuntAutonomousFishing_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , GO_HOME_WHEN_DONE( "Go Home when Done:
After finding a shiny, go to the Switch Home menu to idle. (turn this off for unattended streaming)", false ) + , LANGUAGE( + "Game Language:
Attempt to read and log the encountered " + STRING_POKEMON + " in this language.
Set to \"None\" to disable this feature.", + m_name_reader.languages(), false + ) , TIME_ROLLBACK_HOURS( "Time Rollback (in hours):
Periodically roll back the time to keep the weather the same. If set to zero, this feature is disabled.", 1, 0, 11 @@ -40,13 +52,13 @@ ShinyHuntAutonomousFishing::ShinyHuntAutonomousFishing() , m_advanced_options( "Advanced Options: You should not need to touch anything below here." ) - , EXIT_BATTLE_MASH_TIME( - "Exit Battle Time:
After running, wait this long to return to overworld and for the fish to reappear.", - "6 * TICKS_PER_SECOND" + , EXIT_BATTLE_TIMEOUT( + "Exit Battle Timeout:
After running, wait this long to return to overworld and for the fish to reappear.", + "10 * TICKS_PER_SECOND" ) , FISH_RESPAWN_TIME( "Fish Respawn Time:
Wait this long for fish to respawn.", - "4 * TICKS_PER_SECOND" + "5 * TICKS_PER_SECOND" ) , VIDEO_ON_SHINY( "Video Capture:
Take a video of the encounter if it is shiny.", @@ -58,11 +70,12 @@ ShinyHuntAutonomousFishing::ShinyHuntAutonomousFishing() ) { m_options.emplace_back(&GO_HOME_WHEN_DONE, "GO_HOME_WHEN_DONE"); + m_options.emplace_back(&LANGUAGE, "LANGUAGE"); m_options.emplace_back(&TIME_ROLLBACK_HOURS, "TIME_ROLLBACK_HOURS"); m_options.emplace_back(&m_advanced_options, ""); - m_options.emplace_back(&EXIT_BATTLE_MASH_TIME, "EXIT_BATTLE_MASH_TIME"); + m_options.emplace_back(&EXIT_BATTLE_TIMEOUT, "EXIT_BATTLE_TIMEOUT"); m_options.emplace_back(&FISH_RESPAWN_TIME, "FISH_RESPAWN_TIME"); - if (settings.developer_mode){ + if (PERSISTENT_SETTINGS().developer_mode){ m_options.emplace_back(&VIDEO_ON_SHINY, "VIDEO_ON_SHINY"); m_options.emplace_back(&RUN_FROM_EVERYTHING, "RUN_FROM_EVERYTHING"); } @@ -78,6 +91,8 @@ struct ShinyHuntAutonomousFishing::Stats : public ShinyHuntTracker{ { m_display_order.insert(m_display_order.begin() + 1, Stat("Misses")); m_display_order.insert(m_display_order.begin() + 2, Stat("Errors")); + m_aliases["Timeouts"] = "Errors"; + m_aliases["Unexpected Battles"] = "Errors"; } uint64_t& m_misses; uint64_t& m_errors; @@ -88,18 +103,19 @@ std::unique_ptr ShinyHuntAutonomousFishing::make_stats() const{ -void ShinyHuntAutonomousFishing::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); - resume_game_no_interact(TOLERATE_SYSTEM_UPDATE_MENU_FAST); +void ShinyHuntAutonomousFishing::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + resume_game_no_interact(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST); const uint32_t PERIOD = (uint32_t)TIME_ROLLBACK_HOURS * 3600 * TICKS_PER_SECOND; - uint32_t last_touch = system_clock(); + uint32_t last_touch = system_clock(env.console); Stats& stats = env.stats(); StandardEncounterTracker tracker( - stats, env.console, + stats, env, env.console, + &m_name_reader, LANGUAGE, false, - EXIT_BATTLE_MASH_TIME, + EXIT_BATTLE_TIMEOUT, VIDEO_ON_SHINY, RUN_FROM_EVERYTHING ); @@ -108,45 +124,45 @@ void ShinyHuntAutonomousFishing::program(SingleSwitchProgramEnvironment& env) co env.update_stats(); // Touch the date. - if (TIME_ROLLBACK_HOURS > 0 && system_clock() - last_touch >= PERIOD){ - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - rollback_hours_from_home(TIME_ROLLBACK_HOURS, SETTINGS_TO_HOME_DELAY); - resume_game_no_interact(TOLERATE_SYSTEM_UPDATE_MENU_FAST); + if (TIME_ROLLBACK_HOURS > 0 && system_clock(env.console) - last_touch >= PERIOD){ + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + rollback_hours_from_home(env.console, TIME_ROLLBACK_HOURS, SETTINGS_TO_HOME_DELAY); + resume_game_no_interact(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST); last_touch += PERIOD; } - pbf_wait(FISH_RESPAWN_TIME); + pbf_wait(env.console, FISH_RESPAWN_TIME); env.console.botbase().wait_for_all_requests(); // Trigger encounter. { FishingDetector detector(env.console); - pbf_press_button(BUTTON_A, 10, 10); - pbf_mash_button(BUTTON_B, TICKS_PER_SECOND); + pbf_press_button(env.console, BUTTON_A, 10, 10); + pbf_mash_button(env.console, BUTTON_B, TICKS_PER_SECOND); env.console.botbase().wait_for_all_requests(); FishingDetector::Detection detection = detector.wait_for_detection(env); switch (detection){ case FishingDetector::NO_DETECTION: stats.m_errors++; - pbf_mash_button(BUTTON_B, 2 * TICKS_PER_SECOND); + pbf_mash_button(env.console, BUTTON_B, 2 * TICKS_PER_SECOND); continue; case FishingDetector::HOOKED: - pbf_press_button(BUTTON_A, 10, 0); + pbf_press_button(env.console, BUTTON_A, 10, 0); break; case FishingDetector::MISSED: stats.m_misses++; - pbf_mash_button(BUTTON_B, 2 * TICKS_PER_SECOND); + pbf_mash_button(env.console, BUTTON_B, 2 * TICKS_PER_SECOND); continue; case FishingDetector::BATTLE_MENU: stats.m_errors++; - tracker.run_away(); + tracker.run_away(false); continue; } env.wait(std::chrono::seconds(3)); detection = detector.detect_now(); if (detection == FishingDetector::MISSED){ stats.m_misses++; - pbf_mash_button(BUTTON_B, 2 * TICKS_PER_SECOND); + pbf_mash_button(env.console, BUTTON_B, 2 * TICKS_PER_SECOND); continue; } } @@ -163,19 +179,19 @@ void ShinyHuntAutonomousFishing::program(SingleSwitchProgramEnvironment& env) co } if (detection == ShinyDetection::NO_BATTLE_MENU){ stats.m_errors++; - pbf_mash_button(BUTTON_B, TICKS_PER_SECOND); - tracker.run_away(); + pbf_mash_button(env.console, BUTTON_B, TICKS_PER_SECOND); + tracker.run_away(false); } } env.update_stats(); if (GO_HOME_WHEN_DONE){ - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); } - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Fishing.h b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Fishing.h index c36cab6546..fb1a0e0b92 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Fishing.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Fishing.h @@ -10,28 +10,41 @@ #include "CommonFramework/Options/SectionDivider.h" #include "CommonFramework/Options/BooleanCheckBox.h" #include "CommonFramework/Options/SimpleInteger.h" +#include "CommonFramework/Options/LanguageOCR.h" #include "NintendoSwitch/Options/TimeExpression.h" #include "NintendoSwitch/Framework/SingleSwitchProgram.h" +#include "Pokemon/Pokemon_NameReader.h" namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class ShinyHuntAutonomousFishing : public SingleSwitchProgram{ +class ShinyHuntAutonomousFishing_Descriptor : public RunnableSwitchProgramDescriptor{ public: - ShinyHuntAutonomousFishing(); + ShinyHuntAutonomousFishing_Descriptor(); +}; + + + +class ShinyHuntAutonomousFishing : public SingleSwitchProgramInstance{ +public: + ShinyHuntAutonomousFishing(const ShinyHuntAutonomousFishing_Descriptor& descriptor); virtual std::unique_ptr make_stats() const override; - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: struct Stats; BooleanCheckBox GO_HOME_WHEN_DONE; + + Pokemon::PokemonNameReader m_name_reader; + LanguageOCR LANGUAGE; + SimpleInteger TIME_ROLLBACK_HOURS; SectionDivider m_advanced_options; - TimeExpression EXIT_BATTLE_MASH_TIME; + TimeExpression EXIT_BATTLE_TIMEOUT; TimeExpression FISH_RESPAWN_TIME; BooleanCheckBox VIDEO_ON_SHINY; BooleanCheckBox RUN_FROM_EVERYTHING; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-IoATrade.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-IoATrade.cpp index 3b143b4077..52c3d75545 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-IoATrade.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-IoATrade.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/FrameworkSettings.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSettings.h" @@ -20,13 +20,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -ShinyHuntAutonomousIoATrade::ShinyHuntAutonomousIoATrade() - : SingleSwitchProgram( - FeedbackType::REQUIRED, PABotBaseLevel::PABOTBASE_12KB, + +ShinyHuntAutonomousIoATrade_Descriptor::ShinyHuntAutonomousIoATrade_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:ShinyHuntAutonomousIoATrade", "Shiny Hunt Autonomous - IoA Trade", "SerialPrograms/ShinyHuntAutonomous-IoATrade.md", - "Hunt for shiny Isle of Armor trade using video feedback." + "Hunt for shiny Isle of Armor trade using video feedback.", + FeedbackType::REQUIRED, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +ShinyHuntAutonomousIoATrade::ShinyHuntAutonomousIoATrade(const ShinyHuntAutonomousIoATrade_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , GO_HOME_WHEN_DONE( "Go Home when Done:
After finding a shiny, go to the Switch Home menu to idle. (turn this off for unattended streaming)", false @@ -55,7 +64,7 @@ ShinyHuntAutonomousIoATrade::ShinyHuntAutonomousIoATrade() m_options.emplace_back(&TOUCH_DATE_INTERVAL, "TOUCH_DATE_INTERVAL"); m_options.emplace_back(&m_advanced_options, ""); m_options.emplace_back(&MASH_TO_TRADE_DELAY, "MASH_TO_TRADE_DELAY"); - if (settings.developer_mode){ + if (PERSISTENT_SETTINGS().developer_mode){ m_options.emplace_back(&VIDEO_ON_SHINY, "VIDEO_ON_SHINY"); m_options.emplace_back(&RUN_FROM_EVERYTHING, "RUN_FROM_EVERYTHING"); } @@ -80,39 +89,40 @@ std::unique_ptr ShinyHuntAutonomousIoATrade::make_stats() const{ -void ShinyHuntAutonomousIoATrade::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); - resume_game_back_out(TOLERATE_SYSTEM_UPDATE_MENU_FAST, 500); +void ShinyHuntAutonomousIoATrade::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + resume_game_back_out(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST, 500); - uint32_t last_touch = system_clock() - TOUCH_DATE_INTERVAL; + uint32_t last_touch = system_clock(env.console) - TOUCH_DATE_INTERVAL; Stats& stats = env.stats(); while (true){ env.update_stats(); - pbf_press_button(BUTTON_A, 10, 100); - pbf_press_button(BUTTON_A, 10, 60); - pbf_press_button(BUTTON_A, 10, 100); - pbf_press_button(BUTTON_A, 10, 50); - pbf_press_button(BUTTON_A, 10, POKEMON_TO_BOX_DELAY); - pbf_press_dpad(DPAD_LEFT, 10, 10); - pbf_mash_button(BUTTON_A, MASH_TO_TRADE_DELAY); + pbf_press_button(env.console, BUTTON_A, 10, 100); + pbf_press_button(env.console, BUTTON_A, 10, 60); + pbf_press_button(env.console, BUTTON_A, 10, 100); + pbf_press_button(env.console, BUTTON_A, 10, 50); + pbf_press_button(env.console, BUTTON_A, 10, POKEMON_TO_BOX_DELAY); + pbf_press_dpad(env.console, DPAD_LEFT, 10, 10); + pbf_mash_button(env.console, BUTTON_A, MASH_TO_TRADE_DELAY); // Enter box system. - pbf_press_button(BUTTON_X, 10, OVERWORLD_TO_MENU_DELAY); - pbf_press_dpad(DPAD_RIGHT, 10, 10); - pbf_press_button(BUTTON_A, 10, MENU_TO_POKEMON_DELAY); + pbf_press_button(env.console, BUTTON_X, 10, OVERWORLD_TO_MENU_DELAY); + pbf_press_dpad(env.console, DPAD_RIGHT, 10, 10); + pbf_press_button(env.console, BUTTON_A, 10, MENU_TO_POKEMON_DELAY); // View summary. - pbf_press_button(BUTTON_A, 10, 100); - pbf_press_button(BUTTON_A, 10, 0); + pbf_press_button(env.console, BUTTON_A, 10, 100); + pbf_press_button(env.console, BUTTON_A, 10, 0); env.console.botbase().wait_for_all_requests(); SummaryShinySymbolDetector::Detection detection; { SummaryShinySymbolDetector detector(env.console, env.logger()); detection = detector.wait_for_detection(env); +// detection = SummaryShinySymbolDetector::SHINY; } switch (detection){ case SummaryShinySymbolDetector::NO_DETECTION: @@ -124,18 +134,18 @@ void ShinyHuntAutonomousIoATrade::program(SingleSwitchProgramEnvironment& env) c case SummaryShinySymbolDetector::SHINY: stats.add_unknown_shiny(); if (VIDEO_ON_SHINY){ - pbf_wait(1 * TICKS_PER_SECOND); - pbf_press_button(BUTTON_CAPTURE, 2 * TICKS_PER_SECOND, 5 * TICKS_PER_SECOND); + pbf_wait(env.console, 1 * TICKS_PER_SECOND); + pbf_press_button(env.console, BUTTON_CAPTURE, 2 * TICKS_PER_SECOND, 5 * TICKS_PER_SECOND); } if (!RUN_FROM_EVERYTHING){ goto StopProgram; } } - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - if (TOUCH_DATE_INTERVAL > 0 && system_clock() - last_touch >= TOUCH_DATE_INTERVAL){ + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + if (TOUCH_DATE_INTERVAL > 0 && system_clock(env.console) - last_touch >= TOUCH_DATE_INTERVAL){ env.log("Touching date to prevent rollover."); - touch_date_from_home(SETTINGS_TO_HOME_DELAY); + touch_date_from_home(env.console, SETTINGS_TO_HOME_DELAY); last_touch += TOUCH_DATE_INTERVAL; } reset_game_from_home_with_inference( @@ -148,11 +158,11 @@ void ShinyHuntAutonomousIoATrade::program(SingleSwitchProgramEnvironment& env) c env.update_stats(); if (GO_HOME_WHEN_DONE){ - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); } - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-IoATrade.h b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-IoATrade.h index f33dc7a76b..31d9bbf95e 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-IoATrade.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-IoATrade.h @@ -16,12 +16,20 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class ShinyHuntAutonomousIoATrade : public SingleSwitchProgram{ + +class ShinyHuntAutonomousIoATrade_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + ShinyHuntAutonomousIoATrade_Descriptor(); +}; + + + +class ShinyHuntAutonomousIoATrade : public SingleSwitchProgramInstance{ public: - ShinyHuntAutonomousIoATrade(); + ShinyHuntAutonomousIoATrade(const ShinyHuntAutonomousIoATrade_Descriptor& descriptor); virtual std::unique_ptr make_stats() const override; - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: struct Stats; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Overworld.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Overworld.cpp deleted file mode 100644 index c9eacf240e..0000000000 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Overworld.cpp +++ /dev/null @@ -1,453 +0,0 @@ -/* Shiny Hunt Autonomous - Overworld - * - * From: https://github.com/PokemonAutomation/Arduino-Source - * - */ - -#include -#include "Common/Clientside/PrettyPrint.h" -#include "Common/SwitchFramework/FrameworkSettings.h" -#include "Common/SwitchFramework/Switch_PushButtons.h" -#include "Common/PokemonSwSh/PokemonSettings.h" -#include "Common/PokemonSwSh/PokemonSwShGameEntry.h" -#include "Common/PokemonSwSh/PokemonSwShDateSpam.h" -#include "CommonFramework/PersistentSettings.h" -#include "CommonFramework/Inference/ImageTools.h" -#include "CommonFramework/Inference/InferenceThrottler.h" -#include "PokemonSwSh/ShinyHuntTracker.h" -#include "PokemonSwSh/Inference/PokemonSwSh_MarkFinder.h" -#include "PokemonSwSh/Inference/PokemonSwSh_StartBattleDetector.h" -#include "PokemonSwSh/Inference/PokemonSwSh_BattleMenuDetector.h" -#include "PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_ShinyEncounterDetector.h" -#include "PokemonSwSh/Programs/PokemonSwSh_StartGame.h" -#include "PokemonSwSh/Programs/PokemonSwSh_OverworldTrajectory.h" -#include "PokemonSwSh_ShinyHuntAutonomous-Overworld.h" - -namespace PokemonAutomation{ -namespace NintendoSwitch{ -namespace PokemonSwSh{ - - -ShinyHuntAutonomousOverworld::ShinyHuntAutonomousOverworld() - : SingleSwitchProgram( - FeedbackType::REQUIRED, PABotBaseLevel::PABOTBASE_12KB, - "Shiny Hunt Autonomous - Overworld", - "SerialPrograms/ShinyHuntAutonomous-Overworld.md", - "Automatically shiny hunt overworld " + STRING_POKEMON + " with video feedback." - ) - , GO_HOME_WHEN_DONE( - "Go Home when Done:
After finding a shiny, go to the Switch Home menu to idle. (turn this off for unattended streaming)", - false - ) - , PRIORITIZE_EXCLAMATION_POINTS( - "Prioritize Exclamation Points:
Given multiple options, prefer those with exclamation points." - " This prioritizes random grass encounters and " + STRING_POKEMON + " that flee.", - true - ) - , TARGET_CIRCLING( - "Target Circling:
After moving towards a " + STRING_POKEMON + ", make a circle." - " This increases the chance of encountering the " + STRING_POKEMON + " if it has moved or if the trajectory missed.", - true - ) - , LOCAL_CIRCLING( - "Local Circling:
If nothing is found after this many whistles, run in a circle." - " Set this to zero to disable this feature.", - 3, 0, 10 - ) - , MAX_MOVE_DURATION( - "Maximum Move Duration:
Do not move in the same direction for more than this long." - " If you set this too high, you may wander too far from the grassy area.", - "200" - ) - , WATCHDOG_TIMER( - "Watchdog Timer:
Reset the game if you go this long without any encounters.", - "120 * TICKS_PER_SECOND" - ) - , TIME_ROLLBACK_HOURS( - "Time Rollback (in hours):
Periodically roll back the time to keep the weather the same. If set to zero, this feature is disabled.", - 1, 0, 11 - ) - , m_advanced_options( - "Advanced Options: You should not need to touch anything below here." - ) - , EXIT_BATTLE_MASH_TIME( - "Exit Battle Time:
After running, wait this long to return to overworld.", - "6 * TICKS_PER_SECOND" - ) - , VIDEO_ON_SHINY( - "Video Capture:
Take a video of the encounter if it is shiny.", - true - ) - , RUN_FROM_EVERYTHING( - "Run from Everything:
Run from everything - even if it is shiny. (For testing only.)", - false - ) -{ - m_options.emplace_back(&GO_HOME_WHEN_DONE, "GO_HOME_WHEN_DONE"); - m_options.emplace_back(&PRIORITIZE_EXCLAMATION_POINTS, "PRIORITIZE_EXCLAMATION_POINTS"); - m_options.emplace_back(&TARGET_CIRCLING, "ENABLE_CIRCLING"); - m_options.emplace_back(&LOCAL_CIRCLING, "LOCAL_CIRCLING"); - m_options.emplace_back(&MAX_MOVE_DURATION, "MAX_MOVE_DURATION"); - m_options.emplace_back(&WATCHDOG_TIMER, "WATCHDOG_TIMER"); - m_options.emplace_back(&TIME_ROLLBACK_HOURS, "TIME_ROLLBACK_HOURS"); - m_options.emplace_back(&m_advanced_options, ""); - m_options.emplace_back(&EXIT_BATTLE_MASH_TIME, "EXIT_BATTLE_MASH_TIME"); - if (settings.developer_mode){ - m_options.emplace_back(&VIDEO_ON_SHINY, "VIDEO_ON_SHINY"); - m_options.emplace_back(&RUN_FROM_EVERYTHING, "RUN_FROM_EVERYTHING"); - } -} - - - -struct ShinyHuntAutonomousOverworld::Stats : public ShinyHuntTracker{ - Stats() - : ShinyHuntTracker(true) - , m_errors(m_stats["Errors"]) - , m_resets(m_stats["Resets"]) - { - m_display_order.insert(m_display_order.begin() + 1, Stat("Errors")); - m_display_order.insert(m_display_order.begin() + 2, Stat("Resets")); - } - uint64_t& m_errors; - uint64_t& m_resets; -}; -std::unique_ptr ShinyHuntAutonomousOverworld::make_stats() const{ - return std::unique_ptr(new Stats()); -} - - - - -void ShinyHuntAutonomousOverworld::move_in_circle( - SingleSwitchProgramEnvironment& env, - uint8_t size_ticks, - uint8_t current_direction_x, - uint8_t current_direction_y -) const{ -// cout << "size_ticks = " << (int)size_ticks << endl; - - if (current_direction_x <= 128){ - pbf_move_left_joystick(env.console, 0, 128, size_ticks, 0); // Correct for bias. - pbf_move_left_joystick(env.console, 128, 0, size_ticks, 0); - pbf_move_left_joystick(env.console, 255, 0, size_ticks, 0); - pbf_move_left_joystick(env.console, 255, 128, size_ticks, 0); - pbf_move_left_joystick(env.console, 255, 255, size_ticks, 0); - pbf_move_left_joystick(env.console, 128, 255, size_ticks, 0); - pbf_move_left_joystick(env.console, 0, 255, size_ticks, 0); - pbf_move_left_joystick(env.console, 0, 128, size_ticks, 0); - pbf_move_left_joystick(env.console, 0, 0, size_ticks, 0); - pbf_move_left_joystick(env.console, 255, 128, size_ticks, 0); // Correct for bias. - }else{ - pbf_move_left_joystick(env.console, 255, 128, size_ticks, 0); // Correct for bias. - pbf_move_left_joystick(env.console, 128, 0, size_ticks, 0); - pbf_move_left_joystick(env.console, 0, 0, size_ticks, 0); - pbf_move_left_joystick(env.console, 0, 128, size_ticks, 0); - pbf_move_left_joystick(env.console, 0, 255, size_ticks, 0); - pbf_move_left_joystick(env.console, 128, 255, size_ticks, 0); - pbf_move_left_joystick(env.console, 255, 255, size_ticks, 0); - pbf_move_left_joystick(env.console, 255, 128, size_ticks, 0); - pbf_move_left_joystick(env.console, 255, 0, size_ticks, 0); - pbf_move_left_joystick(env.console, 0, 128, size_ticks, 0); // Correct for bias. - } -} - - -ShinyHuntAutonomousOverworld::WatchResult ShinyHuntAutonomousOverworld::whistle_and_watch( - SingleSwitchProgramEnvironment& env, - std::vector& exclamations, - std::vector& questions -) const{ - StartBattleDetector start_battle(env.console, std::chrono::milliseconds(0)); - StandardBattleMenuDetector battle_menu(env.console); - InferenceBoxScope search_area(env.console, 0.0, 0.2, 1.0, 0.8); - - const double center_x = 0.5; - const double center_y = 0.70; - InferenceBoxScope self(env.console, Qt::cyan, center_x - 0.02, center_y - 0.05, 0.04, 0.1); - - - // Whistle - pbf_press_button(env.console, BUTTON_LCLICK, 5, 0); - - std::deque detection_boxes; - - size_t count = 0; - - InferenceThrottler throttler(std::chrono::milliseconds(1000), std::chrono::milliseconds(50)); - while (true){ - env.check_stopping(); - - QImage screen = env.console.video().snapshot(); - - // Check if a battle has started. - if (battle_menu.detect(screen)){ - return WatchResult::BATTLE_MENU; - } - if (start_battle.detect(screen)){ - return WatchResult::BATTLE_START; - } - - // Look for exclamation points and question marks. - QImage search_image = extract_box(screen, search_area); - - std::vector exclamation_marks; - std::vector question_marks; - count += find_marks( - search_image, - &exclamation_marks, - &question_marks - ); - - detection_boxes.clear(); - for (const PixelBox& mark : exclamation_marks){ - InferenceBox box = translate_to_parent(screen, search_area, mark); - box.color = Qt::magenta; - box.x -= box.width; - box.width *= 3; - box.height *= 2; - detection_boxes.emplace_back(env.console, box); - exclamations.emplace_back(box); - } - for (const PixelBox& mark : question_marks){ - InferenceBox box = translate_to_parent(screen, search_area, mark); - box.color = Qt::magenta; - box.x -= box.width / 2; - box.width *= 2; - box.height *= 2; - detection_boxes.emplace_back(env.console, box); - questions.emplace_back(box); - } - - if (throttler.end_iteration(env)){ - return WatchResult::TIMEOUT; - } - } -} - - -bool ShinyHuntAutonomousOverworld::find_encounter( - SingleSwitchProgramEnvironment& env, - Stats& stats, - StandardEncounterTracker& tracker -) const{ - const double center_x = 0.5; - const double center_y = 0.70; - InferenceBoxScope self(env.console, Qt::cyan, center_x - 0.02, center_y - 0.05, 0.04, 0.1); - - const std::chrono::milliseconds TIMEOUT((uint64_t)WATCHDOG_TIMER * 1000 / TICKS_PER_SECOND); - - size_t nothing_found_counter = 0; - - auto last = std::chrono::system_clock::now(); - while (true){ - // No battle for a long time. Reset the game. - auto now = std::chrono::system_clock::now(); - if (now - last > TIMEOUT){ - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - reset_game_from_home_with_inference( - env, env.console, - TOLERATE_SYSTEM_UPDATE_MENU_FAST - ); - stats.m_resets++; - return false; - } - - std::vector exclamation_marks; - std::vector question_marks; - WatchResult result = whistle_and_watch( - env, - exclamation_marks, - question_marks - ); - switch (result){ - case WatchResult::BATTLE_MENU: - stats.m_errors++; - tracker.run_away(); - return false; - case WatchResult::BATTLE_START: - env.log("Battle started! (whistle)"); - return true; - default:; - } - - AsyncStartBattleDetector start_battle(env, env.console); - - // Nothing was found. Rotate the view and try again. - if (exclamation_marks.empty() && question_marks.empty()){ - env.log("Nothing found. Rotating view."); - nothing_found_counter++; - if (LOCAL_CIRCLING != 0 && nothing_found_counter >= LOCAL_CIRCLING){ - move_in_circle(env, 32, 0, 0); - nothing_found_counter = 0; - }else{ - pbf_move_right_joystick(192, 255, 50, 70); - } - env.console.botbase().wait_for_all_requests(); - if (start_battle.detected()){ - env.log("Battle started! (rotate)"); - return true; - } - continue; - } - - nothing_found_counter = 0; - - std::multimap> exclamations; - for (const InferenceBox& box : exclamation_marks){ - double delta_x = box.x + box.width / 2 - center_x; - double delta_y = box.y + box.height * 1.5 - center_y; - env.log( - "Exclamation at: [" + QString::number(delta_x) + " , " + QString::number(-delta_y) + "]", - "purple" - ); - Trajectory trajectory = get_trajectory_float(delta_x, delta_y); - exclamations.emplace( - trajectory.distance_in_ticks, - std::pair(trajectory, box) - ); - break; - } - - std::multimap> questions; - for (const InferenceBox& box : question_marks){ - double delta_x = box.x + box.width / 2 - center_x; - double delta_y = box.y + box.height * 1.5 - center_y; - env.log( - "Question at: [" + QString::number(delta_x) + " , " + QString::number(-delta_y) + "]", - "purple" - ); - Trajectory trajectory = get_trajectory_float(delta_x, delta_y); - questions.emplace( - trajectory.distance_in_ticks, - std::pair(trajectory, box) - ); - break; - } - - - // Pick a target. - std::pair target; - target.first.distance_in_ticks = (uint16_t)0 - 1; - - if (PRIORITIZE_EXCLAMATION_POINTS && !exclamations.empty()){ - questions.clear(); - } - if (!exclamations.empty() && target.first.distance_in_ticks > exclamations.begin()->first){ - target = exclamations.begin()->second; - } - if (!questions.empty() && target.first.distance_in_ticks > questions.begin()->first){ - target = questions.begin()->second; - } - - target.second.color = Qt::yellow; - InferenceBoxScope target_box(env.console, target.second); - - double angle = std::atan2( - (double)target.first.joystick_y - 128, - (double)target.first.joystick_x - 128 - ) * 57.295779513082320877; - env.log( - "Found something. Distance: " + QString::number(target.first.distance_in_ticks) + - ", Direction: " + QString::number(-angle) + " degrees" - ); - - - - // Move towards target. - - int duration = target.first.distance_in_ticks + 30; - if (duration > (int)MAX_MOVE_DURATION){ - duration = MAX_MOVE_DURATION; - } - pbf_move_left_joystick( - target.first.joystick_x, - target.first.joystick_y, - (uint16_t)duration, 0 - ); - - // Circle Maneuver - if (TARGET_CIRCLING){ - move_in_circle( - env, 16, - target.first.joystick_x, - target.first.joystick_y - ); - } - - env.console.botbase().wait_for_all_requests(); - if (start_battle.detected()){ - env.log("Battle started! (move)"); - return true; - } - } -} - -void ShinyHuntAutonomousOverworld::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); - resume_game_back_out(TOLERATE_SYSTEM_UPDATE_MENU_FAST, 200); - pbf_move_right_joystick(128, 255, TICKS_PER_SECOND, 0); - - const uint32_t PERIOD = (uint32_t)TIME_ROLLBACK_HOURS * 3600 * TICKS_PER_SECOND; - uint32_t last_touch = system_clock(); - - Stats& stats = env.stats(); - StandardEncounterTracker tracker( - stats, env.console, - false, - EXIT_BATTLE_MASH_TIME, - VIDEO_ON_SHINY, - RUN_FROM_EVERYTHING - ); - - // Encounter Loop - while (true){ - env.update_stats(); - - // Touch the date. - if (TIME_ROLLBACK_HOURS > 0 && system_clock() - last_touch >= PERIOD){ - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - rollback_hours_from_home(TIME_ROLLBACK_HOURS, SETTINGS_TO_HOME_DELAY); - resume_game_no_interact(TOLERATE_SYSTEM_UPDATE_MENU_FAST); - last_touch += PERIOD; - } - env.console.botbase().wait_for_all_requests(); - - bool battle = find_encounter(env, stats, tracker); - if (!battle){ - continue; - } - - // Detect shiny. - ShinyDetection detection = detect_shiny_battle( - env, env.console, - SHINY_BATTLE_REGULAR, - std::chrono::seconds(30) - ); - - if (tracker.process_result(detection)){ - break; - } - if (detection == ShinyDetection::NO_BATTLE_MENU){ - stats.m_errors++; - pbf_mash_button(BUTTON_B, TICKS_PER_SECOND); - tracker.run_away(); - } - } - - env.update_stats(); - - if (GO_HOME_WHEN_DONE){ - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - } - - end_program_callback(); - end_program_loop(); -} - - - -} -} -} - diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regi.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regi.cpp index 9db4c99caa..7fdefc0d53 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regi.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regi.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/FrameworkSettings.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSettings.h" @@ -20,13 +20,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -ShinyHuntAutonomousRegi::ShinyHuntAutonomousRegi() - : SingleSwitchProgram( - FeedbackType::REQUIRED, PABotBaseLevel::PABOTBASE_12KB, + +ShinyHuntAutonomousRegi_Descriptor::ShinyHuntAutonomousRegi_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:ShinyHuntAutonomousRegi", "Shiny Hunt Autonomous - Regi", "SerialPrograms/ShinyHuntAutonomous-Regi.md", - "Automatically hunt for shiny Regi using video feedback." + "Automatically hunt for shiny Regi using video feedback.", + FeedbackType::REQUIRED, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +ShinyHuntAutonomousRegi::ShinyHuntAutonomousRegi(const ShinyHuntAutonomousRegi_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , GO_HOME_WHEN_DONE( "Go Home when Done:
After finding a shiny, go to the Switch Home menu to idle. (turn this off for unattended streaming)", false @@ -42,9 +51,13 @@ ShinyHuntAutonomousRegi::ShinyHuntAutonomousRegi() , m_advanced_options( "Advanced Options: You should not need to touch anything below here." ) - , EXIT_BATTLE_MASH_TIME( - "Exit Battle Time:
After running, wait this long to return to overworld.", - "6 * TICKS_PER_SECOND" + , EXIT_BATTLE_TIMEOUT( + "Exit Battle Timeout:
After running, wait this long to return to overworld.", + "10 * TICKS_PER_SECOND" + ) + , POST_BATTLE_MASH_TIME( + "Post-Battle Mash:
After each battle, mash B for this long to clear the dialogs.", + "1 * TICKS_PER_SECOND" ) , TRANSITION_DELAY( "Transition Delay:
Time to enter/exit the building.", @@ -64,9 +77,10 @@ ShinyHuntAutonomousRegi::ShinyHuntAutonomousRegi() m_options.emplace_back(®I_NAME, "REGI_NAME"); m_options.emplace_back(&TOUCH_DATE_INTERVAL, "TOUCH_DATE_INTERVAL"); m_options.emplace_back(&m_advanced_options, ""); - m_options.emplace_back(&EXIT_BATTLE_MASH_TIME, "EXIT_BATTLE_MASH_TIME"); + m_options.emplace_back(&EXIT_BATTLE_TIMEOUT, "EXIT_BATTLE_TIMEOUT"); + m_options.emplace_back(&POST_BATTLE_MASH_TIME, "POST_BATTLE_MASH_TIME"); m_options.emplace_back(&TRANSITION_DELAY, "TRANSITION_DELAY"); - if (settings.developer_mode){ + if (PERSISTENT_SETTINGS().developer_mode){ m_options.emplace_back(&VIDEO_ON_SHINY, "VIDEO_ON_SHINY"); m_options.emplace_back(&RUN_FROM_EVERYTHING, "RUN_FROM_EVERYTHING"); } @@ -91,24 +105,26 @@ std::unique_ptr ShinyHuntAutonomousRegi::make_stats() const{ -void ShinyHuntAutonomousRegi::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); - resume_game_back_out(TOLERATE_SYSTEM_UPDATE_MENU_FAST, 200); +void ShinyHuntAutonomousRegi::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + resume_game_back_out(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST, 200); Stats& stats = env.stats(); StandardEncounterTracker tracker( - stats, env.console, + stats, env, env.console, + nullptr, Language::None, REQUIRE_SQUARE, - EXIT_BATTLE_MASH_TIME, + EXIT_BATTLE_TIMEOUT, VIDEO_ON_SHINY, RUN_FROM_EVERYTHING ); - uint32_t last_touch = system_clock() - TOUCH_DATE_INTERVAL; + uint32_t last_touch = system_clock(env.console) - TOUCH_DATE_INTERVAL; bool error = false; while (true){ env.update_stats(); + pbf_mash_button(env.console, BUTTON_B, POST_BATTLE_MASH_TIME); move_to_corner(env, error, TRANSITION_DELAY); if (error){ stats.m_light_resets++; @@ -117,11 +133,11 @@ void ShinyHuntAutonomousRegi::program(SingleSwitchProgramEnvironment& env) const } // Touch the date. - if (TOUCH_DATE_INTERVAL > 0 && system_clock() - last_touch >= TOUCH_DATE_INTERVAL){ + if (TOUCH_DATE_INTERVAL > 0 && system_clock(env.console) - last_touch >= TOUCH_DATE_INTERVAL){ env.log("Touching date to prevent rollover."); - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - touch_date_from_home(SETTINGS_TO_HOME_DELAY); - resume_game_no_interact(TOLERATE_SYSTEM_UPDATE_MENU_FAST); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + touch_date_from_home(env.console, SETTINGS_TO_HOME_DELAY); + resume_game_no_interact(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST); last_touch += TOUCH_DATE_INTERVAL; } @@ -129,7 +145,7 @@ void ShinyHuntAutonomousRegi::program(SingleSwitchProgramEnvironment& env) const run_regi_light_puzzle(env, REGI_NAME, stats.encounters()); // Start the encounter. - pbf_mash_button(BUTTON_A, 5 * TICKS_PER_SECOND); + pbf_mash_button(env.console, BUTTON_A, 5 * TICKS_PER_SECOND); env.console.botbase().wait_for_all_requests(); // Detect shiny. @@ -143,8 +159,8 @@ void ShinyHuntAutonomousRegi::program(SingleSwitchProgramEnvironment& env) const break; } if (detection == ShinyDetection::NO_BATTLE_MENU){ - pbf_mash_button(BUTTON_B, TICKS_PER_SECOND); - tracker.run_away(); + pbf_mash_button(env.console, BUTTON_B, TICKS_PER_SECOND); + tracker.run_away(false); error = true; } } @@ -152,11 +168,11 @@ void ShinyHuntAutonomousRegi::program(SingleSwitchProgramEnvironment& env) const env.update_stats(); if (GO_HOME_WHEN_DONE){ - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); } - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regi.h b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regi.h index 15c8ed23e3..e4635b0967 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regi.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regi.h @@ -18,12 +18,20 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class ShinyHuntAutonomousRegi : public SingleSwitchProgram{ + +class ShinyHuntAutonomousRegi_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + ShinyHuntAutonomousRegi_Descriptor(); +}; + + + +class ShinyHuntAutonomousRegi : public SingleSwitchProgramInstance{ public: - ShinyHuntAutonomousRegi(); + ShinyHuntAutonomousRegi(const ShinyHuntAutonomousRegi_Descriptor& descriptor); virtual std::unique_ptr make_stats() const override; - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: struct Stats; @@ -33,7 +41,8 @@ class ShinyHuntAutonomousRegi : public SingleSwitchProgram{ BooleanCheckBox REQUIRE_SQUARE; TimeExpression TOUCH_DATE_INTERVAL; SectionDivider m_advanced_options; - TimeExpression EXIT_BATTLE_MASH_TIME; + TimeExpression EXIT_BATTLE_TIMEOUT; + TimeExpression POST_BATTLE_MASH_TIME; TimeExpression TRANSITION_DELAY; BooleanCheckBox VIDEO_ON_SHINY; BooleanCheckBox RUN_FROM_EVERYTHING; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regigigas2.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regigigas2.cpp index 44848edcdd..3bfd184e59 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regigigas2.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regigigas2.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/FrameworkSettings.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSettings.h" @@ -21,13 +21,22 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -ShinyHuntAutonomousRegigigas2::ShinyHuntAutonomousRegigigas2() - : SingleSwitchProgram( - FeedbackType::REQUIRED, PABotBaseLevel::PABOTBASE_12KB, + +ShinyHuntAutonomousRegigigas2_Descriptor::ShinyHuntAutonomousRegigigas2_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:ShinyHuntAutonomousRegigigas2", "Shiny Hunt Autonomous - Regigigas2", "SerialPrograms/ShinyHuntAutonomous-Regigigas2.md", - "Automatically hunt for shiny Regigigas using video feedback." + "Automatically hunt for shiny Regigigas using video feedback.", + FeedbackType::REQUIRED, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +ShinyHuntAutonomousRegigigas2::ShinyHuntAutonomousRegigigas2(const ShinyHuntAutonomousRegigigas2_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , GO_HOME_WHEN_DONE( "Go Home when Done:
After finding a shiny, go to the Switch Home menu to idle. (turn this off for unattended streaming)", false @@ -66,7 +75,7 @@ ShinyHuntAutonomousRegigigas2::ShinyHuntAutonomousRegigigas2() m_options.emplace_back(&TOUCH_DATE_INTERVAL, "TOUCH_DATE_INTERVAL"); m_options.emplace_back(&m_advanced_options, ""); m_options.emplace_back(&CATCH_TO_OVERWORLD_DELAY, "CATCH_TO_OVERWORLD_DELAY"); - if (settings.developer_mode){ + if (PERSISTENT_SETTINGS().developer_mode){ m_options.emplace_back(&VIDEO_ON_SHINY, "VIDEO_ON_SHINY"); m_options.emplace_back(&RUN_FROM_EVERYTHING, "RUN_FROM_EVERYTHING"); } @@ -100,45 +109,51 @@ ShinyHuntAutonomousRegigigas2::Tracker::Tracker( bool take_video, bool run_from_everything ) - : StandardEncounterTracker(stats, console, require_square, exit_battle_time, take_video, run_from_everything) + : StandardEncounterTracker( + stats, env, console, + nullptr, Language::None, + require_square, + exit_battle_time, + take_video, run_from_everything + ) , m_env(env) {} -bool ShinyHuntAutonomousRegigigas2::Tracker::run_away(){ +bool ShinyHuntAutonomousRegigigas2::Tracker::run_away(bool confirmed_encounter){ RaidCatchDetector detector(m_console, std::chrono::seconds(30)); - pbf_mash_button(BUTTON_A, 4 * TICKS_PER_SECOND); + pbf_mash_button(m_console, BUTTON_A, 4 * TICKS_PER_SECOND); if (!detector.wait(m_env)){ m_env.log("Raid Catch Menu not found.", Qt::red); return false; } - pbf_press_dpad(DPAD_DOWN, 10, 0); - pbf_press_button(BUTTON_A, 10, m_exit_battle_time); + pbf_press_dpad(m_console, DPAD_DOWN, 10, 0); + pbf_press_button(m_console, BUTTON_A, 10, m_exit_battle_time); return true; } bool ShinyHuntAutonomousRegigigas2::kill_and_return(SingleSwitchProgramEnvironment& env) const{ RaidCatchDetector detector(env.console, std::chrono::seconds(30)); - pbf_mash_button(BUTTON_A, 4 * TICKS_PER_SECOND); + pbf_mash_button(env.console, BUTTON_A, 4 * TICKS_PER_SECOND); if (!detector.wait(env)){ env.log("Raid Catch Menu not found.", Qt::red); return false; } - pbf_press_dpad(DPAD_DOWN, 10, 0); - pbf_press_button(BUTTON_A, 10, CATCH_TO_OVERWORLD_DELAY); + pbf_press_dpad(env.console, DPAD_DOWN, 10, 0); + pbf_press_button(env.console, BUTTON_A, 10, CATCH_TO_OVERWORLD_DELAY); return true; } -void ShinyHuntAutonomousRegigigas2::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); +void ShinyHuntAutonomousRegigigas2::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); - uint32_t last_touch = system_clock(); + uint32_t last_touch = system_clock(env.console); if (TOUCH_DATE_INTERVAL > 0){ - touch_date_from_home(SETTINGS_TO_HOME_DELAY); + touch_date_from_home(env.console, SETTINGS_TO_HOME_DELAY); } - resume_game_back_out(TOLERATE_SYSTEM_UPDATE_MENU_FAST, 500); + resume_game_back_out(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST, 500); Stats& stats = env.stats(); Tracker tracker( @@ -156,12 +171,12 @@ void ShinyHuntAutonomousRegigigas2::program(SingleSwitchProgramEnvironment& env) env.log("Starting Regigigas Encounter: " + tostr_u_commas(stats.encounters() + 1)); - pbf_mash_button(BUTTON_A, 18 * TICKS_PER_SECOND); + pbf_mash_button(env.console, BUTTON_A, 18 * TICKS_PER_SECOND); env.console.botbase().wait_for_all_requests(); - { - StartBattleDetector detector(env.console, std::chrono::seconds(30)); - detector.wait(env); + if (!wait_for_start_battle(env, env.console, std::chrono::seconds(30))){ + stats.m_timeouts++; + break; } ShinyDetection detection = detect_shiny_battle( @@ -173,15 +188,15 @@ void ShinyHuntAutonomousRegigigas2::program(SingleSwitchProgramEnvironment& env) if (tracker.process_result(detection)){ goto StopProgram; } - if (detection == ShinyDetection::NO_BATTLE_MENU || !tracker.run_away()){ + if (detection == ShinyDetection::NO_BATTLE_MENU || !tracker.run_away(false)){ stats.m_timeouts++; break; } } - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - if (TOUCH_DATE_INTERVAL > 0 && system_clock() - last_touch >= TOUCH_DATE_INTERVAL){ - touch_date_from_home(SETTINGS_TO_HOME_DELAY); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + if (TOUCH_DATE_INTERVAL > 0 && system_clock(env.console) - last_touch >= TOUCH_DATE_INTERVAL){ + touch_date_from_home(env.console, SETTINGS_TO_HOME_DELAY); last_touch += TOUCH_DATE_INTERVAL; } reset_game_from_home_with_inference( @@ -195,11 +210,11 @@ void ShinyHuntAutonomousRegigigas2::program(SingleSwitchProgramEnvironment& env) env.update_stats(); if (GO_HOME_WHEN_DONE){ - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); } - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regigigas2.h b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regigigas2.h index 403c852a2b..fe397bc716 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regigigas2.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Regigigas2.h @@ -18,12 +18,20 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class ShinyHuntAutonomousRegigigas2 : public SingleSwitchProgram{ + +class ShinyHuntAutonomousRegigigas2_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + ShinyHuntAutonomousRegigigas2_Descriptor(); +}; + + + +class ShinyHuntAutonomousRegigigas2 : public SingleSwitchProgramInstance{ public: - ShinyHuntAutonomousRegigigas2(); + ShinyHuntAutonomousRegigigas2(const ShinyHuntAutonomousRegigigas2_Descriptor& descriptor); virtual std::unique_ptr make_stats() const override; - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: bool kill_and_return(SingleSwitchProgramEnvironment& env) const; @@ -40,7 +48,7 @@ class ShinyHuntAutonomousRegigigas2 : public SingleSwitchProgram{ bool take_video, bool run_from_everything ); - virtual bool run_away() override; + virtual bool run_away(bool confirmed_encounter) override; ProgramEnvironment& m_env; }; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-StrongSpawn.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-StrongSpawn.cpp index 46b38f0d0a..582db5e05c 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-StrongSpawn.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-StrongSpawn.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/FrameworkSettings.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSettings.h" @@ -21,13 +21,21 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ -ShinyHuntAutonomousStrongSpawn::ShinyHuntAutonomousStrongSpawn() - : SingleSwitchProgram( - FeedbackType::REQUIRED, PABotBaseLevel::PABOTBASE_12KB, +ShinyHuntAutonomousStrongSpawn_Descriptor::ShinyHuntAutonomousStrongSpawn_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:ShinyHuntAutonomousStrongSpawn", "Shiny Hunt Autonomous - Strong Spawn", "SerialPrograms/ShinyHuntAutonomous-StrongSpawn.md", - "Automatically hunt for shiny strong spawns using video feedback." + "Automatically hunt for shiny strong spawns using video feedback.", + FeedbackType::REQUIRED, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +ShinyHuntAutonomousStrongSpawn::ShinyHuntAutonomousStrongSpawn(const ShinyHuntAutonomousStrongSpawn_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , GO_HOME_WHEN_DONE( "Go Home when Done:
After finding a shiny, go to the Switch Home menu to idle. (turn this off for unattended streaming)", false @@ -39,10 +47,6 @@ ShinyHuntAutonomousStrongSpawn::ShinyHuntAutonomousStrongSpawn() , m_advanced_options( "Advanced Options: You should not need to touch anything below here." ) - , EXIT_BATTLE_MASH_TIME( - "Exit Battle Time:
After running, wait this long to return to overworld.", - "6 * TICKS_PER_SECOND" - ) , VIDEO_ON_SHINY( "Video Capture:
Take a video of the encounter if it is shiny.", true @@ -54,9 +58,8 @@ ShinyHuntAutonomousStrongSpawn::ShinyHuntAutonomousStrongSpawn() { m_options.emplace_back(&GO_HOME_WHEN_DONE, "GO_HOME_WHEN_DONE"); m_options.emplace_back(&TIME_ROLLBACK_HOURS, "TIME_ROLLBACK_HOURS"); - m_options.emplace_back(&m_advanced_options, ""); - m_options.emplace_back(&EXIT_BATTLE_MASH_TIME, "EXIT_BATTLE_MASH_TIME"); - if (settings.developer_mode){ + if (PERSISTENT_SETTINGS().developer_mode){ + m_options.emplace_back(&m_advanced_options, ""); m_options.emplace_back(&VIDEO_ON_SHINY, "VIDEO_ON_SHINY"); m_options.emplace_back(&RUN_FROM_EVERYTHING, "RUN_FROM_EVERYTHING"); } @@ -82,33 +85,41 @@ std::unique_ptr ShinyHuntAutonomousStrongSpawn::make_stats() const ShinyHuntAutonomousStrongSpawn::Tracker::Tracker( ShinyHuntTracker& stats, + ProgramEnvironment& env, ConsoleHandle& console, bool take_video, bool run_from_everything ) - : StandardEncounterTracker(stats, console, false, 0, take_video, run_from_everything) + : StandardEncounterTracker( + stats, env, console, + nullptr, Language::None, + false, + 0, + take_video, + run_from_everything + ) {} -bool ShinyHuntAutonomousStrongSpawn::Tracker::run_away(){ - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); +bool ShinyHuntAutonomousStrongSpawn::Tracker::run_away(bool confirmed_encounter){ + pbf_press_button(m_console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); return true; } -void ShinyHuntAutonomousStrongSpawn::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); -// resume_game_no_interact(TOLERATE_SYSTEM_UPDATE_MENU_FAST); +void ShinyHuntAutonomousStrongSpawn::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); +// resume_game_no_interact(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST); const uint32_t PERIOD = (uint32_t)TIME_ROLLBACK_HOURS * 3600 * TICKS_PER_SECOND; - uint32_t last_touch = system_clock(); + uint32_t last_touch = system_clock(env.console); Stats& stats = env.stats(); - Tracker tracker(stats, env.console, VIDEO_ON_SHINY, RUN_FROM_EVERYTHING); + Tracker tracker(stats, env, env.console, VIDEO_ON_SHINY, RUN_FROM_EVERYTHING); while (true){ env.update_stats(); - uint32_t now = system_clock(); + uint32_t now = system_clock(env.console); if (TIME_ROLLBACK_HOURS > 0 && now - last_touch >= PERIOD){ - rollback_hours_from_home(TIME_ROLLBACK_HOURS, SETTINGS_TO_HOME_DELAY); + rollback_hours_from_home(env.console, TIME_ROLLBACK_HOURS, SETTINGS_TO_HOME_DELAY); last_touch += PERIOD; } reset_game_from_home_with_inference( @@ -130,18 +141,18 @@ void ShinyHuntAutonomousStrongSpawn::program(SingleSwitchProgramEnvironment& env } if (detection == ShinyDetection::NO_BATTLE_MENU){ stats.m_timeouts++; - tracker.run_away(); + tracker.run_away(false); } } env.update_stats(); if (GO_HOME_WHEN_DONE){ - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); } - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-StrongSpawn.h b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-StrongSpawn.h index 5186d233ac..81036b8c68 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-StrongSpawn.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-StrongSpawn.h @@ -18,29 +18,37 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class ShinyHuntAutonomousStrongSpawn : public SingleSwitchProgram{ + +class ShinyHuntAutonomousStrongSpawn_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + ShinyHuntAutonomousStrongSpawn_Descriptor(); +}; + + + +class ShinyHuntAutonomousStrongSpawn : public SingleSwitchProgramInstance{ public: - ShinyHuntAutonomousStrongSpawn(); + ShinyHuntAutonomousStrongSpawn(const ShinyHuntAutonomousStrongSpawn_Descriptor& descriptor); virtual std::unique_ptr make_stats() const override; - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: struct Stats; struct Tracker : public StandardEncounterTracker{ Tracker( ShinyHuntTracker& stats, + ProgramEnvironment& env, ConsoleHandle& console, bool take_video, bool run_from_everything ); - virtual bool run_away() override; + virtual bool run_away(bool confirmed_encounter) override; }; BooleanCheckBox GO_HOME_WHEN_DONE; SimpleInteger TIME_ROLLBACK_HOURS; SectionDivider m_advanced_options; - TimeExpression EXIT_BATTLE_MASH_TIME; BooleanCheckBox VIDEO_ON_SHINY; BooleanCheckBox RUN_FROM_EVERYTHING; }; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-SwordsOfJustice.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-SwordsOfJustice.cpp index 9fd57fd17b..0bc73a938e 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-SwordsOfJustice.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-SwordsOfJustice.cpp @@ -4,13 +4,16 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/FrameworkSettings.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSettings.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" #include "Common/PokemonSwSh/PokemonSwShDateSpam.h" #include "CommonFramework/PersistentSettings.h" +#include "CommonFramework/Inference/VisualInferenceWait.h" +#include "PokemonSwSh/Inference/PokemonSwSh_StartBattleDetector.h" +#include "PokemonSwSh/Inference/PokemonSwSh_BattleMenuDetector.h" #include "PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_ShinyEncounterDetector.h" #include "PokemonSwSh_EncounterTracker.h" #include "PokemonSwSh_ShinyHuntAutonomous-SwordsOfJustice.h" @@ -20,13 +23,21 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ -ShinyHuntAutonomousSwordsOfJustice::ShinyHuntAutonomousSwordsOfJustice() - : SingleSwitchProgram( - FeedbackType::REQUIRED, PABotBaseLevel::PABOTBASE_12KB, +ShinyHuntAutonomousSwordsOfJustice_Descriptor::ShinyHuntAutonomousSwordsOfJustice_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:ShinyHuntAutonomousSwordsOfJustice", "Shiny Hunt Autonomous - Swords Of Justice", "SerialPrograms/ShinyHuntAutonomous-SwordsOfJustice.md", - "Automatically hunt for shiny Sword of Justice using video feedback." + "Automatically hunt for shiny Sword of Justice using video feedback.", + FeedbackType::REQUIRED, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +ShinyHuntAutonomousSwordsOfJustice::ShinyHuntAutonomousSwordsOfJustice(const ShinyHuntAutonomousSwordsOfJustice_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , GO_HOME_WHEN_DONE( "Go Home when Done:
After finding a shiny, go to the Switch Home menu to idle. (turn this off for unattended streaming)", false @@ -42,9 +53,13 @@ ShinyHuntAutonomousSwordsOfJustice::ShinyHuntAutonomousSwordsOfJustice() , m_advanced_options( "Advanced Options: You should not need to touch anything below here." ) - , EXIT_BATTLE_MASH_TIME( - "Exit Battle Time:
After running, wait this long to return to overworld.", - "6 * TICKS_PER_SECOND" + , EXIT_BATTLE_TIMEOUT( + "Exit Battle Timeout:
After running, wait this long to return to overworld.", + "10 * TICKS_PER_SECOND" + ) + , POST_BATTLE_MASH_TIME( + "Post-Battle Mash:
After each battle, mash B for this long before entering the camp.", + "1 * TICKS_PER_SECOND" ) , ENTER_CAMP_DELAY( "Enter Camp Delay:", @@ -63,9 +78,10 @@ ShinyHuntAutonomousSwordsOfJustice::ShinyHuntAutonomousSwordsOfJustice() m_options.emplace_back(&AIRPLANE_MODE, "AIRPLANE_MODE"); m_options.emplace_back(&TIME_ROLLBACK_HOURS, "TIME_ROLLBACK_HOURS"); m_options.emplace_back(&m_advanced_options, ""); - m_options.emplace_back(&EXIT_BATTLE_MASH_TIME, "EXIT_BATTLE_MASH_TIME"); + m_options.emplace_back(&EXIT_BATTLE_TIMEOUT, "EXIT_BATTLE_TIMEOUT"); + m_options.emplace_back(&POST_BATTLE_MASH_TIME, "POST_BATTLE_MASH_TIME"); m_options.emplace_back(&ENTER_CAMP_DELAY, "ENTER_CAMP_DELAY"); - if (settings.developer_mode){ + if (PERSISTENT_SETTINGS().developer_mode){ m_options.emplace_back(&VIDEO_ON_SHINY, "VIDEO_ON_SHINY"); m_options.emplace_back(&RUN_FROM_EVERYTHING, "RUN_FROM_EVERYTHING"); } @@ -89,18 +105,19 @@ std::unique_ptr ShinyHuntAutonomousSwordsOfJustice::make_stats() c -void ShinyHuntAutonomousSwordsOfJustice::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); - resume_game_no_interact(TOLERATE_SYSTEM_UPDATE_MENU_FAST); +void ShinyHuntAutonomousSwordsOfJustice::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + resume_game_no_interact(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST); const uint32_t PERIOD = (uint32_t)TIME_ROLLBACK_HOURS * 3600 * TICKS_PER_SECOND; - uint32_t last_touch = system_clock(); + uint32_t last_touch = system_clock(env.console); Stats& stats = env.stats(); StandardEncounterTracker tracker( - stats, env.console, + stats, env, env.console, + nullptr, Language::None, false, - EXIT_BATTLE_MASH_TIME, + EXIT_BATTLE_TIMEOUT, VIDEO_ON_SHINY, RUN_FROM_EVERYTHING ); @@ -109,26 +126,37 @@ void ShinyHuntAutonomousSwordsOfJustice::program(SingleSwitchProgramEnvironment& env.update_stats(); // Touch the date. - if (TIME_ROLLBACK_HOURS > 0 && system_clock() - last_touch >= PERIOD){ - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - rollback_hours_from_home(TIME_ROLLBACK_HOURS, SETTINGS_TO_HOME_DELAY); - resume_game_no_interact(TOLERATE_SYSTEM_UPDATE_MENU_FAST); + if (TIME_ROLLBACK_HOURS > 0 && system_clock(env.console) - last_touch >= PERIOD){ + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + rollback_hours_from_home(env.console, TIME_ROLLBACK_HOURS, SETTINGS_TO_HOME_DELAY); + resume_game_no_interact(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST); last_touch += PERIOD; } // Trigger encounter. - pbf_press_button(BUTTON_X, 10, OVERWORLD_TO_MENU_DELAY); - pbf_press_button(BUTTON_A, 10, ENTER_CAMP_DELAY); + pbf_mash_button(env.console, BUTTON_B, POST_BATTLE_MASH_TIME); + pbf_press_button(env.console, BUTTON_X, 10, OVERWORLD_TO_MENU_DELAY); + pbf_press_button(env.console, BUTTON_A, 10, ENTER_CAMP_DELAY); if (AIRPLANE_MODE){ - pbf_press_button(BUTTON_A, 10, 100); - pbf_press_button(BUTTON_A, 10, 100); + pbf_press_button(env.console, BUTTON_A, 10, 100); + pbf_press_button(env.console, BUTTON_A, 10, 100); } - pbf_press_button(BUTTON_X, 10, 50); - pbf_press_dpad(DPAD_LEFT, 10, 10); + pbf_press_button(env.console, BUTTON_X, 10, 50); + pbf_press_dpad(env.console, DPAD_LEFT, 10, 10); env.log("Starting Encounter: " + tostr_u_commas(stats.encounters() + 1)); - pbf_press_button(BUTTON_A, 10, 0); + pbf_press_button(env.console, BUTTON_A, 10, 0); env.console.botbase().wait_for_all_requests(); + { + // Wait for start of battle. + StandardBattleMenuDetector battle_menu_detector(env.console); + StartBattleDetector start_back_detector(env.console); + VisualInferenceWait inference(env, env.console, std::chrono::seconds(30)); + inference += battle_menu_detector; + inference += start_back_detector; + inference.run(); + } + // Detect shiny. ShinyDetection detection = detect_shiny_battle( env, env.console, @@ -141,19 +169,19 @@ void ShinyHuntAutonomousSwordsOfJustice::program(SingleSwitchProgramEnvironment& } if (detection == ShinyDetection::NO_BATTLE_MENU){ stats.m_timeouts++; - pbf_mash_button(BUTTON_B, TICKS_PER_SECOND); - tracker.run_away(); + pbf_mash_button(env.console, BUTTON_B, TICKS_PER_SECOND); + tracker.run_away(false); } } env.update_stats(); if (GO_HOME_WHEN_DONE){ - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); } - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-SwordsOfJustice.h b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-SwordsOfJustice.h index 4fc0d14c36..ff187cb874 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-SwordsOfJustice.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-SwordsOfJustice.h @@ -17,12 +17,20 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class ShinyHuntAutonomousSwordsOfJustice : public SingleSwitchProgram{ + +class ShinyHuntAutonomousSwordsOfJustice_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + ShinyHuntAutonomousSwordsOfJustice_Descriptor(); +}; + + + +class ShinyHuntAutonomousSwordsOfJustice : public SingleSwitchProgramInstance{ public: - ShinyHuntAutonomousSwordsOfJustice(); + ShinyHuntAutonomousSwordsOfJustice(const ShinyHuntAutonomousSwordsOfJustice_Descriptor& descriptor); virtual std::unique_ptr make_stats() const override; - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: struct Stats; @@ -31,7 +39,8 @@ class ShinyHuntAutonomousSwordsOfJustice : public SingleSwitchProgram{ BooleanCheckBox AIRPLANE_MODE; SimpleInteger TIME_ROLLBACK_HOURS; SectionDivider m_advanced_options; - TimeExpression EXIT_BATTLE_MASH_TIME; + TimeExpression EXIT_BATTLE_TIMEOUT; + TimeExpression POST_BATTLE_MASH_TIME; TimeExpression ENTER_CAMP_DELAY; BooleanCheckBox VIDEO_ON_SHINY; BooleanCheckBox RUN_FROM_EVERYTHING; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Whistling.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Whistling.cpp index a23d482a27..d5267f49d8 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Whistling.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Whistling.cpp @@ -4,13 +4,15 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/FrameworkSettings.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSettings.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" #include "Common/PokemonSwSh/PokemonSwShDateSpam.h" #include "CommonFramework/PersistentSettings.h" +#include "CommonFramework/Tools/InterruptableCommands.h" +#include "CommonFramework/Inference/VisualInferenceSession.h" #include "PokemonSwSh/Inference/PokemonSwSh_StartBattleDetector.h" #include "PokemonSwSh/Inference/PokemonSwSh_BattleMenuDetector.h" #include "PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_ShinyEncounterDetector.h" @@ -22,17 +24,29 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ -ShinyHuntAutonomousWhistling::ShinyHuntAutonomousWhistling() - : SingleSwitchProgram( - FeedbackType::REQUIRED, PABotBaseLevel::PABOTBASE_12KB, +ShinyHuntAutonomousWhistling_Descriptor::ShinyHuntAutonomousWhistling_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:ShinyHuntAutonomousWhistling", "Shiny Hunt Autonomous - Whistling", "SerialPrograms/ShinyHuntAutonomous-Whistling.md", - "Stand in one place and whistle. Shiny hunt everything that attacks you using video feedback." + "Stand in one place and whistle. Shiny hunt everything that attacks you using video feedback.", + FeedbackType::REQUIRED, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +ShinyHuntAutonomousWhistling::ShinyHuntAutonomousWhistling(const ShinyHuntAutonomousWhistling_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , GO_HOME_WHEN_DONE( "Go Home when Done:
After finding a shiny, go to the Switch Home menu to idle. (turn this off for unattended streaming)", false ) + , LANGUAGE( + "Game Language:
Attempt to read and log the encountered " + STRING_POKEMON + " in this language.
Set to \"None\" to disable this feature.", + m_name_reader.languages(), false + ) , TIME_ROLLBACK_HOURS( "Time Rollback (in hours):
Periodically roll back the time to keep the weather the same. If set to zero, this feature is disabled.", 1, 0, 11 @@ -40,9 +54,9 @@ ShinyHuntAutonomousWhistling::ShinyHuntAutonomousWhistling() , m_advanced_options( "Advanced Options: You should not need to touch anything below here." ) - , EXIT_BATTLE_MASH_TIME( - "Exit Battle Time:
After running, wait this long to return to overworld.", - "6 * TICKS_PER_SECOND" + , EXIT_BATTLE_TIMEOUT( + "Exit Battle Timeout:
After running, wait this long to return to overworld.", + "10 * TICKS_PER_SECOND" ) , VIDEO_ON_SHINY( "Video Capture:
Take a video of the encounter if it is shiny.", @@ -54,10 +68,11 @@ ShinyHuntAutonomousWhistling::ShinyHuntAutonomousWhistling() ) { m_options.emplace_back(&GO_HOME_WHEN_DONE, "GO_HOME_WHEN_DONE"); + m_options.emplace_back(&LANGUAGE, "LANGUAGE"); m_options.emplace_back(&TIME_ROLLBACK_HOURS, "TIME_ROLLBACK_HOURS"); m_options.emplace_back(&m_advanced_options, ""); - m_options.emplace_back(&EXIT_BATTLE_MASH_TIME, "EXIT_BATTLE_MASH_TIME"); - if (settings.developer_mode){ + m_options.emplace_back(&EXIT_BATTLE_TIMEOUT, "EXIT_BATTLE_TIMEOUT"); + if (PERSISTENT_SETTINGS().developer_mode){ m_options.emplace_back(&VIDEO_ON_SHINY, "VIDEO_ON_SHINY"); m_options.emplace_back(&RUN_FROM_EVERYTHING, "RUN_FROM_EVERYTHING"); } @@ -85,18 +100,19 @@ std::unique_ptr ShinyHuntAutonomousWhistling::make_stats() const{ -void ShinyHuntAutonomousWhistling::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); - resume_game_back_out(TOLERATE_SYSTEM_UPDATE_MENU_FAST, 200); +void ShinyHuntAutonomousWhistling::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + resume_game_back_out(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST, 200); const uint32_t PERIOD = (uint32_t)TIME_ROLLBACK_HOURS * 3600 * TICKS_PER_SECOND; - uint32_t last_touch = system_clock(); + uint32_t last_touch = system_clock(env.console); Stats& stats = env.stats(); StandardEncounterTracker tracker( - stats, env.console, + stats, env, env.console, + &m_name_reader, LANGUAGE, false, - EXIT_BATTLE_MASH_TIME, + EXIT_BATTLE_TIMEOUT, VIDEO_ON_SHINY, RUN_FROM_EVERYTHING ); @@ -105,40 +121,44 @@ void ShinyHuntAutonomousWhistling::program(SingleSwitchProgramEnvironment& env) env.update_stats(); // Touch the date. - if (TIME_ROLLBACK_HOURS > 0 && system_clock() - last_touch >= PERIOD){ - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - rollback_hours_from_home(TIME_ROLLBACK_HOURS, SETTINGS_TO_HOME_DELAY); - resume_game_no_interact(TOLERATE_SYSTEM_UPDATE_MENU_FAST); + if (TIME_ROLLBACK_HOURS > 0 && system_clock(env.console) - last_touch >= PERIOD){ + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + rollback_hours_from_home(env.console, TIME_ROLLBACK_HOURS, SETTINGS_TO_HOME_DELAY); + resume_game_no_interact(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST); last_touch += PERIOD; } env.console.botbase().wait_for_all_requests(); { - StandardBattleMenuDetector menu(env.console); - StartBattleDetector detector(env.console, std::chrono::seconds(0)); - - // Detect start of battle. - bool unexpected = false; - QImage screen; - do{ - screen = env.console.video().snapshot(); - if (menu.detect(screen)){ - env.log("ScreenChangeDetector: Unexpected battle menu.", Qt::red); - stats.m_unexpected_battles++; - unexpected = true; - break; + InterruptableCommandSession commands(env.console); + + StandardBattleMenuDetector battle_menu_detector(env.console); + battle_menu_detector.register_command_stop(commands); + + StartBattleDetector start_battle_detector(env.console); + start_battle_detector.register_command_stop(commands); + + AsyncVisualInferenceSession inference(env, env.console); + inference += battle_menu_detector; + inference += start_battle_detector; + + commands.run([](const BotBaseContext& context){ + while (true){ + pbf_mash_button(context, BUTTON_LCLICK, TICKS_PER_SECOND); + pbf_move_right_joystick(context, 192, 128, TICKS_PER_SECOND, 0); } - pbf_mash_button(BUTTON_LCLICK, 10); - pbf_move_right_joystick(192, 128, 10, 0); - env.console.botbase().wait_for_all_requests(); - }while (!detector.detect(screen)); - - if (unexpected){ - pbf_mash_button(BUTTON_B, TICKS_PER_SECOND); - tracker.run_away(); + }); + + if (battle_menu_detector.triggered()){ + env.log("Unexpected battle menu.", Qt::red); + stats.m_unexpected_battles++; + pbf_mash_button(env.console, BUTTON_B, TICKS_PER_SECOND); + tracker.run_away(false); continue; } - pbf_mash_button(BUTTON_B, 5 * TICKS_PER_SECOND); + if (start_battle_detector.triggered()){ + env.log("Battle started!"); + } } // Detect shiny. @@ -153,19 +173,19 @@ void ShinyHuntAutonomousWhistling::program(SingleSwitchProgramEnvironment& env) } if (detection == ShinyDetection::NO_BATTLE_MENU){ stats.m_timeouts++; - pbf_mash_button(BUTTON_B, TICKS_PER_SECOND); - tracker.run_away(); + pbf_mash_button(env.console, BUTTON_B, TICKS_PER_SECOND); + tracker.run_away(false); } } env.update_stats(); if (GO_HOME_WHEN_DONE){ - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); } - end_program_callback(); - end_program_loop(); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Whistling.h b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Whistling.h index 11a208aa89..98046bfa5b 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Whistling.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntAutonomous-Whistling.h @@ -10,27 +10,41 @@ #include "CommonFramework/Options/SectionDivider.h" #include "CommonFramework/Options/BooleanCheckBox.h" #include "CommonFramework/Options/SimpleInteger.h" +#include "CommonFramework/Options/LanguageOCR.h" #include "NintendoSwitch/Options/TimeExpression.h" #include "NintendoSwitch/Framework/SingleSwitchProgram.h" +#include "Pokemon/Pokemon_NameReader.h" namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class ShinyHuntAutonomousWhistling : public SingleSwitchProgram{ + +class ShinyHuntAutonomousWhistling_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + ShinyHuntAutonomousWhistling_Descriptor(); +}; + + + +class ShinyHuntAutonomousWhistling : public SingleSwitchProgramInstance{ public: - ShinyHuntAutonomousWhistling(); + ShinyHuntAutonomousWhistling(const ShinyHuntAutonomousWhistling_Descriptor& descriptor); virtual std::unique_ptr make_stats() const override; - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: struct Stats; BooleanCheckBox GO_HOME_WHEN_DONE; + + Pokemon::PokemonNameReader m_name_reader; + LanguageOCR LANGUAGE; + SimpleInteger TIME_ROLLBACK_HOURS; SectionDivider m_advanced_options; - TimeExpression EXIT_BATTLE_MASH_TIME; + TimeExpression EXIT_BATTLE_TIMEOUT; BooleanCheckBox VIDEO_ON_SHINY; BooleanCheckBox RUN_FROM_EVERYTHING; }; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntTools.h b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntTools.h index 02d310357b..87a05ebcc9 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntTools.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntTools.h @@ -19,57 +19,57 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -static void run_away_with_lights(void){ - set_leds(true); - pbf_press_dpad(DPAD_UP, 10, 0); - pbf_press_button(BUTTON_A, 10, 3 * TICKS_PER_SECOND); - set_leds(false); +static void run_away_with_lights(const BotBaseContext& context){ + set_leds(context, true); + pbf_press_dpad(context, DPAD_UP, 10, 0); + pbf_press_button(context, BUTTON_A, 10, 3 * TICKS_PER_SECOND); + set_leds(context, false); } -static void enter_summary(bool regi_move_right){ - pbf_press_dpad(DPAD_DOWN, 10, 0); - pbf_press_button(BUTTON_A, 10, 2 * TICKS_PER_SECOND); - pbf_press_button(BUTTON_A, 10, 200); +static void enter_summary(const BotBaseContext& context, bool regi_move_right){ + pbf_press_dpad(context, DPAD_DOWN, 10, 0); + pbf_press_button(context, BUTTON_A, 10, 2 * TICKS_PER_SECOND); + pbf_press_button(context, BUTTON_A, 10, 200); if (regi_move_right){ - pbf_move_left_joystick(255, 128, 20, 30); + pbf_move_left_joystick(context, 255, 128, 20, 30); } - pbf_press_dpad(DPAD_DOWN, 10, 0); - pbf_press_button(BUTTON_A, 10, 10); // For Regi, this clears the dialog after running. + pbf_press_dpad(context, DPAD_DOWN, 10, 0); + pbf_press_button(context, BUTTON_A, 10, 10); // For Regi, this clears the dialog after running. } -static void close_game_if_overworld(bool touch_date, uint8_t rollback_hours){ +static void close_game_if_overworld(const BotBaseContext& context, bool touch_date, uint8_t rollback_hours){ // Enter Y-COMM. - ssf_press_button2(BUTTON_Y, OPEN_YCOMM_DELAY, 10); + ssf_press_button2(context, BUTTON_Y, OPEN_YCOMM_DELAY, 10); // Move the cursor as far away from Link Trade and Surprise Trade as possible. // This is added safety in case connect to internet takes too long. - pbf_press_dpad(DPAD_UP, 5, 0); - pbf_move_right_joystick(128, 0, 5, 0); - pbf_press_dpad(DPAD_RIGHT, 5, 0); + pbf_press_dpad(context, DPAD_UP, 5, 0); + pbf_move_right_joystick(context, 128, 0, 5, 0); + pbf_press_dpad(context, DPAD_RIGHT, 5, 0); // Connect to internet. - pbf_press_button(BUTTON_PLUS, 10, TICKS_PER_SECOND); + pbf_press_button(context, BUTTON_PLUS, 10, TICKS_PER_SECOND); // Enter Switch Home. - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + pbf_press_button(context, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); if (touch_date){ - touch_date_from_home(SETTINGS_TO_HOME_DELAY); + touch_date_from_home(context, SETTINGS_TO_HOME_DELAY); } if (rollback_hours > 0){ - rollback_hours_from_home(rollback_hours, SETTINGS_TO_HOME_DELAY); + rollback_hours_from_home(context, rollback_hours, SETTINGS_TO_HOME_DELAY); } // Enter profile. - pbf_press_dpad(DPAD_UP, 10, 10); - pbf_press_button(BUTTON_A, 10, ENTER_PROFILE_DELAY); + pbf_press_dpad(context, DPAD_UP, 10, 10); + pbf_press_button(context, BUTTON_A, 10, ENTER_PROFILE_DELAY); // Back out. - pbf_press_dpad(DPAD_LEFT, 10, 10); - pbf_press_button(BUTTON_B, 10, TICKS_PER_SECOND); - pbf_press_dpad(DPAD_DOWN, 10, 10); + pbf_press_dpad(context, DPAD_LEFT, 10, 10); + pbf_press_button(context, BUTTON_B, 10, TICKS_PER_SECOND); + pbf_press_dpad(context, DPAD_DOWN, 10, 10); // Close and restart game. - close_game(); - pbf_press_button(BUTTON_HOME, 10, 190); + close_game(context); + pbf_press_button(context, BUTTON_HOME, 10, 190); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-IoATrade.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-IoATrade.cpp index e80f879ac6..068b285c8c 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-IoATrade.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-IoATrade.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSettings.h" #include "Common/PokemonSwSh/PokemonSwShMisc.h" @@ -16,13 +16,21 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ -ShinyHuntUnattendedIoATrade::ShinyHuntUnattendedIoATrade() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_31KB, +ShinyHuntUnattendedIoATrade_Descriptor::ShinyHuntUnattendedIoATrade_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:ShinyHuntUnattendedIoATrade", "Shiny Hunt Unattended - IoA Trade", "NativePrograms/ShinyHuntUnattended-IoATrade.md", - "Hunt for shiny Isle of Armor trade. Stop when a shiny is found." + "Hunt for shiny Isle of Armor trade. Stop when a shiny is found.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_31KB ) +{} + + + +ShinyHuntUnattendedIoATrade::ShinyHuntUnattendedIoATrade(const ShinyHuntUnattendedIoATrade_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , START_TO_RUN_DELAY( "Start to Run Delay:
This needs to be carefully calibrated.", "1260" @@ -55,80 +63,80 @@ ShinyHuntUnattendedIoATrade::ShinyHuntUnattendedIoATrade() m_options.emplace_back(&MASH_TO_TRADE_DELAY, "MASH_TO_TRADE_DELAY"); } -void ShinyHuntUnattendedIoATrade::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); - resume_game_back_out(TOLERATE_SYSTEM_UPDATE_MENU_FAST, 500); +void ShinyHuntUnattendedIoATrade::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + resume_game_back_out(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST, 500); - uint32_t last_touch = system_clock() - TOUCH_DATE_INTERVAL; + uint32_t last_touch = system_clock(env.console) - TOUCH_DATE_INTERVAL; for (uint32_t c = 0; ; c++){ env.log("Starting Trade: " + tostr_u_commas(c + 1)); - pbf_press_button(BUTTON_A, 10, 100); - pbf_press_button(BUTTON_A, 10, 60); - pbf_press_button(BUTTON_A, 10, 100); - pbf_press_button(BUTTON_A, 10, 50); - pbf_press_button(BUTTON_A, 10, POKEMON_TO_BOX_DELAY); - pbf_press_dpad(DPAD_LEFT, 10, 10); - pbf_mash_button(BUTTON_A, MASH_TO_TRADE_DELAY); + pbf_press_button(env.console, BUTTON_A, 10, 100); + pbf_press_button(env.console, BUTTON_A, 10, 60); + pbf_press_button(env.console, BUTTON_A, 10, 100); + pbf_press_button(env.console, BUTTON_A, 10, 50); + pbf_press_button(env.console, BUTTON_A, 10, POKEMON_TO_BOX_DELAY); + pbf_press_dpad(env.console, DPAD_LEFT, 10, 10); + pbf_mash_button(env.console, BUTTON_A, MASH_TO_TRADE_DELAY); if (true){ // Enter box system. - pbf_press_button(BUTTON_X, 10, OVERWORLD_TO_MENU_DELAY); - pbf_press_dpad(DPAD_RIGHT, 10, 10); - pbf_press_button(BUTTON_A, 10, MENU_TO_POKEMON_DELAY); + pbf_press_button(env.console, BUTTON_X, 10, OVERWORLD_TO_MENU_DELAY); + pbf_press_dpad(env.console, DPAD_RIGHT, 10, 10); + pbf_press_button(env.console, BUTTON_A, 10, MENU_TO_POKEMON_DELAY); // Move item from 2nd party member to 1st. - pbf_press_button(BUTTON_X, 10, 50); - pbf_press_dpad(DPAD_DOWN, 10, 50); - pbf_press_button(BUTTON_A, 10, 50); - pbf_press_dpad(DPAD_UP, 10, 50); - pbf_press_button(BUTTON_A, 10, 50); + pbf_press_button(env.console, BUTTON_X, 10, 50); + pbf_press_dpad(env.console, DPAD_DOWN, 10, 50); + pbf_press_button(env.console, BUTTON_A, 10, 50); + pbf_press_dpad(env.console, DPAD_UP, 10, 50); + pbf_press_button(env.console, BUTTON_A, 10, 50); // Back out to menu. // Prepend each B press by a DOWN press so that the B gets // swallowed while in the summary. - IoA_backout(POKEMON_TO_MENU_DELAY); + IoA_backout(env.console, POKEMON_TO_MENU_DELAY); // Enter map. - pbf_press_dpad(DPAD_LEFT, 10, 0); - pbf_move_left_joystick(128, 255, 10, 0); + pbf_press_dpad(env.console, DPAD_LEFT, 10, 0); + pbf_move_left_joystick(env.console, 128, 255, 10, 0); }else{ - pbf_press_dpad(DPAD_DOWN, 10, 50); + pbf_press_dpad(env.console, DPAD_DOWN, 10, 50); } - pbf_press_button(BUTTON_A, 10, 350); + pbf_press_button(env.console, BUTTON_A, 10, 350); // Fly to Route 10. - pbf_press_button(BUTTON_L, 10, 100); - pbf_press_button(BUTTON_L, 10, 100); - pbf_press_dpad(DPAD_RIGHT, 15, 10); - pbf_press_dpad(DPAD_DOWN, 30, 10); - pbf_mash_button(BUTTON_A, FLY_DURATION); + pbf_press_button(env.console, BUTTON_L, 10, 100); + pbf_press_button(env.console, BUTTON_L, 10, 100); + pbf_press_dpad(env.console, DPAD_RIGHT, 15, 10); + pbf_press_dpad(env.console, DPAD_DOWN, 30, 10); + pbf_mash_button(env.console, BUTTON_A, FLY_DURATION); // Move to Beartic. - pbf_move_left_joystick(240, 0, MOVE_DURATION, 0); + pbf_move_left_joystick(env.console, 240, 0, MOVE_DURATION, 0); - pbf_wait(START_TO_RUN_DELAY); + pbf_wait(env.console, START_TO_RUN_DELAY); // Run away. - run_away_with_lights(); + run_away_with_lights(env.console); // Enter Pokemon menu if shiny. - enter_summary(false); + enter_summary(env.console, false); // Touch the date and conditional close game. - if (TOUCH_DATE_INTERVAL > 0 && system_clock() - last_touch >= TOUCH_DATE_INTERVAL){ + if (TOUCH_DATE_INTERVAL > 0 && system_clock(env.console) - last_touch >= TOUCH_DATE_INTERVAL){ last_touch += TOUCH_DATE_INTERVAL; - close_game_if_overworld(true, 0); + close_game_if_overworld(env.console, true, 0); }else{ - close_game_if_overworld(false, 0); + close_game_if_overworld(env.console, false, 0); } - start_game_from_home(TOLERATE_SYSTEM_UPDATE_MENU_FAST, 0, 0, false); + start_game_from_home(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST, 0, 0, false); } - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - end_program_callback(); - end_program_loop(); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-IoATrade.h b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-IoATrade.h index 824c9ac9f7..a61986ab3d 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-IoATrade.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-IoATrade.h @@ -15,11 +15,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class ShinyHuntUnattendedIoATrade : public SingleSwitchProgram{ + +class ShinyHuntUnattendedIoATrade_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + ShinyHuntUnattendedIoATrade_Descriptor(); +}; + + + +class ShinyHuntUnattendedIoATrade : public SingleSwitchProgramInstance{ public: - ShinyHuntUnattendedIoATrade(); + ShinyHuntUnattendedIoATrade(const ShinyHuntUnattendedIoATrade_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: TimeExpression START_TO_RUN_DELAY; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regi.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regi.cpp index 718eeaf43e..a50aaf7052 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regi.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regi.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/FrameworkSettings.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSettings.h" @@ -18,13 +18,21 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ -ShinyHuntUnattendedRegi::ShinyHuntUnattendedRegi() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, +ShinyHuntUnattendedRegi_Descriptor::ShinyHuntUnattendedRegi_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:ShinyHuntUnattendedRegi", "Shiny Hunt Unattended - Regi", "NativePrograms/ShinyHuntUnattended-Regi.md", - "Hunt for shiny Regis. Stop when a shiny is found." + "Hunt for shiny Regis. Stop when a shiny is found.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +ShinyHuntUnattendedRegi::ShinyHuntUnattendedRegi(const ShinyHuntUnattendedRegi_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , START_TO_RUN_DELAY( "Start to Run Delay:
This needs to be carefully calibrated.", "1990" @@ -55,14 +63,14 @@ ShinyHuntUnattendedRegi::ShinyHuntUnattendedRegi() -void ShinyHuntUnattendedRegi::program(SingleSwitchProgramEnvironment& env) const{ +void ShinyHuntUnattendedRegi::program(SingleSwitchProgramEnvironment& env){ // BotBase& botbase = env.console; // start_program_flash(CONNECT_CONTROLLER_DELAY); - grip_menu_connect_go_home(); - resume_game_back_out(TOLERATE_SYSTEM_UPDATE_MENU_FAST, 200); + grip_menu_connect_go_home(env.console); + resume_game_back_out(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST, 200); - uint32_t last_touch = system_clock() - TOUCH_DATE_INTERVAL; + uint32_t last_touch = system_clock(env.console) - TOUCH_DATE_INTERVAL; uint16_t correct_count = 0; for (uint32_t c = 0; ; c++){ // Auto-correction. @@ -73,11 +81,11 @@ void ShinyHuntUnattendedRegi::program(SingleSwitchProgramEnvironment& env) const } // Touch the date. - if (TOUCH_DATE_INTERVAL > 0 && system_clock() - last_touch >= TOUCH_DATE_INTERVAL){ + if (TOUCH_DATE_INTERVAL > 0 && system_clock(env.console) - last_touch >= TOUCH_DATE_INTERVAL){ env.log("Touching date to prevent rollover."); - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - touch_date_from_home(SETTINGS_TO_HOME_DELAY); - resume_game_no_interact(TOLERATE_SYSTEM_UPDATE_MENU_FAST); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + touch_date_from_home(env.console, SETTINGS_TO_HOME_DELAY); + resume_game_no_interact(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST); last_touch += TOUCH_DATE_INTERVAL; } @@ -85,28 +93,28 @@ void ShinyHuntUnattendedRegi::program(SingleSwitchProgramEnvironment& env) const // Do the light puzzle. run_regi_light_puzzle(env, REGI_NAME, c); - pbf_press_button(BUTTON_A, 10, 100); - pbf_press_button(BUTTON_A, 10, 100); + pbf_press_button(env.console, BUTTON_A, 10, 100); + pbf_press_button(env.console, BUTTON_A, 10, 100); if (START_TO_RUN_DELAY >= 500){ // Extra A press to fix A parity if the lights were messed up. - pbf_press_button(BUTTON_A, 10, 500); - pbf_press_button(BUTTON_A, 10, START_TO_RUN_DELAY - 500); + pbf_press_button(env.console, BUTTON_A, 10, 500); + pbf_press_button(env.console, BUTTON_A, 10, START_TO_RUN_DELAY - 500); }else{ - pbf_press_button(BUTTON_A, 10, START_TO_RUN_DELAY); + pbf_press_button(env.console, BUTTON_A, 10, START_TO_RUN_DELAY); } // Run away if not shiny. - run_away_with_lights(); + run_away_with_lights(env.console); // Enter Pokemon menu if shiny. - enter_summary(true); + enter_summary(env.console, true); correct_count++; } - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - end_program_callback(); - end_program_loop(); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regi.h b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regi.h index 9158b51fb0..00f8e362c0 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regi.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regi.h @@ -17,11 +17,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class ShinyHuntUnattendedRegi : public SingleSwitchProgram{ + +class ShinyHuntUnattendedRegi_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + ShinyHuntUnattendedRegi_Descriptor(); +}; + + + +class ShinyHuntUnattendedRegi : public SingleSwitchProgramInstance{ public: - ShinyHuntUnattendedRegi(); + ShinyHuntUnattendedRegi(const ShinyHuntUnattendedRegi_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: TimeExpression START_TO_RUN_DELAY; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regigigas2.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regigigas2.cpp index cff9d8f25a..0207862390 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regigigas2.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regigigas2.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSettings.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" @@ -16,13 +16,21 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ -ShinyHuntUnattendedRegigigas2::ShinyHuntUnattendedRegigigas2() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, +ShinyHuntUnattendedRegigigas2_Descriptor::ShinyHuntUnattendedRegigigas2_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:ShinyHuntUnattendedRegigigas2", "Shiny Hunt Unattended - Regigigas2", "NativePrograms/ShinyHuntUnattended-Regigigas2.md", - "A new version of the Regigigas program that is faster." + "A new version of the Regigigas program that is faster.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +ShinyHuntUnattendedRegigigas2::ShinyHuntUnattendedRegigigas2(const ShinyHuntUnattendedRegigigas2_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , REVERSAL_PP( "Reversal PP:
The amount of Reversal PP you are saved with.", 24 @@ -55,57 +63,57 @@ ShinyHuntUnattendedRegigigas2::ShinyHuntUnattendedRegigigas2() m_options.emplace_back(&CATCH_TO_OVERWORLD_DELAY, "CATCH_TO_OVERWORLD_DELAY"); } -void ShinyHuntUnattendedRegigigas2::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); +void ShinyHuntUnattendedRegigigas2::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); - uint32_t last_touch = system_clock(); + uint32_t last_touch = system_clock(env.console); if (TOUCH_DATE_INTERVAL > 0){ - touch_date_from_home(SETTINGS_TO_HOME_DELAY); + touch_date_from_home(env.console, SETTINGS_TO_HOME_DELAY); } - resume_game_back_out(TOLERATE_SYSTEM_UPDATE_MENU_FAST, 500); + resume_game_back_out(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST, 500); uint32_t encounter = 0; while (true){ for (uint8_t pp = REVERSAL_PP; pp > 0; pp--){ env.log("Starting Regigigas Encounter: " + tostr_u_commas(++encounter)); - pbf_press_button(BUTTON_A, 10, 3 * TICKS_PER_SECOND); - pbf_press_button(BUTTON_A, 10, TICKS_PER_SECOND); - pbf_press_button(BUTTON_A, 10, START_TO_ATTACK_DELAY); + pbf_press_button(env.console, BUTTON_A, 10, 3 * TICKS_PER_SECOND); + pbf_press_button(env.console, BUTTON_A, 10, TICKS_PER_SECOND); + pbf_press_button(env.console, BUTTON_A, 10, START_TO_ATTACK_DELAY); - set_leds(true); - pbf_press_button(BUTTON_A, 10, 2 * TICKS_PER_SECOND); - set_leds(false); + set_leds(env.console, true); + pbf_press_button(env.console, BUTTON_A, 10, 2 * TICKS_PER_SECOND); + set_leds(env.console, false); // Enter Pokemon menu if shiny. - pbf_press_dpad(DPAD_DOWN, 10, 0); - pbf_mash_button(BUTTON_A, 2 * TICKS_PER_SECOND); + pbf_press_dpad(env.console, DPAD_DOWN, 10, 0); + pbf_mash_button(env.console, BUTTON_A, 2 * TICKS_PER_SECOND); - pbf_press_dpad(DPAD_DOWN, 10, 0); - pbf_press_button(BUTTON_A, 10, TICKS_PER_SECOND); - pbf_press_dpad(DPAD_DOWN, 10, 0); - pbf_press_button(BUTTON_A, 10, TICKS_PER_SECOND); + pbf_press_dpad(env.console, DPAD_DOWN, 10, 0); + pbf_press_button(env.console, BUTTON_A, 10, TICKS_PER_SECOND); + pbf_press_dpad(env.console, DPAD_DOWN, 10, 0); + pbf_press_button(env.console, BUTTON_A, 10, TICKS_PER_SECOND); - pbf_wait(ATTACK_TO_CATCH_DELAY); - pbf_press_dpad(DPAD_DOWN, 10, 0); - pbf_press_button(BUTTON_A, 10, CATCH_TO_OVERWORLD_DELAY); + pbf_wait(env.console, ATTACK_TO_CATCH_DELAY); + pbf_press_dpad(env.console, DPAD_DOWN, 10, 0); + pbf_press_button(env.console, BUTTON_A, 10, CATCH_TO_OVERWORLD_DELAY); } // Touch the date and conditional close game. - if (TOUCH_DATE_INTERVAL > 0 && system_clock() - last_touch >= TOUCH_DATE_INTERVAL){ + if (TOUCH_DATE_INTERVAL > 0 && system_clock(env.console) - last_touch >= TOUCH_DATE_INTERVAL){ last_touch += TOUCH_DATE_INTERVAL; - close_game_if_overworld(true, 0); + close_game_if_overworld(env.console, true, 0); }else{ - close_game_if_overworld(false, 0); + close_game_if_overworld(env.console, false, 0); } - start_game_from_home(TOLERATE_SYSTEM_UPDATE_MENU_FAST, 0, 0, false); + start_game_from_home(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST, 0, 0, false); } - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - end_program_callback(); - end_program_loop(); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regigigas2.h b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regigigas2.h index b57800e52d..23f1777ed5 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regigigas2.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-Regigigas2.h @@ -16,11 +16,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class ShinyHuntUnattendedRegigigas2 : public SingleSwitchProgram{ + +class ShinyHuntUnattendedRegigigas2_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + ShinyHuntUnattendedRegigigas2_Descriptor(); +}; + + + +class ShinyHuntUnattendedRegigigas2 : public SingleSwitchProgramInstance{ public: - ShinyHuntUnattendedRegigigas2(); + ShinyHuntUnattendedRegigigas2(const ShinyHuntUnattendedRegigigas2_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: SimpleInteger REVERSAL_PP; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-StrongSpawn.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-StrongSpawn.cpp index 4f45ed29b1..3bc53a34e2 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-StrongSpawn.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-StrongSpawn.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSettings.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" @@ -16,13 +16,21 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ -ShinyHuntUnattendedStrongSpawn::ShinyHuntUnattendedStrongSpawn() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, +ShinyHuntUnattendedStrongSpawn_Descriptor::ShinyHuntUnattendedStrongSpawn_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:ShinyHuntUnattendedStrongSpawn", "Shiny Hunt Unattended - Strong Spawn", "NativePrograms/ShinyHuntUnattended-StrongSpawn.md", - "Hunt for shiny strong spawns. Stop when a shiny is found." + "Hunt for shiny strong spawns. Stop when a shiny is found.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + + +ShinyHuntUnattendedStrongSpawn::ShinyHuntUnattendedStrongSpawn(const ShinyHuntUnattendedStrongSpawn_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , ENTER_GAME_TO_RUN_DELAY( "Enter Game to Run Delay:
This needs to be carefully calibrated.", "2280" @@ -43,23 +51,23 @@ ShinyHuntUnattendedStrongSpawn::ShinyHuntUnattendedStrongSpawn() -void ShinyHuntUnattendedStrongSpawn::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); -// resume_game_no_interact(false); +void ShinyHuntUnattendedStrongSpawn::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); +// resume_game_no_interact(env.console, false); const uint32_t PERIOD = (uint32_t)TIME_ROLLBACK_HOURS * 3600 * TICKS_PER_SECOND; - uint32_t last_touch = system_clock(); + uint32_t last_touch = system_clock(env.console); for (uint32_t c = 0; ; c++){ // If the update menu isn't there, these will get swallowed by the opening // animation for the select user menu. if (TOLERATE_SYSTEM_UPDATE_MENU_FAST){ - pbf_press_button(BUTTON_A, 5, 35); // Choose game - pbf_press_dpad(DPAD_UP, 5, 0); // Skip the update window. + pbf_press_button(env.console, BUTTON_A, 5, 35); // Choose game + pbf_press_dpad(env.console, DPAD_UP, 5, 0); // Skip the update window. } - pbf_press_button(BUTTON_A, 10, 180); // Enter select user menu. - pbf_press_button(BUTTON_A, 10, 10); // Enter game + pbf_press_button(env.console, BUTTON_A, 10, 180); // Enter select user menu. + pbf_press_button(env.console, BUTTON_A, 10, 10); // Enter game // Switch to mashing ZR instead of A to get into the game. // Mash your way into the game. @@ -68,35 +76,35 @@ void ShinyHuntUnattendedStrongSpawn::program(SingleSwitchProgramEnvironment& env // Need to wait a bit longer for the internet check. duration += START_GAME_INTERNET_CHECK_DELAY; } - pbf_mash_button(BUTTON_ZR, duration); + pbf_mash_button(env.console, BUTTON_ZR, duration); // Wait for game to start. - pbf_wait(START_GAME_WAIT_DELAY); + pbf_wait(env.console, START_GAME_WAIT_DELAY); // Enter game. env.log("Starting Encounter: " + tostr_u_commas(c + 1)); - pbf_press_button(BUTTON_A, 10, ENTER_GAME_TO_RUN_DELAY); + pbf_press_button(env.console, BUTTON_A, 10, ENTER_GAME_TO_RUN_DELAY); // Run away. - run_away_with_lights(); + run_away_with_lights(env.console); // Enter Pokemon menu if shiny. - enter_summary(false); + enter_summary(env.console, false); // Touch the date and conditional close game. // if (true){ - if (TIME_ROLLBACK_HOURS > 0 && system_clock() - last_touch >= PERIOD){ + if (TIME_ROLLBACK_HOURS > 0 && system_clock(env.console) - last_touch >= PERIOD){ last_touch += PERIOD; - close_game_if_overworld(false, TIME_ROLLBACK_HOURS); + close_game_if_overworld(env.console, false, TIME_ROLLBACK_HOURS); }else{ - close_game_if_overworld(false, 0); + close_game_if_overworld(env.console, false, 0); } } - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - end_program_callback(); - end_program_loop(); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-StrongSpawn.h b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-StrongSpawn.h index fb6e84c960..dfb614d585 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-StrongSpawn.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-StrongSpawn.h @@ -17,11 +17,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class ShinyHuntUnattendedStrongSpawn : public SingleSwitchProgram{ + +class ShinyHuntUnattendedStrongSpawn_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + ShinyHuntUnattendedStrongSpawn_Descriptor(); +}; + + + +class ShinyHuntUnattendedStrongSpawn : public SingleSwitchProgramInstance{ public: - ShinyHuntUnattendedStrongSpawn(); + ShinyHuntUnattendedStrongSpawn(const ShinyHuntUnattendedStrongSpawn_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: TimeExpression ENTER_GAME_TO_RUN_DELAY; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-SwordsOfJustice.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-SwordsOfJustice.cpp index 46845b0770..d84521f1ea 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-SwordsOfJustice.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-SwordsOfJustice.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Clientside/PrettyPrint.h" +#include "Common/Cpp/PrettyPrint.h" #include "Common/SwitchFramework/Switch_PushButtons.h" #include "Common/PokemonSwSh/PokemonSettings.h" #include "Common/PokemonSwSh/PokemonSwShGameEntry.h" @@ -16,13 +16,20 @@ namespace NintendoSwitch{ namespace PokemonSwSh{ -ShinyHuntUnattendedSwordsOfJustice::ShinyHuntUnattendedSwordsOfJustice() - : SingleSwitchProgram( - FeedbackType::NONE, PABotBaseLevel::PABOTBASE_12KB, +ShinyHuntUnattendedSwordsOfJustice_Descriptor::ShinyHuntUnattendedSwordsOfJustice_Descriptor() + : RunnableSwitchProgramDescriptor( + "PokemonSwSh:ShinyHuntUnattendedSwordsOfJustice", "Shiny Hunt Unattended - Swords Of Justice", "NativePrograms/ShinyHuntUnattended-SwordsOfJustice.md", - "Hunt for shiny SOJs. Stop when a shiny is found." + "Hunt for shiny SOJs. Stop when a shiny is found.", + FeedbackType::NONE, + PABotBaseLevel::PABOTBASE_12KB ) +{} + + +ShinyHuntUnattendedSwordsOfJustice::ShinyHuntUnattendedSwordsOfJustice(const ShinyHuntUnattendedSwordsOfJustice_Descriptor& descriptor) + : SingleSwitchProgramInstance(descriptor) , EXIT_CAMP_TO_RUN_DELAY( "Exit Camp to Run Delay:
This needs to be carefully calibrated.", "1890" @@ -52,43 +59,43 @@ ShinyHuntUnattendedSwordsOfJustice::ShinyHuntUnattendedSwordsOfJustice() -void ShinyHuntUnattendedSwordsOfJustice::program(SingleSwitchProgramEnvironment& env) const{ - grip_menu_connect_go_home(); - resume_game_no_interact(TOLERATE_SYSTEM_UPDATE_MENU_FAST); +void ShinyHuntUnattendedSwordsOfJustice::program(SingleSwitchProgramEnvironment& env){ + grip_menu_connect_go_home(env.console); + resume_game_no_interact(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST); const uint32_t PERIOD = (uint32_t)TIME_ROLLBACK_HOURS * 3600 * TICKS_PER_SECOND; - uint32_t last_touch = system_clock(); + uint32_t last_touch = system_clock(env.console); for (uint32_t c = 0; ; c++){ // Touch the date. - if (TIME_ROLLBACK_HOURS > 0 && system_clock() - last_touch >= PERIOD){ - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - rollback_hours_from_home(TIME_ROLLBACK_HOURS, SETTINGS_TO_HOME_DELAY); - resume_game_no_interact(TOLERATE_SYSTEM_UPDATE_MENU_FAST); + if (TIME_ROLLBACK_HOURS > 0 && system_clock(env.console) - last_touch >= PERIOD){ + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + rollback_hours_from_home(env.console, TIME_ROLLBACK_HOURS, SETTINGS_TO_HOME_DELAY); + resume_game_no_interact(env.console, TOLERATE_SYSTEM_UPDATE_MENU_FAST); last_touch += PERIOD; } // Trigger encounter. - pbf_press_button(BUTTON_X, 10, OVERWORLD_TO_MENU_DELAY); - pbf_press_button(BUTTON_A, 10, ENTER_CAMP_DELAY); + pbf_press_button(env.console, BUTTON_X, 10, OVERWORLD_TO_MENU_DELAY); + pbf_press_button(env.console, BUTTON_A, 10, ENTER_CAMP_DELAY); if (AIRPLANE_MODE){ - pbf_press_button(BUTTON_A, 10, 100); - pbf_press_button(BUTTON_A, 10, 100); + pbf_press_button(env.console, BUTTON_A, 10, 100); + pbf_press_button(env.console, BUTTON_A, 10, 100); } - pbf_press_button(BUTTON_X, 10, 50); - pbf_press_dpad(DPAD_LEFT, 10, 10); + pbf_press_button(env.console, BUTTON_X, 10, 50); + pbf_press_dpad(env.console, DPAD_LEFT, 10, 10); env.log("Starting Encounter: " + tostr_u_commas(c + 1)); - pbf_press_button(BUTTON_A, 10, EXIT_CAMP_TO_RUN_DELAY); + pbf_press_button(env.console, BUTTON_A, 10, EXIT_CAMP_TO_RUN_DELAY); // Run away if not shiny. - run_away_with_lights(); + run_away_with_lights(env.console); // Enter Pokemon menu if shiny. - enter_summary(false); + enter_summary(env.console, false); } - pbf_press_button(BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); - end_program_callback(); - end_program_loop(); + pbf_press_button(env.console, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); + end_program_callback(env.console); + end_program_loop(env.console); } diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-SwordsOfJustice.h b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-SwordsOfJustice.h index 08f713cbfe..6eafd38730 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-SwordsOfJustice.h +++ b/SerialPrograms/Source/PokemonSwSh/Programs/ShinyHunting/PokemonSwSh_ShinyHuntUnattended-SwordsOfJustice.h @@ -17,11 +17,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSwSh{ -class ShinyHuntUnattendedSwordsOfJustice : public SingleSwitchProgram{ + +class ShinyHuntUnattendedSwordsOfJustice_Descriptor : public RunnableSwitchProgramDescriptor{ +public: + ShinyHuntUnattendedSwordsOfJustice_Descriptor(); +}; + + + +class ShinyHuntUnattendedSwordsOfJustice : public SingleSwitchProgramInstance{ public: - ShinyHuntUnattendedSwordsOfJustice(); + ShinyHuntUnattendedSwordsOfJustice(const ShinyHuntUnattendedSwordsOfJustice_Descriptor& descriptor); - virtual void program(SingleSwitchProgramEnvironment& env) const override; + virtual void program(SingleSwitchProgramEnvironment& env) override; private: TimeExpression EXIT_CAMP_TO_RUN_DELAY; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/TestProgram.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/TestProgram.cpp deleted file mode 100644 index 86aacc57dd..0000000000 --- a/SerialPrograms/Source/PokemonSwSh/Programs/TestProgram.cpp +++ /dev/null @@ -1,419 +0,0 @@ -/* Test Program - * - * From: https://github.com/PokemonAutomation/Arduino-Source - * - */ - -#include -#include "Common/Clientside/PrettyPrint.h" -#include "ClientSource/Libraries/Logging.h" -#include "Common/SwitchFramework/FrameworkSettings.h" -#include "Common/SwitchFramework/Switch_PushButtons.h" -#include "Common/PokemonSwSh/PokemonSettings.h" -#include "Common/PokemonSwSh/PokemonSwShGameEntry.h" -#include "CommonFramework/Tools/StatsTracking.h" -#include "CommonFramework/Tools/StatsDatabase.h" -#include "CommonFramework/Inference/ImageTools.h" -#include "CommonFramework/Inference/InferenceThrottler.h" -#include "CommonFramework/Inference/FillGeometry.h" -#include "CommonFramework/Inference/AnomalyDetector.h" -#include "CommonFramework/Inference/ColorClustering.h" -#include "CommonFramework/Inference/StatAccumulator.h" -#include "CommonFramework/Inference/TimeWindowStatTracker.h" -#include "PokemonSwSh/ShinyHuntTracker.h" -#include "PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_ShinyFilters.h" -#include "PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_SparkleTrigger.h" -#include "PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_SquareTrigger.h" -#include "PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_SquareDetector.h" -#include "PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_ShinyTrigger.h" -#include "PokemonSwSh/Inference/ShinyDetection/PokemonSwSh_ShinyEncounterDetector.h" -#include "PokemonSwSh/Inference/PokemonSwSh_StartBattleDetector.h" -#include "PokemonSwSh/Inference/PokemonSwSh_SummaryShinySymbolDetector.h" -#include "PokemonSwSh/Inference/PokemonSwSh_RaidCatchDetector.h" -#include "PokemonSwSh/Inference/PokemonSwSh_BattleMenuDetector.h" -#include "PokemonSwSh/Inference/PokemonSwSh_FishingDetector.h" -#include "PokemonSwSh/Inference/PokemonSwSh_MarkFinder.h" -#include "PokemonSwSh_StartGame.h" -#include "TestProgram.h" - -#include - -#include -using std::cout; -using std::endl; - -namespace PokemonAutomation{ -namespace NintendoSwitch{ -namespace PokemonSwSh{ - -TestProgram::TestProgram() - : SingleSwitchProgram( - FeedbackType::REQUIRED, PABotBaseLevel::PABOTBASE_12KB, - "Test Program", - "", - "Test Program" - ) -{} - - - - - - -void TestProgram::program(SingleSwitchProgramEnvironment& env) const{ -// BotBase& botbase = env.console; - VideoFeed& feed = env.console; - -#if 0 - StatSet set; - set.open_from_file("test.txt"); - -// cout << set.to_str() << endl; - - set.save_to_file("test2.txt"); -#endif - - -#if 0 -// start_game_from_home_with_inference(env, env.logger, env.console, true, 0, 0, true); - -// std::pair coord = get_direction(-3, -1.0); -// cout << "direction = " << (int)coord.first << ", " << (int)coord.second << endl; - -// Trajectory trajectory = get_trajectory_float(.09, .09); -// cout << trajectory.distance_in_ticks << " : " << (int)trajectory.joystick_x << "," << (int)trajectory.joystick_y << endl; - - ShinyHuntTracker tracker(true); - tracker.parse_and_append_line("Encounters: 100 - Star Shinies: 2 - Square Shinies: 1"); -// cout << tracker.to_str() << endl; - -// StatLine line(tracker); -// cout << line.to_str() << endl; - -// StatLine line1("2021-04-08 00:25:12.131850 - Encounters: 100 - Star Shinies: 2 - Square Shinies: 1"); -// cout << line1.to_str() << endl; - - StatList list; - list += tracker; - list += "2021-04-08 00:25:12.131850 - Encounters: 200 - Star Shinies: 1 - Square Shinies: 0"; - - cout << list.to_str() << endl; - - StatSet set; - StatList& program0 = set["program 0"]; - program0 += "Timestamp - Encounters: 100 - Star Shinies: 2 - Square Shinies: 1"; - program0 += "Timestamp - Encounters: 200 - Star Shinies: 1 - Square Shinies: 0"; - StatList& program1 = set["program 1"]; - program1 += "Timestamp - Encounters: 300 - Star Shinies: 3 - Square Shinies: 2"; - program1 += "Timestamp - Encounters: 400 - Star Shinies: 4 - Square Shinies: 1"; - - set.save_to_file("test.txt"); -#endif - - -#if 0 - QImage image("test-screen.png"); -// QImage image("test-1617471750423682600-O.png"); -// QImage image = feed.snapshot(); -// image.save("square-test0.png"); - FillMatrix matrix(image); - - BrightYellowLightFilterDebug filter; - matrix.apply_filter(image, filter); - image.save("square-test0.png"); - - std::vector objects; - objects = find_all_objects(matrix, 1, true); - cout << "objects = " << objects.size() << endl; - - std::deque boxes; - for (const FillGeometry& object : objects){ - if (is_square2(image, matrix, object)){ - InferenceBox box = translate_to_parent(image, InferenceBox(0, 0, 1, 1), object.box); - box.color = Qt::green; - boxes.emplace_back(feed, box); - } - } - - env.wait(std::chrono::seconds(600)); -#endif - - -#if 0 - std::deque grid; - for (size_t r = 0; r < 10; r++){ - for (size_t c = 0; c < 10; c++){ - grid.emplace_back(feed, 0.1 * c, 0.1 * r, 0.1, 0.1); - } - } - - env.wait(std::chrono::seconds(5)); - - pbf_move_left_joystick(208, 16, 500, 0); - - env.wait(std::chrono::seconds(600)); -#endif - - - -#if 1 - QImage screen("mark-test0.png"); - - std::vector marks; - find_marks(screen, nullptr, &marks); - - for (const PixelBox& box : marks){ - cout << box.width() << " x " << box.height() << endl; - } -#endif - - -#if 0 - FillMatrix blue_matrix(screen); - BlueFilter blue_filter; - blue_matrix.apply_filter(blue, blue_filter); - blue.save("blue.png"); -#endif - - - -#if 0 - SummaryShinySymbolDetector detector(feed, env.logger); - - detector.wait_for_detection(env); - - env.wait(std::chrono::seconds(600)); -#endif - -#if 1 - detect_shiny_battle( - env, env.console, - SHINY_BATTLE_REGULAR, - std::chrono::seconds(60) - ); -#endif - - -#if 0 - StandardBattleMenuDetector detector(feed); - cout << "Battle Menu = " << detector.detect(feed.snapshot()) << endl; - env.wait(std::chrono::seconds(600)); -#endif - -#if 0 - FishingDetector detector(feed); - detector.wait_for_detection(env, env.logger); -#endif - - -#if 0 - QImage screen("FishingBig.jpg"); - - FillMatrix matrix(screen); - PinkFilter2 filter; - matrix.apply_filter(screen, filter); - screen.save("test.png"); - - std::vector objects = find_all_objects(matrix, false); - std::multimap candidate_top; - std::multimap candidate_bot; - for (const FillGeometry& object : objects){ - ImageStats stats = object_stats(screen, matrix, object); - - double aspect_ratio = (double)object.box.width() / object.box.height(); - FloatPixel color_ratio = stats.average / stats.average.sum(); - double stddev = stats.stddev.sum(); - -#if 0 - cout << object.area << " : [" << object.center_x << "," << object.center_y - << "][" << object.box.width() << " x " << object.box.height() - << "], mean = " << stats.average / stats.average.sum() - << ", stddev = " << stats.stddev << endl; -#endif - - if (0.4 < aspect_ratio && aspect_ratio < 0.6 && - stddev < 50 && - euclidean_distance(color_ratio, FloatPixel(0.56, 0.14, 0.30)) < 0.2 - ){ -// cout << "top" << endl; - candidate_top.emplace(object.area, object); - } - if (1.0 < aspect_ratio && aspect_ratio < 1.5 && - stddev < 25 && - euclidean_distance(color_ratio, FloatPixel(0.56, 0.21, 0.23)) < 0.2 - ){ -// cout << "bottom" << endl; - candidate_bot.emplace(object.area, object); - } - } - - for (auto iter = candidate_top.rbegin(); iter != candidate_top.rend(); ++iter){ - const FillGeometry& top = iter->second; - size_t top_area = top.area; - size_t area_low = top_area / 7.; - size_t area_high = top_area / 5.; -// cout << "area = " << top_area << ", low = " << area_low << ", high = " << area_high << endl; - auto iter0 = candidate_bot.lower_bound(area_low); - auto iter1 = candidate_bot.upper_bound(area_high); - for (; iter0 != iter1; ++iter0){ - const FillGeometry& bottom = iter0->second; - -// cout << "top_area = " << top_area << ", bot_area = " << bottom.area << endl; - - // Verify that top is above bottom. - if (top.box.max_y >= bottom.box.min_y){ - continue; - } -// cout << "check 1" << endl; - - // Verify bottom is left of the top. - if (top.center_x <= bottom.center_x){ - continue; - } - - // Make sure horizontal alignment is reasonable. - int mid = (top.box.min_x + top.box.max_x) / 2; - if (std::abs(bottom.box.max_x - mid) * 5 > top.box.width()){ - continue; - } - - // Make sure vertical alignment is reasonable. - if (top.box.max_y + top.box.height() <= bottom.box.min_y){ - continue; - } - - cout << "match!" << endl; - } - } -#endif - - - - -#if 0 - RaidCatchDetector detector(feed, std::chrono::seconds(60)); - - size_t c = 0; - while (true){ - auto start = std::chrono::system_clock::now(); - env.check_stopping(); - - if (detector.has_timed_out()){ - break; - } - if (detector.detect()){ - break; - } - - - auto end = std::chrono::system_clock::now(); - auto duration = end - start; -// cout << std::chrono::duration_cast(duration).count() << endl; - if (duration < std::chrono::milliseconds(50)){ - env.wait(std::chrono::milliseconds(50) - duration); - } - c++; -// break; - } -#endif - - -// QImage image = feed.snapshot(); -// cout << detector.detect(image) << endl; -// cout << "box1 = " << cluster_distance_2(extract_box(image, box1), qRgb(255, 255, 255), qRgb(90, 180, 90)) << endl; -// cout << "box1 = " << cluster_distance_2(extract_box(image, box1), qRgb(0, 0, 0), qRgb(90, 180, 90)) << endl; -// cout << "box2 = " << cluster_distance_2(extract_box(image, box2), qRgb(255, 255, 255), qRgb(150, 132, 80)) << endl; -// cout << "box3 = " << cluster_distance_2(extract_box(image, box3), qRgb(255, 255, 255), qRgb(140, 90, 180)) << endl; -// cout << "box2 = " << cluster_distance_2(extract_box(image, box2), qRgb(0, 0, 0), qRgb(150, 132, 80)) << endl; -// cout << "box3 = " << cluster_distance_2(extract_box(image, box3), qRgb(0, 0, 0), qRgb(140, 90, 180)) << endl; - -#if 0 - QImage image("detection-381-O.png"); - - ShinyImageDetection signatures; - signatures.accumulate(image); -#endif - -// QImage image("battle-menu.png"); -// StandardBattleMenuDetector detector(env.console); -// detector.detect(image); - -#if 0 - ShinyEncounterDetector detector( - env.console, env.logger, - ShinyEncounterDetector::RAID_BATTLE, - std::chrono::seconds(30) - ); - detector.detect(env); -#endif - -#if 0 -// InferenceBoxScope box(env.console, 0.0, 0.1, 0.6, 0.8); -// InferenceBoxScope box(env.console, 0.5, 0.2, 0.5, 0.55); -// InferenceBoxScope box(env.console, 0.3, 0.0, 0.4, 0.8); -// StandardBattleMenuDetector battle_menu(env.console); -// ShinyImageDetection shiny_animation; - -// QImage last; -// std::deque window; - -// TimeNormalizedDeltaAnomalyDetector detector(40, 255); - - - size_t c = 0; - while (true){ - auto start = std::chrono::system_clock::now(); - env.check_stopping(); - - QImage image = feed.snapshot(); -// cout << battle_menu.detect(image) << endl; - - detector.detect(); - -// cout << image.width() << " x " << image.height() << " : " << image.sizeInBytes() << endl; -// image = extract_box(image, box); - -// double diff = image_diff(last, image); -// last = std::move(image); -// double sigma = detector.push(diff); -// if (std::abs(sigma) > 3){ -// cout << "sigma = " << sigma << endl; -// env.logger.log("Screen Anomaly: sigma = " + QString::number(sigma), "purple"); -// } - -// ShinyImageDetection shiny_signatures; -// shiny_signatures.detect(image, &env.logger); - - auto end = std::chrono::system_clock::now(); - auto duration = end - start; -// cout << std::chrono::duration_cast(duration).count() << endl; - if (duration < std::chrono::milliseconds(50)){ - env.wait(std::chrono::milliseconds(50) - duration); - } - c++; -// break; - } -#endif - - - -// BeamReader reader(feed, env.logger); -// if (!reader.run(env, botbase, 3 * TICKS_PER_SECOND)){ -// pbf_press_button(botbase, BUTTON_HOME, 10, GAME_TO_HOME_DELAY_SAFE); -// } - -} - - - - - - - -} -} -} - - - - diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/TestProgram.h b/SerialPrograms/Source/PokemonSwSh/Programs/TestProgram.h deleted file mode 100644 index c61d50be02..0000000000 --- a/SerialPrograms/Source/PokemonSwSh/Programs/TestProgram.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Test Program - * - * From: https://github.com/PokemonAutomation/Arduino-Source - * - */ - -#ifndef PokemonAutomation_PokemonSwSh_TestProgram_H -#define PokemonAutomation_PokemonSwSh_TestProgram_H - -#include "NintendoSwitch/Framework/SingleSwitchProgram.h" - -namespace PokemonAutomation{ -namespace NintendoSwitch{ -namespace PokemonSwSh{ - -class TestProgram : public SingleSwitchProgram{ -public: - TestProgram(); - - virtual void program(SingleSwitchProgramEnvironment& env) const override; -}; - - - -} -} -} -#endif - diff --git a/SerialPrograms/Source/PokemonSwSh/ShinyHuntTracker.cpp b/SerialPrograms/Source/PokemonSwSh/ShinyHuntTracker.cpp index 5dff46bef2..e7ae3a8758 100644 --- a/SerialPrograms/Source/PokemonSwSh/ShinyHuntTracker.cpp +++ b/SerialPrograms/Source/PokemonSwSh/ShinyHuntTracker.cpp @@ -13,7 +13,7 @@ namespace PokemonAutomation{ ShinyHuntTracker::ShinyHuntTracker(bool shiny_types) : m_encounters(m_stats["Encounters"]) - , m_unknown_shinies(m_stats["Unknown Shinies"]) + , m_unknown_shinies(m_stats[shiny_types ? "Unknown Shinies" : "Shinies"]) , m_star_shinies(m_stats["Star Shinies"]) , m_square_shinies(m_stats["Square Shinies"]) { diff --git a/SerialPrograms/libtesseractc.dll b/SerialPrograms/libtesseractc.dll deleted file mode 100644 index f5af1e6ea4..0000000000 Binary files a/SerialPrograms/libtesseractc.dll and /dev/null differ diff --git a/SerialPrograms/libtesseractc.lib b/SerialPrograms/libtesseractc.lib deleted file mode 100644 index ed102c1859..0000000000 Binary files a/SerialPrograms/libtesseractc.lib and /dev/null differ diff --git a/SerialPrograms/tesseractPA.dll b/SerialPrograms/tesseractPA.dll new file mode 100644 index 0000000000..fc9ce8b981 Binary files /dev/null and b/SerialPrograms/tesseractPA.dll differ diff --git a/SerialPrograms/tesseractPA.lib b/SerialPrograms/tesseractPA.lib new file mode 100644 index 0000000000..d68d86348a Binary files /dev/null and b/SerialPrograms/tesseractPA.lib differ