Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #11236 from AdmiralCurtiss/gci-path-config
Add config setting for base GCI folder path.
  • Loading branch information
AdmiralCurtiss committed Nov 22, 2022
2 parents 8ac8d5a + 81557f6 commit 132bf65
Show file tree
Hide file tree
Showing 9 changed files with 266 additions and 23 deletions.
2 changes: 2 additions & 0 deletions Source/Core/Common/CommonPaths.h
Expand Up @@ -28,9 +28,11 @@
#endif

// Dirs in both User and Sys
// Legacy setups used /JAP/ while newer setups use /JPN/ by default.
#define EUR_DIR "EUR"
#define USA_DIR "USA"
#define JAP_DIR "JAP"
#define JPN_DIR "JPN"

// Subdirs in the User dir returned by GetUserPath(D_USER_IDX)
#define GC_USER_DIR "GC"
Expand Down
79 changes: 76 additions & 3 deletions Source/Core/Core/Config/MainSettings.cpp
Expand Up @@ -76,6 +76,18 @@ const Info<std::string>& GetInfoForAGPCartPath(ExpansionInterface::Slot slot)
};
return *infos[slot];
}
const Info<std::string> MAIN_GCI_FOLDER_A_PATH{{System::Main, "Core", "GCIFolderAPath"}, ""};
const Info<std::string> MAIN_GCI_FOLDER_B_PATH{{System::Main, "Core", "GCIFolderBPath"}, ""};
const Info<std::string>& GetInfoForGCIPath(ExpansionInterface::Slot slot)
{
ASSERT(ExpansionInterface::IsMemcardSlot(slot));
static constexpr Common::EnumMap<const Info<std::string>*, ExpansionInterface::MAX_MEMCARD_SLOT>
infos{
&MAIN_GCI_FOLDER_A_PATH,
&MAIN_GCI_FOLDER_B_PATH,
};
return *infos[slot];
}
const Info<std::string> MAIN_GCI_FOLDER_A_PATH_OVERRIDE{
{System::Main, "Core", "GCIFolderAPathOverride"}, ""};
const Info<std::string> MAIN_GCI_FOLDER_B_PATH_OVERRIDE{
Expand Down Expand Up @@ -549,15 +561,15 @@ DiscIO::Region ToGameCubeRegion(DiscIO::Region region)
return DiscIO::Region::NTSC_J;
}

const char* GetDirectoryForRegion(DiscIO::Region region)
const char* GetDirectoryForRegion(DiscIO::Region region, RegionDirectoryStyle style)
{
if (region == DiscIO::Region::Unknown)
region = ToGameCubeRegion(Config::Get(Config::MAIN_FALLBACK_REGION));

switch (region)
{
case DiscIO::Region::NTSC_J:
return JAP_DIR;
return style == RegionDirectoryStyle::Legacy ? JAP_DIR : JPN_DIR;

case DiscIO::Region::NTSC_U:
return USA_DIR;
Expand All @@ -566,8 +578,9 @@ const char* GetDirectoryForRegion(DiscIO::Region region)
return EUR_DIR;

case DiscIO::Region::NTSC_K:
// See ToGameCubeRegion
ASSERT_MSG(BOOT, false, "NTSC-K is not a valid GameCube region");
return JAP_DIR; // See ToGameCubeRegion
return style == RegionDirectoryStyle::Legacy ? JAP_DIR : JPN_DIR;

default:
ASSERT_MSG(BOOT, false, "Default case should not be reached");
Expand Down Expand Up @@ -650,4 +663,64 @@ bool IsDefaultMemcardPathConfigured(ExpansionInterface::Slot slot)
{
return Config::Get(GetInfoForMemcardPath(slot)).empty();
}

std::string GetGCIFolderPath(ExpansionInterface::Slot slot, std::optional<DiscIO::Region> region)
{
return GetGCIFolderPath(Config::Get(GetInfoForGCIPath(slot)), slot, region);
}

std::string GetGCIFolderPath(std::string configured_folder, ExpansionInterface::Slot slot,
std::optional<DiscIO::Region> region)
{
if (configured_folder.empty())
{
const auto region_dir = Config::GetDirectoryForRegion(
Config::ToGameCubeRegion(region ? *region : Config::Get(Config::MAIN_FALLBACK_REGION)));
const bool is_slot_a = slot == ExpansionInterface::Slot::A;
return fmt::format("{}{}/Card {}", File::GetUserPath(D_GCUSER_IDX), region_dir,
is_slot_a ? 'A' : 'B');
}

// Custom path is expected to be stored in the form of
// "/path/to/folder/{region_code}"
// with an arbitrary but supported region code.
// Try to extract and replace that region code.
// If there's no region code just insert one at the end.

UnifyPathSeparators(configured_folder);
while (StringEndsWith(configured_folder, "/"))
configured_folder.pop_back();

constexpr std::string_view us_region = "/" USA_DIR;
constexpr std::string_view jp_region = "/" JPN_DIR;
constexpr std::string_view eu_region = "/" EUR_DIR;
std::string_view base_path = configured_folder;
std::optional<DiscIO::Region> path_region = std::nullopt;
if (StringEndsWith(base_path, us_region))
{
base_path = base_path.substr(0, base_path.size() - us_region.size());
path_region = DiscIO::Region::NTSC_U;
}
else if (StringEndsWith(base_path, jp_region))
{
base_path = base_path.substr(0, base_path.size() - jp_region.size());
path_region = DiscIO::Region::NTSC_J;
}
else if (StringEndsWith(base_path, eu_region))
{
base_path = base_path.substr(0, base_path.size() - eu_region.size());
path_region = DiscIO::Region::PAL;
}

const DiscIO::Region used_region =
region ? *region : (path_region ? *path_region : Config::Get(Config::MAIN_FALLBACK_REGION));
return fmt::format("{}/{}", base_path,
Config::GetDirectoryForRegion(Config::ToGameCubeRegion(used_region),
Config::RegionDirectoryStyle::Modern));
}

bool IsDefaultGCIFolderPathConfigured(ExpansionInterface::Slot slot)
{
return Config::Get(GetInfoForGCIPath(slot)).empty();
}
} // namespace Config
17 changes: 16 additions & 1 deletion Source/Core/Core/Config/MainSettings.h
Expand Up @@ -75,6 +75,9 @@ const Info<std::string>& GetInfoForMemcardPath(ExpansionInterface::Slot slot);
extern const Info<std::string> MAIN_AGP_CART_A_PATH;
extern const Info<std::string> MAIN_AGP_CART_B_PATH;
const Info<std::string>& GetInfoForAGPCartPath(ExpansionInterface::Slot slot);
extern const Info<std::string> MAIN_GCI_FOLDER_A_PATH;
extern const Info<std::string> MAIN_GCI_FOLDER_B_PATH;
const Info<std::string>& GetInfoForGCIPath(ExpansionInterface::Slot slot);
extern const Info<std::string> MAIN_GCI_FOLDER_A_PATH_OVERRIDE;
extern const Info<std::string> MAIN_GCI_FOLDER_B_PATH_OVERRIDE;
const Info<std::string>& GetInfoForGCIPathOverride(ExpansionInterface::Slot slot);
Expand Down Expand Up @@ -341,8 +344,16 @@ void SetUSBDeviceWhitelist(const std::set<std::pair<u16, u16>>& devices);

// Replaces NTSC-K with some other region, and doesn't replace non-NTSC-K regions
DiscIO::Region ToGameCubeRegion(DiscIO::Region region);

// The region argument must be valid for GameCube (i.e. must not be NTSC-K)
const char* GetDirectoryForRegion(DiscIO::Region region);
enum class RegionDirectoryStyle
{
Legacy,
Modern,
};
const char* GetDirectoryForRegion(DiscIO::Region region,
RegionDirectoryStyle style = RegionDirectoryStyle::Legacy);

std::string GetBootROMPath(const std::string& region_directory);
// Builds the memory card according to the configuration with the given region and size. If the
// given region is std::nullopt, the region in the configured path is used if there is one, or the
Expand All @@ -352,4 +363,8 @@ std::string GetMemcardPath(ExpansionInterface::Slot slot, std::optional<DiscIO::
std::string GetMemcardPath(std::string configured_filename, ExpansionInterface::Slot slot,
std::optional<DiscIO::Region> region, u16 size_mb = 0x80);
bool IsDefaultMemcardPathConfigured(ExpansionInterface::Slot slot);
std::string GetGCIFolderPath(ExpansionInterface::Slot slot, std::optional<DiscIO::Region> region);
std::string GetGCIFolderPath(std::string configured_folder, ExpansionInterface::Slot slot,
std::optional<DiscIO::Region> region);
bool IsDefaultGCIFolderPathConfigured(ExpansionInterface::Slot slot);
} // namespace Config
2 changes: 2 additions & 0 deletions Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp
Expand Up @@ -131,6 +131,8 @@ bool IsSettingSaveable(const Config::Location& config_location)
&Config::MAIN_SYNC_GPU_MIN_DISTANCE.GetLocation(),
&Config::MAIN_SYNC_GPU_OVERCLOCK.GetLocation(),
&Config::MAIN_OVERRIDE_BOOT_IOS.GetLocation(),
&Config::MAIN_GCI_FOLDER_A_PATH.GetLocation(),
&Config::MAIN_GCI_FOLDER_B_PATH.GetLocation(),

// UI.General

Expand Down
14 changes: 7 additions & 7 deletions Source/Core/Core/HW/EXI/EXI_DeviceMemoryCard.cpp
Expand Up @@ -154,20 +154,20 @@ CEXIMemoryCard::GetGCIFolderPath(Slot card_slot, AllowMovieFolder allow_movie_fo
if (!path_override.empty())
return {std::move(path_override), false};

std::string path = File::GetUserPath(D_GCUSER_IDX);

const bool use_movie_folder = allow_movie_folder == AllowMovieFolder::Yes &&
Movie::IsPlayingInput() && Movie::IsConfigSaved() &&
Movie::IsUsingMemcard(card_slot) &&
Movie::IsStartingFromClearSave();

const DiscIO::Region region = Config::ToGameCubeRegion(SConfig::GetInstance().m_region);
if (use_movie_folder)
path += "Movie" DIR_SEP;
{
return {fmt::format("{}{}/Movie/Card {}", File::GetUserPath(D_GCUSER_IDX),
Config::GetDirectoryForRegion(region), s_card_short_names[card_slot]),
false};
}

const DiscIO::Region region = Config::ToGameCubeRegion(SConfig::GetInstance().m_region);
path = path + Config::GetDirectoryForRegion(region) + DIR_SEP +
fmt::format("Card {}", s_card_short_names[card_slot]);
return {std::move(path), !use_movie_folder};
return {Config::GetGCIFolderPath(card_slot, region), true};
}

void CEXIMemoryCard::SetupGciFolder(const Memcard::HeaderData& header_data)
Expand Down
6 changes: 3 additions & 3 deletions Source/Core/Core/NetPlayServer.cpp
Expand Up @@ -1686,7 +1686,8 @@ bool NetPlayServer::SyncSaveData(const SaveSyncInfo& sync_info)
return true;

const auto game_region = sync_info.game->GetRegion();
const std::string region = Config::GetDirectoryForRegion(Config::ToGameCubeRegion(game_region));
const auto gamecube_region = Config::ToGameCubeRegion(game_region);
const std::string region = Config::GetDirectoryForRegion(gamecube_region);

for (ExpansionInterface::Slot slot : ExpansionInterface::MEMCARD_SLOTS)
{
Expand Down Expand Up @@ -1723,8 +1724,7 @@ bool NetPlayServer::SyncSaveData(const SaveSyncInfo& sync_info)
else if (Config::Get(Config::GetInfoForEXIDevice(slot)) ==
ExpansionInterface::EXIDeviceType::MemoryCardFolder)
{
const std::string path = File::GetUserPath(D_GCUSER_IDX) + region + DIR_SEP +
fmt::format("Card {}", is_slot_a ? 'A' : 'B');
const std::string path = Config::GetGCIFolderPath(slot, gamecube_region);

sf::Packet pac;
pac << MessageID::SyncSaveData;
Expand Down
12 changes: 3 additions & 9 deletions Source/Core/DolphinQt/GameList/GameList.cpp
Expand Up @@ -716,16 +716,10 @@ void GameList::OpenGCSaveFolder()
{
case ExpansionInterface::EXIDeviceType::MemoryCardFolder:
{
std::string path = fmt::format("{}/{}/{}", File::GetUserPath(D_GCUSER_IDX),
Config::GetDirectoryForRegion(game->GetRegion()),
slot == Slot::A ? "Card A" : "Card B");

std::string override_path = Config::Get(Config::GetInfoForGCIPathOverride(slot));

if (!override_path.empty())
path = override_path;

QDir dir(QString::fromStdString(path));
QDir dir(QString::fromStdString(override_path.empty() ?
Config::GetGCIFolderPath(slot, game->GetRegion()) :
override_path));

if (!dir.entryList({QStringLiteral("%1-%2-*.gci")
.arg(QString::fromStdString(game->GetMakerID()))
Expand Down

0 comments on commit 132bf65

Please sign in to comment.