Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add North detection to Overworld watcher #487

Merged
merged 2 commits into from
Sep 19, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,16 @@ DirectionDetector::DirectionDetector(Color color, const ImageFloatBox& box)
{}


std::pair<double, double> DirectionDetector::locate_north(ConsoleHandle& console, const ImageViewRGB32& screen) const{
assert_16_9_720p_min(console, screen);
bool DirectionDetector::detect_north(Logger& logger, const ImageViewRGB32& screen) const{
std::pair<double, double> north_location = locate_north(logger, screen);

return !(north_location.first == 0 && north_location.second == 0);
}


std::pair<double, double> DirectionDetector::locate_north(Logger& logger, const ImageViewRGB32& screen) const{
assert_16_9_720p_min(logger, screen);

const std::vector<std::pair<uint32_t, uint32_t>> filters = {
{combine_rgb(0, 100, 0), combine_rgb(50, 230, 80)},

Expand All @@ -77,7 +85,7 @@ std::pair<double, double> DirectionDetector::locate_north(ConsoleHandle& console
if (zero_coord.first > 0.91 || zero_coord.first < 0.90 ||
zero_coord.second > 0.84 || zero_coord.second < 0.82)
{
console.log("Unable to locate the overworld radar ball, falling back on hard coded location.", COLOR_ORANGE);
logger.log("Unable to locate the overworld radar ball, falling back on hard coded location.", COLOR_ORANGE);
zero_coord.first = 0.9061;
zero_coord.second = 0.8328;
// throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "Unable to locate the overworld radar ball.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@ class DirectionDetector {
DirectionDetector(Color color = COLOR_RED, const ImageFloatBox& box = ImageFloatBox(0.815, 0.680, 0.180, 0.310));
virtual ~DirectionDetector();

bool detect_north(Logger& logger, const ImageViewRGB32& screen) const;

// return the coordinates of the N symbol, where the coordinates are measured in absolute pixels (scaled to 1080/height)
// with respect to the radar ball
// return 0,0 if unable to locate the N symbol
std::pair<double, double> locate_north(ConsoleHandle& console, const ImageViewRGB32& screen) const;
std::pair<double, double> locate_north(Logger& logger, const ImageViewRGB32& screen) const;

// return the direction of the N symbol, in radians, using North-clockwise convention. [0, 2pi)
// return -1 if unable to locate the N symbol
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,34 +130,43 @@ std::pair<double, double> OverworldDetector::locate_ball(const ImageViewRGB32& s



OverworldWatcher::OverworldWatcher(Color color, bool detect_event)
OverworldWatcher::OverworldWatcher(Logger& logger, Color color, bool detect_event)
: OverworldDetector(color)
, VisualInferenceCallback("OverworldWatcher")
, m_logger(logger)
, m_ball_hold_duration(std::chrono::milliseconds(5000))
, m_map_hold_duration(std::chrono::milliseconds(1000))
, m_north_hold_duration(std::chrono::milliseconds(1000))
, m_last_ball(WallClock::min())
, m_last_north(WallClock::min())
, m_detect_event(detect_event)
{}
{
m_direction_detector = DirectionDetector(COLOR_RED);
}

void OverworldWatcher::make_overlays(VideoOverlaySet& items) const{
OverworldDetector::make_overlays(items);
}
bool OverworldWatcher::process_frame(const VideoSnapshot& frame){
// Return true if either of the following is true:
// - Ball is held and radar map stays still for 1 second.
// - Ball is held for 1 second and N symbol is held for 1 second
// - Ball is held for 5 seconds.

// The map is not static when there is an event raid in it as it will
// sparkle. So instead, we revert to the ball being held for 5 seconds.

// Using Ball detection alone can false positive on the slow moving lights after a tera raid.
// To reduce false positives, we also require: either the map staying still for 1 second, or detecting the N symbol.

// No detection.
if (!detect(frame)){
m_last_ball = WallClock::min();
m_start_of_detection.clear();
return false;
}

// First detection.
// First detection of ball
if (m_last_ball == WallClock::min()){
m_last_ball = frame.timestamp;
}
Expand All @@ -166,11 +175,27 @@ bool OverworldWatcher::process_frame(const VideoSnapshot& frame){
return false;
}

// Ball held for long enough.
// Ball held for long enough. (5 seconds)
if (!m_detect_event && (frame.timestamp - m_last_ball >= m_ball_hold_duration)){
return true;
}


// check for North symbol
if (!m_direction_detector.detect_north(m_logger, frame)){
m_last_north = WallClock::min(); // not detecting north
}else{
if (m_last_north == WallClock::min()){ // first detection of north
m_last_north = frame.timestamp;
}
if (frame.timestamp - m_last_north >= m_north_hold_duration){
return true;
}
}


// Check if radar map stays still for 1 second.

// Mismatching image sizes.
ImageViewRGB32 start = extract_box_reference(m_start_of_detection, m_detect_event ? m_ball : m_radar_inside);
ImageViewRGB32 current = extract_box_reference(frame, m_detect_event ? m_ball : m_radar_inside);
Expand All @@ -179,15 +204,15 @@ bool OverworldWatcher::process_frame(const VideoSnapshot& frame){
return false;
}

// Image has changed too much.

double rmsd = ImageMatch::pixel_RMSD(start, current);
// cout << "rmsd = " << rmsd << endl;
if (rmsd > 2.0){
if (rmsd > 2.0){ // Image of radar map has changed too much.
m_start_of_detection = frame;
return false;
}

// Make sure it's held for long enough.
// Make sure radar map held for long enough.
return frame.timestamp - m_start_of_detection.timestamp >= m_map_hold_duration;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "CommonFramework/VideoPipeline/VideoFeed.h"
#include "CommonFramework/InferenceInfra/VisualInferenceCallback.h"
#include "CommonFramework/Inference/VisualDetector.h"
#include "PokemonSV/Inference/Overworld/PokemonSV_DirectionDetector.h"

namespace PokemonAutomation{
namespace NintendoSwitch{
Expand Down Expand Up @@ -39,18 +40,22 @@ class OverworldDetector : public StaticScreenDetector{

class OverworldWatcher : public OverworldDetector, public VisualInferenceCallback{
public:
OverworldWatcher(Color color = COLOR_RED, bool detect_event = false);
OverworldWatcher(Logger& logger, Color color = COLOR_RED, bool detect_event = false);

virtual void make_overlays(VideoOverlaySet& items) const override;
virtual bool process_frame(const VideoSnapshot& frame) override;


private:
Logger& m_logger;
std::chrono::milliseconds m_ball_hold_duration;
std::chrono::milliseconds m_map_hold_duration;
std::chrono::milliseconds m_north_hold_duration;
WallClock m_last_ball;
WallClock m_last_north;
VideoSnapshot m_start_of_detection;
bool m_detect_event;
DirectionDetector m_direction_detector;
};


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ void run_battle_press_A(
while (true){
NormalBattleMenuWatcher battle(COLOR_BLUE);
// SwapMenuWatcher fainted(COLOR_PURPLE);
OverworldWatcher overworld(COLOR_CYAN);
OverworldWatcher overworld(console, COLOR_CYAN);
AdvanceDialogWatcher dialog(COLOR_RED);
context.wait_for_all_requests();

Expand Down Expand Up @@ -164,7 +164,7 @@ void clear_dialog(ConsoleHandle& console, BotBaseContext& context,
}

AdvanceDialogWatcher advance_dialog(COLOR_RED);
OverworldWatcher overworld(COLOR_CYAN);
OverworldWatcher overworld(console, COLOR_CYAN);
PromptDialogWatcher prompt(COLOR_YELLOW);
WhiteButtonWatcher whitebutton(COLOR_GREEN, WhiteButton::ButtonA_DarkBackground, {0.725, 0.833, 0.024, 0.045}); // {0.650, 0.650, 0.140, 0.240}
DialogArrowWatcher dialog_arrow(COLOR_RED, console.overlay(), {0.850, 0.820, 0.020, 0.050}, 0.8365, 0.846);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ CatchResults basic_catcher(
WallClock last_battle_menu = WallClock::min();
while (true){
NormalBattleMenuWatcher battle_menu(COLOR_RED);
OverworldWatcher overworld(COLOR_YELLOW);
OverworldWatcher overworld(console, COLOR_YELLOW);
GradientArrowWatcher next_pokemon(COLOR_GREEN, GradientArrowType::RIGHT, {0.50, 0.51, 0.30, 0.10});
GradientArrowWatcher add_to_party(COLOR_BLUE, GradientArrowType::RIGHT, {0.50, 0.39, 0.30, 0.10});
AdvanceDialogWatcher dialog(COLOR_PURPLE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ void auto_heal_from_menu_or_overworld(
);
}

OverworldWatcher overworld(COLOR_RED);
OverworldWatcher overworld(console, COLOR_RED);
MainMenuWatcher main_menu(COLOR_CYAN);
AdvanceDialogWatcher dialog(COLOR_YELLOW);
context.wait_for_all_requests();
Expand Down Expand Up @@ -90,7 +90,7 @@ int run_from_battle(const ProgramInfo& info, ConsoleHandle& console, BotBaseCont

int attempts = 0;
for (size_t c = 0; c < 10; c++){
OverworldWatcher overworld(COLOR_RED);
OverworldWatcher overworld(console, COLOR_RED);
NormalBattleMenuWatcher battle_menu(COLOR_YELLOW);
GradientArrowWatcher next_pokemon(COLOR_GREEN, GradientArrowType::RIGHT, {0.50, 0.51, 0.30, 0.10});
context.wait_for_all_requests();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ bool run_pokemon(
GradientArrowWatcher next_pokemon(COLOR_BLUE, GradientArrowType::RIGHT, {0.50, 0.51, 0.30, 0.10});
SwapMenuWatcher swap_menu(COLOR_BLUE);
AdvanceDialogWatcher dialog(COLOR_CYAN);
OverworldWatcher overworld(COLOR_GREEN);
OverworldWatcher overworld(console, COLOR_GREEN);
context.wait_for_all_requests();
int ret = run_until(
console, context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ void handle_egg_hatching(const ProgramInfo& info, ConsoleHandle& console, BotBas
{
console.log("Detect hatching dialog: " + std::to_string(egg_idx+1) + "/" + std::to_string(num_eggs_in_party));
console.overlay().add_log("Hatched " + std::to_string(egg_idx+1) + "/" + std::to_string(num_eggs_in_party), COLOR_GREEN);
OverworldWatcher overworld(COLOR_CYAN);
OverworldWatcher overworld(console, COLOR_CYAN);
int ret = run_until(
console, context,
[](BotBaseContext& context){
Expand Down Expand Up @@ -217,7 +217,7 @@ void order_compote_du_fils(const ProgramInfo& info, ConsoleHandle& console, BotB
context.wait_for_all_requests();

AdvanceDialogWatcher dialog_watcher(COLOR_RED, std::chrono::milliseconds(100));
OverworldWatcher overworld(COLOR_CYAN);
OverworldWatcher overworld(console, COLOR_CYAN);
int ret = wait_until(
console, context,
std::chrono::seconds(60),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ void AuctionFarmer::bid_on_item(SingleSwitchProgramEnvironment& env, BotBaseCont
PromptDialogWatcher high_detector(COLOR_RED, { 0.50, 0.40, 0.40, 0.082 });
PromptDialogWatcher mid_detector(COLOR_PURPLE, { 0.50, 0.475, 0.40, 0.082 });
PromptDialogWatcher low_detector(COLOR_PURPLE, { 0.50, 0.55, 0.40, 0.082 });
OverworldWatcher overworld_detector(COLOR_BLUE);
OverworldWatcher overworld_detector(env.console, COLOR_BLUE);
bool won_auction = true;
bool auction_ongoing = true;
int64_t current_bid = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ void quest_photo(const ProgramInfo& info, ConsoleHandle& console, BotBaseContext
//Take photo.
console.log("Taking photo.");
PromptDialogWatcher photo_prompt(COLOR_RED);
OverworldWatcher overworld(COLOR_BLUE);
OverworldWatcher overworld(console, COLOR_BLUE);

pbf_press_dpad(context, DPAD_DOWN, 50, 20);
pbf_wait(context, 100);
Expand Down Expand Up @@ -663,7 +663,7 @@ void quest_catch_handle_battle(const ProgramInfo& info, ConsoleHandle& console,
console.log("Catching Pokemon.");
AdvanceDialogWatcher advance_dialog(COLOR_MAGENTA);
PromptDialogWatcher add_to_party(COLOR_PURPLE);
OverworldWatcher overworld(COLOR_RED);
OverworldWatcher overworld(console, COLOR_RED);

uint8_t switch_party_slot = 1;
bool quickball_thrown = false;
Expand Down Expand Up @@ -888,7 +888,7 @@ void quest_catch(const ProgramInfo& info, ConsoleHandle& console, BotBaseContext
resume_game_from_home(console, context);

//Heal up and then reset position again.
OverworldWatcher done_healing(COLOR_BLUE);
OverworldWatcher done_healing(console, COLOR_BLUE);
pbf_move_left_joystick(context, 128, 0, 100, 20);

pbf_mash_button(context, BUTTON_A, 300);
Expand All @@ -912,7 +912,7 @@ void quest_catch(const ProgramInfo& info, ConsoleHandle& console, BotBaseContext

void wild_battle_tera(const ProgramInfo& info, ConsoleHandle& console, BotBaseContext& context, bool& tera_self){
AdvanceDialogWatcher lost(COLOR_YELLOW);
OverworldWatcher overworld(COLOR_RED);
OverworldWatcher overworld(console, COLOR_RED);
WallClock start = current_time();
uint8_t switch_party_slot = 1;
bool first_turn = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ void quest_make_tm(const ProgramInfo& info, ConsoleHandle& console, BotBaseConte

GradientArrowWatcher machine(COLOR_BLUE, GradientArrowType::DOWN, {0.181, 0.127, 0.045, 0.070});
PromptDialogWatcher makeTM(COLOR_RED);
OverworldWatcher overworld(COLOR_BLUE);
OverworldWatcher overworld(console, COLOR_BLUE);

pbf_move_left_joystick(context, 255, 0, 100, 20);
pbf_press_button(context, BUTTON_L, 10, 50);
Expand Down Expand Up @@ -568,7 +568,7 @@ void quest_tera_self_defeat(const ProgramInfo& info, ConsoleHandle& console, Bot
resume_game_from_home(console, context);

//Heal up and then reset position again.
OverworldWatcher done_healing(COLOR_BLUE);
OverworldWatcher done_healing(console, COLOR_BLUE);
pbf_move_left_joystick(context, 128, 0, 100, 20);

pbf_mash_button(context, BUTTON_A, 300);
Expand Down Expand Up @@ -645,7 +645,7 @@ void quest_sneak_up(const ProgramInfo& info, ConsoleHandle& console, BotBaseCont
pbf_press_button(context, BUTTON_CAPTURE, 2 * TICKS_PER_SECOND, 5 * TICKS_PER_SECOND);
throw ProgramFinishedException();
}else{
OverworldWatcher overworld(COLOR_BLUE);
OverworldWatcher overworld(console, COLOR_BLUE);

int ret2 = run_until(
console, context,
Expand Down Expand Up @@ -768,7 +768,7 @@ void quest_wild_tera(const ProgramInfo& info, ConsoleHandle& console, BotBaseCon
resume_game_from_home(console, context);

//Heal up and then reset position again.
OverworldWatcher done_healing(COLOR_BLUE);
OverworldWatcher done_healing(console, COLOR_BLUE);
pbf_move_left_joystick(context, 128, 0, 100, 20);

pbf_mash_button(context, BUTTON_A, 300);
Expand Down Expand Up @@ -1176,7 +1176,7 @@ void quest_auto_battle(ProgramEnvironment& env, ConsoleHandle& console, BotBaseC
context.wait_for_all_requests();
return_to_plaza(env.program_info(), console, context);

OverworldWatcher done_healing(COLOR_BLUE);
OverworldWatcher done_healing(console, COLOR_BLUE);
pbf_move_left_joystick(context, 128, 0, 100, 20);

pbf_mash_button(context, BUTTON_A, 300);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ void ESPTraining::program(SingleSwitchProgramEnvironment& env, BotBaseContext& c
}

//Program done, mash B until overworld detected
OverworldWatcher overworld(COLOR_CYAN);
OverworldWatcher overworld(env.console, COLOR_CYAN);
int ret = run_until(
env.console, context,
[](BotBaseContext& context){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ bool FlyingTrialFarmer::run_rewards(SingleSwitchProgramEnvironment& env, BotBase
bool trial_failed = true;
while (true){
DialogBoxWatcher dialog(COLOR_GREEN, true, std::chrono::milliseconds(250), DialogType::DIALOG_BLACK);
OverworldWatcher overworld(COLOR_CYAN);
OverworldWatcher overworld(env.console, COLOR_CYAN);
context.wait_for_all_requests();

int ret_finish = run_until(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ void GimmighoulChestFarmer::program(SingleSwitchProgramEnvironment& env, BotBase
pbf_mash_button(context, BUTTON_A, 90);
c++;
context.wait_for_all_requests();
OverworldWatcher overworld(COLOR_RED);
OverworldWatcher overworld(env.console, COLOR_RED);
int ret2 = wait_until(
env.console, context,
std::chrono::seconds(120),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,7 @@ void move_from_blueberry_entrance_to_league_club(const ProgramInfo& info, Consol
pbf_mash_button(context, BUTTON_A, 100);

// check for overworld
OverworldWatcher overworld(COLOR_CYAN);
OverworldWatcher overworld(console, COLOR_CYAN);
ret = wait_until(console, context, Milliseconds(10000), { overworld });
if (ret == 0){
console.log("Entered League club room.");
Expand Down Expand Up @@ -795,7 +795,7 @@ void move_from_item_printer_to_blueberry_entrance(const ProgramInfo& info, Conso
pbf_mash_button(context, BUTTON_A, 100);

// check for overworld
OverworldWatcher overworld(COLOR_CYAN);
OverworldWatcher overworld(console, COLOR_CYAN);
ret = wait_until(console, context, std::chrono::seconds(30), { overworld });
if (ret == 0){
console.log("Overworld detected");
Expand Down
Loading
Loading