Core/WiiRoot: Handle the combination of NetPlay and savegame redirects.

This commit is contained in:
Admiral H. Curtiss 2021-11-14 02:22:59 +01:00
parent 387d148357
commit b928900f6e
No known key found for this signature in database
GPG Key ID: F051B4C4044F33FB
8 changed files with 140 additions and 34 deletions

View File

@ -155,6 +155,11 @@ const std::vector<u64>& BootSessionData::GetWiiSyncTitles() const
return m_wii_sync_titles;
}
const std::string& BootSessionData::GetWiiSyncRedirectFolder() const
{
return m_wii_sync_redirect_folder;
}
void BootSessionData::InvokeWiiSyncCleanup() const
{
if (m_wii_sync_cleanup)
@ -162,10 +167,12 @@ void BootSessionData::InvokeWiiSyncCleanup() const
}
void BootSessionData::SetWiiSyncData(std::unique_ptr<IOS::HLE::FS::FileSystem> fs,
std::vector<u64> titles, WiiSyncCleanupFunction cleanup)
std::vector<u64> titles, std::string redirect_folder,
WiiSyncCleanupFunction cleanup)
{
m_wii_sync_fs = std::move(fs);
m_wii_sync_titles = std::move(titles);
m_wii_sync_redirect_folder = std::move(redirect_folder);
m_wii_sync_cleanup = std::move(cleanup);
}

View File

@ -66,9 +66,10 @@ public:
IOS::HLE::FS::FileSystem* GetWiiSyncFS() const;
const std::vector<u64>& GetWiiSyncTitles() const;
const std::string& GetWiiSyncRedirectFolder() const;
void InvokeWiiSyncCleanup() const;
void SetWiiSyncData(std::unique_ptr<IOS::HLE::FS::FileSystem> fs, std::vector<u64> titles,
WiiSyncCleanupFunction cleanup);
std::string redirect_folder, WiiSyncCleanupFunction cleanup);
private:
std::optional<std::string> m_savestate_path;
@ -76,6 +77,7 @@ private:
std::unique_ptr<IOS::HLE::FS::FileSystem> m_wii_sync_fs;
std::vector<u64> m_wii_sync_titles;
std::string m_wii_sync_redirect_folder;
WiiSyncCleanupFunction m_wii_sync_cleanup;
};

View File

@ -1077,6 +1077,7 @@ void NetPlayClient::OnSyncSaveDataGCI(sf::Packet& packet)
void NetPlayClient::OnSyncSaveDataWii(sf::Packet& packet)
{
const std::string path = File::GetUserPath(D_USER_IDX) + "Wii" GC_MEMCARD_NETPLAY DIR_SEP;
std::string redirect_path = File::GetUserPath(D_USER_IDX) + "Redirect" GC_MEMCARD_NETPLAY DIR_SEP;
if (File::Exists(path) && !File::DeleteDirRecursively(path))
{
@ -1084,6 +1085,12 @@ void NetPlayClient::OnSyncSaveDataWii(sf::Packet& packet)
SyncSaveDataResponse(false);
return;
}
if (File::Exists(redirect_path) && !File::DeleteDirRecursively(redirect_path))
{
PanicAlertFmtT("Failed to reset NetPlay redirect folder. Verify your write permissions.");
SyncSaveDataResponse(false);
return;
}
auto temp_fs = std::make_unique<IOS::HLE::FS::HostFileSystem>(path);
std::vector<u64> titles;
@ -1190,7 +1197,19 @@ void NetPlayClient::OnSyncSaveDataWii(sf::Packet& packet)
}
}
SetWiiSyncData(std::move(temp_fs), std::move(titles));
bool has_redirected_save;
packet >> has_redirected_save;
if (has_redirected_save)
{
if (!DecompressPacketIntoFolder(packet, redirect_path))
{
PanicAlertFmtT("Failed to write redirected save.");
SyncSaveDataResponse(false);
return;
}
}
SetWiiSyncData(std::move(temp_fs), std::move(titles), std::move(redirect_path));
SyncSaveDataResponse(true);
}
@ -1721,11 +1740,17 @@ bool NetPlayClient::StartGame(const std::string& path)
// boot game
auto boot_session_data = std::make_unique<BootSessionData>();
boot_session_data->SetWiiSyncData(std::move(m_wii_sync_fs), std::move(m_wii_sync_titles), [] {
boot_session_data->SetWiiSyncData(
std::move(m_wii_sync_fs), std::move(m_wii_sync_titles), std::move(m_wii_sync_redirect_folder),
[] {
// on emulation end clean up the Wii save sync directory -- see OnSyncSaveDataWii()
const std::string path = File::GetUserPath(D_USER_IDX) + "Wii" GC_MEMCARD_NETPLAY DIR_SEP;
if (File::Exists(path))
File::DeleteDirRecursively(path);
const std::string redirect_path =
File::GetUserPath(D_USER_IDX) + "Redirect" GC_MEMCARD_NETPLAY DIR_SEP;
if (File::Exists(redirect_path))
File::DeleteDirRecursively(redirect_path);
});
m_dialog->BootGame(path, std::move(boot_session_data));
@ -2501,10 +2526,11 @@ void NetPlayClient::AdjustPadBufferSize(const unsigned int size)
}
void NetPlayClient::SetWiiSyncData(std::unique_ptr<IOS::HLE::FS::FileSystem> fs,
std::vector<u64> titles)
std::vector<u64> titles, std::string redirect_folder)
{
m_wii_sync_fs = std::move(fs);
m_wii_sync_titles = std::move(titles);
m_wii_sync_redirect_folder = std::move(redirect_folder);
}
SyncIdentifier NetPlayClient::GetSDCardIdentifier()

View File

@ -86,7 +86,7 @@ public:
virtual void HideChunkedProgressDialog() = 0;
virtual void SetChunkedProgress(int pid, u64 progress) = 0;
virtual void SetHostWiiSyncTitles(std::vector<u64> titles) = 0;
virtual void SetHostWiiSyncData(std::vector<u64> titles, std::string redirect_folder) = 0;
};
class Player
@ -157,7 +157,8 @@ public:
void AdjustPadBufferSize(unsigned int size);
void SetWiiSyncData(std::unique_ptr<IOS::HLE::FS::FileSystem> fs, std::vector<u64> titles);
void SetWiiSyncData(std::unique_ptr<IOS::HLE::FS::FileSystem> fs, std::vector<u64> titles,
std::string redirect_folder);
static SyncIdentifier GetSDCardIdentifier();
@ -328,6 +329,7 @@ private:
std::unique_ptr<IOS::HLE::FS::FileSystem> m_wii_sync_fs;
std::vector<u64> m_wii_sync_titles;
std::string m_wii_sync_redirect_folder;
};
void NetPlay_Enable(NetPlayClient* const np);

View File

@ -31,6 +31,7 @@
#include "Common/Version.h"
#include "Core/ActionReplay.h"
#include "Core/Boot/Boot.h"
#include "Core/Config/GraphicsSettings.h"
#include "Core/Config/MainSettings.h"
#include "Core/Config/NetplaySettings.h"
@ -60,6 +61,7 @@
#include "Core/SyncIdentifier.h"
#include "DiscIO/Enums.h"
#include "DiscIO/RiivolutionPatcher.h"
#include "InputCommon/ControllerEmu/ControlGroup/Attachments.h"
#include "InputCommon/GCPadStatus.h"
@ -1616,6 +1618,17 @@ bool NetPlayServer::SyncSaveData()
save_count++;
}
std::optional<DiscIO::Riivolution::SavegameRedirect> redirected_save;
if (wii_save && game->GetBlobType() == DiscIO::BlobType::MOD_DESCRIPTOR)
{
auto boot_params = BootParameters::GenerateFromFile(game->GetFilePath());
if (boot_params)
{
redirected_save =
DiscIO::Riivolution::ExtractSavegameRedirect(boot_params->riivolution_patches);
}
}
for (const auto& config : m_gba_config)
{
if (config.enabled && config.has_rom)
@ -1818,8 +1831,20 @@ bool NetPlayServer::SyncSaveData()
}
}
if (redirected_save)
{
pac << true;
if (!CompressFolderIntoPacket(redirected_save->m_target_path, pac))
return false;
}
else
{
pac << false; // no redirected save
}
// Set titles for host-side loading in WiiRoot
m_dialog->SetHostWiiSyncTitles(std::move(titles));
m_dialog->SetHostWiiSyncData(std::move(titles),
redirected_save ? redirected_save->m_target_path : "");
SendChunkedToClients(std::move(pac), 1, "Wii Save Synchronization");
}

View File

@ -35,9 +35,19 @@ namespace Core
namespace FS = IOS::HLE::FS;
static std::string s_temp_wii_root;
static std::string s_temp_redirect_root;
static bool s_wii_root_initialized = false;
static std::vector<IOS::HLE::FS::NandRedirect> s_nand_redirects;
// When Temp NAND + Redirects are both active, we need to keep track of where each redirect path
// should be copied back to after a successful session finish.
struct TempRedirectPath
{
std::string real_path;
std::string temp_path;
};
static std::vector<TempRedirectPath> s_temp_nand_redirects;
const std::vector<IOS::HLE::FS::NandRedirect>& GetActiveNandRedirects()
{
return s_nand_redirects;
@ -175,6 +185,28 @@ static void InitializeDeterministicWiiSaves(FS::FileSystem* session_fs,
WARN_LOG_FMT(CORE, "Failed to copy Mii database to the NAND");
}
}
const auto& netplay_redirect_folder = boot_session_data.GetWiiSyncRedirectFolder();
if (!netplay_redirect_folder.empty())
File::CopyDir(netplay_redirect_folder, s_temp_redirect_root + "/");
}
}
static void MoveToBackupIfExists(const std::string& path)
{
if (File::Exists(path))
{
const std::string backup_path = path.substr(0, path.size() - 1) + ".backup" DIR_SEP;
WARN_LOG_FMT(IOS_FS, "Temporary directory at {} exists, moving to backup...", path);
// If backup exists, delete it as we don't want a mess
if (File::Exists(backup_path))
{
WARN_LOG_FMT(IOS_FS, "Temporary backup directory at {} exists, deleting...", backup_path);
File::DeleteDirRecursively(backup_path);
}
File::CopyDir(path, backup_path, true);
}
}
@ -185,24 +217,13 @@ void InitializeWiiRoot(bool use_temporary)
if (use_temporary)
{
s_temp_wii_root = File::GetUserPath(D_USER_IDX) + "WiiSession" DIR_SEP;
s_temp_redirect_root = File::GetUserPath(D_USER_IDX) + "RedirectSession" DIR_SEP;
WARN_LOG_FMT(IOS_FS, "Using temporary directory {} for minimal Wii FS", s_temp_wii_root);
WARN_LOG_FMT(IOS_FS, "Using temporary directory {} for redirected saves", s_temp_redirect_root);
// If directory exists, make a backup
if (File::Exists(s_temp_wii_root))
{
const std::string backup_path =
s_temp_wii_root.substr(0, s_temp_wii_root.size() - 1) + ".backup" DIR_SEP;
WARN_LOG_FMT(IOS_FS, "Temporary Wii FS directory exists, moving to backup...");
// If backup exists, delete it as we don't want a mess
if (File::Exists(backup_path))
{
WARN_LOG_FMT(IOS_FS, "Temporary Wii FS backup directory exists, deleting...");
File::DeleteDirRecursively(backup_path);
}
File::CopyDir(s_temp_wii_root, backup_path, true);
}
MoveToBackupIfExists(s_temp_wii_root);
MoveToBackupIfExists(s_temp_redirect_root);
File::SetUserPath(D_SESSION_WIIROOT_IDX, s_temp_wii_root);
}
@ -221,6 +242,9 @@ void ShutdownWiiRoot()
{
File::DeleteDirRecursively(s_temp_wii_root);
s_temp_wii_root.clear();
File::DeleteDirRecursively(s_temp_redirect_root);
s_temp_redirect_root.clear();
s_temp_nand_redirects.clear();
}
s_nand_redirects.clear();
@ -312,7 +336,8 @@ void InitializeWiiFileSystemContents(
if (!CopySysmenuFilesToFS(fs.get(), File::GetSysDirectory() + WII_USER_DIR, ""))
WARN_LOG_FMT(CORE, "Failed to copy initial System Menu files to the NAND");
if (WiiRootIsTemporary())
const bool is_temp_nand = WiiRootIsTemporary();
if (is_temp_nand)
{
// Generate a SYSCONF with default settings for the temporary Wii NAND.
SysConf sysconf{fs};
@ -320,16 +345,26 @@ void InitializeWiiFileSystemContents(
InitializeDeterministicWiiSaves(fs.get(), boot_session_data);
}
else if (save_redirect)
if (save_redirect)
{
const u64 title_id = SConfig::GetInstance().GetTitleID();
std::string source_path = Common::GetTitleDataPath(title_id);
if (is_temp_nand)
{
// remember the actual path for copying back on shutdown and redirect to a temp folder instead
s_temp_nand_redirects.emplace_back(
TempRedirectPath{save_redirect->m_target_path, s_temp_redirect_root});
save_redirect->m_target_path = s_temp_redirect_root;
}
if (!File::IsDirectory(save_redirect->m_target_path))
{
File::CreateFullPath(save_redirect->m_target_path + "/");
if (save_redirect->m_clone)
{
File::CopyDir(Common::GetTitleDataPath(title_id, Common::FROM_CONFIGURED_ROOT),
File::CopyDir(Common::GetTitleDataPath(title_id, Common::FROM_SESSION_ROOT),
save_redirect->m_target_path);
}
}
@ -347,7 +382,16 @@ void CleanUpWiiFileSystemContents(const BootSessionData& boot_session_data)
return;
}
// copy back the temp nand redirected files to where they should normally be redirected to
for (const auto& redirect : s_temp_nand_redirects)
File::CopyDir(redirect.temp_path, redirect.real_path + "/", true);
IOS::HLE::EmulationKernel* ios = IOS::HLE::GetIOS();
// clear the redirects in the session FS, otherwise the back-copy might grab redirected files
s_nand_redirects.clear();
ios->GetFS()->SetNandRedirects({});
const auto configured_fs = FS::MakeFileSystem(FS::Location::Configured);
// Copy back Mii data

View File

@ -1179,9 +1179,9 @@ void NetPlayDialog::SetChunkedProgress(const int pid, const u64 progress)
});
}
void NetPlayDialog::SetHostWiiSyncTitles(std::vector<u64> titles)
void NetPlayDialog::SetHostWiiSyncData(std::vector<u64> titles, std::string redirect_folder)
{
auto client = Settings::Instance().GetNetPlayClient();
if (client)
client->SetWiiSyncData(nullptr, std::move(titles));
client->SetWiiSyncData(nullptr, std::move(titles), std::move(redirect_folder));
}

View File

@ -95,7 +95,7 @@ public:
void HideChunkedProgressDialog() override;
void SetChunkedProgress(int pid, u64 progress) override;
void SetHostWiiSyncTitles(std::vector<u64> titles) override;
void SetHostWiiSyncData(std::vector<u64> titles, std::string redirect_folder) override;
signals:
void Stop();