Automatic disc change for 2-disc games
This commit is contained in:
parent
fc68b835e7
commit
bd665aad5d
|
@ -54,6 +54,12 @@
|
||||||
#include "DiscIO/Enums.h"
|
#include "DiscIO/Enums.h"
|
||||||
#include "DiscIO/Volume.h"
|
#include "DiscIO/Volume.h"
|
||||||
|
|
||||||
|
std::vector<std::string> ReadM3UFile(const std::string& path)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
BootParameters::BootParameters(Parameters&& parameters_,
|
BootParameters::BootParameters(Parameters&& parameters_,
|
||||||
const std::optional<std::string>& savestate_path_)
|
const std::optional<std::string>& savestate_path_)
|
||||||
: parameters(std::move(parameters_)), savestate_path(savestate_path_)
|
: parameters(std::move(parameters_)), savestate_path(savestate_path_)
|
||||||
|
@ -61,40 +67,68 @@ BootParameters::BootParameters(Parameters&& parameters_,
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<BootParameters>
|
std::unique_ptr<BootParameters>
|
||||||
BootParameters::GenerateFromFile(const std::string& path,
|
BootParameters::GenerateFromFile(std::string boot_path,
|
||||||
const std::optional<std::string>& savestate_path)
|
const std::optional<std::string>& savestate_path)
|
||||||
{
|
{
|
||||||
const bool is_drive = Common::IsCDROMDevice(path);
|
return GenerateFromFile(std::vector<std::string>{std::move(boot_path)}, savestate_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<BootParameters>
|
||||||
|
BootParameters::GenerateFromFile(std::vector<std::string> paths,
|
||||||
|
const std::optional<std::string>& savestate_path)
|
||||||
|
{
|
||||||
|
ASSERT(!paths.empty());
|
||||||
|
|
||||||
|
const bool is_drive = Common::IsCDROMDevice(paths.front());
|
||||||
// Check if the file exist, we may have gotten it from a --elf command line
|
// Check if the file exist, we may have gotten it from a --elf command line
|
||||||
// that gave an incorrect file name
|
// that gave an incorrect file name
|
||||||
if (!is_drive && !File::Exists(path))
|
if (!is_drive && !File::Exists(paths.front()))
|
||||||
{
|
{
|
||||||
PanicAlertT("The specified file \"%s\" does not exist", path.c_str());
|
PanicAlertT("The specified file \"%s\" does not exist", paths.front().c_str());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string extension;
|
std::string extension;
|
||||||
SplitPath(path, nullptr, nullptr, &extension);
|
SplitPath(paths.front(), nullptr, nullptr, &extension);
|
||||||
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
|
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
|
||||||
|
|
||||||
|
if (extension == ".m3u")
|
||||||
|
{
|
||||||
|
std::vector<std::string> new_paths = ReadM3UFile(paths.front());
|
||||||
|
if (!new_paths.empty())
|
||||||
|
{
|
||||||
|
paths = new_paths;
|
||||||
|
|
||||||
|
SplitPath(paths.front(), nullptr, nullptr, &extension);
|
||||||
|
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string path = paths.front();
|
||||||
|
if (paths.size() == 1)
|
||||||
|
paths.clear();
|
||||||
|
|
||||||
static const std::unordered_set<std::string> disc_image_extensions = {
|
static const std::unordered_set<std::string> disc_image_extensions = {
|
||||||
{".gcm", ".iso", ".tgc", ".wbfs", ".ciso", ".gcz", ".dol", ".elf"}};
|
{".gcm", ".iso", ".tgc", ".wbfs", ".ciso", ".gcz", ".dol", ".elf"}};
|
||||||
if (disc_image_extensions.find(extension) != disc_image_extensions.end() || is_drive)
|
if (disc_image_extensions.find(extension) != disc_image_extensions.end() || is_drive)
|
||||||
{
|
{
|
||||||
std::unique_ptr<DiscIO::Volume> volume = DiscIO::CreateVolumeFromFilename(path);
|
std::unique_ptr<DiscIO::Volume> volume = DiscIO::CreateVolumeFromFilename(path);
|
||||||
if (volume)
|
if (volume)
|
||||||
return std::make_unique<BootParameters>(Disc{path, std::move(volume)}, savestate_path);
|
{
|
||||||
|
return std::make_unique<BootParameters>(Disc{std::move(path), std::move(volume), paths},
|
||||||
|
savestate_path);
|
||||||
|
}
|
||||||
|
|
||||||
if (extension == ".elf")
|
if (extension == ".elf")
|
||||||
{
|
{
|
||||||
return std::make_unique<BootParameters>(Executable{path, std::make_unique<ElfReader>(path)},
|
return std::make_unique<BootParameters>(
|
||||||
savestate_path);
|
Executable{std::move(path), std::make_unique<ElfReader>(path)}, savestate_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extension == ".dol")
|
if (extension == ".dol")
|
||||||
{
|
{
|
||||||
return std::make_unique<BootParameters>(Executable{path, std::make_unique<DolReader>(path)},
|
return std::make_unique<BootParameters>(
|
||||||
savestate_path);
|
Executable{std::move(path), std::make_unique<DolReader>(path)}, savestate_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_drive)
|
if (is_drive)
|
||||||
|
@ -113,10 +147,10 @@ BootParameters::GenerateFromFile(const std::string& path,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extension == ".dff")
|
if (extension == ".dff")
|
||||||
return std::make_unique<BootParameters>(DFF{path}, savestate_path);
|
return std::make_unique<BootParameters>(DFF{std::move(path)}, savestate_path);
|
||||||
|
|
||||||
if (extension == ".wad")
|
if (extension == ".wad")
|
||||||
return std::make_unique<BootParameters>(DiscIO::WiiWAD{path}, savestate_path);
|
return std::make_unique<BootParameters>(DiscIO::WiiWAD{std::move(path)}, savestate_path);
|
||||||
|
|
||||||
PanicAlertT("Could not recognize file %s", path.c_str());
|
PanicAlertT("Could not recognize file %s", path.c_str());
|
||||||
return {};
|
return {};
|
||||||
|
@ -136,10 +170,11 @@ BootParameters::IPL::IPL(DiscIO::Region region_, Disc&& disc_) : IPL(region_)
|
||||||
// Inserts a disc into the emulated disc drive and returns a pointer to it.
|
// Inserts a disc into the emulated disc drive and returns a pointer to it.
|
||||||
// The returned pointer must only be used while we are still booting,
|
// The returned pointer must only be used while we are still booting,
|
||||||
// because DVDThread can do whatever it wants to the disc after that.
|
// because DVDThread can do whatever it wants to the disc after that.
|
||||||
static const DiscIO::Volume* SetDisc(std::unique_ptr<DiscIO::Volume> volume)
|
static const DiscIO::Volume* SetDisc(std::unique_ptr<DiscIO::Volume> volume,
|
||||||
|
std::vector<std::string> auto_disc_change_paths = {})
|
||||||
{
|
{
|
||||||
const DiscIO::Volume* pointer = volume.get();
|
const DiscIO::Volume* pointer = volume.get();
|
||||||
DVDInterface::SetDisc(std::move(volume));
|
DVDInterface::SetDisc(std::move(volume), auto_disc_change_paths);
|
||||||
return pointer;
|
return pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +361,7 @@ bool CBoot::BootUp(std::unique_ptr<BootParameters> boot)
|
||||||
bool operator()(BootParameters::Disc& disc) const
|
bool operator()(BootParameters::Disc& disc) const
|
||||||
{
|
{
|
||||||
NOTICE_LOG(BOOT, "Booting from disc: %s", disc.path.c_str());
|
NOTICE_LOG(BOOT, "Booting from disc: %s", disc.path.c_str());
|
||||||
const DiscIO::Volume* volume = SetDisc(std::move(disc.volume));
|
const DiscIO::Volume* volume = SetDisc(std::move(disc.volume), disc.auto_disc_change_paths);
|
||||||
|
|
||||||
if (!volume)
|
if (!volume)
|
||||||
return false;
|
return false;
|
||||||
|
@ -420,7 +455,7 @@ bool CBoot::BootUp(std::unique_ptr<BootParameters> boot)
|
||||||
if (ipl.disc)
|
if (ipl.disc)
|
||||||
{
|
{
|
||||||
NOTICE_LOG(BOOT, "Inserting disc: %s", ipl.disc->path.c_str());
|
NOTICE_LOG(BOOT, "Inserting disc: %s", ipl.disc->path.c_str());
|
||||||
SetDisc(DiscIO::CreateVolumeFromFilename(ipl.disc->path));
|
SetDisc(DiscIO::CreateVolumeFromFilename(ipl.disc->path), ipl.disc->auto_disc_change_paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LoadMapFromFilename())
|
if (LoadMapFromFilename())
|
||||||
|
|
|
@ -40,6 +40,7 @@ struct BootParameters
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
std::unique_ptr<DiscIO::Volume> volume;
|
std::unique_ptr<DiscIO::Volume> volume;
|
||||||
|
std::vector<std::string> auto_disc_change_paths;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Executable
|
struct Executable
|
||||||
|
@ -69,7 +70,9 @@ struct BootParameters
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::unique_ptr<BootParameters>
|
static std::unique_ptr<BootParameters>
|
||||||
GenerateFromFile(const std::string& boot_path,
|
GenerateFromFile(std::string boot_path, const std::optional<std::string>& savestate_path = {});
|
||||||
|
static std::unique_ptr<BootParameters>
|
||||||
|
GenerateFromFile(std::vector<std::string> paths,
|
||||||
const std::optional<std::string>& savestate_path = {});
|
const std::optional<std::string>& savestate_path = {});
|
||||||
|
|
||||||
using Parameters = std::variant<Disc, Executable, DiscIO::WiiWAD, NANDTitle, IPL, DFF>;
|
using Parameters = std::variant<Disc, Executable, DiscIO::WiiWAD, NANDTitle, IPL, DFF>;
|
||||||
|
|
|
@ -104,6 +104,7 @@ const ConfigInfo<u32> MAIN_CUSTOM_RTC_VALUE{{System::Main, "Core", "CustomRTCVal
|
||||||
const ConfigInfo<bool> MAIN_ENABLE_SIGNATURE_CHECKS{{System::Main, "Core", "EnableSignatureChecks"},
|
const ConfigInfo<bool> MAIN_ENABLE_SIGNATURE_CHECKS{{System::Main, "Core", "EnableSignatureChecks"},
|
||||||
true};
|
true};
|
||||||
const ConfigInfo<bool> MAIN_REDUCE_POLLING_RATE{{System::Main, "Core", "ReducePollingRate"}, false};
|
const ConfigInfo<bool> MAIN_REDUCE_POLLING_RATE{{System::Main, "Core", "ReducePollingRate"}, false};
|
||||||
|
const ConfigInfo<bool> MAIN_AUTO_DISC_CHANGE{{System::Main, "Core", "AutoDiscChange"}, false};
|
||||||
|
|
||||||
// Main.DSP
|
// Main.DSP
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,7 @@ extern const ConfigInfo<bool> MAIN_CUSTOM_RTC_ENABLE;
|
||||||
extern const ConfigInfo<u32> MAIN_CUSTOM_RTC_VALUE;
|
extern const ConfigInfo<u32> MAIN_CUSTOM_RTC_VALUE;
|
||||||
extern const ConfigInfo<bool> MAIN_ENABLE_SIGNATURE_CHECKS;
|
extern const ConfigInfo<bool> MAIN_ENABLE_SIGNATURE_CHECKS;
|
||||||
extern const ConfigInfo<bool> MAIN_REDUCE_POLLING_RATE;
|
extern const ConfigInfo<bool> MAIN_REDUCE_POLLING_RATE;
|
||||||
|
extern const ConfigInfo<bool> MAIN_AUTO_DISC_CHANGE;
|
||||||
|
|
||||||
// Main.DSP
|
// Main.DSP
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ bool IsSettingSaveable(const Config::ConfigLocation& config_location)
|
||||||
Config::MAIN_DEFAULT_ISO.location,
|
Config::MAIN_DEFAULT_ISO.location,
|
||||||
Config::MAIN_MEMCARD_A_PATH.location,
|
Config::MAIN_MEMCARD_A_PATH.location,
|
||||||
Config::MAIN_MEMCARD_B_PATH.location,
|
Config::MAIN_MEMCARD_B_PATH.location,
|
||||||
|
Config::MAIN_AUTO_DISC_CHANGE.location,
|
||||||
|
|
||||||
// Graphics.Hardware
|
// Graphics.Hardware
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,10 @@
|
||||||
#include "Common/Align.h"
|
#include "Common/Align.h"
|
||||||
#include "Common/ChunkFile.h"
|
#include "Common/ChunkFile.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Config/Config.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
|
|
||||||
|
#include "Core/Config/MainSettings.h"
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/CoreTiming.h"
|
#include "Core/CoreTiming.h"
|
||||||
#include "Core/HW/AudioInterface.h"
|
#include "Core/HW/AudioInterface.h"
|
||||||
|
@ -36,6 +38,8 @@
|
||||||
#include "DiscIO/Volume.h"
|
#include "DiscIO/Volume.h"
|
||||||
#include "DiscIO/VolumeWii.h"
|
#include "DiscIO/VolumeWii.h"
|
||||||
|
|
||||||
|
#include "VideoCommon/OnScreenDisplay.h"
|
||||||
|
|
||||||
// The minimum time it takes for the DVD drive to process a command (in
|
// The minimum time it takes for the DVD drive to process a command (in
|
||||||
// microseconds)
|
// microseconds)
|
||||||
constexpr u64 COMMAND_LATENCY_US = 300;
|
constexpr u64 COMMAND_LATENCY_US = 300;
|
||||||
|
@ -231,6 +235,8 @@ static u64 s_read_buffer_end_offset;
|
||||||
|
|
||||||
// Disc changing
|
// Disc changing
|
||||||
static std::string s_disc_path_to_insert;
|
static std::string s_disc_path_to_insert;
|
||||||
|
static std::vector<std::string> s_auto_disc_change_paths;
|
||||||
|
static size_t s_auto_disc_change_index;
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
static CoreTiming::EventType* s_finish_executing_command;
|
static CoreTiming::EventType* s_finish_executing_command;
|
||||||
|
@ -441,11 +447,21 @@ void Shutdown()
|
||||||
DVDThread::Stop();
|
DVDThread::Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDisc(std::unique_ptr<DiscIO::Volume> disc)
|
void SetDisc(std::unique_ptr<DiscIO::Volume> disc,
|
||||||
|
std::optional<std::vector<std::string>> auto_disc_change_paths = {})
|
||||||
{
|
{
|
||||||
if (disc)
|
if (disc)
|
||||||
s_current_partition = disc->GetGamePartition();
|
s_current_partition = disc->GetGamePartition();
|
||||||
|
|
||||||
|
if (auto_disc_change_paths)
|
||||||
|
{
|
||||||
|
ASSERT_MSG(DISCIO, (*auto_disc_change_paths).size() != 1,
|
||||||
|
"Cannot automatically change between one disc");
|
||||||
|
|
||||||
|
s_auto_disc_change_paths = *auto_disc_change_paths;
|
||||||
|
s_auto_disc_change_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
DVDThread::SetDisc(std::move(disc));
|
DVDThread::SetDisc(std::move(disc));
|
||||||
SetLidOpen();
|
SetLidOpen();
|
||||||
}
|
}
|
||||||
|
@ -457,7 +473,7 @@ bool IsDiscInside()
|
||||||
|
|
||||||
static void EjectDiscCallback(u64 userdata, s64 cyclesLate)
|
static void EjectDiscCallback(u64 userdata, s64 cyclesLate)
|
||||||
{
|
{
|
||||||
SetDisc(nullptr);
|
SetDisc(nullptr, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InsertDiscCallback(u64 userdata, s64 cyclesLate)
|
static void InsertDiscCallback(u64 userdata, s64 cyclesLate)
|
||||||
|
@ -466,7 +482,7 @@ static void InsertDiscCallback(u64 userdata, s64 cyclesLate)
|
||||||
DiscIO::CreateVolumeFromFilename(s_disc_path_to_insert);
|
DiscIO::CreateVolumeFromFilename(s_disc_path_to_insert);
|
||||||
|
|
||||||
if (new_volume)
|
if (new_volume)
|
||||||
SetDisc(std::move(new_volume));
|
SetDisc(std::move(new_volume), {});
|
||||||
else
|
else
|
||||||
PanicAlertT("The disc that was about to be inserted couldn't be found.");
|
PanicAlertT("The disc that was about to be inserted couldn't be found.");
|
||||||
|
|
||||||
|
@ -479,6 +495,20 @@ void EjectDisc()
|
||||||
CoreTiming::ScheduleEvent(0, s_eject_disc);
|
CoreTiming::ScheduleEvent(0, s_eject_disc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Must only be called on the CPU thread
|
||||||
|
void ChangeDisc(const std::vector<std::string>& paths)
|
||||||
|
{
|
||||||
|
ASSERT_MSG(DISCIO, !paths.empty(), "Trying to insert an empty list of discs");
|
||||||
|
|
||||||
|
if (paths.size() > 1)
|
||||||
|
{
|
||||||
|
s_auto_disc_change_paths = paths;
|
||||||
|
s_auto_disc_change_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChangeDisc(paths[0]);
|
||||||
|
}
|
||||||
|
|
||||||
// Must only be called on the CPU thread
|
// Must only be called on the CPU thread
|
||||||
void ChangeDisc(const std::string& new_path)
|
void ChangeDisc(const std::string& new_path)
|
||||||
{
|
{
|
||||||
|
@ -493,6 +523,28 @@ void ChangeDisc(const std::string& new_path)
|
||||||
s_disc_path_to_insert = new_path;
|
s_disc_path_to_insert = new_path;
|
||||||
CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond(), s_insert_disc);
|
CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond(), s_insert_disc);
|
||||||
Movie::SignalDiscChange(new_path);
|
Movie::SignalDiscChange(new_path);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < s_auto_disc_change_paths.size(); ++i)
|
||||||
|
{
|
||||||
|
if (s_auto_disc_change_paths[i] == new_path)
|
||||||
|
{
|
||||||
|
s_auto_disc_change_index = i;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s_auto_disc_change_paths.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must only be called on the CPU thread
|
||||||
|
bool AutoChangeDisc()
|
||||||
|
{
|
||||||
|
if (s_auto_disc_change_paths.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
s_auto_disc_change_index = (s_auto_disc_change_index + 1) % s_auto_disc_change_paths.size();
|
||||||
|
ChangeDisc(s_auto_disc_change_paths[s_auto_disc_change_index]);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetLidOpen()
|
void SetLidOpen()
|
||||||
|
@ -983,12 +1035,20 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DVDLowStopMotor:
|
case DVDLowStopMotor:
|
||||||
|
{
|
||||||
INFO_LOG(DVDINTERFACE, "DVDLowStopMotor %s %s", command_1 ? "eject" : "",
|
INFO_LOG(DVDINTERFACE, "DVDLowStopMotor %s %s", command_1 ? "eject" : "",
|
||||||
command_2 ? "kill!" : "");
|
command_2 ? "kill!" : "");
|
||||||
|
|
||||||
if (command_1 && !command_2)
|
bool auto_disc_change = Config::Get(Config::MAIN_AUTO_DISC_CHANGE) && !Movie::IsPlayingInput();
|
||||||
|
if (auto_disc_change)
|
||||||
|
auto_disc_change = AutoChangeDisc();
|
||||||
|
if (auto_disc_change)
|
||||||
|
OSD::AddMessage("Changing discs automatically...", OSD::Duration::NORMAL);
|
||||||
|
|
||||||
|
if (!auto_disc_change && command_1 && !command_2)
|
||||||
EjectDiscCallback(0, 0);
|
EjectDiscCallback(0, 0);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// DVD Audio Enable/Disable (Immediate). GC uses this, and apparently Wii also does...?
|
// DVD Audio Enable/Disable (Immediate). GC uses this, and apparently Wii also does...?
|
||||||
case DVDLowAudioBufferConfig:
|
case DVDLowAudioBufferConfig:
|
||||||
|
|
|
@ -111,10 +111,13 @@ void DoState(PointerWrap& p);
|
||||||
|
|
||||||
void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
|
void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
|
||||||
|
|
||||||
void SetDisc(std::unique_ptr<DiscIO::Volume> disc);
|
void SetDisc(std::unique_ptr<DiscIO::Volume> disc,
|
||||||
|
std::optional<std::vector<std::string>> auto_disc_change_paths);
|
||||||
bool IsDiscInside();
|
bool IsDiscInside();
|
||||||
void EjectDisc(); // Must only be called on the CPU thread
|
void EjectDisc(); // Must only be called on the CPU thread
|
||||||
|
void ChangeDisc(const std::vector<std::string>& paths); // Must only be called on the CPU thread
|
||||||
void ChangeDisc(const std::string& new_path); // Must only be called on the CPU thread
|
void ChangeDisc(const std::string& new_path); // Must only be called on the CPU thread
|
||||||
|
bool AutoChangeDisc(); // Must only be called on the CPU thread
|
||||||
|
|
||||||
// This function returns true and calls SConfig::SetRunningGameMetadata(Volume&, Partition&)
|
// This function returns true and calls SConfig::SetRunningGameMetadata(Volume&, Partition&)
|
||||||
// if both of the following conditions are true:
|
// if both of the following conditions are true:
|
||||||
|
|
|
@ -1176,29 +1176,13 @@ void PlayController(GCPadStatus* PadStatus, int controllerID)
|
||||||
PadStatus->button |= PAD_TRIGGER_R;
|
PadStatus->button |= PAD_TRIGGER_R;
|
||||||
if (s_padState.disc)
|
if (s_padState.disc)
|
||||||
{
|
{
|
||||||
// This implementation assumes the disc change will only happen once. Trying
|
Core::RunAsCPUThread([] {
|
||||||
// to change more than that will cause it to load the last disc every time.
|
if (!DVDInterface::AutoChangeDisc())
|
||||||
// As far as I know, there are no 3+ disc games, so this should be fine.
|
|
||||||
bool found = false;
|
|
||||||
std::string path;
|
|
||||||
for (const std::string& iso_folder : SConfig::GetInstance().m_ISOFolder)
|
|
||||||
{
|
|
||||||
path = iso_folder + '/' + s_discChange;
|
|
||||||
if (File::Exists(path))
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (found)
|
|
||||||
{
|
|
||||||
Core::RunAsCPUThread([&path] { DVDInterface::ChangeDisc(path); });
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
CPU::Break();
|
CPU::Break();
|
||||||
PanicAlertT("Change the disc to %s", s_discChange.c_str());
|
PanicAlertT("Change the disc to %s", s_discChange.c_str());
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_padState.reset)
|
if (s_padState.reset)
|
||||||
|
|
|
@ -368,7 +368,10 @@ int main(int argc, char* argv[])
|
||||||
std::unique_ptr<BootParameters> boot;
|
std::unique_ptr<BootParameters> boot;
|
||||||
if (options.is_set("exec"))
|
if (options.is_set("exec"))
|
||||||
{
|
{
|
||||||
boot = BootParameters::GenerateFromFile(static_cast<const char*>(options.get("exec")));
|
const std::list<std::string> paths_list = options.all("exec");
|
||||||
|
const std::vector<std::string> paths{std::make_move_iterator(std::begin(paths_list)),
|
||||||
|
std::make_move_iterator(std::end(paths_list))};
|
||||||
|
boot = BootParameters::GenerateFromFile(paths);
|
||||||
}
|
}
|
||||||
else if (options.is_set("nand_title"))
|
else if (options.is_set("nand_title"))
|
||||||
{
|
{
|
||||||
|
|
|
@ -737,6 +737,17 @@ bool GameList::HasMultipleSelected() const
|
||||||
m_grid->selectionModel()->selectedIndexes().size() > 1;
|
m_grid->selectionModel()->selectedIndexes().size() > 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<const UICommon::GameFile> GameList::FindGame(const std::string& path) const
|
||||||
|
{
|
||||||
|
return m_model->FindGame(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<const UICommon::GameFile>
|
||||||
|
GameList::FindSecondDisc(const UICommon::GameFile& game) const
|
||||||
|
{
|
||||||
|
return m_model->FindSecondDisc(game);
|
||||||
|
}
|
||||||
|
|
||||||
void GameList::SetViewColumn(int col, bool view)
|
void GameList::SetViewColumn(int col, bool view)
|
||||||
{
|
{
|
||||||
m_list->setColumnHidden(col, !view);
|
m_list->setColumnHidden(col, !view);
|
||||||
|
|
|
@ -30,6 +30,8 @@ public:
|
||||||
std::shared_ptr<const UICommon::GameFile> GetSelectedGame() const;
|
std::shared_ptr<const UICommon::GameFile> GetSelectedGame() const;
|
||||||
QList<std::shared_ptr<const UICommon::GameFile>> GetSelectedGames() const;
|
QList<std::shared_ptr<const UICommon::GameFile>> GetSelectedGames() const;
|
||||||
bool HasMultipleSelected() const;
|
bool HasMultipleSelected() const;
|
||||||
|
std::shared_ptr<const UICommon::GameFile> FindGame(const std::string& path) const;
|
||||||
|
std::shared_ptr<const UICommon::GameFile> FindSecondDisc(const UICommon::GameFile& game) const;
|
||||||
|
|
||||||
void SetListView() { SetPreferredView(true); }
|
void SetListView() { SetPreferredView(true); }
|
||||||
void SetGridView() { SetPreferredView(false); }
|
void SetGridView() { SetPreferredView(false); }
|
||||||
|
|
|
@ -278,7 +278,7 @@ void GameListModel::AddGame(const std::shared_ptr<const UICommon::GameFile>& gam
|
||||||
|
|
||||||
void GameListModel::UpdateGame(const std::shared_ptr<const UICommon::GameFile>& game)
|
void GameListModel::UpdateGame(const std::shared_ptr<const UICommon::GameFile>& game)
|
||||||
{
|
{
|
||||||
int index = FindGame(game->GetFilePath());
|
int index = FindGameIndex(game->GetFilePath());
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
{
|
{
|
||||||
AddGame(game);
|
AddGame(game);
|
||||||
|
@ -292,7 +292,7 @@ void GameListModel::UpdateGame(const std::shared_ptr<const UICommon::GameFile>&
|
||||||
|
|
||||||
void GameListModel::RemoveGame(const std::string& path)
|
void GameListModel::RemoveGame(const std::string& path)
|
||||||
{
|
{
|
||||||
int entry = FindGame(path);
|
int entry = FindGameIndex(path);
|
||||||
if (entry < 0)
|
if (entry < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -301,7 +301,13 @@ void GameListModel::RemoveGame(const std::string& path)
|
||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
int GameListModel::FindGame(const std::string& path) const
|
std::shared_ptr<const UICommon::GameFile> GameListModel::FindGame(const std::string& path) const
|
||||||
|
{
|
||||||
|
const int index = FindGameIndex(path);
|
||||||
|
return index < 0 ? nullptr : m_games[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
int GameListModel::FindGameIndex(const std::string& path) const
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_games.size(); i++)
|
for (int i = 0; i < m_games.size(); i++)
|
||||||
{
|
{
|
||||||
|
@ -311,6 +317,29 @@ int GameListModel::FindGame(const std::string& path) const
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<const UICommon::GameFile>
|
||||||
|
GameListModel::FindSecondDisc(const UICommon::GameFile& game) const
|
||||||
|
{
|
||||||
|
std::shared_ptr<const UICommon::GameFile> match_without_revision = nullptr;
|
||||||
|
|
||||||
|
if (DiscIO::IsDisc(game.GetPlatform()))
|
||||||
|
{
|
||||||
|
for (auto& other_game : m_games)
|
||||||
|
{
|
||||||
|
if (game.GetGameID() == other_game->GetGameID() &&
|
||||||
|
game.GetDiscNumber() != other_game->GetDiscNumber())
|
||||||
|
{
|
||||||
|
if (game.GetRevision() == other_game->GetRevision())
|
||||||
|
return other_game;
|
||||||
|
else
|
||||||
|
match_without_revision = other_game;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return match_without_revision;
|
||||||
|
}
|
||||||
|
|
||||||
void GameListModel::SetSearchTerm(const QString& term)
|
void GameListModel::SetSearchTerm(const QString& term)
|
||||||
{
|
{
|
||||||
m_term = term;
|
m_term = term;
|
||||||
|
|
|
@ -63,6 +63,9 @@ public:
|
||||||
void UpdateGame(const std::shared_ptr<const UICommon::GameFile>& game);
|
void UpdateGame(const std::shared_ptr<const UICommon::GameFile>& game);
|
||||||
void RemoveGame(const std::string& path);
|
void RemoveGame(const std::string& path);
|
||||||
|
|
||||||
|
std::shared_ptr<const UICommon::GameFile> FindGame(const std::string& path) const;
|
||||||
|
std::shared_ptr<const UICommon::GameFile> FindSecondDisc(const UICommon::GameFile& game) const;
|
||||||
|
|
||||||
void SetScale(float scale);
|
void SetScale(float scale);
|
||||||
float GetScale() const;
|
float GetScale() const;
|
||||||
|
|
||||||
|
@ -79,7 +82,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Index in m_games, or -1 if it isn't found
|
// Index in m_games, or -1 if it isn't found
|
||||||
int FindGame(const std::string& path) const;
|
int FindGameIndex(const std::string& path) const;
|
||||||
|
|
||||||
QStringList m_tag_list;
|
QStringList m_tag_list;
|
||||||
QMap<QString, QVariant> m_game_tags;
|
QMap<QString, QVariant> m_game_tags;
|
||||||
|
|
|
@ -147,7 +147,10 @@ int main(int argc, char* argv[])
|
||||||
std::unique_ptr<BootParameters> boot;
|
std::unique_ptr<BootParameters> boot;
|
||||||
if (options.is_set("exec"))
|
if (options.is_set("exec"))
|
||||||
{
|
{
|
||||||
boot = BootParameters::GenerateFromFile(static_cast<const char*>(options.get("exec")));
|
const std::list<std::string> paths_list = options.all("exec");
|
||||||
|
const std::vector<std::string> paths{std::make_move_iterator(std::begin(paths_list)),
|
||||||
|
std::make_move_iterator(std::end(paths_list))};
|
||||||
|
boot = BootParameters::GenerateFromFile(paths);
|
||||||
}
|
}
|
||||||
else if (options.is_set("nand_title"))
|
else if (options.is_set("nand_title"))
|
||||||
{
|
{
|
||||||
|
|
|
@ -168,6 +168,17 @@ static WindowSystemInfo GetWindowSystemInfo(QWindow* window)
|
||||||
return wsi;
|
return wsi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> StringListToStdVector(QStringList list)
|
||||||
|
{
|
||||||
|
std::vector<std::string> result;
|
||||||
|
result.reserve(list.size());
|
||||||
|
|
||||||
|
for (const QString& s : list)
|
||||||
|
result.push_back(s.toStdString());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
MainWindow::MainWindow(std::unique_ptr<BootParameters> boot_parameters) : QMainWindow(nullptr)
|
MainWindow::MainWindow(std::unique_ptr<BootParameters> boot_parameters) : QMainWindow(nullptr)
|
||||||
{
|
{
|
||||||
setWindowTitle(QString::fromStdString(Common::scm_rev_str));
|
setWindowTitle(QString::fromStdString(Common::scm_rev_str));
|
||||||
|
@ -387,7 +398,7 @@ void MainWindow::ConnectMenuBar()
|
||||||
connect(m_menu_bar, &MenuBar::EjectDisc, this, &MainWindow::EjectDisc);
|
connect(m_menu_bar, &MenuBar::EjectDisc, this, &MainWindow::EjectDisc);
|
||||||
connect(m_menu_bar, &MenuBar::ChangeDisc, this, &MainWindow::ChangeDisc);
|
connect(m_menu_bar, &MenuBar::ChangeDisc, this, &MainWindow::ChangeDisc);
|
||||||
connect(m_menu_bar, &MenuBar::BootDVDBackup, this,
|
connect(m_menu_bar, &MenuBar::BootDVDBackup, this,
|
||||||
[this](const QString& drive) { StartGame(drive); });
|
[this](const QString& drive) { StartGame(drive, ScanForSecondDisc::No); });
|
||||||
|
|
||||||
// Emulation
|
// Emulation
|
||||||
connect(m_menu_bar, &MenuBar::Pause, this, &MainWindow::Pause);
|
connect(m_menu_bar, &MenuBar::Pause, this, &MainWindow::Pause);
|
||||||
|
@ -610,30 +621,30 @@ void MainWindow::RefreshGameList()
|
||||||
Settings::Instance().RefreshGameList();
|
Settings::Instance().RefreshGameList();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MainWindow::PromptFileName()
|
QStringList MainWindow::PromptFileNames()
|
||||||
{
|
{
|
||||||
auto& settings = Settings::Instance().GetQSettings();
|
auto& settings = Settings::Instance().GetQSettings();
|
||||||
QString path = QFileDialog::getOpenFileName(
|
QStringList paths = QFileDialog::getOpenFileNames(
|
||||||
this, tr("Select a File"),
|
this, tr("Select a File"),
|
||||||
settings.value(QStringLiteral("mainwindow/lastdir"), QStringLiteral("")).toString(),
|
settings.value(QStringLiteral("mainwindow/lastdir"), QStringLiteral("")).toString(),
|
||||||
tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.tgc *.wbfs *.ciso *.gcz *.wad *.dff);;"
|
tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.tgc *.wbfs *.ciso *.gcz *.wad *.dff);;"
|
||||||
"All Files (*)"));
|
"All Files (*)"));
|
||||||
|
|
||||||
if (!path.isEmpty())
|
if (!paths.isEmpty())
|
||||||
{
|
{
|
||||||
settings.setValue(QStringLiteral("mainwindow/lastdir"),
|
settings.setValue(QStringLiteral("mainwindow/lastdir"),
|
||||||
QFileInfo(path).absoluteDir().absolutePath());
|
QFileInfo(paths.front()).absoluteDir().absolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
return path;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::ChangeDisc()
|
void MainWindow::ChangeDisc()
|
||||||
{
|
{
|
||||||
QString file = PromptFileName();
|
std::vector<std::string> paths = StringListToStdVector(PromptFileNames());
|
||||||
|
|
||||||
if (!file.isEmpty())
|
if (!paths.empty())
|
||||||
Core::RunAsCPUThread([&file] { DVDInterface::ChangeDisc(file.toStdString()); });
|
Core::RunAsCPUThread([&paths] { DVDInterface::ChangeDisc(paths); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::EjectDisc()
|
void MainWindow::EjectDisc()
|
||||||
|
@ -643,9 +654,9 @@ void MainWindow::EjectDisc()
|
||||||
|
|
||||||
void MainWindow::Open()
|
void MainWindow::Open()
|
||||||
{
|
{
|
||||||
QString file = PromptFileName();
|
QStringList files = PromptFileNames();
|
||||||
if (!file.isEmpty())
|
if (!files.isEmpty())
|
||||||
StartGame(file);
|
StartGame(StringListToStdVector(files));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::Play(const std::optional<std::string>& savestate_path)
|
void MainWindow::Play(const std::optional<std::string>& savestate_path)
|
||||||
|
@ -664,7 +675,7 @@ void MainWindow::Play(const std::optional<std::string>& savestate_path)
|
||||||
std::shared_ptr<const UICommon::GameFile> selection = m_game_list->GetSelectedGame();
|
std::shared_ptr<const UICommon::GameFile> selection = m_game_list->GetSelectedGame();
|
||||||
if (selection)
|
if (selection)
|
||||||
{
|
{
|
||||||
StartGame(selection->GetFilePath(), savestate_path);
|
StartGame(selection->GetFilePath(), ScanForSecondDisc::Yes, savestate_path);
|
||||||
EnableScreenSaver(false);
|
EnableScreenSaver(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -672,7 +683,7 @@ void MainWindow::Play(const std::optional<std::string>& savestate_path)
|
||||||
const QString default_path = QString::fromStdString(Config::Get(Config::MAIN_DEFAULT_ISO));
|
const QString default_path = QString::fromStdString(Config::Get(Config::MAIN_DEFAULT_ISO));
|
||||||
if (!default_path.isEmpty() && QFile::exists(default_path))
|
if (!default_path.isEmpty() && QFile::exists(default_path))
|
||||||
{
|
{
|
||||||
StartGame(default_path, savestate_path);
|
StartGame(default_path, ScanForSecondDisc::Yes, savestate_path);
|
||||||
EnableScreenSaver(false);
|
EnableScreenSaver(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -833,17 +844,46 @@ void MainWindow::ScreenShot()
|
||||||
Core::SaveScreenShot();
|
Core::SaveScreenShot();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::StartGame(const QString& path, const std::optional<std::string>& savestate_path)
|
void MainWindow::ScanForSecondDiscAndStartGame(const UICommon::GameFile& game,
|
||||||
{
|
|
||||||
StartGame(path.toStdString(), savestate_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::StartGame(const std::string& path,
|
|
||||||
const std::optional<std::string>& savestate_path)
|
const std::optional<std::string>& savestate_path)
|
||||||
{
|
{
|
||||||
|
auto second_game = m_game_list->FindSecondDisc(game);
|
||||||
|
|
||||||
|
std::vector<std::string> paths = {game.GetFilePath()};
|
||||||
|
if (second_game != nullptr)
|
||||||
|
paths.push_back(second_game->GetFilePath());
|
||||||
|
|
||||||
|
StartGame(paths, savestate_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::StartGame(const QString& path, ScanForSecondDisc scan,
|
||||||
|
const std::optional<std::string>& savestate_path)
|
||||||
|
{
|
||||||
|
StartGame(path.toStdString(), scan, savestate_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::StartGame(const std::string& path, ScanForSecondDisc scan,
|
||||||
|
const std::optional<std::string>& savestate_path)
|
||||||
|
{
|
||||||
|
if (scan == ScanForSecondDisc::Yes)
|
||||||
|
{
|
||||||
|
std::shared_ptr<const UICommon::GameFile> game = m_game_list->FindGame(path);
|
||||||
|
if (game != nullptr)
|
||||||
|
{
|
||||||
|
ScanForSecondDiscAndStartGame(*game, savestate_path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
StartGame(BootParameters::GenerateFromFile(path, savestate_path));
|
StartGame(BootParameters::GenerateFromFile(path, savestate_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::StartGame(const std::vector<std::string>& paths,
|
||||||
|
const std::optional<std::string>& savestate_path)
|
||||||
|
{
|
||||||
|
StartGame(BootParameters::GenerateFromFile(paths, savestate_path));
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::StartGame(std::unique_ptr<BootParameters>&& parameters)
|
void MainWindow::StartGame(std::unique_ptr<BootParameters>&& parameters)
|
||||||
{
|
{
|
||||||
// If we're running, only start a new game once we've stopped the last.
|
// If we're running, only start a new game once we've stopped the last.
|
||||||
|
@ -1075,7 +1115,7 @@ void MainWindow::ShowFIFOPlayer()
|
||||||
{
|
{
|
||||||
m_fifo_window = new FIFOPlayerWindow(this);
|
m_fifo_window = new FIFOPlayerWindow(this);
|
||||||
connect(m_fifo_window, &FIFOPlayerWindow::LoadFIFORequested, this,
|
connect(m_fifo_window, &FIFOPlayerWindow::LoadFIFORequested, this,
|
||||||
[this](const QString& path) { StartGame(path); });
|
[this](const QString& path) { StartGame(path, ScanForSecondDisc::No); });
|
||||||
}
|
}
|
||||||
|
|
||||||
m_fifo_window->show();
|
m_fifo_window->show();
|
||||||
|
@ -1170,7 +1210,7 @@ void MainWindow::NetPlayInit()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
connect(m_netplay_dialog, &NetPlayDialog::Boot, this,
|
connect(m_netplay_dialog, &NetPlayDialog::Boot, this,
|
||||||
[this](const QString& path) { StartGame(path); });
|
[this](const QString& path) { StartGame(path, ScanForSecondDisc::Yes); });
|
||||||
connect(m_netplay_dialog, &NetPlayDialog::Stop, this, &MainWindow::ForceStop);
|
connect(m_netplay_dialog, &NetPlayDialog::Stop, this, &MainWindow::ForceStop);
|
||||||
connect(m_netplay_dialog, &NetPlayDialog::rejected, this, &MainWindow::NetPlayQuit);
|
connect(m_netplay_dialog, &NetPlayDialog::rejected, this, &MainWindow::NetPlayQuit);
|
||||||
connect(m_netplay_setup_dialog, &NetPlaySetupDialog::Join, this, &MainWindow::NetPlayJoin);
|
connect(m_netplay_setup_dialog, &NetPlaySetupDialog::Join, this, &MainWindow::NetPlayJoin);
|
||||||
|
@ -1346,14 +1386,17 @@ void MainWindow::dragEnterEvent(QDragEnterEvent* event)
|
||||||
|
|
||||||
void MainWindow::dropEvent(QDropEvent* event)
|
void MainWindow::dropEvent(QDropEvent* event)
|
||||||
{
|
{
|
||||||
const auto& urls = event->mimeData()->urls();
|
const QList<QUrl>& urls = event->mimeData()->urls();
|
||||||
if (urls.empty())
|
if (urls.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto& url = urls[0];
|
QStringList files;
|
||||||
QFileInfo file_info(url.toLocalFile());
|
QStringList folders;
|
||||||
|
|
||||||
auto path = file_info.filePath();
|
for (const QUrl& url : urls)
|
||||||
|
{
|
||||||
|
QFileInfo file_info(url.toLocalFile());
|
||||||
|
QString path = file_info.filePath();
|
||||||
|
|
||||||
if (!file_info.exists() || !file_info.isReadable())
|
if (!file_info.exists() || !file_info.isReadable())
|
||||||
{
|
{
|
||||||
|
@ -1361,23 +1404,30 @@ void MainWindow::dropEvent(QDropEvent* event)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file_info.isFile())
|
(file_info.isFile() ? files : folders).append(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!files.isEmpty())
|
||||||
{
|
{
|
||||||
StartGame(path);
|
StartGame(StringListToStdVector(files));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto& settings = Settings::Instance();
|
Settings& settings = Settings::Instance();
|
||||||
|
const bool show_confirm = settings.GetPaths().size() != 0;
|
||||||
|
|
||||||
if (settings.GetPaths().size() != 0)
|
for (const QString& folder : folders)
|
||||||
|
{
|
||||||
|
if (show_confirm)
|
||||||
{
|
{
|
||||||
if (QMessageBox::question(
|
if (QMessageBox::question(
|
||||||
this, tr("Confirm"),
|
this, tr("Confirm"),
|
||||||
tr("Do you want to add \"%1\" to the list of Game Paths?").arg(path)) !=
|
tr("Do you want to add \"%1\" to the list of Game Paths?").arg(folder)) !=
|
||||||
QMessageBox::Yes)
|
QMessageBox::Yes)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
settings.AddPath(path);
|
settings.AddPath(folder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
@ -47,6 +48,11 @@ namespace DiscIO
|
||||||
enum class Region;
|
enum class Region;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace UICommon
|
||||||
|
{
|
||||||
|
class GameFile;
|
||||||
|
}
|
||||||
|
|
||||||
namespace X11Utils
|
namespace X11Utils
|
||||||
{
|
{
|
||||||
class XRRConfiguration;
|
class XRRConfiguration;
|
||||||
|
@ -115,8 +121,20 @@ private:
|
||||||
|
|
||||||
void InitCoreCallbacks();
|
void InitCoreCallbacks();
|
||||||
|
|
||||||
void StartGame(const QString& path, const std::optional<std::string>& savestate_path = {});
|
enum class ScanForSecondDisc
|
||||||
void StartGame(const std::string& path, const std::optional<std::string>& savestate_path = {});
|
{
|
||||||
|
Yes,
|
||||||
|
No,
|
||||||
|
};
|
||||||
|
|
||||||
|
void ScanForSecondDiscAndStartGame(const UICommon::GameFile& game,
|
||||||
|
const std::optional<std::string>& savestate_path = {});
|
||||||
|
void StartGame(const QString& path, ScanForSecondDisc scan,
|
||||||
|
const std::optional<std::string>& savestate_path = {});
|
||||||
|
void StartGame(const std::string& path, ScanForSecondDisc scan,
|
||||||
|
const std::optional<std::string>& savestate_path = {});
|
||||||
|
void StartGame(const std::vector<std::string>& paths,
|
||||||
|
const std::optional<std::string>& savestate_path = {});
|
||||||
void StartGame(std::unique_ptr<BootParameters>&& parameters);
|
void StartGame(std::unique_ptr<BootParameters>&& parameters);
|
||||||
void ShowRenderWidget();
|
void ShowRenderWidget();
|
||||||
void HideRenderWidget(bool reinit = true);
|
void HideRenderWidget(bool reinit = true);
|
||||||
|
@ -155,7 +173,7 @@ private:
|
||||||
void ChangeDisc();
|
void ChangeDisc();
|
||||||
void EjectDisc();
|
void EjectDisc();
|
||||||
|
|
||||||
QString PromptFileName();
|
QStringList PromptFileNames();
|
||||||
|
|
||||||
void EnableScreenSaver(bool enable);
|
void EnableScreenSaver(bool enable);
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,7 @@ void GeneralPane::ConnectLayout()
|
||||||
{
|
{
|
||||||
connect(m_checkbox_dualcore, &QCheckBox::toggled, this, &GeneralPane::OnSaveConfig);
|
connect(m_checkbox_dualcore, &QCheckBox::toggled, this, &GeneralPane::OnSaveConfig);
|
||||||
connect(m_checkbox_cheats, &QCheckBox::toggled, this, &GeneralPane::OnSaveConfig);
|
connect(m_checkbox_cheats, &QCheckBox::toggled, this, &GeneralPane::OnSaveConfig);
|
||||||
|
connect(m_checkbox_auto_disc_change, &QCheckBox::toggled, this, &GeneralPane::OnSaveConfig);
|
||||||
#ifdef USE_DISCORD_PRESENCE
|
#ifdef USE_DISCORD_PRESENCE
|
||||||
connect(m_checkbox_discord_presence, &QCheckBox::toggled, this, &GeneralPane::OnSaveConfig);
|
connect(m_checkbox_discord_presence, &QCheckBox::toggled, this, &GeneralPane::OnSaveConfig);
|
||||||
#endif
|
#endif
|
||||||
|
@ -137,6 +138,9 @@ void GeneralPane::CreateBasic()
|
||||||
m_checkbox_cheats = new QCheckBox(tr("Enable Cheats"));
|
m_checkbox_cheats = new QCheckBox(tr("Enable Cheats"));
|
||||||
basic_group_layout->addWidget(m_checkbox_cheats);
|
basic_group_layout->addWidget(m_checkbox_cheats);
|
||||||
|
|
||||||
|
m_checkbox_auto_disc_change = new QCheckBox(tr("Change Discs Automatically"));
|
||||||
|
basic_group_layout->addWidget(m_checkbox_auto_disc_change);
|
||||||
|
|
||||||
#ifdef USE_DISCORD_PRESENCE
|
#ifdef USE_DISCORD_PRESENCE
|
||||||
m_checkbox_discord_presence = new QCheckBox(tr("Show Current Game on Discord"));
|
m_checkbox_discord_presence = new QCheckBox(tr("Show Current Game on Discord"));
|
||||||
basic_group_layout->addWidget(m_checkbox_discord_presence);
|
basic_group_layout->addWidget(m_checkbox_discord_presence);
|
||||||
|
@ -236,6 +240,7 @@ void GeneralPane::LoadConfig()
|
||||||
#endif
|
#endif
|
||||||
m_checkbox_dualcore->setChecked(SConfig::GetInstance().bCPUThread);
|
m_checkbox_dualcore->setChecked(SConfig::GetInstance().bCPUThread);
|
||||||
m_checkbox_cheats->setChecked(Settings::Instance().GetCheatsEnabled());
|
m_checkbox_cheats->setChecked(Settings::Instance().GetCheatsEnabled());
|
||||||
|
m_checkbox_auto_disc_change->setChecked(Config::Get(Config::MAIN_AUTO_DISC_CHANGE));
|
||||||
#ifdef USE_DISCORD_PRESENCE
|
#ifdef USE_DISCORD_PRESENCE
|
||||||
m_checkbox_discord_presence->setChecked(Config::Get(Config::MAIN_USE_DISCORD_PRESENCE));
|
m_checkbox_discord_presence->setChecked(Config::Get(Config::MAIN_USE_DISCORD_PRESENCE));
|
||||||
#endif
|
#endif
|
||||||
|
@ -295,6 +300,7 @@ void GeneralPane::OnSaveConfig()
|
||||||
settings.bCPUThread = m_checkbox_dualcore->isChecked();
|
settings.bCPUThread = m_checkbox_dualcore->isChecked();
|
||||||
Config::SetBaseOrCurrent(Config::MAIN_CPU_THREAD, m_checkbox_dualcore->isChecked());
|
Config::SetBaseOrCurrent(Config::MAIN_CPU_THREAD, m_checkbox_dualcore->isChecked());
|
||||||
Settings::Instance().SetCheatsEnabled(m_checkbox_cheats->isChecked());
|
Settings::Instance().SetCheatsEnabled(m_checkbox_cheats->isChecked());
|
||||||
|
Config::SetBase(Config::MAIN_AUTO_DISC_CHANGE, m_checkbox_auto_disc_change->isChecked());
|
||||||
Config::SetBaseOrCurrent(Config::MAIN_ENABLE_CHEATS, m_checkbox_cheats->isChecked());
|
Config::SetBaseOrCurrent(Config::MAIN_ENABLE_CHEATS, m_checkbox_cheats->isChecked());
|
||||||
settings.m_EmulationSpeed = m_combobox_speedlimit->currentIndex() * 0.1f;
|
settings.m_EmulationSpeed = m_combobox_speedlimit->currentIndex() * 0.1f;
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ private:
|
||||||
QComboBox* m_combobox_update_track;
|
QComboBox* m_combobox_update_track;
|
||||||
QCheckBox* m_checkbox_dualcore;
|
QCheckBox* m_checkbox_dualcore;
|
||||||
QCheckBox* m_checkbox_cheats;
|
QCheckBox* m_checkbox_cheats;
|
||||||
|
QCheckBox* m_checkbox_auto_disc_change;
|
||||||
#ifdef USE_DISCORD_PRESENCE
|
#ifdef USE_DISCORD_PRESENCE
|
||||||
QCheckBox* m_checkbox_discord_presence;
|
QCheckBox* m_checkbox_discord_presence;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -75,7 +75,7 @@ std::unique_ptr<optparse::OptionParser> CreateParser(ParserOptions options)
|
||||||
parser->add_option("-u", "--user").action("store").help("User folder path");
|
parser->add_option("-u", "--user").action("store").help("User folder path");
|
||||||
parser->add_option("-m", "--movie").action("store").help("Play a movie file");
|
parser->add_option("-m", "--movie").action("store").help("Play a movie file");
|
||||||
parser->add_option("-e", "--exec")
|
parser->add_option("-e", "--exec")
|
||||||
.action("store")
|
.action("append")
|
||||||
.metavar("<file>")
|
.metavar("<file>")
|
||||||
.type("string")
|
.type("string")
|
||||||
.help("Load the specified file");
|
.help("Load the specified file");
|
||||||
|
|
Loading…
Reference in New Issue