Skip to content
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 @@ -124,6 +124,7 @@
#include "NintendoSwitch/Programs/DateSpam/NintendoSwitch_HomeToDateTime.h"
#include "NintendoSwitch/Inference/NintendoSwitch_ConsoleTypeDetector.h"
#include "NintendoSwitch/Inference/NintendoSwitch_HomeMenuDetector.h"
#include "NintendoSwitch/Inference/NintendoSwitch_CloseGameDetector.h"
#include "NintendoSwitch/Inference/NintendoSwitch_StartGameUserSelectDetector.h"
#include "NintendoSwitch/Inference/NintendoSwitch_UpdatePopupDetector.h"
#include "NintendoSwitch/Programs/DateSpam/NintendoSwitch_RollDateForward1.h"
Expand Down Expand Up @@ -289,9 +290,28 @@ void TestProgram::program(MultiSwitchProgramEnvironment& env, CancellableScope&
[[maybe_unused]] VideoFeed& feed = env.consoles[0];
[[maybe_unused]] VideoOverlay& overlay = env.consoles[0];
ProControllerContext context(scope, console.controller<ProController>());
// JoyconContext context(scope, console.controller<JoyconController>());
VideoOverlaySet overlays(overlay);


#if 0
close_game_from_home(console, context);
// ssf_issue_scroll(context, DPAD_DOWN, 24ms);
#endif

#if 0
// auto snapshot = feed.snapshot();
// CloseGameDetector detector(console);
// cout << detector.detect(snapshot) << endl;
CloseGameWatcher watcher(console);

int ret = wait_until(console, context, Seconds(10), {watcher});

if (ret == 0){
console.log("CloseGameWatcher detected.");
}

#endif

#if 0
ImageRGB32 image1("itemprinter.png");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/* Close Game Detector
*
* From: https://github.com/PokemonAutomation/
*
*/

#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h"
#include "CommonTools/Images/SolidColorTest.h"
#include "NintendoSwitch/NintendoSwitch_ConsoleHandle.h"
#include "NintendoSwitch_CloseGameDetector.h"

#include <iostream>
using std::cout;
using std::endl;

namespace PokemonAutomation{
namespace NintendoSwitch{



CloseGameDetector::CloseGameDetector(ConsoleHandle& console, Color color)
: m_color(color)
, m_top_box(0.226358, 0.272648, 0.407445, 0.033989)
, m_left_box(0.225, 0.275, 0.01995, 0.350)
, m_close_game_text_row(0.330986, 0.649052, 0.342052, 0.051878)
{}
void CloseGameDetector::make_overlays(VideoOverlaySet& items) const{
items.add(m_color, m_top_box);
items.add(m_color, m_left_box);
items.add(m_color, m_close_game_text_row);
}


bool CloseGameDetector::detect(const ImageViewRGB32& screen){

ImageStats stats_top = image_stats(extract_box_reference(screen, m_top_box)); // the top portion of the Close game popup
ImageStats stats_left = image_stats(extract_box_reference(screen, m_left_box)); // the left portion of the Close game popup
ImageStats stats_close_game_text = image_stats(extract_box_reference(screen, m_close_game_text_row)); // the bottom portion of the Close game popup. overlapping with the close game text.

// cout << "stats_close_game_text.stddev.sum()" << stats_close_game_text.stddev.sum() << endl;
bool white;
// cout << "stats_top.average.sum() = " << stats_top.average.sum() << endl;
if (stats_top.average.sum() < 300){
white = false;
}else if (stats_top.average.sum() > 500){
white = true;
}else{
return false;
}

// cout << "stats_top.stddev.sum() = " << stats_top.stddev.sum() << endl;

// ensure top is uniform in color
if (stats_top.stddev.sum() > 20){
return false;
}

// cout << "stats_left.stddev.sum() = " << stats_left.stddev.sum() << endl;
// ensure left is uniform in color
if (stats_left.stddev.sum() > 20){
return false;
}

// ensure bottom is NOT uniform in color
if (stats_close_game_text.stddev.sum() < 50){
return false;
}

if (white){ // if top is white, ensure left is also white
if (!is_white(stats_top) || !is_white(stats_left)){
// cout << "asdf" << endl;
return false;
}
}else{
if (!is_grey(stats_top, 0, 300) || !is_grey(stats_left, 0, 300)){
// cout << "qwer" << endl;
return false;
}
}

// ensure top and left are the same color.
if (euclidean_distance(stats_top.average, stats_left.average) > 20){
// cout << "qwer = " << euclidean_distance(stats_bottom_row.average, stats_bottom_row.average) << endl;
return false;
}


return true;
}






}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/* Close Game Detector
*
* From: https://github.com/PokemonAutomation/
*
*/

#ifndef PokemonAutomation_NintendoSwitch_CloseGameDetector_H
#define PokemonAutomation_NintendoSwitch_CloseGameDetector_H

#include "Common/Cpp/Color.h"
#include "CommonFramework/ImageTools/ImageBoxes.h"
#include "CommonTools/VisualDetector.h"

namespace PokemonAutomation{
namespace NintendoSwitch{



class CloseGameDetector : public StaticScreenDetector{
public:
CloseGameDetector(ConsoleHandle& console, Color color = COLOR_RED);

virtual void make_overlays(VideoOverlaySet& items) const override;
virtual bool detect(const ImageViewRGB32& screen) override;

private:
Color m_color;
ImageFloatBox m_top_box;
ImageFloatBox m_left_box;
ImageFloatBox m_close_game_text_row;

};
class CloseGameWatcher : public DetectorToFinder<CloseGameDetector>{
public:
CloseGameWatcher(
ConsoleHandle& console,
std::chrono::milliseconds hold_duration = std::chrono::milliseconds(250)
)
: DetectorToFinder("CloseGameWatcher", hold_duration, console)
{}
};




}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "NintendoSwitch/Commands/NintendoSwitch_Commands_Superscalar.h"
#include "NintendoSwitch/Inference/NintendoSwitch_DetectHome.h"
#include "NintendoSwitch/Inference/NintendoSwitch_HomeMenuDetector.h"
#include "NintendoSwitch/Inference/NintendoSwitch_CloseGameDetector.h"
#include "NintendoSwitch/Inference/NintendoSwitch_StartGameUserSelectDetector.h"
#include "NintendoSwitch/Inference/NintendoSwitch_UpdatePopupDetector.h"
#include "NintendoSwitch_GameEntry.h"
Expand Down Expand Up @@ -99,13 +100,12 @@ void ensure_at_home(ConsoleHandle& console, JoyconContext& context){
}



//
// close_game_from_home()
//

void close_game_from_home(ConsoleHandle& console, ProControllerContext& context){
console.log("close_game_from_home");
void close_game_from_home_blind(ConsoleHandle& console, ProControllerContext& context){
console.log("close_game_from_home_blind");
ensure_at_home(console, context);

// Use mashing to ensure that the X press succeeds. If it fails, the SR
Expand All @@ -125,8 +125,9 @@ void close_game_from_home(ConsoleHandle& console, ProControllerContext& context)
pbf_mash_button(context, BUTTON_X, 50);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Since we're now using visual inference, mashing X and B are no longer necessary, right? Should we remove them?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh yes. Commented below without seeing this one on top (on the otherwise identical code).

pbf_mash_button(context, BUTTON_B, 350);
}
void close_game_from_home(ConsoleHandle& console, JoyconContext& context){
console.log("close_game_from_home");

void close_game_from_home_blind(ConsoleHandle& console, JoyconContext& context){
console.log("close_game_from_home_blind");
ensure_at_home(console, context);
// Use mashing to ensure that the X press succeeds. If it fails, the SR
// will fail and can kill a den for the autohosts.
Expand All @@ -146,6 +147,87 @@ void close_game_from_home(ConsoleHandle& console, JoyconContext& context){
pbf_mash_button(context, BUTTON_B, 2000ms);
}

template <typename ControllerContext>
void close_game_from_home(ConsoleHandle& console, ControllerContext& context){
if (!console.video().snapshot()){ // no visual feedback available
close_game_from_home_blind(console, context);
return;
}

console.log("close_game_from_home");
ensure_at_home(console, context);

// this sequence will close the game from the home screen,
// regardless of whether the game is initially open or closed.
bool seen_close_game = false;
size_t times_seen_home_before = 0;
while (true){
context.wait_for_all_requests();

CloseGameWatcher close_game(console);
HomeMenuWatcher home(console);
int ret = wait_until(
console, context,
Seconds(10),
{close_game, home}
);

switch(ret){
case 0: // close_game
console.log("Detected close game menu.");
pbf_mash_button(context, BUTTON_A, 400ms);
seen_close_game = true;
continue;
case 1: // home
if (seen_close_game){ // successfully closed the game
return;
}

if (times_seen_home_before == 0){ // Try closing the game
pbf_mash_button(context, BUTTON_X, 800ms);
times_seen_home_before++;
continue;
}

if (times_seen_home_before == 1){ // The game not being selected can happen in Switch 2, when you touch the touchscreen on empty space on the Home screen.
console.log("Failed to close game once. Either game is already closed, or the game is not selected.");
ssf_issue_scroll(context, DPAD_DOWN, 24ms); // moving the DPAD/joystick will allow the selection to come back.
ssf_issue_scroll(context, DPAD_DOWN, 24ms);
ssf_issue_scroll(context, DPAD_DOWN, 24ms);
console.log("Click the Home button to ensure that current game is selected.");
pbf_press_button(context, BUTTON_HOME, 160ms, 500ms); // clicking home ensures that the cursor is selected on the current game.
go_home(console, context);
console.log("Try again to close the game.");
pbf_mash_button(context, BUTTON_X, 800ms); // try again to close the game.
times_seen_home_before++;
continue;
}

if (times_seen_home_before == 2){
console.log("Game was already closed.");
return;
}

throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "close_game_from_home: Unexpected state.");

default:
OperationFailedException::fire(
ErrorReport::SEND_ERROR_REPORT,
"close_game_from_home(): Failed to detect either the Home screen or the Close game menu after 10 seconds.",
console
);
}
}

}

void close_game_from_home(ConsoleHandle& console, ProControllerContext& context){
close_game_from_home<ProControllerContext>(console, context);
}

void close_game_from_home(ConsoleHandle& console, JoyconContext& context){
close_game_from_home<JoyconContext>(console, context);
}


//
Expand Down
2 changes: 2 additions & 0 deletions SerialPrograms/SourceFiles.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -1000,6 +1000,8 @@ file(GLOB LIBRARY_SOURCES
Source/NintendoSwitch/Framework/UI/NintendoSwitch_SwitchSystemWidget.h
Source/NintendoSwitch/Inference/NintendoSwitch2_BinarySliderDetector.cpp
Source/NintendoSwitch/Inference/NintendoSwitch2_BinarySliderDetector.h
Source/NintendoSwitch/Inference/NintendoSwitch_CloseGameDetector.cpp
Source/NintendoSwitch/Inference/NintendoSwitch_CloseGameDetector.h
Source/NintendoSwitch/Inference/NintendoSwitch_ConsoleTypeDetector.cpp
Source/NintendoSwitch/Inference/NintendoSwitch_ConsoleTypeDetector.h
Source/NintendoSwitch/Inference/NintendoSwitch_DateChangeDetector.cpp
Expand Down