Add md5 testing to netplay

Allows to test current game, an arbitrary game or the sdcard of all players
at once.
This commit is contained in:
Aestek 2016-07-14 00:45:38 +02:00
parent bb87bb73f4
commit 51c77e8eea
18 changed files with 531 additions and 44 deletions

View file

@ -30,6 +30,7 @@ set(SRCS Analytics.cpp
Version.cpp
x64ABI.cpp
x64Emitter.cpp
MD5.cpp
Crypto/bn.cpp
Crypto/ec.cpp
Logging/LogManager.cpp)

View file

@ -114,6 +114,7 @@
<ClInclude Include="JitRegister.h" />
<ClInclude Include="LinearDiskCache.h" />
<ClInclude Include="MathUtil.h" />
<ClInclude Include="MD5.h" />
<ClInclude Include="MemArena.h" />
<ClInclude Include="MemoryUtil.h" />
<ClInclude Include="MsgHandler.h" />
@ -158,6 +159,7 @@
<ClCompile Include="JitRegister.cpp" />
<ClCompile Include="Logging\ConsoleListenerWin.cpp" />
<ClCompile Include="MathUtil.cpp" />
<ClCompile Include="MD5.cpp" />
<ClCompile Include="MemArena.cpp" />
<ClCompile Include="MemoryUtil.cpp" />
<ClCompile Include="Misc.cpp" />

View file

@ -0,0 +1,52 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <fstream>
#include <functional>
#include <mbedtls/md5.h>
#include <string>
#include "Common/MD5.h"
#include "Common/StringUtil.h"
#include "DiscIO/Blob.h"
namespace MD5
{
std::string MD5Sum(const std::string& file_path, std::function<bool(int)> report_progress)
{
std::string output_string;
std::vector<u8> data(8 * 1024 * 1024);
u64 read_offset = 0;
mbedtls_md5_context ctx;
std::unique_ptr<DiscIO::IBlobReader> file(DiscIO::CreateBlobReader(file_path));
u64 game_size = file->GetDataSize();
mbedtls_md5_starts(&ctx);
while (read_offset < game_size)
{
size_t read_size = std::min(static_cast<u64>(data.size()), game_size - read_offset);
if (!file->Read(read_offset, read_size, data.data()))
return output_string;
mbedtls_md5_update(&ctx, data.data(), read_size);
read_offset += read_size;
int progress =
static_cast<int>(static_cast<float>(read_offset) / static_cast<float>(game_size) * 100);
if (!report_progress(progress))
return output_string;
}
std::array<u8, 16> output;
mbedtls_md5_finish(&ctx, output.data());
// Convert to hex
for (u8 n : output)
output_string += StringFromFormat("%02x", n);
return output_string;
}
}

13
Source/Core/Common/MD5.h Normal file
View file

@ -0,0 +1,13 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <functional>
#include <string>
namespace MD5
{
std::string MD5Sum(const std::string& file_name, std::function<bool(int)> progress);
}

View file

@ -4,10 +4,14 @@
#include "Core/NetPlayClient.h"
#include <algorithm>
#include <fstream>
#include <mbedtls/md5.h>
#include <memory>
#include <thread>
#include "Common/Common.h"
#include "Common/CommonTypes.h"
#include "Common/ENetUtil.h"
#include "Common/MD5.h"
#include "Common/MsgHandler.h"
#include "Common/Timer.h"
#include "Core/ConfigManager.h"
@ -19,6 +23,8 @@
#include "Core/HW/WiimoteReal/WiimoteReal.h"
#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h"
#include "Core/Movie.h"
#include "Core/Movie.h"
#include "Core/NetPlayClient.h"
#include "InputCommon/GCAdapter.h"
static std::mutex crit_netplay_client;
@ -500,6 +506,55 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
}
break;
case NP_MSG_COMPUTE_MD5:
{
std::string file_identifier;
packet >> file_identifier;
ComputeMD5(file_identifier);
}
break;
case NP_MSG_MD5_PROGRESS:
{
PlayerId pid;
int progress;
packet >> pid;
packet >> progress;
m_dialog->SetMD5Progress(pid, progress);
}
break;
case NP_MSG_MD5_RESULT:
{
PlayerId pid;
std::string result;
packet >> pid;
packet >> result;
m_dialog->SetMD5Result(pid, result);
}
break;
case NP_MSG_MD5_ERROR:
{
PlayerId pid;
std::string error;
packet >> pid;
packet >> error;
m_dialog->SetMD5Result(pid, error);
}
break;
case NP_MSG_MD5_ABORT:
{
m_should_compute_MD5 = false;
m_dialog->AbortMD5();
}
break;
default:
PanicAlertT("Unknown message received with id : %d", mid);
break;
@ -1197,6 +1252,47 @@ bool NetPlayClient::DoAllPlayersHaveGame()
[](auto entry) { return entry.second.game_status == PlayerGameStatus::Ok; });
}
void NetPlayClient::ComputeMD5(const std::string& file_identifier)
{
if (m_should_compute_MD5)
return;
m_dialog->ShowMD5Dialog(file_identifier);
m_should_compute_MD5 = true;
std::string file;
if (file_identifier == "sd.raw")
file = File::GetUserPath(D_WIIROOT_IDX) + "/sd.raw";
else
file = m_dialog->FindGame(file_identifier);
if (file.empty() || !File::Exists(file))
{
sf::Packet spac;
spac << static_cast<MessageId>(NP_MSG_MD5_ERROR);
spac << "file not found";
Send(spac);
return;
}
m_MD5_thread = std::thread([this, file]() {
std::string sum = MD5::MD5Sum(file, [&](int progress) {
sf::Packet spac;
spac << static_cast<MessageId>(NP_MSG_MD5_PROGRESS);
spac << progress;
Send(spac);
return m_should_compute_MD5;
});
sf::Packet spac;
spac << static_cast<MessageId>(NP_MSG_MD5_RESULT);
spac << sum;
Send(spac);
});
m_MD5_thread.detach();
}
// stuff hacked into dolphin
// called from ---CPU--- thread

View file

@ -34,6 +34,10 @@ public:
virtual void OnMsgStopGame() = 0;
virtual bool IsRecording() = 0;
virtual std::string FindGame(const std::string& game) = 0;
virtual void ShowMD5Dialog(const std::string& file_identifier) = 0;
virtual void SetMD5Progress(int pid, int progress) = 0;
virtual void SetMD5Result(int pid, const std::string& result) = 0;
virtual void AbortMD5() = 0;
};
enum class PlayerGameStatus
@ -155,6 +159,7 @@ private:
void Send(sf::Packet& packet);
void Disconnect();
bool Connect();
void ComputeMD5(const std::string& file_identifier);
bool m_is_connected = false;
ConnectionState m_connection_state = ConnectionState::Failure;
@ -165,6 +170,8 @@ private:
std::string m_player_name;
bool m_connecting = false;
TraversalClient* m_traversal_client = nullptr;
std::thread m_MD5_thread;
bool m_should_compute_MD5 = false;
u32 m_timebase_frame = 0;
};

View file

@ -58,6 +58,12 @@ enum
NP_MSG_TIMEBASE = 0xB0,
NP_MSG_DESYNC_DETECTED = 0xB1,
NP_MSG_COMPUTE_MD5 = 0xC0,
NP_MSG_MD5_PROGRESS = 0xC1,
NP_MSG_MD5_RESULT = 0xC2,
NP_MSG_MD5_ABORT = 0xC3,
NP_MSG_MD5_ERROR = 0xC4,
NP_MSG_READY = 0xD0,
NP_MSG_NOT_READY = 0xD1,

View file

@ -664,6 +664,49 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
}
}
break;
case NP_MSG_MD5_PROGRESS:
{
int progress;
packet >> progress;
sf::Packet spac;
spac << static_cast<MessageId>(NP_MSG_MD5_PROGRESS);
spac << player.pid;
spac << progress;
SendToClients(spac);
}
break;
case NP_MSG_MD5_RESULT:
{
std::string result;
packet >> result;
sf::Packet spac;
spac << static_cast<MessageId>(NP_MSG_MD5_RESULT);
spac << player.pid;
spac << result;
SendToClients(spac);
}
break;
case NP_MSG_MD5_ERROR:
{
std::string error;
packet >> error;
sf::Packet spac;
spac << static_cast<MessageId>(NP_MSG_MD5_ERROR);
spac << player.pid;
spac << error;
SendToClients(spac);
}
break;
default:
PanicAlertT("Unknown message with id:%d received from player:%d Kicking player!", mid,
player.pid);
@ -685,8 +728,8 @@ void NetPlayServer::OnTraversalStateChanged()
void NetPlayServer::SendChatMessage(const std::string& msg)
{
auto spac = std::make_unique<sf::Packet>();
*spac << (MessageId)NP_MSG_CHAT_MESSAGE;
*spac << (PlayerId)0; // server id always 0
*spac << static_cast<MessageId>(NP_MSG_CHAT_MESSAGE);
*spac << static_cast<PlayerId>(0); // server id always 0
*spac << msg;
SendAsyncToClients(std::move(spac));
@ -701,7 +744,7 @@ bool NetPlayServer::ChangeGame(const std::string& game)
// send changed game to clients
auto spac = std::make_unique<sf::Packet>();
*spac << (MessageId)NP_MSG_CHANGE_GAME;
*spac << static_cast<MessageId>(NP_MSG_CHANGE_GAME);
*spac << game;
SendAsyncToClients(std::move(spac));
@ -709,6 +752,29 @@ bool NetPlayServer::ChangeGame(const std::string& game)
return true;
}
// called from ---GUI--- thread
bool NetPlayServer::ComputeMD5(const std::string& file_identifier)
{
auto spac = std::make_unique<sf::Packet>();
*spac << static_cast<MessageId>(NP_MSG_COMPUTE_MD5);
*spac << file_identifier;
SendAsyncToClients(std::move(spac));
return true;
}
// called from ---GUI--- thread
bool NetPlayServer::AbortMD5()
{
auto spac = std::make_unique<sf::Packet>();
*spac << static_cast<MessageId>(NP_MSG_MD5_ABORT);
SendAsyncToClients(std::move(spac));
return true;
}
// called from ---GUI--- thread
void NetPlayServer::SetNetSettings(const NetSettings& settings)
{

View file

@ -20,6 +20,7 @@
enum class PlayerGameStatus;
class NetPlayUI;
enum class PlayerGameStatus;
class NetPlayServer : public TraversalClientClient
{
@ -31,6 +32,8 @@ public:
~NetPlayServer();
bool ChangeGame(const std::string& game);
bool ComputeMD5(const std::string& file_identifier);
bool AbortMD5();
void SendChatMessage(const std::string& msg);
void SetNetSettings(const NetSettings& settings);

View file

@ -34,6 +34,7 @@ set(GUI_SRCS
Debugger/WatchView.cpp
Debugger/WatchWindow.cpp
NetPlay/ChangeGameDialog.cpp
NetPlay/MD5Dialog.cpp
NetPlay/NetPlaySetupFrame.cpp
NetPlay/NetWindow.cpp
NetPlay/PadMapDialog.cpp

View file

@ -89,6 +89,7 @@
<ClCompile Include="Debugger\WatchView.cpp" />
<ClCompile Include="Debugger\WatchWindow.cpp" />
<ClCompile Include="NetPlay\ChangeGameDialog.cpp" />
<ClCompile Include="NetPlay\MD5Dialog.cpp" />
<ClCompile Include="NetPlay\NetPlaySetupFrame.cpp" />
<ClCompile Include="NetPlay\NetWindow.cpp" />
<ClCompile Include="FifoPlayerDlg.cpp" />
@ -127,6 +128,7 @@
<ClInclude Include="Config\PathConfigPane.h" />
<ClInclude Include="Config\WiiConfigPane.h" />
<ClInclude Include="NetPlay\ChangeGameDialog.h" />
<ClInclude Include="NetPlay\MD5Dialog.h" />
<ClInclude Include="NetPlay\NetPlaySetupFrame.h" />
<ClInclude Include="NetPlay\PadMapDialog.h" />
<ClInclude Include="resource.h" />

View file

@ -360,6 +360,9 @@
<ClInclude Include="NetPlay\ChangeGameDialog.h">
<Filter>GUI\NetPlay</Filter>
</ClInclude>
<ClInclude Include="NetPlay\MD5Dialog.h">
<Filter>GUI\NetPlay</Filter>
</ClInclude>
<ClInclude Include="NetPlay\PadMapDialog.h">
<Filter>GUI\NetPlay</Filter>
</ClInclude>

View file

@ -51,6 +51,7 @@
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
#include "Common/IniFile.h"
#include "Common/MD5.h"
#include "Common/StringUtil.h"
#include "Common/SysConf.h"
#include "Core/ActionReplay.h"
@ -1304,42 +1305,13 @@ void CISOProperties::OnEditConfig(wxCommandEvent& WXUNUSED(event))
void CISOProperties::OnComputeMD5Sum(wxCommandEvent& WXUNUSED(event))
{
u8 output[16];
std::string output_string;
std::vector<u8> data(8 * 1024 * 1024);
u64 read_offset = 0;
mbedtls_md5_context ctx;
std::unique_ptr<DiscIO::IBlobReader> file(
DiscIO::CreateBlobReader(OpenGameListItem.GetFileName()));
u64 game_size = file->GetDataSize();
wxProgressDialog progressDialog(_("Computing MD5 checksum"), _("Working..."), 1000, this,
wxProgressDialog progressDialog(_("Computing MD5 checksum"), _("Working..."), 100, this,
wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME |
wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | wxPD_SMOOTH);
mbedtls_md5_starts(&ctx);
while (read_offset < game_size)
{
if (!progressDialog.Update((int)((double)read_offset / (double)game_size * 1000)))
return;
size_t read_size = std::min((u64)data.size(), game_size - read_offset);
if (!file->Read(read_offset, read_size, data.data()))
return;
mbedtls_md5_update(&ctx, data.data(), read_size);
read_offset += read_size;
}
mbedtls_md5_finish(&ctx, output);
// Convert to hex
for (int a = 0; a < 16; ++a)
output_string += StringFromFormat("%02x", output[a]);
m_MD5Sum->SetValue(output_string);
m_MD5Sum->SetValue(MD5::MD5Sum(OpenGameListItem.GetFileName(), [&progressDialog](int progress) {
return progressDialog.Update(progress);
}));
}
// Opens all pre-defined INIs for the game. If there are multiple ones,

View file

@ -10,7 +10,7 @@
#include "DolphinWX/NetPlay/NetWindow.h"
ChangeGameDialog::ChangeGameDialog(wxWindow* parent, const CGameListCtrl* const game_list)
: wxDialog(parent, wxID_ANY, _("Change Game"))
: wxDialog(parent, wxID_ANY, _("Select Game"))
{
m_game_lbox =
new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT);
@ -18,7 +18,7 @@ ChangeGameDialog::ChangeGameDialog(wxWindow* parent, const CGameListCtrl* const
NetPlayDialog::FillWithGameNames(m_game_lbox, *game_list);
wxButton* const ok_btn = new wxButton(this, wxID_OK, _("Change"));
wxButton* const ok_btn = new wxButton(this, wxID_OK, _("Select"));
ok_btn->Bind(wxEVT_BUTTON, &ChangeGameDialog::OnPick, this);
wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL);

View file

@ -0,0 +1,100 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <wx/button.h>
#include <wx/event.h>
#include <wx/gauge.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include "Common/StringUtil.h"
#include "DolphinWX/NetPlay/MD5Dialog.h"
#include "DolphinWX/NetPlay/NetWindow.h"
MD5Dialog::MD5Dialog(wxWindow* parent, NetPlayServer* server, std::vector<const Player*> players,
const std::string& game)
: wxDialog(parent, wxID_ANY, _("MD5 Checksum")), m_parent(parent), m_netplay_server(server)
{
Bind(wxEVT_CLOSE_WINDOW, &MD5Dialog::OnClose, this);
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->Add(new wxStaticText(this, wxID_ANY, _("Computing MD5 Checksum for:") + "\n" + game,
wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL),
0, wxALIGN_CENTER_HORIZONTAL | wxALL, 5);
for (const Player* player : players)
{
wxStaticBoxSizer* const player_szr = new wxStaticBoxSizer(
wxVERTICAL, this, player->name + " (p" + std::to_string(player->pid) + ")");
wxGauge* gauge = new wxGauge(this, wxID_ANY, 100);
m_progress_bars[player->pid] = gauge;
player_szr->Add(gauge, 0, wxEXPAND | wxALL, 5);
m_result_labels[player->pid] =
new wxStaticText(this, wxID_ANY, _("Computing..."), wxDefaultPosition, wxSize(250, 20),
wxALIGN_CENTRE_HORIZONTAL);
m_result_labels[player->pid]->SetSize(250, 15);
player_szr->Add(m_result_labels[player->pid], 0, wxALL, 5);
main_sizer->Add(player_szr, 0, wxEXPAND | wxALL, 5);
}
m_final_result_label =
new wxStaticText(this, wxID_ANY,
" ", // so it takes space
wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL);
main_sizer->Add(m_final_result_label, 1, wxALL, 5);
wxButton* close_btn = new wxButton(this, wxID_ANY, _("Close"));
close_btn->Bind(wxEVT_BUTTON, &MD5Dialog::OnCloseBtnPressed, this);
main_sizer->Add(close_btn, 0, wxEXPAND | wxALL, 5);
SetSizerAndFit(main_sizer);
SetFocus();
Center();
}
void MD5Dialog::SetProgress(int pid, int progress)
{
if (m_progress_bars[pid] == nullptr)
return;
m_progress_bars[pid]->SetValue(progress);
m_result_labels[pid]->SetLabel(_("Computing: ") + std::to_string(progress) + "%");
Update();
}
void MD5Dialog::SetResult(int pid, const std::string& result)
{
if (m_result_labels[pid] == nullptr)
return;
m_result_labels[pid]->SetLabel(result);
m_hashes.push_back(result);
if (m_hashes.size() <= 1)
return;
wxString label = AllHashesMatch() ? _("Hashes match!") : _("Hashes do not match.");
m_final_result_label->SetLabel(label);
}
bool MD5Dialog::AllHashesMatch() const
{
return std::adjacent_find(m_hashes.begin(), m_hashes.end(), std::not_equal_to<>()) ==
m_hashes.end();
}
void MD5Dialog::OnClose(wxCloseEvent& event)
{
m_netplay_server->AbortMD5();
}
void MD5Dialog::OnCloseBtnPressed(wxCommandEvent&)
{
Close();
}

View file

@ -0,0 +1,40 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <map>
#include <string>
#include <vector>
#include <vector>
#include <wx/dialog.h>
class NetPlayServer;
class Player;
class wxCloseEvent;
class wxGauge;
class wxStaticText;
class wxWindow;
class MD5Dialog final : public wxDialog
{
public:
MD5Dialog(wxWindow* parent, NetPlayServer* server, std::vector<const Player*> players,
const std::string& game);
void SetProgress(int pid, int progress);
void SetResult(int pid, const std::string& result);
private:
bool AllHashesMatch() const;
void OnClose(wxCloseEvent& event);
void OnCloseBtnPressed(wxCommandEvent& event);
wxWindow* m_parent;
wxStaticText* m_final_result_label;
NetPlayServer* m_netplay_server;
std::map<int, wxGauge*> m_progress_bars;
std::map<int, wxStaticText*> m_result_labels;
std::vector<std::string> m_hashes;
};

View file

@ -6,6 +6,7 @@
#include <cstddef>
#include <sstream>
#include <string>
#include <tuple>
#include <vector>
#include <wx/button.h>
#include <wx/checkbox.h>
@ -44,6 +45,7 @@
#include "DolphinWX/NetPlay/NetWindow.h"
#include "DolphinWX/NetPlay/PadMapDialog.h"
#include "DolphinWX/WxUtils.h"
#include "MD5Dialog.h"
NetPlayServer* NetPlayDialog::netplay_server = nullptr;
NetPlayClient* NetPlayDialog::netplay_client = nullptr;
@ -120,7 +122,8 @@ NetPlayDialog::NetPlayDialog(wxWindow* const parent, const CGameListCtrl* const
wxPanel* const panel = new wxPanel(this);
// top crap
wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL);
m_game_btn = new wxButton(panel, wxID_ANY, StrToWxStr(m_selected_game).Prepend(_(" Game : ")),
wxDefaultPosition, wxDefaultSize, wxBU_LEFT);
@ -129,6 +132,21 @@ NetPlayDialog::NetPlayDialog(wxWindow* const parent, const CGameListCtrl* const
else
m_game_btn->Disable();
top_szr->Add(m_game_btn, 1, wxALL | wxEXPAND);
if (m_is_hosting)
{
m_MD5_choice = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(150, -1));
m_MD5_choice->Bind(wxEVT_CHOICE, &NetPlayDialog::OnMD5ComputeRequested, this);
m_MD5_choice->Append(_("MD5 check..."));
m_MD5_choice->Append(_("Curent game"));
m_MD5_choice->Append(_("Other game"));
m_MD5_choice->Append(_("SD card"));
m_MD5_choice->SetSelection(0);
top_szr->Add(m_MD5_choice, 0, wxALL);
}
// middle crap
// chat
@ -232,7 +250,7 @@ NetPlayDialog::NetPlayDialog(wxWindow* const parent, const CGameListCtrl* const
// main sizer
wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL);
main_szr->Add(m_game_btn, 0, wxEXPAND | wxALL, 5);
main_szr->Add(top_szr, 0, wxEXPAND | wxALL, 5);
main_szr->Add(mid_szr, 1, wxEXPAND | wxLEFT | wxRIGHT, 5);
main_szr->Add(bottom_szr, 0, wxEXPAND | wxALL, 5);
@ -471,6 +489,31 @@ void NetPlayDialog::OnThread(wxThreadEvent& event)
netplay_client->StopGame();
}
break;
case NP_GUI_EVT_DISPLAY_MD5_DIALOG:
{
m_MD5_dialog = new MD5Dialog(this, netplay_server, netplay_client->GetPlayers(),
event.GetString().ToStdString());
m_MD5_dialog->Show();
}
break;
case NP_GUI_EVT_MD5_PROGRESS:
{
if (m_MD5_dialog == nullptr || m_MD5_dialog->IsBeingDeleted())
break;
std::pair<int, int> payload = event.GetPayload<std::pair<int, int>>();
m_MD5_dialog->SetProgress(payload.first, payload.second);
}
break;
case NP_GUI_EVT_MD5_RESULT:
{
if (m_MD5_dialog == nullptr || m_MD5_dialog->IsBeingDeleted())
break;
std::pair<int, std::string> payload = event.GetPayload<std::pair<int, std::string>>();
m_MD5_dialog->SetResult(payload.first, payload.second);
}
break;
}
// chat messages
@ -485,10 +528,10 @@ void NetPlayDialog::OnThread(wxThreadEvent& event)
void NetPlayDialog::OnChangeGame(wxCommandEvent&)
{
ChangeGameDialog cgd(this, m_game_list);
cgd.ShowModal();
ChangeGameDialog change_game_dialog(this, m_game_list);
change_game_dialog.ShowModal();
wxString game_name = cgd.GetChosenGameName();
wxString game_name = change_game_dialog.GetChosenGameName();
if (game_name.empty())
return;
@ -497,6 +540,66 @@ void NetPlayDialog::OnChangeGame(wxCommandEvent&)
m_game_btn->SetLabel(game_name.Prepend(_(" Game : ")));
}
void NetPlayDialog::OnMD5ComputeRequested(wxCommandEvent&)
{
MD5Target selection = static_cast<MD5Target>(m_MD5_choice->GetSelection());
std::string file_identifier;
ChangeGameDialog change_game_dialog(this, m_game_list);
m_MD5_choice->SetSelection(0);
switch (selection)
{
case MD5Target::CurrentGame:
file_identifier = m_selected_game;
break;
case MD5Target::OtherGame:
change_game_dialog.ShowModal();
file_identifier = WxStrToStr(change_game_dialog.GetChosenGameName());
if (file_identifier.empty())
return;
break;
case MD5Target::SdCard:
file_identifier = "sd.raw";
break;
default:
return;
}
netplay_server->ComputeMD5(file_identifier);
}
void NetPlayDialog::ShowMD5Dialog(const std::string& file_identifier)
{
wxThreadEvent evt(wxEVT_THREAD, NP_GUI_EVT_DISPLAY_MD5_DIALOG);
evt.SetString(file_identifier);
GetEventHandler()->AddPendingEvent(evt);
}
void NetPlayDialog::SetMD5Progress(int pid, int progress)
{
wxThreadEvent evt(wxEVT_THREAD, NP_GUI_EVT_MD5_PROGRESS);
evt.SetPayload(std::pair<int, int>(pid, progress));
GetEventHandler()->AddPendingEvent(evt);
}
void NetPlayDialog::SetMD5Result(int pid, const std::string& result)
{
wxThreadEvent evt(wxEVT_THREAD, NP_GUI_EVT_MD5_RESULT);
evt.SetPayload(std::pair<int, std::string>(pid, result));
GetEventHandler()->AddPendingEvent(evt);
}
void NetPlayDialog::AbortMD5()
{
if (m_MD5_dialog != nullptr && !m_MD5_dialog->IsBeingDeleted())
m_MD5_dialog->Destroy();
}
void NetPlayDialog::OnAssignPads(wxCommandEvent&)
{
PadMapDialog pmd(this, netplay_server, netplay_client);

View file

@ -14,12 +14,13 @@
#include "Core/NetPlayServer.h"
class CGameListCtrl;
class MD5Dialog;
class wxButton;
class wxCheckBox;
class wxChoice;
class wxListBox;
class wxString;
class wxStaticText;
class wxString;
class wxTextCtrl;
enum
@ -27,6 +28,9 @@ enum
NP_GUI_EVT_CHANGE_GAME = 45,
NP_GUI_EVT_START_GAME,
NP_GUI_EVT_STOP_GAME,
NP_GUI_EVT_DISPLAY_MD5_DIALOG,
NP_GUI_EVT_MD5_PROGRESS,
NP_GUI_EVT_MD5_RESULT,
};
enum
@ -34,6 +38,14 @@ enum
INITIAL_PAD_BUFFER_SIZE = 5
};
// IDs are UI-dependent here
enum class MD5Target
{
CurrentGame = 1,
OtherGame = 2,
SdCard = 3
};
class NetPlayDialog : public wxFrame, public NetPlayUI
{
public:
@ -52,6 +64,11 @@ public:
void Update() override;
void AppendChat(const std::string& msg) override;
void ShowMD5Dialog(const std::string& file_identifier) override;
void SetMD5Progress(int pid, int progress) override;
void SetMD5Result(int pid, const std::string& result) override;
void AbortMD5() override;
void OnMsgChangeGame(const std::string& filename) override;
void OnMsgStartGame() override;
void OnMsgStopGame() override;
@ -68,6 +85,7 @@ private:
void OnQuit(wxCommandEvent& event);
void OnThread(wxThreadEvent& event);
void OnChangeGame(wxCommandEvent& event);
void OnMD5ComputeRequested(wxCommandEvent& event);
void OnAdjustBuffer(wxCommandEvent& event);
void OnAssignPads(wxCommandEvent& event);
void OnKick(wxCommandEvent& event);
@ -94,6 +112,8 @@ private:
wxStaticText* m_host_label;
wxChoice* m_host_type_choice;
wxButton* m_host_copy_btn;
wxChoice* m_MD5_choice;
MD5Dialog* m_MD5_dialog = nullptr;
bool m_host_copy_btn_is_retry;
bool m_is_hosting;