Skip to content
Permalink
Browse files

Automatic disc change for 2-disc games

  • Loading branch information...
JosJuice committed Nov 5, 2018
1 parent fc68b83 commit bd665aad5d6924783a66495eadb0628157062748
@@ -54,47 +54,81 @@
#include "DiscIO/Enums.h"
#include "DiscIO/Volume.h"

std::vector<std::string> ReadM3UFile(const std::string& path)
{
// TODO
return {};
}

BootParameters::BootParameters(Parameters&& parameters_,
const std::optional<std::string>& savestate_path_)
: parameters(std::move(parameters_)), savestate_path(savestate_path_)
{
}

std::unique_ptr<BootParameters>
BootParameters::GenerateFromFile(const std::string& path,
BootParameters::GenerateFromFile(std::string boot_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
// 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 {};
}

std::string extension;
SplitPath(path, nullptr, nullptr, &extension);
SplitPath(paths.front(), nullptr, nullptr, &extension);
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 = {
{".gcm", ".iso", ".tgc", ".wbfs", ".ciso", ".gcz", ".dol", ".elf"}};
if (disc_image_extensions.find(extension) != disc_image_extensions.end() || is_drive)
{
std::unique_ptr<DiscIO::Volume> volume = DiscIO::CreateVolumeFromFilename(path);
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")
{
return std::make_unique<BootParameters>(Executable{path, std::make_unique<ElfReader>(path)},
savestate_path);
return std::make_unique<BootParameters>(
Executable{std::move(path), std::make_unique<ElfReader>(path)}, savestate_path);
}

if (extension == ".dol")
{
return std::make_unique<BootParameters>(Executable{path, std::make_unique<DolReader>(path)},
savestate_path);
return std::make_unique<BootParameters>(
Executable{std::move(path), std::make_unique<DolReader>(path)}, savestate_path);
}

if (is_drive)
@@ -113,10 +147,10 @@ BootParameters::GenerateFromFile(const std::string& path,
}

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")
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());
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.
// The returned pointer must only be used while we are still booting,
// 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();
DVDInterface::SetDisc(std::move(volume));
DVDInterface::SetDisc(std::move(volume), auto_disc_change_paths);
return pointer;
}

@@ -326,7 +361,7 @@ bool CBoot::BootUp(std::unique_ptr<BootParameters> boot)
bool operator()(BootParameters::Disc& disc) const
{
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)
return false;
@@ -420,7 +455,7 @@ bool CBoot::BootUp(std::unique_ptr<BootParameters> boot)
if (ipl.disc)
{
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())
@@ -40,6 +40,7 @@ struct BootParameters
{
std::string path;
std::unique_ptr<DiscIO::Volume> volume;
std::vector<std::string> auto_disc_change_paths;
};

struct Executable
@@ -69,7 +70,9 @@ struct 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 = {});

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"},
true};
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

@@ -78,6 +78,7 @@ extern const ConfigInfo<bool> MAIN_CUSTOM_RTC_ENABLE;
extern const ConfigInfo<u32> MAIN_CUSTOM_RTC_VALUE;
extern const ConfigInfo<bool> MAIN_ENABLE_SIGNATURE_CHECKS;
extern const ConfigInfo<bool> MAIN_REDUCE_POLLING_RATE;
extern const ConfigInfo<bool> MAIN_AUTO_DISC_CHANGE;

// Main.DSP

@@ -31,6 +31,7 @@ bool IsSettingSaveable(const Config::ConfigLocation& config_location)
Config::MAIN_DEFAULT_ISO.location,
Config::MAIN_MEMCARD_A_PATH.location,
Config::MAIN_MEMCARD_B_PATH.location,
Config::MAIN_AUTO_DISC_CHANGE.location,

// Graphics.Hardware

@@ -16,8 +16,10 @@
#include "Common/Align.h"
#include "Common/ChunkFile.h"
#include "Common/CommonTypes.h"
#include "Common/Config/Config.h"
#include "Common/Logging/Log.h"

#include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h"
#include "Core/CoreTiming.h"
#include "Core/HW/AudioInterface.h"
@@ -36,6 +38,8 @@
#include "DiscIO/Volume.h"
#include "DiscIO/VolumeWii.h"

#include "VideoCommon/OnScreenDisplay.h"

// The minimum time it takes for the DVD drive to process a command (in
// microseconds)
constexpr u64 COMMAND_LATENCY_US = 300;
@@ -231,6 +235,8 @@ static u64 s_read_buffer_end_offset;

// Disc changing
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
static CoreTiming::EventType* s_finish_executing_command;
@@ -441,11 +447,21 @@ void Shutdown()
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)
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));
SetLidOpen();
}
@@ -457,7 +473,7 @@ bool IsDiscInside()

static void EjectDiscCallback(u64 userdata, s64 cyclesLate)
{
SetDisc(nullptr);
SetDisc(nullptr, {});
}

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);

if (new_volume)
SetDisc(std::move(new_volume));
SetDisc(std::move(new_volume), {});
else
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);
}

// 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
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;
CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond(), s_insert_disc);
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()
@@ -983,12 +1035,20 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
break;

case DVDLowStopMotor:
{
INFO_LOG(DVDINTERFACE, "DVDLowStopMotor %s %s", command_1 ? "eject" : "",
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);
break;
}

// DVD Audio Enable/Disable (Immediate). GC uses this, and apparently Wii also does...?
case DVDLowAudioBufferConfig:
@@ -111,10 +111,13 @@ void DoState(PointerWrap& p);

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();
void EjectDisc(); // Must only be called on the CPU thread
void ChangeDisc(const std::string& new_path); // 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
bool AutoChangeDisc(); // Must only be called on the CPU thread

// This function returns true and calls SConfig::SetRunningGameMetadata(Volume&, Partition&)
// if both of the following conditions are true:
@@ -1176,29 +1176,13 @@ void PlayController(GCPadStatus* PadStatus, int controllerID)
PadStatus->button |= PAD_TRIGGER_R;
if (s_padState.disc)
{
// This implementation assumes the disc change will only happen once. Trying
// to change more than that will cause it to load the last disc every time.
// 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))
Core::RunAsCPUThread([] {
if (!DVDInterface::AutoChangeDisc())
{
found = true;
break;
CPU::Break();
PanicAlertT("Change the disc to %s", s_discChange.c_str());
}
}
if (found)
{
Core::RunAsCPUThread([&path] { DVDInterface::ChangeDisc(path); });
}
else
{
CPU::Break();
PanicAlertT("Change the disc to %s", s_discChange.c_str());
}
});
}

if (s_padState.reset)
@@ -368,7 +368,10 @@ int main(int argc, char* argv[])
std::unique_ptr<BootParameters> boot;
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"))
{

0 comments on commit bd665aa

Please sign in to comment.
You can’t perform that action at this time.