* Fixed installation destination for multi-Disc based games.

Second ISO is now properly going into the existing folder instead
  of using the Disc's internal Game Title.
* Prevent deleting a folder when installation is canceled if
  the folder still contains another disc number.
* Added a new setting to select GameCube game source: SD, USB, Auto
  Auto = based on DIOS MIOS (Lite).
  This new setting fix two known problems:
  - Device selection for Devolution is no more dependent of
    the installed DM(L) type. (Select manually before launching a game)
  - Installation of a game on a device if the game is already
    on another device is now possible.
This commit is contained in:
Cyan 2012-12-09 21:36:32 +00:00
parent 77f7daf9dc
commit 9e993326e5
10 changed files with 106 additions and 28 deletions

View File

@ -2,8 +2,8 @@
<app version="1"> <app version="1">
<name> USB Loader GX</name> <name> USB Loader GX</name>
<coder>USB Loader GX Team</coder> <coder>USB Loader GX Team</coder>
<version>3.0 r1206</version> <version>3.0 r1207</version>
<release_date>20121209202238</release_date> <release_date>20121209211824</release_date>
<!-- // remove this line to enable arguments <!-- // remove this line to enable arguments
<arguments> <arguments>
<arg>--ios=250</arg> <arg>--ios=250</arg>

View File

@ -201,7 +201,7 @@ int GCDumper::ReadDiscInfo(const u64 &game_offset)
return 0; return 0;
} }
s32 GCDumper::InstallGame(const char *installpath, u32 game) s32 GCDumper::InstallGame(const char *installpath, u32 game, const char *installedGamePath)
{ {
if(!ReadBuffer || game >= discHeaders.size() || game >= gameOffsets.size() || game >= gameSizes.size()) if(!ReadBuffer || game >= discHeaders.size() || game >= gameOffsets.size() || game >= gameSizes.size())
return -1; return -1;
@ -266,6 +266,10 @@ s32 GCDumper::InstallGame(const char *installpath, u32 game)
// snprintf(gamepath, sizeof(gamepath), "%s%s [%.6s]%s/", installpath, gametitle, gcheader.id, Disc ? "2" : ""); // Disc2 currently needs to be on the same folder. // snprintf(gamepath, sizeof(gamepath), "%s%s [%.6s]%s/", installpath, gametitle, gcheader.id, Disc ? "2" : ""); // Disc2 currently needs to be on the same folder.
snprintf(gamepath, sizeof(gamepath), "%s%s [%.6s]/", installpath, gametitle, gcheader.id); snprintf(gamepath, sizeof(gamepath), "%s%s [%.6s]/", installpath, gametitle, gcheader.id);
// If another Disc from the same gameID already exists, let's use that path
if(strlen((char *)installedGamePath) != 0)
snprintf(gamepath, sizeof(gamepath), "%s/", installedGamePath);
CreateSubfolder(gamepath); CreateSubfolder(gamepath);
// snprintf(gamepath, sizeof(gamepath), "%s%s [%.6s]%s/game.iso", installpath, gametitle, gcheader.id, Disc ? "2" : ""); // Disc2 currently needs to be on the same folder. // snprintf(gamepath, sizeof(gamepath), "%s%s [%.6s]%s/game.iso", installpath, gametitle, gcheader.id, Disc ? "2" : ""); // Disc2 currently needs to be on the same folder.
@ -384,9 +388,12 @@ s32 GCDumper::InstallGame(const char *installpath, u32 game)
if(result < 0) if(result < 0)
{ {
RemoveFile(gamepath); RemoveFile(gamepath);
char *pathPtr = strrchr(gamepath, '/'); if(strlen((char *)installedGamePath) == 0) // If no other disc is installed in that folder, delete it.
if(pathPtr) *pathPtr = 0; {
RemoveFile(gamepath); char *pathPtr = strrchr(gamepath, '/');
if(pathPtr) *pathPtr = 0;
RemoveFile(gamepath);
}
if(result != PROGRESS_CANCELED) if(result != PROGRESS_CANCELED)
ShowError(tr("Disc read error.")); ShowError(tr("Disc read error."));

View File

@ -37,7 +37,7 @@ class GCDumper
public: public:
GCDumper(); GCDumper();
~GCDumper(); ~GCDumper();
s32 InstallGame(const char *installpath, u32 game); s32 InstallGame(const char *installpath, u32 game, const char *installedGamePath);
s32 ReadDiscHeader(void); s32 ReadDiscHeader(void);
int ReadDiscInfo(const u64 &game_offset); int ReadDiscInfo(const u64 &game_offset);
void SetForceAlign(bool b) { force_align32 = b; } void SetForceAlign(bool b) { force_align32 = b; }

View File

@ -222,38 +222,47 @@ u32 GCGames::LoadAllGames(void)
sdGCList.clear(); sdGCList.clear();
sdGCPathList.clear(); sdGCPathList.clear();
LoadGameList(Settings.GameCubePath, HeaderList, PathList); if(strcmp(Settings.GameCubePath, Settings.GameCubeSDPath) == 0 || Settings.GameCubeSource != GC_SOURCE_SD)
LoadGameList(Settings.GameCubePath, HeaderList, PathList);
if(strcmp(Settings.GameCubePath, Settings.GameCubeSDPath) != 0) if(strcmp(Settings.GameCubePath, Settings.GameCubeSDPath) != 0 && (Settings.GameCubeSource != GC_SOURCE_MAIN))
{ {
LoadGameList(Settings.GameCubeSDPath, sdGCList, sdGCPathList); LoadGameList(Settings.GameCubeSDPath, sdGCList, sdGCPathList);
for(u32 i = 0; i < sdGCList.size(); ++i) for(u32 i = 0; i < sdGCList.size(); ++i)
{ {
u32 n; if(Settings.GameCubeSource == GC_SOURCE_AUTO)
for(n = 0; n < HeaderList.size(); ++n)
{ {
//! Display only one game if it is present on both SD and USB. u32 n;
if(memcmp(HeaderList[n].id, sdGCList[i].id, 6) == 0) for(n = 0; n < HeaderList.size(); ++n)
{ {
if(IosLoader::GetMIOSInfo() == DIOS_MIOS) // DIOS MIOS - Show only the game on USB //! Display only one game if it is present on both SD and USB.
if(memcmp(HeaderList[n].id, sdGCList[i].id, 6) == 0)
{ {
break; if(IosLoader::GetMIOSInfo() == DIOS_MIOS) // DIOS MIOS - Show only the game on USB
} {
else // replace the one loaded from USB with the same games on SD since we can load them directly break;
{ }
memcpy(&HeaderList[n], &sdGCList[i], sizeof(struct discHdr)); else // replace the one loaded from USB with the same games on SD since we can load them directly
PathList[n] = sdGCPathList[i]; {
break; memcpy(&HeaderList[n], &sdGCList[i], sizeof(struct discHdr));
PathList[n] = sdGCPathList[i];
break;
}
} }
} }
}
// Not available in the main GC path // Not available in the main GC path
if(n == HeaderList.size()) { if(n == HeaderList.size()) {
HeaderList.push_back(sdGCList[i]); HeaderList.push_back(sdGCList[i]);
PathList.push_back(sdGCPathList[i]); PathList.push_back(sdGCPathList[i]);
}
} }
else // GC_SOURCE_SD, or GC_SOURCE_BOTH (show duplicates)
{
HeaderList.push_back(sdGCList[i]);
PathList.push_back(sdGCPathList[i]);
}
} }
} }
@ -386,7 +395,7 @@ bool GCGames::IsInstalled(const char *gameID, u8 disc_number) const
{ {
if(memcmp(HeaderList[n].id, gameID, 6) == 0) if(memcmp(HeaderList[n].id, gameID, 6) == 0)
{ {
if(HeaderList[n].type == TYPE_GAME_GC_EXTRACTED) if(HeaderList[n].type == TYPE_GAME_GC_EXTRACTED || Settings.GCInstallCompressed)
return true; // Multi-disc games in extracted form are currently unsupported by DML, no need to check further. return true; // Multi-disc games in extracted form are currently unsupported by DML, no need to check further.
if(HeaderList[n].disc_no == disc_number) // Disc number already in headerList. If Disc2 is loaded in headerList, then Disc1 is not installed yet if(HeaderList[n].disc_no == disc_number) // Disc number already in headerList. If Disc2 is loaded in headerList, then Disc1 is not installed yet

View File

@ -84,6 +84,11 @@ int MenuGCInstall()
return MENU_DISCLIST; return MENU_DISCLIST;
} }
// Load only available games from the selected device
int oldGameCubeSource = Settings.GameCubeSource;
Settings.GameCubeSource = destination-1;
GCGames::Instance()->LoadAllGames();
const char *InstallPath = destination == 1 ? Settings.GameCubePath : Settings.GameCubeSDPath; const char *InstallPath = destination == 1 ? Settings.GameCubePath : Settings.GameCubeSDPath;
//! Start of install process, enable wii slot light //! Start of install process, enable wii slot light
@ -125,8 +130,20 @@ int MenuGCInstall()
} }
} }
// Check if another Disc number from the same game is already installed on this device
GCGames::Instance()->LoadAllGames(); // refresh installed game list
char installedGamePath[512];
if(GCGames::Instance()->IsInstalled((char *)gcDumper.GetDiscHeaders().at(installGames[i]).id, gcDumper.GetDiscHeaders().at(installGames[i]).disc_no == 0 ? 1 : 0))
{
snprintf(installedGamePath, sizeof(installedGamePath), GCGames::Instance()->GetPath((char *)gcDumper.GetDiscHeaders().at(installGames[i]).id));
char *pathPtr = strrchr(installedGamePath, '/');
if(pathPtr) *pathPtr = 0;
}
else
installedGamePath[0] = 0;
// game is not yet installed so let's install it // game is not yet installed so let's install it
int ret = gcDumper.InstallGame(InstallPath, installGames[i]); int ret = gcDumper.InstallGame(InstallPath, installGames[i], installedGamePath);
if(ret >= 0) { if(ret >= 0) {
//! success //! success
installed_games++; installed_games++;
@ -157,6 +174,7 @@ int MenuGCInstall()
} }
wiilight(0); wiilight(0);
Settings.GameCubeSource = oldGameCubeSource;
GCGames::Instance()->LoadAllGames(); GCGames::Instance()->LoadAllGames();
//! no game was installed so don't show successfully installed prompt //! no game was installed so don't show successfully installed prompt

View File

@ -169,6 +169,7 @@ void CSettings::SetDefault()
BannerProjectionHeight = (Settings.PAL50 ? 448.0f : (NTSC ? 470.0f : 464.0f)); BannerProjectionHeight = (Settings.PAL50 ? 448.0f : (NTSC ? 470.0f : 464.0f));
GCBannerScale = 1.5f; GCBannerScale = 1.5f;
GameCubeMode = GC_MODE_MIOS; GameCubeMode = GC_MODE_MIOS;
GameCubeSource = AUTO;
DMLVideo = DML_VIDEO_AUTO; DMLVideo = DML_VIDEO_AUTO;
DMLProgPatch = OFF; DMLProgPatch = OFF;
DMLNMM = OFF; DMLNMM = OFF;
@ -398,6 +399,7 @@ bool CSettings::Save()
fprintf(file, "GameCubePath = %s\n", GameCubePath); fprintf(file, "GameCubePath = %s\n", GameCubePath);
fprintf(file, "GameCubeSDPath = %s\n", GameCubeSDPath); fprintf(file, "GameCubeSDPath = %s\n", GameCubeSDPath);
fprintf(file, "GameCubeMode = %d\n", GameCubeMode); fprintf(file, "GameCubeMode = %d\n", GameCubeMode);
fprintf(file, "GameCubeSource = %d\n", GameCubeSource);
fprintf(file, "DMLVideo = %d\n", DMLVideo); fprintf(file, "DMLVideo = %d\n", DMLVideo);
fprintf(file, "DMLProgPatch = %d\n", DMLProgPatch); fprintf(file, "DMLProgPatch = %d\n", DMLProgPatch);
fprintf(file, "DMLNMM = %d\n", DMLNMM); fprintf(file, "DMLNMM = %d\n", DMLNMM);
@ -806,6 +808,11 @@ bool CSettings::SetSetting(char *name, char *value)
GameCubeMode = atoi(value); GameCubeMode = atoi(value);
return true; return true;
} }
else if (strcmp(name, "GameCubeSource") == 0)
{
GameCubeSource = atoi(value);
return true;
}
else if (strcmp(name, "DMLVideo") == 0) else if (strcmp(name, "DMLVideo") == 0)
{ {
DMLVideo = atoi(value); DMLVideo = atoi(value);

View File

@ -171,6 +171,7 @@ class CSettings
float BannerProjectionHeight; float BannerProjectionHeight;
float GCBannerScale; float GCBannerScale;
short GameCubeMode; short GameCubeMode;
short GameCubeSource;
short DMLVideo; short DMLVideo;
short DMLProgPatch; short DMLProgPatch;
short DMLNMM; short DMLNMM;

View File

@ -280,6 +280,16 @@ enum
}; };
enum
{
GC_SOURCE_MAIN,
GC_SOURCE_SD,
GC_SOURCE_AUTO,
// GC_SOURCE_BOTH, // GCGames::getPath(GameID) always returns the first encountered path in the gameList
CG_SOURCE_MAX_CHOICE
};
enum enum
{ {
DEVO_MC_OFF, DEVO_MC_OFF,

View File

@ -35,6 +35,7 @@
#include "usbloader/GameList.h" #include "usbloader/GameList.h"
#include "utils/tools.h" #include "utils/tools.h"
#include "menu.h" #include "menu.h"
#include "gamecube/GCGames.h"
static const char * OnOffText[] = static const char * OnOffText[] =
{ {
@ -115,6 +116,14 @@ static const char * GCMode[] =
trNOOP( "Devolution" ), trNOOP( "Devolution" ),
}; };
static const char * GCSourceText[] =
{
trNOOP( "Main Path" ),
trNOOP( "SD Path" ),
trNOOP( "Auto" ),
trNOOP( "Both" ),
};
static const char * DMLVideoText[] = static const char * DMLVideoText[] =
{ {
trNOOP( "DML Auto" ), trNOOP( "DML Auto" ),
@ -167,6 +176,7 @@ LoaderSettings::LoaderSettings()
Options->SetName(Idx++, "%s", tr( "Debugger Paused Start" )); Options->SetName(Idx++, "%s", tr( "Debugger Paused Start" ));
Options->SetName(Idx++, "%s", tr( "Channel Launcher" )); Options->SetName(Idx++, "%s", tr( "Channel Launcher" ));
Options->SetName(Idx++, "%s", tr( "GameCube Mode" )); Options->SetName(Idx++, "%s", tr( "GameCube Mode" ));
Options->SetName(Idx++, "%s", tr( "GameCube Source" ));
Options->SetName(Idx++, "%s", tr( "DML Video Mode" )); Options->SetName(Idx++, "%s", tr( "DML Video Mode" ));
Options->SetName(Idx++, "%s", tr( "DML Progressive Patch" )); Options->SetName(Idx++, "%s", tr( "DML Progressive Patch" ));
Options->SetName(Idx++, "%s", tr( "DML NMM Mode" )); Options->SetName(Idx++, "%s", tr( "DML NMM Mode" ));
@ -184,6 +194,7 @@ LoaderSettings::LoaderSettings()
SetOptionValues(); SetOptionValues();
oldLoaderMode = Settings.LoaderMode; oldLoaderMode = Settings.LoaderMode;
oldGameCubeSource = Settings.GameCubeSource;
} }
LoaderSettings::~LoaderSettings() LoaderSettings::~LoaderSettings()
@ -199,6 +210,11 @@ LoaderSettings::~LoaderSettings()
gameList.LoadUnfiltered(); gameList.LoadUnfiltered();
GameTitles.LoadTitlesFromGameTDB(Settings.titlestxt_path, false); GameTitles.LoadTitlesFromGameTDB(Settings.titlestxt_path, false);
} }
if(oldGameCubeSource != Settings.GameCubeSource)
{
GCGames::Instance()->LoadAllGames();
}
} }
void LoaderSettings::SetOptionValues() void LoaderSettings::SetOptionValues()
@ -270,6 +286,9 @@ void LoaderSettings::SetOptionValues()
//! Settings: GameCube Mode //! Settings: GameCube Mode
Options->SetValue(Idx++, "%s", tr(GCMode[Settings.GameCubeMode])); Options->SetValue(Idx++, "%s", tr(GCMode[Settings.GameCubeMode]));
//! Settings: GameCube Source
Options->SetValue(Idx++, "%s", tr(GCSourceText[Settings.GameCubeSource]));
//! Settings: DML Video Mode //! Settings: DML Video Mode
Options->SetValue(Idx++, "%s", tr(DMLVideoText[Settings.DMLVideo])); Options->SetValue(Idx++, "%s", tr(DMLVideoText[Settings.DMLVideo]));
@ -458,6 +477,12 @@ int LoaderSettings::GetMenuInternal()
if (++Settings.GameCubeMode >= CG_MODE_MAX_CHOICE) Settings.GameCubeMode = 0; if (++Settings.GameCubeMode >= CG_MODE_MAX_CHOICE) Settings.GameCubeMode = 0;
} }
//! Settings: GameCube Source
else if (ret == ++Idx)
{
if (++Settings.GameCubeSource >= CG_SOURCE_MAX_CHOICE) Settings.GameCubeSource = 0;
}
//! Settings: DML Video Mode //! Settings: DML Video Mode
else if (ret == ++Idx) else if (ret == ++Idx)
{ {

View File

@ -36,6 +36,7 @@ class LoaderSettings : public SettingsMenu
int GetMenuInternal(); int GetMenuInternal();
short oldLoaderMode; short oldLoaderMode;
short oldGameCubeSource;
OptionList GuiOptions; OptionList GuiOptions;
}; };