Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 14 additions & 24 deletions SerialPrograms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -352,12 +352,6 @@ else() # macOS and Linux
target_link_directories(SerialProgramsLib PUBLIC ${ONNXRUNTIME_LIBRARY_DIRS})
target_link_libraries(SerialProgramsLib PUBLIC ${ONNXRUNTIME_LINK_LIBRARIES})
endif()
# Find OpenCV
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is the same as #774 I guess it will need to be merged in and rebase before ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ya i'll do a rebase later

if(CMAKE_SYSTEM_PROCESSOR MATCHES "(arm64)|(ARM64)")
find_package(OpenCV REQUIRED HINTS "/opt/homebrew/opt/opencv/lib/cmake/opencv4/")
else()
find_package(OpenCV REQUIRED HINTS "/usr/local/opt/opencv/lib/cmake/opencv4/")
endif()
else() # Linux
# ONNX RUNTIME LINUX CONFIG
# NOTE: users can specify their own ONNX_ROOT_PATH (this is the base folder for ONNX) on the command line when evoking cmake.
Expand Down Expand Up @@ -435,26 +429,26 @@ else() # macOS and Linux
else()
message(FATAL_ERROR "Could not find ONNX Runtime headers or library.")
endif()
# Find OpenCV
find_package(OpenCV REQUIRED HINTS "/usr/local/opt/opencv/lib/cmake/opencv4/")
endif() # end Linux

include_directories(${OpenCV_INCLUDE_DIRS})
link_directories(${OpenCV_LIBRARY_DIRS})
target_link_libraries(SerialProgramsLib PRIVATE ${OpenCV_LIBS})
# Find OpenCV
pkg_search_module(OpenCV REQUIRED opencv4 opencv)
target_include_directories(SerialProgramsLib SYSTEM PRIVATE ${OpenCV_INCLUDE_DIRS}) # "SYSTEM" to suppress warnings
target_link_directories(SerialProgramsLib PUBLIC ${OpenCV_LIBRARY_DIRS})
target_link_libraries(SerialProgramsLib PUBLIC ${OpenCV_LINK_LIBRARIES})

#we hope to use our own Tesseract build in future so we can rid that dependency
#but right now to run on Linux and Mac we need to use external Tesseract library
if (UNIX_LINK_TESSERACT)
pkg_search_module(TESSERACT tesseract)
pkg_search_module(LEPTONICA lept)
if (TESSERACT_FOUND AND LEPTONICA_FOUND)
target_compile_definitions(SerialProgramsLib PRIVATE PA_TESSERACT UNIX_LINK_TESSERACT)
pkg_search_module(TESSERACT REQUIRED tesseract)
pkg_search_module(LEPTONICA REQUIRED lept)
include_directories(${TESSERACT_INCLUDE_DIRS})
include_directories(${LEPTONICA_INCLUDE_DIRS})
link_directories(${TESSERACT_LIBRARY_DIRS})
link_directories(${LEPTONICA_LIBRARY_DIRS})
target_link_libraries(SerialProgramsLib PRIVATE ${TESSERACT_LINK_LIBRARIES})
target_link_libraries(SerialProgramsLib PRIVATE ${LEPTONICA_LINK_LIBRARIES})
target_include_directories(SerialProgramsLib SYSTEM PRIVATE ${TESSERACT_INCLUDE_DIRS})
target_include_directories(SerialProgramsLib SYSTEM PRIVATE ${LEPTONICA_INCLUDE_DIRS})
target_link_directories(SerialProgramsLib PUBLIC ${TESSERACT_LIBRARY_DIRS})
target_link_directories(SerialProgramsLib PUBLIC ${LEPTONICA_LIBRARY_DIRS})
target_link_libraries(SerialProgramsLib PUBLIC ${TESSERACT_LINK_LIBRARIES})
target_link_libraries(SerialProgramsLib PUBLIC ${LEPTONICA_LINK_LIBRARIES})
endif()

pkg_search_module(DPP dpp=10.0.22)
Expand All @@ -468,10 +462,6 @@ else() # macOS and Linux
endif()

if (APPLE)
# Add -Wno-c11-extensions to avoid clang gives
# /usr/local/Cellar/opencv/4.5.5_3/include/opencv4/opencv2/core/mat.inl.hpp:2116:9: error: '_Atomic' is a C11 extension
# when compiling OpenCV
# target_compile_options(SerialProgramsLib PRIVATE -Wall -Wextra -Wpedantic -Werror -Wno-c11-extensions)
target_compile_options(SerialProgramsLib PRIVATE -Wall -Wextra -Wpedantic -Werror -Wshorten-64-to-32)
# on macOS, need this framework to query OS API to control display sleep and system sleep behavior
target_link_libraries(SerialProgramsLib PRIVATE "-framework IOKit -framework CoreFoundation")
Expand Down
2 changes: 2 additions & 0 deletions SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "Programs/ShinyHunting/PokemonLZA_ShinyHunt_OverworldReset.h"
#include "Programs/ShinyHunting/PokemonLZA_BeldumHunter.h"
#include "Programs/ShinyHunting/PokemonLZA_AutoFossil.h"
#include "Programs/ShinyHunting/PokemonLZA_WildZoneEntrance.h"

// Developer
#include "Programs/TestPrograms/PokemonLZA_OverworldWatcher.h"
Expand Down Expand Up @@ -52,6 +53,7 @@ std::vector<PanelEntry> PanelListFactory::make_panels() const{
ret.emplace_back("---- Shiny Hunting ----");
ret.emplace_back(make_single_switch_program<ShinyHunt_BenchSit_Descriptor, ShinyHunt_BenchSit>());
ret.emplace_back(make_single_switch_program<ShinyHunt_OverworldReset_Descriptor, ShinyHunt_OverworldReset>());
ret.emplace_back(make_single_switch_program<ShinyHunt_WildZoneEntrance_Descriptor, ShinyHunt_WildZoneEntrance>());

if (PreloadSettings::instance().DEVELOPER_MODE){
ret.emplace_back(make_single_switch_program<BeldumHunter_Descriptor, BeldumHunter>());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/* Shiny Hunt - Wild Zone Entrance
*
* From: https://github.com/PokemonAutomation/
*
*/

#include "CommonFramework/Exceptions/OperationFailedException.h"
#include "CommonFramework/ProgramStats/StatsTracking.h"
#include "CommonFramework/Notifications/ProgramNotifications.h"
#include "CommonTools/Async/InferenceRoutines.h"
#include "CommonTools/VisualDetectors/BlackScreenDetector.h"
#include "NintendoSwitch/Programs/NintendoSwitch_GameEntry.h"
#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h"
#include "Pokemon/Pokemon_Strings.h"
#include "PokemonLA/Inference/Sounds/PokemonLA_ShinySoundDetector.h"
#include "PokemonLZA/Inference/PokemonLZA_ButtonDetector.h"
#include "PokemonLZA/Programs/PokemonLZA_BasicNavigation.h"
#include "PokemonLZA_WildZoneEntrance.h"

namespace PokemonAutomation {
namespace NintendoSwitch {
namespace PokemonLZA {

using namespace Pokemon;


ShinyHunt_WildZoneEntrance_Descriptor::ShinyHunt_WildZoneEntrance_Descriptor()
: SingleSwitchProgramDescriptor("PokemonLZA:ShinyHunt-WildZoneEntrance", STRING_POKEMON + " LZA",
"Shiny Hunt - Wild Zone Entrance",
"Programs/PokemonLZA/ShinyHunt-WildZoneEntrance.html",
"Shiny hunt by repeatedly entering Wild Zone from its entrance.",
ProgramControllerClass::StandardController_NoRestrictions, FeedbackType::REQUIRED,
AllowCommandsWhenRunning::DISABLE_COMMANDS, {}) {}
class ShinyHunt_WildZoneEntrance_Descriptor::Stats : public StatsTracker {
public:
Stats() : resets(m_stats["Wild Zone"]), shinies(m_stats["Shiny Sounds"]), errors(m_stats["Errors"]) {
m_display_order.emplace_back("Wild Zone");
m_display_order.emplace_back("Shiny Sounds");
m_display_order.emplace_back("Errors", HIDDEN_IF_ZERO);

m_aliases["Shinies"] = "Shiny Sounds";
m_aliases["Shinies Detected"] = "Shiny Sounds";
}

std::atomic<uint64_t>& resets;
std::atomic<uint64_t>& shinies;
std::atomic<uint64_t>& errors;
};
std::unique_ptr<StatsTracker> ShinyHunt_WildZoneEntrance_Descriptor::make_stats() const {
return std::unique_ptr<StatsTracker>(new Stats());
}


ShinyHunt_WildZoneEntrance::ShinyHunt_WildZoneEntrance()
: WALK_IN_ZONE("<b>WALK IN ZONE:</b><br>Walk this long in the zone after passing through the gate.",
LockMode::UNLOCK_WHILE_RUNNING, "500 ms"),
SHINY_DETECTED("Shiny Detected", "", "2000 ms", ShinySoundDetectedAction::NOTIFY_ON_FIRST_ONLY),
NOTIFICATION_STATUS("Status Update", true, false, std::chrono::seconds(3600)),
NOTIFICATIONS({
&NOTIFICATION_STATUS,
&SHINY_DETECTED.NOTIFICATIONS,
&NOTIFICATION_PROGRAM_FINISH,
&NOTIFICATION_ERROR_RECOVERABLE,
&NOTIFICATION_ERROR_FATAL,
}) {
PA_ADD_STATIC(SHINY_REQUIRES_AUDIO);
PA_ADD_OPTION(WALK_IN_ZONE);
PA_ADD_OPTION(SHINY_DETECTED);
PA_ADD_OPTION(NOTIFICATIONS);
}


void run_to_gate(ConsoleHandle& console, ProControllerContext& context) {
ButtonWatcher buttonA(COLOR_RED, ButtonType::ButtonA, {0, 0, 1, 1}, &console.overlay());
int ret = run_until<ProControllerContext>(console, context,
[](ProControllerContext& context) {
for (int c = 0; c < 10; c++) {
pbf_move_left_joystick(context, 128, 0, 800ms, 200ms);
}
},
{{buttonA}});

switch (ret) {
case 0:
break;
default:
OperationFailedException::fire(ErrorReport::SEND_ERROR_REPORT,
"run_to_gate(): Unable to detect entrance after 10 seconds.", console);
}
}

void enter_wild_zone_entrance(ConsoleHandle& console, ProControllerContext& context, Milliseconds walk_in_zone) {
BlackScreenOverWatcher black_screen(COLOR_BLUE);
int ret = run_until<ProControllerContext>(console, context,
[&](ProControllerContext& context) {
pbf_mash_button(context, BUTTON_B, 200ms); // dismiss menu if any
run_to_gate(console, context);
pbf_mash_button(context, BUTTON_A, 2000ms);
pbf_move_left_joystick(context, 128, 0, walk_in_zone, 200ms);
context.wait_for_all_requests();
pbf_press_button(context, BUTTON_PLUS, 100ms, 100ms); // open map
},
{{black_screen}});
if (ret == 0) {
console.log("[WildZoneEntrance] Detected day/night change after entering.");
context.wait_for(std::chrono::milliseconds(2000));
pbf_mash_button(context, BUTTON_B, 200ms); // dismiss menu if any
pbf_press_button(context, BUTTON_PLUS, 100ms, 100ms); // open map again
}
pbf_mash_button(context, BUTTON_A, 800ms); // teleporting or just mashing button
pbf_mash_button(context, BUTTON_B, 200ms); // in case need to dismiss map
context.wait_for_all_requests();
context.wait_for(std::chrono::milliseconds(4000)); // TODO: differ NS1 wait time from NS2
}

void ShinyHunt_WildZoneEntrance::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) {
ShinyHunt_WildZoneEntrance_Descriptor::Stats& stats =
env.current_stats<ShinyHunt_WildZoneEntrance_Descriptor::Stats>();

if (SHINY_DETECTED.ACTION == ShinySoundDetectedAction::NOTIFY_ON_ALL) {
throw UserSetupError(env.console, "Shiny would be detected/notified at most once. Choose one of the other 2 options");
}

uint8_t shiny_count = 0;

{ // first run with shiny detection
float shiny_coefficient = 1.0;
PokemonLA::ShinySoundDetector shiny_detector(env.console, [&](float error_coefficient) -> bool {
// Warning: This callback will be run from a different thread than this function.
shiny_count++;
stats.shinies++;
env.update_stats();
shiny_coefficient = error_coefficient;
return true;
});

run_until<ProControllerContext>(env.console, context,
[&](ProControllerContext& context) {
while (true) {
send_program_status_notification(env, NOTIFICATION_STATUS);
stats.resets++;
enter_wild_zone_entrance(env.console, context, WALK_IN_ZONE);
env.update_stats();
}
},
{{shiny_detector}});

context.wait_for(std::chrono::milliseconds(1000));

// when shiny sound is detected, it's most likely happened inside the zone
// now try to reset position
pbf_mash_button(context, BUTTON_B, 200ms); // dismiss menu if any
pbf_press_button(context, BUTTON_PLUS, 100ms, 100ms); // open map
pbf_mash_button(context, BUTTON_A, 600ms); // teleporting or just mashing button
pbf_mash_button(context, BUTTON_B, 200ms); // in case need to dismiss map

SHINY_DETECTED.on_shiny_sound(env, env.console, context, shiny_count, shiny_coefficient);
}

// continue with shiny sound detection is pointless
if (SHINY_DETECTED.ACTION != ShinySoundDetectedAction::STOP_PROGRAM) {
while (true) {
send_program_status_notification(env, NOTIFICATION_STATUS);
stats.resets++;
enter_wild_zone_entrance(env.console, context, WALK_IN_ZONE);
env.update_stats();
}
}

go_home(env.console, context);
send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH);
}


} // namespace PokemonLZA
} // namespace NintendoSwitch
} // namespace PokemonAutomation
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/* Shiny Hunt - Wild Zone Entrance
*
* From: https://github.com/PokemonAutomation/
*
*/

#ifndef PokemonAutomation_PokemonLZA_WildZoneEntrance_H
#define PokemonAutomation_PokemonLZA_WildZoneEntrance_H

#include "CommonFramework/Notifications/EventNotificationsTable.h"
#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h"
#include "PokemonLA/Options/PokemonLA_ShinyDetectedAction.h"
#include "PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.h"

namespace PokemonAutomation {
namespace NintendoSwitch {
namespace PokemonLZA {


class ShinyHunt_WildZoneEntrance_Descriptor : public SingleSwitchProgramDescriptor {
public:
ShinyHunt_WildZoneEntrance_Descriptor();

class Stats;
virtual std::unique_ptr<StatsTracker> make_stats() const override;
};


class ShinyHunt_WildZoneEntrance : public SingleSwitchProgramInstance {
public:
ShinyHunt_WildZoneEntrance();

virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override;

private:
PokemonLA::ShinyRequiresAudioText SHINY_REQUIRES_AUDIO;
MillisecondsOption WALK_IN_ZONE;

ShinySoundDetectedActionOption SHINY_DETECTED;

EventNotificationOption NOTIFICATION_STATUS;
EventNotificationsOption NOTIFICATIONS;
};


} // namespace PokemonLZA
} // namespace NintendoSwitch
} // namespace PokemonAutomation
#endif
2 changes: 2 additions & 0 deletions SerialPrograms/SourceFiles.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -1579,6 +1579,8 @@ file(GLOB LIBRARY_SOURCES
Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h
Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_OverworldReset.cpp
Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_OverworldReset.h
Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_WildZoneEntrance.cpp
Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_WildZoneEntrance.h
Source/PokemonLZA/Programs/TestPrograms/PokemonLZA_MoveBoxArrow.cpp
Source/PokemonLZA/Programs/TestPrograms/PokemonLZA_MoveBoxArrow.h
Source/PokemonLZA/Programs/TestPrograms/PokemonLZA_OverworldWatcher.cpp
Expand Down