Skip to content

Commit

Permalink
NetPlay: Add full Wii save sync
Browse files Browse the repository at this point in the history
This adds the ability to sync all Wii saves, instead of only the
selected game. Useful for cases like launching a game though GeckoOS.
  • Loading branch information
Techjar committed Nov 14, 2018
1 parent ca70ead commit d548100
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 67 deletions.
2 changes: 2 additions & 0 deletions Source/Core/Core/Config/NetplaySettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,7 @@ const ConfigInfo<bool> NETPLAY_STRICT_SETTINGS_SYNC{{System::Main, "NetPlay", "S
false};
const ConfigInfo<bool> NETPLAY_HOST_INPUT_AUTHORITY{{System::Main, "NetPlay", "HostInputAuthority"},
false};
const ConfigInfo<bool> NETPLAY_SYNC_ALL_WII_SAVES{{System::Main, "NetPlay", "SyncAllWiiSaves"},
false};

} // namespace Config
1 change: 1 addition & 0 deletions Source/Core/Core/Config/NetplaySettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@ extern const ConfigInfo<bool> NETPLAY_RECORD_INPUTS;
extern const ConfigInfo<bool> NETPLAY_REDUCE_POLLING_RATE;
extern const ConfigInfo<bool> NETPLAY_STRICT_SETTINGS_SYNC;
extern const ConfigInfo<bool> NETPLAY_HOST_INPUT_AUTHORITY;
extern const ConfigInfo<bool> NETPLAY_SYNC_ALL_WII_SAVES;

} // namespace Config
61 changes: 41 additions & 20 deletions Source/Core/Core/NetPlayClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ namespace NetPlay
static std::mutex crit_netplay_client;
static NetPlayClient* netplay_client = nullptr;
static std::unique_ptr<IOS::HLE::FS::FileSystem> s_wii_sync_fs;
static std::vector<u64> s_wii_sync_titles;
static bool s_si_poll_batching;

// called from ---GUI--- thread
Expand Down Expand Up @@ -608,6 +609,7 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
packet >> m_net_settings.m_SyncSaveData;
packet >> m_net_settings.m_SaveDataRegion;
packet >> m_net_settings.m_SyncCodes;
packet >> m_net_settings.m_SyncAllWiiSaves;

m_net_settings.m_IsHosting = m_local_player->IsHost();
m_net_settings.m_HostInputAuthority = m_host_input_authority;
Expand Down Expand Up @@ -787,13 +789,6 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
if (m_local_player->IsHost())
return 0;

const auto game = m_dialog->FindGameFile(m_selected_game);
if (game == nullptr)
{
SyncSaveDataResponse(true); // whatever, we won't be booting anyways
return 0;
}

const std::string path = File::GetUserPath(D_USER_IDX) + "Wii" GC_MEMCARD_NETPLAY DIR_SEP;

if (File::Exists(path) && !File::DeleteDirRecursively(path))
Expand All @@ -804,16 +799,25 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
}

auto temp_fs = std::make_unique<IOS::HLE::FS::HostFileSystem>(path);
temp_fs->CreateDirectory(IOS::PID_KERNEL, IOS::PID_KERNEL,
Common::GetTitleDataPath(game->GetTitleID()), 0,
{IOS::HLE::FS::Mode::ReadWrite, IOS::HLE::FS::Mode::ReadWrite,
IOS::HLE::FS::Mode::ReadWrite});
auto save = WiiSave::MakeNandStorage(temp_fs.get(), game->GetTitleID());

bool exists;
packet >> exists;
if (exists)
std::vector<u64> titles;

u32 save_count;
packet >> save_count;
for (u32 n = 0; n < save_count; n++)
{
u64 title_id = Common::PacketReadU64(packet);
titles.push_back(title_id);
temp_fs->CreateDirectory(IOS::PID_KERNEL, IOS::PID_KERNEL,
Common::GetTitleDataPath(title_id), 0,
{IOS::HLE::FS::Mode::ReadWrite, IOS::HLE::FS::Mode::ReadWrite,
IOS::HLE::FS::Mode::ReadWrite});
auto save = WiiSave::MakeNandStorage(temp_fs.get(), title_id);

bool exists;
packet >> exists;
if (!exists)
continue;

// Header
WiiSave::Header header;
packet >> header.tid;
Expand Down Expand Up @@ -879,7 +883,7 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
}
}

SetWiiSyncFS(std::move(temp_fs));
SetWiiSyncData(std::move(temp_fs), titles);
SyncSaveDataResponse(true);
}
break;
Expand Down Expand Up @@ -1925,7 +1929,7 @@ bool NetPlayClient::StopGame()
// stop game
m_dialog->StopGame();

ClearWiiSyncFS();
ClearWiiSyncData();

return true;
}
Expand Down Expand Up @@ -2126,19 +2130,26 @@ IOS::HLE::FS::FileSystem* GetWiiSyncFS()
return s_wii_sync_fs.get();
}

void SetWiiSyncFS(std::unique_ptr<IOS::HLE::FS::FileSystem> fs)
std::vector<u64>& GetWiiSyncTitles()
{
return s_wii_sync_titles;
}

void SetWiiSyncData(std::unique_ptr<IOS::HLE::FS::FileSystem> fs, std::vector<u64>& titles)
{
s_wii_sync_fs = std::move(fs);
s_wii_sync_titles.insert(s_wii_sync_titles.end(), titles.begin(), titles.end());
}

void ClearWiiSyncFS()
void ClearWiiSyncData()
{
// We're just assuming it will always be here because it is
const std::string path = File::GetUserPath(D_USER_IDX) + "Wii" GC_MEMCARD_NETPLAY DIR_SEP;
if (File::Exists(path))
File::DeleteDirRecursively(path);

s_wii_sync_fs.reset();
s_wii_sync_titles.clear();
}

void SetSIPollBatching(bool state)
Expand All @@ -2152,6 +2163,16 @@ void SendPowerButtonEvent()
netplay_client->SendPowerButtonEvent();
}

bool IsSyncingAllWiiSaves()
{
std::lock_guard<std::mutex> lk(crit_netplay_client);

if (netplay_client)
return netplay_client->GetNetSettings().m_SyncAllWiiSaves;

return false;
}

void NetPlay_Enable(NetPlayClient* const np)
{
std::lock_guard<std::mutex> lk(crit_netplay_client);
Expand Down
7 changes: 5 additions & 2 deletions Source/Core/Core/NetPlayProto.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ struct NetSettings
bool m_SyncSaveData;
bool m_SyncCodes;
std::string m_SaveDataRegion;
bool m_SyncAllWiiSaves;
bool m_IsHosting;
bool m_HostInputAuthority;
};
Expand Down Expand Up @@ -202,8 +203,10 @@ bool IsNetPlayRunning();
// IsNetPlayRunning() must be true before calling this.
const NetSettings& GetNetSettings();
IOS::HLE::FS::FileSystem* GetWiiSyncFS();
void SetWiiSyncFS(std::unique_ptr<IOS::HLE::FS::FileSystem> fs);
void ClearWiiSyncFS();
std::vector<u64>& GetWiiSyncTitles();
void SetWiiSyncData(std::unique_ptr<IOS::HLE::FS::FileSystem> fs, std::vector<u64>& titles);
void ClearWiiSyncData();
void SetSIPollBatching(bool state);
void SendPowerButtonEvent();
bool IsSyncingAllWiiSaves();
} // namespace NetPlay
115 changes: 74 additions & 41 deletions Source/Core/Core/NetPlayServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@
#include "Core/HW/Sram.h"
#include "Core/HW/WiiSave.h"
#include "Core/HW/WiiSaveStructs.h"
#include "Core/IOS/ES/ES.h"
#include "Core/IOS/FS/FileSystem.h"
#include "Core/IOS/IOS.h"
#include "Core/NetPlayClient.h" //for NetPlayUI
#include "DiscIO/Enums.h"
#include "InputCommon/GCPadStatus.h"
Expand Down Expand Up @@ -1198,6 +1200,7 @@ bool NetPlayServer::StartGame()
spac << m_settings.m_SyncSaveData;
spac << region;
spac << m_settings.m_SyncCodes;
spac << m_settings.m_SyncAllWiiSaves;

SendAsyncToClients(std::move(spac));

Expand Down Expand Up @@ -1236,7 +1239,8 @@ bool NetPlayServer::SyncSaveData()

bool wii_save = false;
if (m_settings.m_CopyWiiSave && (game->GetPlatform() == DiscIO::Platform::WiiDisc ||
game->GetPlatform() == DiscIO::Platform::WiiWAD))
game->GetPlatform() == DiscIO::Platform::WiiWAD ||
game->GetPlatform() == DiscIO::Platform::ELFOrDOL))
{
wii_save = true;
save_count++;
Expand Down Expand Up @@ -1335,58 +1339,87 @@ bool NetPlayServer::SyncSaveData()
if (wii_save)
{
const auto configured_fs = IOS::HLE::FS::MakeFileSystem(IOS::HLE::FS::Location::Configured);
const auto save = WiiSave::MakeNandStorage(configured_fs.get(), game->GetTitleID());

std::vector<std::pair<u64, WiiSave::StoragePointer>> saves;
if (m_settings.m_SyncAllWiiSaves)
{
IOS::HLE::Kernel ios;
for (const u64 title : ios.GetES()->GetInstalledTitles())
{
auto save = WiiSave::MakeNandStorage(configured_fs.get(), title);
saves.push_back(std::make_pair(title, std::move(save)));
}
}
else if (game->GetPlatform() == DiscIO::Platform::WiiDisc ||
game->GetPlatform() == DiscIO::Platform::WiiWAD)
{
auto save = WiiSave::MakeNandStorage(configured_fs.get(), game->GetTitleID());
saves.push_back(std::make_pair(game->GetTitleID(), std::move(save)));
}

std::vector<u64> titles;

sf::Packet pac;
pac << static_cast<MessageId>(NP_MSG_SYNC_SAVE_DATA);
pac << static_cast<MessageId>(SYNC_SAVE_DATA_WII);
pac << static_cast<u32>(saves.size());

if (save->SaveExists())
for (const auto& pair : saves)
{
const std::optional<WiiSave::Header> header = save->ReadHeader();
const std::optional<WiiSave::BkHeader> bk_header = save->ReadBkHeader();
const std::optional<std::vector<WiiSave::Storage::SaveFile>> files = save->ReadFiles();
if (!header || !bk_header || !files)
return false;

pac << true; // save exists

// Header
pac << sf::Uint64{header->tid};
pac << header->banner_size << header->permissions << header->unk1;
for (size_t i = 0; i < header->md5.size(); i++)
pac << header->md5[i];
pac << header->unk2;
for (size_t i = 0; i < header->banner_size; i++)
pac << header->banner[i];

// BkHeader
pac << bk_header->size << bk_header->magic << bk_header->ngid << bk_header->number_of_files
<< bk_header->size_of_files << bk_header->unk1 << bk_header->unk2
<< bk_header->total_size;
for (size_t i = 0; i < bk_header->unk3.size(); i++)
pac << bk_header->unk3[i];
pac << sf::Uint64{bk_header->tid};
for (size_t i = 0; i < bk_header->mac_address.size(); i++)
pac << bk_header->mac_address[i];

// Files
for (const WiiSave::Storage::SaveFile& file : *files)
pac << sf::Uint64{pair.first};
titles.push_back(pair.first);
const auto& save = pair.second;

if (save->SaveExists())
{
pac << file.mode << file.attributes << static_cast<u8>(file.type) << file.path;
const std::optional<WiiSave::Header> header = save->ReadHeader();
const std::optional<WiiSave::BkHeader> bk_header = save->ReadBkHeader();
const std::optional<std::vector<WiiSave::Storage::SaveFile>> files = save->ReadFiles();
if (!header || !bk_header || !files)
return false;

if (file.type == WiiSave::Storage::SaveFile::Type::File)
pac << true; // save exists

// Header
pac << sf::Uint64{header->tid};
pac << header->banner_size << header->permissions << header->unk1;
for (size_t i = 0; i < header->md5.size(); i++)
pac << header->md5[i];
pac << header->unk2;
for (size_t i = 0; i < header->banner_size; i++)
pac << header->banner[i];

// BkHeader
pac << bk_header->size << bk_header->magic << bk_header->ngid << bk_header->number_of_files
<< bk_header->size_of_files << bk_header->unk1 << bk_header->unk2
<< bk_header->total_size;
for (size_t i = 0; i < bk_header->unk3.size(); i++)
pac << bk_header->unk3[i];
pac << sf::Uint64{bk_header->tid};
for (size_t i = 0; i < bk_header->mac_address.size(); i++)
pac << bk_header->mac_address[i];

// Files
for (const WiiSave::Storage::SaveFile& file : *files)
{
const std::optional<std::vector<u8>>& data = *file.data;
if (!data || !CompressBufferIntoPacket(*data, pac))
return false;
pac << file.mode << file.attributes << static_cast<u8>(file.type) << file.path;

if (file.type == WiiSave::Storage::SaveFile::Type::File)
{
const std::optional<std::vector<u8>>& data = *file.data;
if (!data || !CompressBufferIntoPacket(*data, pac))
return false;
}
}
}
else
{
pac << false; // save does not exist
}
}
else
{
pac << false; // save does not exist
}

// Set titles for host-side loading in WiiRoot
SetWiiSyncData(nullptr, titles);

SendChunkedToClients(std::move(pac), 1, "Wii Save Synchronization");
}
Expand Down
35 changes: 31 additions & 4 deletions Source/Core/Core/WiiRoot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "Common/StringUtil.h"
#include "Core/ConfigManager.h"
#include "Core/HW/WiiSave.h"
#include "Core/IOS/ES/ES.h"
#include "Core/IOS/FS/FileSystem.h"
#include "Core/IOS/IOS.h"
#include "Core/IOS/Uids.h"
Expand All @@ -30,6 +31,14 @@ namespace FS = IOS::HLE::FS;

static std::string s_temp_wii_root;

static void CopySave(FS::FileSystem* source, FS::FileSystem* dest, const u64 title_id)
{
dest->CreateDirectory(IOS::PID_KERNEL, IOS::PID_KERNEL, Common::GetTitleDataPath(title_id), 0, {IOS::HLE::FS::Mode::ReadWrite, IOS::HLE::FS::Mode::ReadWrite, IOS::HLE::FS::Mode::ReadWrite});
const auto source_save = WiiSave::MakeNandStorage(source, title_id);
const auto dest_save = WiiSave::MakeNandStorage(dest, title_id);
WiiSave::Copy(source_save.get(), dest_save.get());
}

static void InitializeDeterministicWiiSaves(FS::FileSystem* session_fs)
{
const u64 title_id = SConfig::GetInstance().GetTitleID();
Expand All @@ -53,10 +62,28 @@ static void InitializeDeterministicWiiSaves(FS::FileSystem* session_fs)
{
// Copy the current user's save to the Blank NAND
auto* sync_fs = NetPlay::GetWiiSyncFS();
const auto user_save =
WiiSave::MakeNandStorage(sync_fs ? sync_fs : configured_fs.get(), title_id);
const auto session_save = WiiSave::MakeNandStorage(session_fs, title_id);
WiiSave::Copy(user_save.get(), session_save.get());
auto& sync_titles = NetPlay::GetWiiSyncTitles();
if (sync_fs)
{
for (const u64 title : sync_titles)
{
CopySave(sync_fs, session_fs, title);
}
}
else
{
if (NetPlay::IsSyncingAllWiiSaves())
{
for (const u64 title : sync_titles)
{
CopySave(configured_fs.get(), session_fs, title);
}
}
else
{
CopySave(configured_fs.get(), session_fs, title_id);
}
}
}
}

Expand Down
Loading

0 comments on commit d548100

Please sign in to comment.