diff --git a/Source/Core/DolphinWX/CMakeLists.txt b/Source/Core/DolphinWX/CMakeLists.txt index da4e8856cb..5e9ea11c96 100644 --- a/Source/Core/DolphinWX/CMakeLists.txt +++ b/Source/Core/DolphinWX/CMakeLists.txt @@ -32,6 +32,10 @@ set(GUI_SRCS Debugger/RegisterWindow.cpp Debugger/WatchView.cpp Debugger/WatchWindow.cpp + NetPlay/ChangeGameDialog.cpp + NetPlay/NetPlaySetupFrame.cpp + NetPlay/NetWindow.cpp + NetPlay/PadMapDialog.cpp FifoPlayerDlg.cpp Frame.cpp FrameAui.cpp @@ -46,7 +50,6 @@ set(GUI_SRCS LogWindow.cpp Main.cpp MemcardManager.cpp - NetWindow.cpp PatchAddEdit.cpp PostProcessingConfigDiag.cpp SoftwareVideoConfigDialog.cpp diff --git a/Source/Core/DolphinWX/DolphinWX.vcxproj b/Source/Core/DolphinWX/DolphinWX.vcxproj index d1592b7516..f6ecb0ae14 100644 --- a/Source/Core/DolphinWX/DolphinWX.vcxproj +++ b/Source/Core/DolphinWX/DolphinWX.vcxproj @@ -80,6 +80,9 @@ + + + @@ -97,7 +100,7 @@ true - + @@ -115,6 +118,9 @@ + + + @@ -140,6 +146,7 @@ + @@ -152,7 +159,6 @@ - diff --git a/Source/Core/DolphinWX/DolphinWX.vcxproj.filters b/Source/Core/DolphinWX/DolphinWX.vcxproj.filters index 9d71b2f175..54604a1a33 100644 --- a/Source/Core/DolphinWX/DolphinWX.vcxproj.filters +++ b/Source/Core/DolphinWX/DolphinWX.vcxproj.filters @@ -97,15 +97,15 @@ GUI\Debugger + + GUI\NetPlay + GUI\InputConfig GUI\InputConfig - - GUI\NetPlay - GUI\Video @@ -190,6 +190,15 @@ GUI\Config + + GUI\NetPlay + + + GUI\NetPlay + + + GUI\NetPlay + @@ -255,12 +264,12 @@ GUI\Debugger + + GUI\NetPlay + GUI\InputConfig - - GUI\NetPlay - GUI\Video @@ -345,6 +354,15 @@ GUI\Config + + GUI\NetPlay + + + GUI\NetPlay + + + GUI\NetPlay + diff --git a/Source/Core/DolphinWX/Frame.h b/Source/Core/DolphinWX/Frame.h index dff539f7c9..5cd026e05b 100644 --- a/Source/Core/DolphinWX/Frame.h +++ b/Source/Core/DolphinWX/Frame.h @@ -38,7 +38,7 @@ class CCodeWindow; class CLogWindow; class FifoPlayerDlg; class LogConfigWindow; -class NetPlaySetupDiag; +class NetPlaySetupFrame; class TASInputDlg; class wxCheatsWindow; @@ -98,7 +98,7 @@ public: // These have to be public CCodeWindow* g_pCodeWindow; - NetPlaySetupDiag* g_NetPlaySetupDiag; + NetPlaySetupFrame* g_NetPlaySetupDiag; wxCheatsWindow* g_CheatsWindow; TASInputDlg* g_TASInputDlg[8]; diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index 4edb08980f..cf705cbd1d 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -75,7 +75,6 @@ #include "DolphinWX/ISOFile.h" #include "DolphinWX/LogWindow.h" #include "DolphinWX/MemcardManager.h" -#include "DolphinWX/NetWindow.h" #include "DolphinWX/TASInputDlg.h" #include "DolphinWX/WXInputBase.h" #include "DolphinWX/WxUtils.h" @@ -84,6 +83,8 @@ #include "DolphinWX/Debugger/BreakpointWindow.h" #include "DolphinWX/Debugger/CodeWindow.h" #include "DolphinWX/Debugger/WatchWindow.h" +#include "DolphinWX/NetPlay/NetPlaySetupFrame.h" +#include "DolphinWX/NetPlay/NetWindow.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" @@ -1213,7 +1214,9 @@ void CFrame::DoStop() DoRecordingSave(); if (Movie::IsMovieActive()) Movie::EndPlayInput(false); - NetPlay::StopGame(); + + if (NetPlayDialog::GetNetPlayClient()) + NetPlayDialog::GetNetPlayClient()->Stop(); BootManager::Stop(); UpdateGUI(); @@ -1450,10 +1453,10 @@ void CFrame::OnNetPlay(wxCommandEvent& WXUNUSED (event)) { if (!g_NetPlaySetupDiag) { - if (NetPlayDiag::GetInstance() != nullptr) - NetPlayDiag::GetInstance()->Raise(); + if (NetPlayDialog::GetInstance() != nullptr) + NetPlayDialog::GetInstance()->Raise(); else - g_NetPlaySetupDiag = new NetPlaySetupDiag(this, m_GameListCtrl); + g_NetPlaySetupDiag = new NetPlaySetupFrame(this, m_GameListCtrl); } else { diff --git a/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.cpp b/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.cpp new file mode 100644 index 0000000000..6151cf8b98 --- /dev/null +++ b/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.cpp @@ -0,0 +1,37 @@ +// Copyright 2015 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include +#include + +#include "DolphinWX/NetPlay/ChangeGameDialog.h" +#include "DolphinWX/NetPlay/NetWindow.h" + +ChangeGameDialog::ChangeGameDialog(wxWindow* parent, const CGameListCtrl* const game_list, wxString& game_name) + : wxDialog(parent, wxID_ANY, _("Change Game")) + , m_game_name(game_name) +{ + m_game_lbox = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT); + m_game_lbox->Bind(wxEVT_LISTBOX_DCLICK, &ChangeGameDialog::OnPick, this); + + NetPlayDialog::FillWithGameNames(m_game_lbox, *game_list); + + wxButton* const ok_btn = new wxButton(this, wxID_OK, _("Change")); + ok_btn->Bind(wxEVT_BUTTON, &ChangeGameDialog::OnPick, this); + + wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL); + szr->Add(m_game_lbox, 1, wxLEFT | wxRIGHT | wxTOP | wxEXPAND, 5); + szr->Add(ok_btn, 0, wxALL | wxALIGN_RIGHT, 5); + + SetSizerAndFit(szr); + SetFocus(); +} + +void ChangeGameDialog::OnPick(wxCommandEvent& event) +{ + // return the selected game name + m_game_name = m_game_lbox->GetStringSelection(); + EndModal(wxID_OK); +} diff --git a/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.h b/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.h new file mode 100644 index 0000000000..fedfc45f17 --- /dev/null +++ b/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.h @@ -0,0 +1,22 @@ +// Copyright 2015 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include + +class CGameListCtrl; +class wxListBox; + +class ChangeGameDialog final : public wxDialog +{ +public: + ChangeGameDialog(wxWindow* parent, const CGameListCtrl* const game_list, wxString& game_name); + +private: + void OnPick(wxCommandEvent& event); + + wxListBox* m_game_lbox; + wxString& m_game_name; +}; diff --git a/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.cpp b/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.cpp new file mode 100644 index 0000000000..857a082ae4 --- /dev/null +++ b/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.cpp @@ -0,0 +1,390 @@ +// Copyright 2015 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Common/FileUtil.h" +#include "Common/IniFile.h" +#include "Core/NetPlayClient.h" +#include "Core/NetPlayServer.h" +#include "DolphinWX/Frame.h" +#include "DolphinWX/Main.h" +#include "DolphinWX/WxUtils.h" +#include "DolphinWX/NetPlay/NetPlaySetupFrame.h" +#include "DolphinWX/NetPlay/NetWindow.h" + +NetPlaySetupFrame::NetPlaySetupFrame(wxWindow* const parent, const CGameListCtrl* const game_list) + : wxFrame(parent, wxID_ANY, _("Dolphin NetPlay Setup")) + , m_game_list(game_list) +{ + IniFile inifile; + inifile.Load(File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"); + IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); + + wxPanel* const panel = new wxPanel(this); + + // top row + wxBoxSizer* const trav_szr = new wxBoxSizer(wxHORIZONTAL); + + m_direct_traversal = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(75, -1)); + m_direct_traversal->Bind(wxEVT_CHOICE, &NetPlaySetupFrame::OnChoice, this); + m_direct_traversal->Append(_("Direct")); + m_direct_traversal->Append(_("Traversal")); + + std::string travChoice; + netplay_section.Get("TraversalChoice", &travChoice, "direct"); + + if (travChoice == "traversal") + { + m_direct_traversal->Select(1); + } + else + { + m_direct_traversal->Select(0); + } + + trav_szr->Add(m_direct_traversal, 0, wxRIGHT); + + wxBoxSizer* const nick_szr = new wxBoxSizer(wxHORIZONTAL); + wxStaticText* const nick_lbl = new wxStaticText(panel, wxID_ANY, _("Nickname :")); + std::string nickname; + netplay_section.Get("Nickname", &nickname, "Player"); + m_nickname_text = new wxTextCtrl(panel, wxID_ANY, StrToWxStr(nickname)); + nick_szr->Add(nick_lbl, 0, wxCENTER); + nick_szr->Add(m_nickname_text, 0, wxALL, 5); + + std::string centralServer; + netplay_section.Get("TraversalServer", ¢ralServer, ""); + m_traversal_server_lbl = new wxStaticText(panel, wxID_ANY, _("Traversal:")); + m_traversal_server = new wxTextCtrl(panel, wxID_ANY, StrToWxStr(centralServer)); + nick_szr->Add(m_traversal_server_lbl, 0, wxCENTER); + nick_szr->Add(m_traversal_server, 0, wxALL, 5); + + std::string centralPort; + netplay_section.Get("TraversalPort", ¢ralPort, ""); + m_traversal_port_lbl = new wxStaticText(panel, wxID_ANY, _("Port:")); + m_traversal_port = new wxTextCtrl(panel, wxID_ANY, StrToWxStr(centralPort)); + nick_szr->Add(m_traversal_port_lbl, 0, wxCENTER); + nick_szr->Add(m_traversal_port, 0, wxALL, 5); + + // tabs + wxNotebook* const notebook = new wxNotebook(panel, wxID_ANY); + wxPanel* const connect_tab = new wxPanel(notebook, wxID_ANY); + notebook->AddPage(connect_tab, _("Connect")); + wxPanel* const host_tab = new wxPanel(notebook, wxID_ANY); + notebook->AddPage(host_tab, _("Host")); + + // connect tab + { + m_ip_lbl = new wxStaticText(connect_tab, wxID_ANY, _("Host Code :")); + + std::string address; + netplay_section.Get("HostCode", &address, "00000000"); + m_connect_ip_text = new wxTextCtrl(connect_tab, wxID_ANY, StrToWxStr(address)); + + m_client_port_lbl = new wxStaticText(connect_tab, wxID_ANY, _("Port :")); + + // string? w/e + std::string port; + netplay_section.Get("ConnectPort", &port, "2626"); + m_connect_port_text = new wxTextCtrl(connect_tab, wxID_ANY, StrToWxStr(port)); + + wxButton* const connect_btn = new wxButton(connect_tab, wxID_ANY, _("Connect")); + connect_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnJoin, this); + + wxStaticText* const alert_lbl = new wxStaticText(connect_tab, wxID_ANY, + _("ALERT:\n\n" + "Netplay will only work with the following settings:\n" + " - DSP Emulator Engine Must be the same on all computers!\n" + " - DSP on Dedicated Thread [OFF]\n" + " - Manually set the extensions for each Wiimote\n" + "\n" + "All players should use the same Dolphin version and settings.\n" + "All memory cards must be identical between players or disabled.\n" + "Wiimote support is probably terrible. Don't use it.\n" + "\n" + "If connecting directly host must have the chosen UDP port open/forwarded!\n")); + + wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL); + + top_szr->Add(m_ip_lbl, 0, wxCENTER | wxRIGHT, 5); + top_szr->Add(m_connect_ip_text, 3); + top_szr->Add(m_client_port_lbl, 0, wxCENTER | wxRIGHT | wxLEFT, 5); + top_szr->Add(m_connect_port_text, 1); + + wxBoxSizer* const con_szr = new wxBoxSizer(wxVERTICAL); + con_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5); + con_szr->AddStretchSpacer(1); + con_szr->Add(alert_lbl, 0, wxLEFT | wxRIGHT | wxEXPAND, 5); + con_szr->AddStretchSpacer(1); + con_szr->Add(connect_btn, 0, wxALL | wxALIGN_RIGHT, 5); + + connect_tab->SetSizerAndFit(con_szr); + } + + // host tab + { + m_host_port_lbl = new wxStaticText(host_tab, wxID_ANY, _("Port :")); + + // string? w/e + std::string port; + netplay_section.Get("HostPort", &port, "2626"); + m_host_port_text = new wxTextCtrl(host_tab, wxID_ANY, StrToWxStr(port)); + + wxButton* const host_btn = new wxButton(host_tab, wxID_ANY, _("Host")); + host_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnHost, this); + + m_game_lbox = new wxListBox(host_tab, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT); + m_game_lbox->Bind(wxEVT_LISTBOX_DCLICK, &NetPlaySetupFrame::OnHost, this); + + NetPlayDialog::FillWithGameNames(m_game_lbox, *game_list); + + wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL); + top_szr->Add(m_host_port_lbl, 0, wxCENTER | wxRIGHT, 5); + top_szr->Add(m_host_port_text, 0); +#ifdef USE_UPNP + m_upnp_chk = new wxCheckBox(host_tab, wxID_ANY, _("Forward port (UPnP)")); + top_szr->Add(m_upnp_chk, 0, wxALL | wxALIGN_RIGHT, 5); +#endif + + wxBoxSizer* const host_szr = new wxBoxSizer(wxVERTICAL); + host_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5); + host_szr->Add(m_game_lbox, 1, wxLEFT | wxRIGHT | wxEXPAND, 5); + host_szr->Add(host_btn, 0, wxALL | wxALIGN_RIGHT, 5); + + host_tab->SetSizerAndFit(host_szr); + } + + // bottom row + wxButton* const quit_btn = new wxButton(panel, wxID_ANY, _("Quit")); + quit_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnQuit, this); + + // main sizer + wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL); + main_szr->Add(trav_szr, 0, wxALL | wxALIGN_LEFT); + main_szr->Add(nick_szr, 0, wxALL | wxALIGN_LEFT, 5); + main_szr->Add(notebook, 1, wxLEFT | wxRIGHT | wxEXPAND, 5); + main_szr->Add(quit_btn, 0, wxALL | wxALIGN_RIGHT, 5); + + panel->SetSizerAndFit(main_szr); + + //wxBoxSizer* const diag_szr = new wxBoxSizer(wxVERTICAL); + //diag_szr->Add(panel, 1, wxEXPAND); + //SetSizerAndFit(diag_szr); + + main_szr->SetSizeHints(this); + + Center(); + Show(); + + // Needs to be done last or it set up the spacing on the page correctly + wxCommandEvent ev; + OnChoice(ev); +} + +NetPlaySetupFrame::~NetPlaySetupFrame() +{ + IniFile inifile; + const std::string dolphin_ini = File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"; + inifile.Load(dolphin_ini); + IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); + + std::string travChoice = "traversal"; + if (m_direct_traversal->GetSelection() == 1) + { + netplay_section.Set("TraversalChoice", travChoice); + } + else + { + travChoice = "direct"; + netplay_section.Set("TraversalChoice", travChoice); + } + + netplay_section.Set("Nickname", WxStrToStr(m_nickname_text->GetValue())); + netplay_section.Set("TraversalServer", WxStrToStr(m_traversal_server->GetValue())); + netplay_section.Set("TraversalPort", WxStrToStr(m_traversal_port->GetValue())); + + if (m_direct_traversal->GetCurrentSelection() == 0) + { + netplay_section.Set("Address", WxStrToStr(m_connect_ip_text->GetValue())); + } + else + { + netplay_section.Set("HostCode", WxStrToStr(m_connect_ip_text->GetValue())); + } + netplay_section.Set("ConnectPort", WxStrToStr(m_connect_port_text->GetValue())); + netplay_section.Set("HostPort", WxStrToStr(m_host_port_text->GetValue())); + + inifile.Save(dolphin_ini); + main_frame->g_NetPlaySetupDiag = nullptr; +} + +void NetPlaySetupFrame::MakeNetPlayDiag(int port, const std::string &game, bool is_hosting) +{ + NetPlayDialog*& npd = NetPlayDialog::GetInstance(); + NetPlayClient*& netplay_client = NetPlayDialog::GetNetPlayClient(); + + std::string ip; + npd = new NetPlayDialog(m_parent, m_game_list, game, is_hosting); + if (is_hosting) + ip = "127.0.0.1"; + else + ip = WxStrToStr(m_connect_ip_text->GetValue()); + + bool trav; + if (!is_hosting && m_direct_traversal->GetCurrentSelection() == 1) + trav = true; + else + trav = false; + + unsigned long centralPort = 0; + m_traversal_port->GetValue().ToULong(¢ralPort); + netplay_client = new NetPlayClient(ip, (u16)port, npd, WxStrToStr(m_nickname_text->GetValue()), trav, WxStrToStr(m_traversal_server->GetValue()), (u16)centralPort); + if (netplay_client->is_connected) + { + npd->Show(); + Destroy(); + } + else + { + npd->Destroy(); + } +} + +void NetPlaySetupFrame::OnHost(wxCommandEvent&) +{ + NetPlayDialog*& npd = NetPlayDialog::GetInstance(); + NetPlayServer*& netplay_server = NetPlayDialog::GetNetPlayServer(); + + if (npd) + { + WxUtils::ShowErrorDialog(_("A NetPlay window is already open!")); + return; + } + + if (m_game_lbox->GetSelection() == wxNOT_FOUND) + { + WxUtils::ShowErrorDialog(_("You must choose a game!")); + return; + } + + std::string game(WxStrToStr(m_game_lbox->GetStringSelection())); + + bool trav; + if (m_direct_traversal->GetCurrentSelection() == 1) + trav = true; + else + trav = false; + + unsigned long port = 0; + m_host_port_text->GetValue().ToULong(&port); + + unsigned long centralPort = 0; + m_traversal_port->GetValue().ToULong(¢ralPort); + netplay_server = new NetPlayServer((u16)port, trav, WxStrToStr(m_traversal_server->GetValue()), (u16)centralPort); + if (netplay_server->is_connected) + { + netplay_server->ChangeGame(game); + netplay_server->AdjustPadBufferSize(INITIAL_PAD_BUFFER_SIZE); +#ifdef USE_UPNP + if (m_upnp_chk->GetValue()) + netplay_server->TryPortmapping(port); +#endif + MakeNetPlayDiag(netplay_server->GetPort(), game, true); + netplay_server->SetNetPlayUI(NetPlayDialog::GetInstance()); + } + else + { + WxUtils::ShowErrorDialog(_("Failed to listen. Is another instance of the NetPlay server running?")); + } +} + +void NetPlaySetupFrame::OnJoin(wxCommandEvent&) +{ + NetPlayDialog*& npd = NetPlayDialog::GetInstance(); + if (npd) + { + WxUtils::ShowErrorDialog(_("A NetPlay window is already open!")); + return; + } + + unsigned long port = 0; + m_connect_port_text->GetValue().ToULong(&port); + MakeNetPlayDiag(port, "", false); +} + +void NetPlaySetupFrame::OnChoice(wxCommandEvent& event) +{ + int sel = m_direct_traversal->GetSelection(); + IniFile inifile; + inifile.Load(File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"); + IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); + + if (sel == 1) + { + m_traversal_server_lbl->Show(); + m_traversal_server->Show(); + + m_traversal_port_lbl->Show(); + m_traversal_port->Show(); + + //Traversal + //client tab + { + m_ip_lbl->SetLabelText("Host Code: "); + + std::string address; + netplay_section.Get("HostCode", &address, "00000000"); + m_connect_ip_text->SetLabelText(address); + + m_client_port_lbl->Hide(); + m_connect_port_text->Hide(); + } + + //server tab + { + m_host_port_lbl->Hide(); + m_host_port_text->Hide(); + m_upnp_chk->Hide(); + } + } + else + { + m_traversal_server_lbl->Hide(); + m_traversal_server->Hide(); + + m_traversal_port_lbl->Hide(); + m_traversal_port->Hide(); + // Direct + // Client tab + { + m_ip_lbl->SetLabelText("IP Address :"); + + std::string address; + netplay_section.Get("Address", &address, "127.0.0.1"); + m_connect_ip_text->SetLabelText(address); + + m_client_port_lbl->Show(); + m_connect_port_text->Show(); + } + + // Server tab + m_host_port_lbl->Show(); + m_host_port_text->Show(); + m_upnp_chk->Show(); + } +} + +void NetPlaySetupFrame::OnQuit(wxCommandEvent&) +{ + Destroy(); +} diff --git a/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.h b/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.h new file mode 100644 index 0000000000..15cddb1841 --- /dev/null +++ b/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.h @@ -0,0 +1,50 @@ +// Copyright 2015 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +class CGameListCtrl; +class wxCheckBox; +class wxChoice; +class wxListBox; +class wxStaticText; +class wxTextCtrl; + +class NetPlaySetupFrame final : public wxFrame +{ +public: + NetPlaySetupFrame(wxWindow* const parent, const CGameListCtrl* const game_list); + ~NetPlaySetupFrame(); + +private: + void OnJoin(wxCommandEvent& event); + void OnHost(wxCommandEvent& event); + void OnQuit(wxCommandEvent& event); + void OnChoice(wxCommandEvent& event); + + void MakeNetPlayDiag(int port, const std::string& game, bool is_hosting); + + wxStaticText* m_ip_lbl; + wxStaticText* m_client_port_lbl; + wxTextCtrl* m_nickname_text; + wxStaticText* m_host_port_lbl; + wxTextCtrl* m_host_port_text; + wxTextCtrl* m_connect_port_text; + wxTextCtrl* m_connect_ip_text; + wxChoice* m_direct_traversal; + wxStaticText* m_traversal_server_lbl; + wxTextCtrl* m_traversal_server; + wxStaticText* m_traversal_port_lbl; + wxTextCtrl* m_traversal_port; + + wxListBox* m_game_lbox; +#ifdef USE_UPNP + wxCheckBox* m_upnp_chk; +#endif + + const CGameListCtrl* const m_game_list; +}; diff --git a/Source/Core/DolphinWX/NetPlay/NetWindow.cpp b/Source/Core/DolphinWX/NetPlay/NetWindow.cpp new file mode 100644 index 0000000000..febb30e570 --- /dev/null +++ b/Source/Core/DolphinWX/NetPlay/NetWindow.cpp @@ -0,0 +1,591 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Common/CommonTypes.h" +#include "Common/FifoQueue.h" +#include "Common/FileUtil.h" +#include "Common/IniFile.h" + +#include "Core/ConfigManager.h" +#include "Core/CoreParameter.h" +#include "Core/NetPlayClient.h" +#include "Core/NetPlayProto.h" +#include "Core/NetPlayServer.h" +#include "Core/HW/EXI_Device.h" + +#include "DolphinWX/Frame.h" +#include "DolphinWX/GameListCtrl.h" +#include "DolphinWX/ISOFile.h" +#include "DolphinWX/Main.h" +#include "DolphinWX/WxUtils.h" +#include "DolphinWX/NetPlay/ChangeGameDialog.h" +#include "DolphinWX/NetPlay/NetWindow.h" +#include "DolphinWX/NetPlay/PadMapDialog.h" + +NetPlayServer* NetPlayDialog::netplay_server = nullptr; +NetPlayClient* NetPlayDialog::netplay_client = nullptr; +NetPlayDialog *NetPlayDialog::npd = nullptr; + +static wxString FailureReasonStringForHostLabel(int reason) +{ + switch (reason) + { + case TraversalClient::BadHost: + return _("(Error: Bad host)"); + case TraversalClient::VersionTooOld: + return _("(Error: Dolphin too old)"); + case TraversalClient::ServerForgotAboutUs: + return _("(Error: Disconnected)"); + case TraversalClient::SocketSendError: + return _("(Error: Socket)"); + case TraversalClient::ResendTimeout: + return _("(Error: Timeout)"); + default: + return _("(Error: Unknown)"); + } +} + +static std::string BuildGameName(const GameListItem& game) +{ + // Lang needs to be consistent + auto const lang = 0; + + std::string name(game.GetName(lang)); + + if (game.GetRevision() != 0) + return name + " (" + game.GetUniqueID() + ", Revision " + std::to_string((long long)game.GetRevision()) + ")"; + else + return name + " (" + game.GetUniqueID() + ")"; +} + +void NetPlayDialog::FillWithGameNames(wxListBox* game_lbox, const CGameListCtrl& game_list) +{ + for (u32 i = 0; auto game = game_list.GetISO(i); ++i) + game_lbox->Append(StrToWxStr(BuildGameName(*game))); +} + +NetPlayDialog::NetPlayDialog(wxWindow* const parent, const CGameListCtrl* const game_list, + const std::string& game, const bool is_hosting) + : wxFrame(parent, wxID_ANY, _("Dolphin NetPlay")) + , m_selected_game(game) + , m_start_btn(nullptr) + , m_host_label(nullptr) + , m_host_type_choice(nullptr) + , m_host_copy_btn(nullptr) + , m_host_copy_btn_is_retry(false) + , m_is_hosting(is_hosting) + , m_game_list(game_list) +{ + Bind(wxEVT_THREAD, &NetPlayDialog::OnThread, this); + + wxPanel* const panel = new wxPanel(this); + + // top crap + m_game_btn = new wxButton(panel, wxID_ANY, + StrToWxStr(m_selected_game).Prepend(_(" Game : ")), + wxDefaultPosition, wxDefaultSize, wxBU_LEFT); + + if (m_is_hosting) + m_game_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnChangeGame, this); + else + m_game_btn->Disable(); + + // middle crap + + // chat + m_chat_text = new wxTextCtrl(panel, wxID_ANY, wxEmptyString + , wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxTE_MULTILINE); + + m_chat_msg_text = new wxTextCtrl(panel, wxID_ANY, wxEmptyString + , wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); + m_chat_msg_text->Bind(wxEVT_TEXT_ENTER, &NetPlayDialog::OnChat, this); + m_chat_msg_text->SetMaxLength(2000); + + wxButton* const chat_msg_btn = new wxButton(panel, wxID_ANY, _("Send")); + chat_msg_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnChat, this); + + wxBoxSizer* const chat_msg_szr = new wxBoxSizer(wxHORIZONTAL); + chat_msg_szr->Add(m_chat_msg_text, 1); + chat_msg_szr->Add(chat_msg_btn, 0); + + wxStaticBoxSizer* const chat_szr = new wxStaticBoxSizer(wxVERTICAL, panel, _("Chat")); + chat_szr->Add(m_chat_text, 1, wxEXPAND); + chat_szr->Add(chat_msg_szr, 0, wxEXPAND | wxTOP, 5); + + m_player_lbox = new wxListBox(panel, wxID_ANY, wxDefaultPosition, wxSize(256, -1)); + + wxStaticBoxSizer* const player_szr = new wxStaticBoxSizer(wxVERTICAL, panel, _("Players")); + + // player list + if (m_is_hosting && g_TraversalClient) + { + wxBoxSizer* const host_szr = new wxBoxSizer(wxHORIZONTAL); + m_host_type_choice = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(60, -1)); + m_host_type_choice->Bind(wxEVT_COMMAND_CHOICE_SELECTED, &NetPlayDialog::OnChoice, this); + m_host_type_choice->Append(_("ID:")); + host_szr->Add(m_host_type_choice); + + m_host_label = new wxStaticText(panel, wxID_ANY, "555.555.555.555:55555", wxDefaultPosition, wxDefaultSize, wxST_NO_AUTORESIZE | wxALIGN_LEFT); + // Update() should fix this immediately. + m_host_label->SetLabel(_("")); + host_szr->Add(m_host_label, 1, wxLEFT | wxCENTER, 5); + + m_host_copy_btn = new wxButton(panel, wxID_ANY, _("Copy")); + m_host_copy_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &NetPlayDialog::OnCopyIP, this); + m_host_copy_btn->Disable(); + host_szr->Add(m_host_copy_btn, 0, wxLEFT | wxCENTER, 5); + player_szr->Add(host_szr, 0, wxEXPAND | wxBOTTOM, 5); + m_host_type_choice->Select(0); + + UpdateHostLabel(); + } + + player_szr->Add(m_player_lbox, 1, wxEXPAND); + + if (m_is_hosting) + { + m_player_lbox->Bind(wxEVT_LISTBOX, &NetPlayDialog::OnPlayerSelect, this); + m_kick_btn = new wxButton(panel, wxID_ANY, _("Kick Player")); + m_kick_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnKick, this); + player_szr->Add(m_kick_btn, 0, wxEXPAND | wxTOP, 5); + m_kick_btn->Disable(); + + m_player_config_btn = new wxButton(panel, wxID_ANY, _("Configure Pads")); + m_player_config_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnConfigPads, this); + player_szr->Add(m_player_config_btn, 0, wxEXPAND | wxTOP, 5); + } + + wxBoxSizer* const mid_szr = new wxBoxSizer(wxHORIZONTAL); + mid_szr->Add(chat_szr, 1, wxEXPAND | wxRIGHT, 5); + mid_szr->Add(player_szr, 0, wxEXPAND); + + // bottom crap + wxButton* const quit_btn = new wxButton(panel, wxID_ANY, _("Quit")); + quit_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnQuit, this); + + wxBoxSizer* const bottom_szr = new wxBoxSizer(wxHORIZONTAL); + if (is_hosting) + { + m_start_btn = new wxButton(panel, wxID_ANY, _("Start")); + m_start_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnStart, this); + bottom_szr->Add(m_start_btn); + + bottom_szr->Add(new wxStaticText(panel, wxID_ANY, _("Buffer:")), 0, wxLEFT | wxCENTER, 5); + wxSpinCtrl* const padbuf_spin = new wxSpinCtrl(panel, wxID_ANY, std::to_string(INITIAL_PAD_BUFFER_SIZE) + , wxDefaultPosition, wxSize(64, -1), wxSP_ARROW_KEYS, 0, 200, INITIAL_PAD_BUFFER_SIZE); + padbuf_spin->Bind(wxEVT_SPINCTRL, &NetPlayDialog::OnAdjustBuffer, this); + bottom_szr->Add(padbuf_spin, 0, wxCENTER); + + m_memcard_write = new wxCheckBox(panel, wxID_ANY, _("Write memcards (GC)")); + bottom_szr->Add(m_memcard_write, 0, wxCENTER); + } + + m_record_chkbox = new wxCheckBox(panel, wxID_ANY, _("Record input")); + bottom_szr->Add(m_record_chkbox, 0, wxCENTER); + + bottom_szr->AddStretchSpacer(1); + bottom_szr->Add(quit_btn); + + // main sizer + wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL); + main_szr->Add(m_game_btn, 0, wxEXPAND | wxALL, 5); + main_szr->Add(mid_szr, 1, wxEXPAND | wxLEFT | wxRIGHT, 5); + main_szr->Add(bottom_szr, 0, wxEXPAND | wxALL, 5); + + panel->SetSizerAndFit(main_szr); + + main_szr->SetSizeHints(this); + SetSize(512, 512 - 128); + + Center(); +} + +NetPlayDialog::~NetPlayDialog() +{ + if (netplay_client) + { + delete netplay_client; + netplay_client = nullptr; + } + if (netplay_server) + { + delete netplay_server; + netplay_server = nullptr; + } + npd = nullptr; +} + +void NetPlayDialog::OnChat(wxCommandEvent&) +{ + wxString text = m_chat_msg_text->GetValue(); + + if (!text.empty()) + { + netplay_client->SendChatMessage(WxStrToStr(text)); + m_chat_text->AppendText(text.Prepend(" >> ").Append('\n')); + m_chat_msg_text->Clear(); + } +} + +void NetPlayDialog::GetNetSettings(NetSettings &settings) +{ + SConfig &instance = SConfig::GetInstance(); + settings.m_CPUthread = instance.m_LocalCoreStartupParameter.bCPUThread; + settings.m_CPUcore = instance.m_LocalCoreStartupParameter.iCPUCore; + settings.m_DSPHLE = instance.m_LocalCoreStartupParameter.bDSPHLE; + settings.m_DSPEnableJIT = instance.m_DSPEnableJIT; + settings.m_WriteToMemcard = m_memcard_write->GetValue(); + settings.m_OCEnable = instance.m_OCEnable; + settings.m_OCFactor = instance.m_OCFactor; + settings.m_EXIDevice[0] = instance.m_EXIDevice[0]; + settings.m_EXIDevice[1] = instance.m_EXIDevice[1]; +} + +std::string NetPlayDialog::FindGame() +{ + // find path for selected game, sloppy.. + for (u32 i = 0; auto game = m_game_list->GetISO(i); ++i) + if (m_selected_game == BuildGameName(*game)) + return game->GetFileName(); + + WxUtils::ShowErrorDialog(_("Game not found!")); + return ""; +} + +void NetPlayDialog::OnStart(wxCommandEvent&) +{ + NetSettings settings; + GetNetSettings(settings); + netplay_server->SetNetSettings(settings); + netplay_server->StartGame(); +} + +void NetPlayDialog::BootGame(const std::string& filename) +{ + main_frame->BootGame(filename); +} + +void NetPlayDialog::StopGame() +{ + main_frame->DoStop(); +} + +// NetPlayUI methods called from ---NETPLAY--- thread +void NetPlayDialog::Update() +{ + wxThreadEvent evt(wxEVT_THREAD, 1); + GetEventHandler()->AddPendingEvent(evt); +} + +void NetPlayDialog::AppendChat(const std::string& msg) +{ + chat_msgs.Push(msg); + // silly + Update(); +} + +void NetPlayDialog::OnMsgChangeGame(const std::string& filename) +{ + wxThreadEvent* evt = new wxThreadEvent(wxEVT_THREAD, NP_GUI_EVT_CHANGE_GAME); + evt->SetString(StrToWxStr(filename)); + GetEventHandler()->QueueEvent(evt); +} + +void NetPlayDialog::OnMsgStartGame() +{ + wxThreadEvent evt(wxEVT_THREAD, NP_GUI_EVT_START_GAME); + GetEventHandler()->AddPendingEvent(evt); + if (m_is_hosting) + { + m_start_btn->Disable(); + m_memcard_write->Disable(); + m_game_btn->Disable(); + m_player_config_btn->Disable(); + } + + m_record_chkbox->Disable(); +} + +void NetPlayDialog::OnMsgStopGame() +{ + wxThreadEvent evt(wxEVT_THREAD, NP_GUI_EVT_STOP_GAME); + GetEventHandler()->AddPendingEvent(evt); + if (m_is_hosting) + { + m_start_btn->Enable(); + m_memcard_write->Enable(); + m_game_btn->Enable(); + m_player_config_btn->Enable(); + } + m_record_chkbox->Enable(); +} + +void NetPlayDialog::OnAdjustBuffer(wxCommandEvent& event) +{ + const int val = ((wxSpinCtrl*)event.GetEventObject())->GetValue(); + netplay_server->AdjustPadBufferSize(val); + + std::ostringstream ss; + ss << "< Pad Buffer: " << val << " >"; + netplay_client->SendChatMessage(ss.str()); + m_chat_text->AppendText(StrToWxStr(ss.str()).Append('\n')); +} + +void NetPlayDialog::OnQuit(wxCommandEvent&) +{ + Destroy(); +} + +// update gui +void NetPlayDialog::OnThread(wxThreadEvent& event) +{ + if (m_is_hosting && m_host_label && g_TraversalClient) + { + UpdateHostLabel(); + } + + // player list + m_playerids.clear(); + std::string tmps; + netplay_client->GetPlayerList(tmps, m_playerids); + + wxString selection; + if (m_player_lbox->GetSelection() != wxNOT_FOUND) + selection = m_player_lbox->GetString(m_player_lbox->GetSelection()); + + m_player_lbox->Clear(); + std::istringstream ss(tmps); + while (std::getline(ss, tmps)) + m_player_lbox->Append(StrToWxStr(tmps)); + + // remove ping from selection string, in case it has changed + selection.erase(selection.find_last_of("|") + 1); + + if (!selection.empty()) + { + for (unsigned int i = 0; i < m_player_lbox->GetCount(); ++i) + { + if (selection == m_player_lbox->GetString(i).Mid(0, selection.length())) + { + m_player_lbox->SetSelection(i); + break; + } + } + } + + // flash window in taskbar when someone joins if window isn't active + static u8 numPlayers = 1; + bool focus = (wxWindow::FindFocus() == this || (wxWindow::FindFocus() != nullptr && wxWindow::FindFocus()->GetParent() == this) || + (wxWindow::FindFocus() != nullptr && wxWindow::FindFocus()->GetParent() != nullptr + && wxWindow::FindFocus()->GetParent()->GetParent() == this)); + if (netplay_server != nullptr && numPlayers < m_playerids.size() && !focus) + { + RequestUserAttention(); + } + numPlayers = m_playerids.size(); + + switch (event.GetId()) + { + case NP_GUI_EVT_CHANGE_GAME: + // update selected game :/ + { + m_selected_game.assign(WxStrToStr(event.GetString())); + + wxString button_label = event.GetString(); + m_game_btn->SetLabel(button_label.Prepend(_(" Game : "))); + } + break; + case NP_GUI_EVT_START_GAME: + // client start game :/ + { + netplay_client->StartGame(FindGame()); + } + break; + case NP_GUI_EVT_STOP_GAME: + // client stop game + { + netplay_client->StopGame(); + } + break; + } + + // chat messages + while (chat_msgs.Size()) + { + std::string s; + chat_msgs.Pop(s); + //PanicAlert("message: %s", s.c_str()); + m_chat_text->AppendText(StrToWxStr(s).Append('\n')); + } +} + +void NetPlayDialog::OnChangeGame(wxCommandEvent&) +{ + wxString game_name; + + ChangeGameDialog cgd(this, m_game_list, game_name); + cgd.ShowModal(); + + if (game_name.length()) + { + m_selected_game = WxStrToStr(game_name); + netplay_server->ChangeGame(m_selected_game); + m_game_btn->SetLabel(game_name.Prepend(_(" Game : "))); + } +} + +void NetPlayDialog::OnConfigPads(wxCommandEvent&) +{ + PadMapping mapping[4]; + PadMapping wiimotemapping[4]; + std::vector player_list; + + netplay_server->GetPadMapping(mapping); + netplay_server->GetWiimoteMapping(wiimotemapping); + netplay_client->GetPlayers(player_list); + + PadMapDialog pmd(this, mapping, wiimotemapping, player_list); + pmd.ShowModal(); + + netplay_server->SetPadMapping(mapping); + netplay_server->SetWiimoteMapping(wiimotemapping); +} + +void NetPlayDialog::OnKick(wxCommandEvent&) +{ + wxString selection = m_player_lbox->GetStringSelection(); + unsigned long player = 0; + selection.Mid(selection.find_last_of("[") + 1, selection.find_last_of("]")).ToULong(&player); + + netplay_server->KickPlayer((u8)player); + + m_player_lbox->SetSelection(wxNOT_FOUND); + wxCommandEvent event; + OnPlayerSelect(event); +} + +void NetPlayDialog::OnPlayerSelect(wxCommandEvent&) +{ + if (m_player_lbox->GetSelection() > 0) + m_kick_btn->Enable(); + else + m_kick_btn->Disable(); +} + +bool NetPlayDialog::IsRecording() +{ + return m_record_chkbox->GetValue(); +} + + +void NetPlayDialog::OnCopyIP(wxCommandEvent&) +{ + if (m_host_copy_btn_is_retry) + { + g_TraversalClient->ReconnectToServer(); + Update(); + } + else + { + if (wxTheClipboard->Open()) + { + wxTheClipboard->SetData(new wxTextDataObject(m_host_label->GetLabel())); + wxTheClipboard->Close(); + } + } +} + +void NetPlayDialog::OnChoice(wxCommandEvent& event) +{ + UpdateHostLabel(); +} + + +void NetPlayDialog::UpdateHostLabel() +{ + wxString label = _(" (internal IP)"); + auto DeLabel = [=](wxString str) { + if (str == _("Localhost")) + return std::string("!local!"); + return WxStrToStr(str.Left(str.Len() - label.Len())); + }; + auto EnLabel = [=](std::string str) -> wxString { + if (str == "!local!") + return _("Localhost"); + return StrToWxStr(str) + label; + }; + int sel = m_host_type_choice->GetSelection(); + if (sel == 0) + { + // the traversal ID + switch (g_TraversalClient->m_State) + { + case TraversalClient::Connecting: + m_host_label->SetForegroundColour(*wxLIGHT_GREY); + m_host_label->SetLabel("..."); + m_host_copy_btn->SetLabel(_("Copy")); + m_host_copy_btn->Disable(); + break; + case TraversalClient::Connected: + m_host_label->SetForegroundColour(*wxBLACK); + m_host_label->SetLabel(wxString(g_TraversalClient->m_HostId.data(), g_TraversalClient->m_HostId.size())); + m_host_copy_btn->SetLabel(_("Copy")); + m_host_copy_btn->Enable(); + m_host_copy_btn_is_retry = false; + break; + case TraversalClient::Failure: + m_host_label->SetForegroundColour(*wxBLACK); + m_host_label->SetLabel(FailureReasonStringForHostLabel(g_TraversalClient->m_FailureReason)); + m_host_copy_btn->SetLabel(_("Retry")); + m_host_copy_btn->Enable(); + m_host_copy_btn_is_retry = true; + break; + } + } + else if (sel != wxNOT_FOUND) // wxNOT_FOUND shouldn't generally happen + { + m_host_label->SetForegroundColour(*wxBLACK); + m_host_label->SetLabel(netplay_server->GetInterfaceHost(DeLabel(m_host_type_choice->GetString(sel)))); + m_host_copy_btn->SetLabel(_("Copy")); + m_host_copy_btn->Enable(); + m_host_copy_btn_is_retry = false; + } + + auto set = netplay_server->GetInterfaceSet(); + for (const std::string& iface : set) + { + wxString wxIface = EnLabel(iface); + if (m_host_type_choice->FindString(wxIface) == wxNOT_FOUND) + m_host_type_choice->Append(wxIface); + } + for (unsigned i = 1, count = m_host_type_choice->GetCount(); i != count; i++) + { + if (set.find(DeLabel(m_host_type_choice->GetString(i))) == set.end()) + { + m_host_type_choice->Delete(i); + i--; + count--; + } + } +} diff --git a/Source/Core/DolphinWX/NetWindow.h b/Source/Core/DolphinWX/NetPlay/NetWindow.h similarity index 51% rename from Source/Core/DolphinWX/NetWindow.h rename to Source/Core/DolphinWX/NetPlay/NetWindow.h index a883bf9692..d1ab7ad90a 100644 --- a/Source/Core/DolphinWX/NetWindow.h +++ b/Source/Core/DolphinWX/NetPlay/NetWindow.h @@ -6,13 +6,12 @@ #include #include -#include -#include #include #include "Common/FifoQueue.h" #include "Core/NetPlayClient.h" #include "Core/NetPlayProto.h" +#include "Core/NetPlayServer.h" class CGameListCtrl; class wxButton; @@ -20,8 +19,8 @@ class wxCheckBox; class wxChoice; class wxListBox; class wxString; +class wxStaticText; class wxTextCtrl; -class wxWindow; enum { @@ -30,47 +29,17 @@ enum NP_GUI_EVT_STOP_GAME, }; -class NetPlaySetupDiag : public wxFrame +enum { -public: - NetPlaySetupDiag(wxWindow* const parent, const CGameListCtrl* const game_list); - ~NetPlaySetupDiag(); -private: - void OnJoin(wxCommandEvent& event); - void OnHost(wxCommandEvent& event); - void OnQuit(wxCommandEvent& event); - - void MakeNetPlayDiag(int port, const std::string &game, bool is_hosting); - - void OnChoice(wxCommandEvent& event); - - wxStaticText* m_ip_lbl; - wxStaticText* m_client_port_lbl; - wxTextCtrl* m_nickname_text; - wxStaticText* m_host_port_lbl; - wxTextCtrl* m_host_port_text; - wxTextCtrl* m_connect_port_text; - wxTextCtrl* m_connect_ip_text; - wxChoice* m_direct_traversal; - wxStaticText* m_traversal_server_lbl; - wxTextCtrl* m_traversal_server; - wxStaticText* m_traversal_port_lbl; - wxTextCtrl* m_traversal_port; - - wxListBox* m_game_lbox; -#ifdef USE_UPNP - wxCheckBox* m_upnp_chk; -#endif - - const CGameListCtrl* const m_game_list; + INITIAL_PAD_BUFFER_SIZE = 5 }; -class NetPlayDiag : public wxFrame, public NetPlayUI +class NetPlayDialog : public wxFrame, public NetPlayUI { public: - NetPlayDiag(wxWindow* const parent, const CGameListCtrl* const game_list + NetPlayDialog(wxWindow* parent, const CGameListCtrl* const game_list , const std::string& game, const bool is_hosting = false); - ~NetPlayDiag(); + ~NetPlayDialog(); Common::FifoQueue chat_msgs; @@ -87,7 +56,10 @@ public: void OnMsgStartGame() override; void OnMsgStopGame() override; - static NetPlayDiag *&GetInstance() { return npd; }; + static NetPlayDialog*& GetInstance() { return npd; } + static NetPlayClient*& GetNetPlayClient() { return netplay_client; } + static NetPlayServer*& GetNetPlayServer() { return netplay_server; } + static void FillWithGameNames(wxListBox* game_lbox, const CGameListCtrl& game_list); bool IsRecording() override; @@ -100,7 +72,7 @@ private: void OnConfigPads(wxCommandEvent& event); void OnKick(wxCommandEvent& event); void OnPlayerSelect(wxCommandEvent& event); - void GetNetSettings(NetSettings &settings); + void GetNetSettings(NetSettings& settings); std::string FindGame(); void OnCopyIP(wxCommandEvent&); @@ -128,36 +100,7 @@ private: const CGameListCtrl* const m_game_list; - static NetPlayDiag* npd; + static NetPlayDialog* npd; + static NetPlayServer* netplay_server; + static NetPlayClient* netplay_client; }; - -class ChangeGameDiag : public wxDialog -{ -public: - ChangeGameDiag(wxWindow* const parent, const CGameListCtrl* const game_list, wxString& game_name); - -private: - void OnPick(wxCommandEvent& event); - - wxListBox* m_game_lbox; - wxString& m_game_name; -}; - -class PadMapDiag : public wxDialog -{ -public: - PadMapDiag(wxWindow* const parent, PadMapping map[], PadMapping wiimotemap[], std::vector& player_list); - -private: - void OnAdjust(wxCommandEvent& event); - - wxChoice* m_map_cbox[8]; - PadMapping* const m_mapping; - PadMapping* const m_wiimapping; - std::vector& m_player_list; -}; - -namespace NetPlay -{ - void StopGame(); -} diff --git a/Source/Core/DolphinWX/NetPlay/PadMapDialog.cpp b/Source/Core/DolphinWX/NetPlay/PadMapDialog.cpp new file mode 100644 index 0000000000..a9e066984f --- /dev/null +++ b/Source/Core/DolphinWX/NetPlay/PadMapDialog.cpp @@ -0,0 +1,106 @@ +// Copyright 2015 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include +#include + +#include "Core/NetPlayClient.h" +#include "Core/NetPlayProto.h" +#include "DolphinWX/NetPlay/PadMapDialog.h" + +PadMapDialog::PadMapDialog(wxWindow* parent, PadMapping map[], PadMapping wiimotemap[], std::vector& player_list) + : wxDialog(parent, wxID_ANY, _("Configure Pads")) + , m_mapping(map) + , m_wiimapping(wiimotemap) + , m_player_list(player_list) +{ + wxBoxSizer* const h_szr = new wxBoxSizer(wxHORIZONTAL); + h_szr->AddSpacer(10); + + wxArrayString player_names; + player_names.Add(_("None")); + for (auto& player : m_player_list) + player_names.Add(player->name); + + for (unsigned int i = 0; i < 4; ++i) + { + wxBoxSizer* const v_szr = new wxBoxSizer(wxVERTICAL); + v_szr->Add(new wxStaticText(this, wxID_ANY, (wxString(_("Pad ")) + (wxChar)('0' + i))), + 1, wxALIGN_CENTER_HORIZONTAL); + + m_map_cbox[i] = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, player_names); + m_map_cbox[i]->Bind(wxEVT_CHOICE, &PadMapDialog::OnAdjust, this); + if (m_mapping[i] == -1) + { + m_map_cbox[i]->Select(0); + } + else + { + for (unsigned int j = 0; j < m_player_list.size(); j++) + { + if (m_mapping[i] == m_player_list[j]->pid) + m_map_cbox[i]->Select(j + 1); + } + } + + v_szr->Add(m_map_cbox[i], 1); + + h_szr->Add(v_szr, 1, wxTOP | wxEXPAND, 20); + h_szr->AddSpacer(10); + } + + for (unsigned int i = 0; i < 4; ++i) + { + wxBoxSizer* const v_szr = new wxBoxSizer(wxVERTICAL); + v_szr->Add(new wxStaticText(this, wxID_ANY, (wxString(_("Wiimote ")) + (wxChar)('0' + i))), + 1, wxALIGN_CENTER_HORIZONTAL); + + m_map_cbox[i + 4] = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, player_names); + m_map_cbox[i + 4]->Bind(wxEVT_CHOICE, &PadMapDialog::OnAdjust, this); + if (m_wiimapping[i] == -1) + { + m_map_cbox[i + 4]->Select(0); + } + else + { + for (unsigned int j = 0; j < m_player_list.size(); j++) + { + if (m_wiimapping[i] == m_player_list[j]->pid) + m_map_cbox[i + 4]->Select(j + 1); + } + } + + v_szr->Add(m_map_cbox[i + 4], 1); + + h_szr->Add(v_szr, 1, wxTOP | wxEXPAND, 20); + h_szr->AddSpacer(10); + } + + wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL); + main_szr->Add(h_szr); + main_szr->AddSpacer(5); + main_szr->Add(CreateButtonSizer(wxOK), 0, wxEXPAND | wxLEFT | wxRIGHT, 20); + main_szr->AddSpacer(5); + SetSizerAndFit(main_szr); + SetFocus(); +} + +void PadMapDialog::OnAdjust(wxCommandEvent& WXUNUSED(event)) +{ + for (unsigned int i = 0; i < 4; i++) + { + int player_idx = m_map_cbox[i]->GetSelection(); + if (player_idx > 0) + m_mapping[i] = m_player_list[player_idx - 1]->pid; + else + m_mapping[i] = -1; + + player_idx = m_map_cbox[i + 4]->GetSelection(); + if (player_idx > 0) + m_wiimapping[i] = m_player_list[player_idx - 1]->pid; + else + m_wiimapping[i] = -1; + } +} diff --git a/Source/Core/DolphinWX/NetPlay/PadMapDialog.h b/Source/Core/DolphinWX/NetPlay/PadMapDialog.h new file mode 100644 index 0000000000..c7a18cc084 --- /dev/null +++ b/Source/Core/DolphinWX/NetPlay/PadMapDialog.h @@ -0,0 +1,27 @@ +// Copyright 2015 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "Core/NetPlayProto.h" + +class Player; +class wxChoice; + +class PadMapDialog final : public wxDialog +{ +public: + PadMapDialog(wxWindow* parent, PadMapping map[], PadMapping wiimotemap[], std::vector& player_list); + +private: + void OnAdjust(wxCommandEvent& event); + + wxChoice* m_map_cbox[8]; + PadMapping* const m_mapping; + PadMapping* const m_wiimapping; + std::vector& m_player_list; +}; diff --git a/Source/Core/DolphinWX/NetWindow.cpp b/Source/Core/DolphinWX/NetWindow.cpp deleted file mode 100644 index fc9289148e..0000000000 --- a/Source/Core/DolphinWX/NetWindow.cpp +++ /dev/null @@ -1,1079 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "Common/CommonTypes.h" -#include "Common/FifoQueue.h" -#include "Common/FileUtil.h" -#include "Common/IniFile.h" - -#include "Core/ConfigManager.h" -#include "Core/CoreParameter.h" -#include "Core/NetPlayClient.h" -#include "Core/NetPlayProto.h" -#include "Core/NetPlayServer.h" -#include "Core/HW/EXI_Device.h" - -#include "DolphinWX/Frame.h" -#include "DolphinWX/GameListCtrl.h" -#include "DolphinWX/ISOFile.h" -#include "DolphinWX/Main.h" -#include "DolphinWX/NetWindow.h" -#include "DolphinWX/WxUtils.h" - -#define INITIAL_PAD_BUFFER_SIZE 5 - -static NetPlayServer* netplay_server = nullptr; -static NetPlayClient* netplay_client = nullptr; -NetPlayDiag *NetPlayDiag::npd = nullptr; - - -static wxString FailureReasonStringForHostLabel(int reason) -{ - switch (reason) - { - case TraversalClient::BadHost: - return _("(Error: Bad host)"); - case TraversalClient::VersionTooOld: - return _("(Error: Dolphin too old)"); - case TraversalClient::ServerForgotAboutUs: - return _("(Error: Disconnected)"); - case TraversalClient::SocketSendError: - return _("(Error: Socket)"); - case TraversalClient::ResendTimeout: - return _("(Error: Timeout)"); - default: - return _("(Error: Unknown)"); - } -} - -static std::string BuildGameName(const GameListItem& game) -{ - // Lang needs to be consistent - auto const lang = 0; - - std::string name(game.GetName(lang)); - - if (game.GetRevision() != 0) - return name + " (" + game.GetUniqueID() + ", Revision " + std::to_string((long long)game.GetRevision()) + ")"; - else - return name + " (" + game.GetUniqueID() + ")"; -} - -static void FillWithGameNames(wxListBox* game_lbox, const CGameListCtrl& game_list) -{ - for (u32 i = 0; auto game = game_list.GetISO(i); ++i) - game_lbox->Append(StrToWxStr(BuildGameName(*game))); -} - -NetPlaySetupDiag::NetPlaySetupDiag(wxWindow* const parent, const CGameListCtrl* const game_list) - : wxFrame(parent, wxID_ANY, _("Dolphin NetPlay Setup")) - , m_game_list(game_list) -{ - IniFile inifile; - inifile.Load(File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"); - IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); - - wxPanel* const panel = new wxPanel(this); - - // top row - wxBoxSizer* const trav_szr = new wxBoxSizer(wxHORIZONTAL); - - m_direct_traversal = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(75, -1)); - m_direct_traversal->Bind(wxEVT_COMMAND_CHOICE_SELECTED, &NetPlaySetupDiag::OnChoice, this); - m_direct_traversal->Append(_("Direct")); - m_direct_traversal->Append(_("Traversal")); - - std::string travChoice; - netplay_section.Get("TraversalChoice", &travChoice, "direct"); - - if (travChoice == "traversal") - { - m_direct_traversal->Select(1); - } - else - { - m_direct_traversal->Select(0); - } - - trav_szr->Add(m_direct_traversal, 0, wxRIGHT); - - wxBoxSizer* const nick_szr = new wxBoxSizer(wxHORIZONTAL); - wxStaticText* const nick_lbl = new wxStaticText(panel, wxID_ANY, _("Nickname :")); - std::string nickname; - netplay_section.Get("Nickname", &nickname, "Player"); - m_nickname_text = new wxTextCtrl(panel, wxID_ANY, StrToWxStr(nickname)); - nick_szr->Add(nick_lbl, 0, wxCENTER); - nick_szr->Add(m_nickname_text, 0, wxALL, 5); - - std::string centralServer; - netplay_section.Get("TraversalServer", ¢ralServer, ""); - m_traversal_server_lbl = new wxStaticText(panel, wxID_ANY, _("Traversal:")); - m_traversal_server = new wxTextCtrl(panel, wxID_ANY, StrToWxStr(centralServer)); - nick_szr->Add(m_traversal_server_lbl, 0, wxCENTER); - nick_szr->Add(m_traversal_server, 0, wxALL, 5); - - std::string centralPort; - netplay_section.Get("TraversalPort", ¢ralPort, ""); - m_traversal_port_lbl = new wxStaticText(panel, wxID_ANY, _("Port:")); - m_traversal_port = new wxTextCtrl(panel, wxID_ANY, StrToWxStr(centralPort)); - nick_szr->Add(m_traversal_port_lbl, 0, wxCENTER); - nick_szr->Add(m_traversal_port, 0, wxALL, 5); - - // tabs - wxNotebook* const notebook = new wxNotebook(panel, wxID_ANY); - wxPanel* const connect_tab = new wxPanel(notebook, wxID_ANY); - notebook->AddPage(connect_tab, _("Connect")); - wxPanel* const host_tab = new wxPanel(notebook, wxID_ANY); - notebook->AddPage(host_tab, _("Host")); - - // connect tab - { - m_ip_lbl = new wxStaticText(connect_tab, wxID_ANY, _("Host Code :")); - - std::string address; - netplay_section.Get("HostCode", &address, "00000000"); - m_connect_ip_text = new wxTextCtrl(connect_tab, wxID_ANY, StrToWxStr(address)); - - m_client_port_lbl = new wxStaticText(connect_tab, wxID_ANY, _("Port :")); - - // string? w/e - std::string port; - netplay_section.Get("ConnectPort", &port, "2626"); - m_connect_port_text = new wxTextCtrl(connect_tab, wxID_ANY, StrToWxStr(port)); - - wxButton* const connect_btn = new wxButton(connect_tab, wxID_ANY, _("Connect")); - connect_btn->Bind(wxEVT_BUTTON, &NetPlaySetupDiag::OnJoin, this); - - wxStaticText* const alert_lbl = new wxStaticText(connect_tab, wxID_ANY, - _("ALERT:\n\n" - "Netplay will only work with the following settings:\n" - " - DSP Emulator Engine Must be the same on all computers!\n" - " - DSP on Dedicated Thread [OFF]\n" - " - Manually set the extensions for each Wiimote\n" - "\n" - "All players should use the same Dolphin version and settings.\n" - "All memory cards must be identical between players or disabled.\n" - "Wiimote support is probably terrible. Don't use it.\n" - "\n" - "If connecting directly host must have the chosen UDP port open/forwarded!\n")); - - wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL); - - top_szr->Add(m_ip_lbl, 0, wxCENTER | wxRIGHT, 5); - top_szr->Add(m_connect_ip_text, 3); - top_szr->Add(m_client_port_lbl, 0, wxCENTER | wxRIGHT | wxLEFT, 5); - top_szr->Add(m_connect_port_text, 1); - - wxBoxSizer* const con_szr = new wxBoxSizer(wxVERTICAL); - con_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5); - con_szr->AddStretchSpacer(1); - con_szr->Add(alert_lbl, 0, wxLEFT | wxRIGHT | wxEXPAND, 5); - con_szr->AddStretchSpacer(1); - con_szr->Add(connect_btn, 0, wxALL | wxALIGN_RIGHT, 5); - - connect_tab->SetSizerAndFit(con_szr); - } - - // host tab - { - m_host_port_lbl = new wxStaticText(host_tab, wxID_ANY, _("Port :")); - - // string? w/e - std::string port; - netplay_section.Get("HostPort", &port, "2626"); - m_host_port_text = new wxTextCtrl(host_tab, wxID_ANY, StrToWxStr(port)); - - wxButton* const host_btn = new wxButton(host_tab, wxID_ANY, _("Host")); - host_btn->Bind(wxEVT_BUTTON, &NetPlaySetupDiag::OnHost, this); - - m_game_lbox = new wxListBox(host_tab, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT); - m_game_lbox->Bind(wxEVT_LISTBOX_DCLICK, &NetPlaySetupDiag::OnHost, this); - - FillWithGameNames(m_game_lbox, *game_list); - - wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL); - top_szr->Add(m_host_port_lbl, 0, wxCENTER | wxRIGHT, 5); - top_szr->Add(m_host_port_text, 0); -#ifdef USE_UPNP - m_upnp_chk = new wxCheckBox(host_tab, wxID_ANY, _("Forward port (UPnP)")); - top_szr->Add(m_upnp_chk, 0, wxALL | wxALIGN_RIGHT, 5); -#endif - - wxBoxSizer* const host_szr = new wxBoxSizer(wxVERTICAL); - host_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5); - host_szr->Add(m_game_lbox, 1, wxLEFT | wxRIGHT | wxEXPAND, 5); - host_szr->Add(host_btn, 0, wxALL | wxALIGN_RIGHT, 5); - - host_tab->SetSizerAndFit(host_szr); - } - - // bottom row - wxButton* const quit_btn = new wxButton(panel, wxID_ANY, _("Quit")); - quit_btn->Bind(wxEVT_BUTTON, &NetPlaySetupDiag::OnQuit, this); - - // main sizer - wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL); - main_szr->Add(trav_szr, 0, wxALL | wxALIGN_LEFT); - main_szr->Add(nick_szr, 0, wxALL | wxALIGN_LEFT, 5); - main_szr->Add(notebook, 1, wxLEFT | wxRIGHT | wxEXPAND, 5); - main_szr->Add(quit_btn, 0, wxALL | wxALIGN_RIGHT, 5); - - panel->SetSizerAndFit(main_szr); - - //wxBoxSizer* const diag_szr = new wxBoxSizer(wxVERTICAL); - //diag_szr->Add(panel, 1, wxEXPAND); - //SetSizerAndFit(diag_szr); - - main_szr->SetSizeHints(this); - - Center(); - Show(); - - // Needs to be done last or it set up the spacing on the page correctly - wxCommandEvent ev; - OnChoice(ev); - -} - -NetPlaySetupDiag::~NetPlaySetupDiag() -{ - IniFile inifile; - const std::string dolphin_ini = File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"; - inifile.Load(dolphin_ini); - IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); - - std::string travChoice = "traversal"; - if (m_direct_traversal->GetSelection() == 1) - { - netplay_section.Set("TraversalChoice", travChoice); - } - else - { - travChoice = "direct"; - netplay_section.Set("TraversalChoice", travChoice); - } - - netplay_section.Set("Nickname", WxStrToStr(m_nickname_text->GetValue())); - netplay_section.Set("TraversalServer", WxStrToStr(m_traversal_server->GetValue())); - netplay_section.Set("TraversalPort", WxStrToStr(m_traversal_port->GetValue())); - - if (m_direct_traversal->GetCurrentSelection() == 0) - { - netplay_section.Set("Address", WxStrToStr(m_connect_ip_text->GetValue())); - } - else - { - netplay_section.Set("HostCode", WxStrToStr(m_connect_ip_text->GetValue())); - } - netplay_section.Set("ConnectPort", WxStrToStr(m_connect_port_text->GetValue())); - netplay_section.Set("HostPort", WxStrToStr(m_host_port_text->GetValue())); - - inifile.Save(dolphin_ini); - main_frame->g_NetPlaySetupDiag = nullptr; -} - -void NetPlaySetupDiag::MakeNetPlayDiag(int port, const std::string &game, bool is_hosting) -{ - NetPlayDiag *&npd = NetPlayDiag::GetInstance(); - std::string ip; - npd = new NetPlayDiag(m_parent, m_game_list, game, is_hosting); - if (is_hosting) - ip = "127.0.0.1"; - else - ip = WxStrToStr(m_connect_ip_text->GetValue()); - - bool trav; - if (!is_hosting && m_direct_traversal->GetCurrentSelection() == 1) - trav = true; - else - trav = false; - - unsigned long centralPort = 0; - m_traversal_port->GetValue().ToULong(¢ralPort); - netplay_client = new NetPlayClient(ip, (u16)port, npd, WxStrToStr(m_nickname_text->GetValue()), trav, WxStrToStr(m_traversal_server->GetValue()), (u16)centralPort); - if (netplay_client->is_connected) - { - npd->Show(); - Destroy(); - } - else - { - npd->Destroy(); - } -} - -void NetPlaySetupDiag::OnHost(wxCommandEvent&) -{ - NetPlayDiag *&npd = NetPlayDiag::GetInstance(); - if (npd) - { - WxUtils::ShowErrorDialog(_("A NetPlay window is already open!")); - return; - } - - if (-1 == m_game_lbox->GetSelection()) - { - WxUtils::ShowErrorDialog(_("You must choose a game!")); - return; - } - - std::string game(WxStrToStr(m_game_lbox->GetStringSelection())); - - bool trav; - if (m_direct_traversal->GetCurrentSelection() == 1) - trav = true; - else - trav = false; - - unsigned long port = 0; - m_host_port_text->GetValue().ToULong(&port); - - unsigned long centralPort = 0; - m_traversal_port->GetValue().ToULong(¢ralPort); - netplay_server = new NetPlayServer(u16(port), trav, WxStrToStr(m_traversal_server->GetValue()), u16(centralPort)); - if (netplay_server->is_connected) - { - netplay_server->ChangeGame(game); - netplay_server->AdjustPadBufferSize(INITIAL_PAD_BUFFER_SIZE); -#ifdef USE_UPNP - if (m_upnp_chk->GetValue()) - netplay_server->TryPortmapping(port); -#endif - MakeNetPlayDiag(netplay_server->GetPort(), game, true); - netplay_server->SetNetPlayUI(NetPlayDiag::GetInstance()); - } - else - { - WxUtils::ShowErrorDialog(_("Failed to listen. Is another instance of the NetPlay server running?")); - } -} - -void NetPlaySetupDiag::OnJoin(wxCommandEvent&) -{ - NetPlayDiag *&npd = NetPlayDiag::GetInstance(); - if (npd) - { - WxUtils::ShowErrorDialog(_("A NetPlay window is already open!")); - return; - } - - unsigned long port = 0; - m_connect_port_text->GetValue().ToULong(&port); - MakeNetPlayDiag(port, "", false); -} - -void NetPlaySetupDiag::OnChoice(wxCommandEvent& event) -{ - int sel = m_direct_traversal->GetSelection(); - IniFile inifile; - inifile.Load(File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"); - IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); - - if (sel == 1) - { - m_traversal_server_lbl->Show(true); - m_traversal_server->Show(true); - - m_traversal_port_lbl->Show(true); - m_traversal_port->Show(true); - - //Traversal - //client tab - { - m_ip_lbl->SetLabelText("Host Code: "); - - std::string address; - netplay_section.Get("HostCode", &address, "00000000"); - m_connect_ip_text->SetLabelText(address); - - m_client_port_lbl->Show(false); - m_connect_port_text->Show(false); - } - - //server tab - { - m_host_port_lbl->Show(false); - m_host_port_text->Show(false); - m_upnp_chk->Show(false); - } - } - else - { - m_traversal_server_lbl->Show(false); - m_traversal_server->Show(false); - - m_traversal_port_lbl->Show(false); - m_traversal_port->Show(false); - //Direct - //client tab - { - m_ip_lbl->SetLabelText("IP Address :"); - - std::string address; - netplay_section.Get("Address", &address, "127.0.0.1"); - m_connect_ip_text->SetLabelText(address); - - m_client_port_lbl->Show(true); - m_connect_port_text->Show(true); - } - - //server tab - { - m_host_port_lbl->Show(true); - m_host_port_text->Show(true); - m_upnp_chk->Show(true); - } - } -} - -void NetPlaySetupDiag::OnQuit(wxCommandEvent&) -{ - Destroy(); -} - -NetPlayDiag::NetPlayDiag(wxWindow* const parent, const CGameListCtrl* const game_list, - const std::string& game, const bool is_hosting) - : wxFrame(parent, wxID_ANY, _("Dolphin NetPlay")) - , m_selected_game(game) - , m_start_btn(nullptr) - , m_host_label(nullptr) - , m_host_type_choice(nullptr) - , m_host_copy_btn(nullptr) - , m_host_copy_btn_is_retry(false) - , m_is_hosting(is_hosting) - , m_game_list(game_list) -{ - Bind(wxEVT_THREAD, &NetPlayDiag::OnThread, this); - - wxPanel* const panel = new wxPanel(this); - - // top crap - m_game_btn = new wxButton(panel, wxID_ANY, - StrToWxStr(m_selected_game).Prepend(_(" Game : ")), - wxDefaultPosition, wxDefaultSize, wxBU_LEFT); - - if (m_is_hosting) - m_game_btn->Bind(wxEVT_BUTTON, &NetPlayDiag::OnChangeGame, this); - else - m_game_btn->Disable(); - - // middle crap - - // chat - m_chat_text = new wxTextCtrl(panel, wxID_ANY, wxEmptyString - , wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxTE_MULTILINE); - - m_chat_msg_text = new wxTextCtrl(panel, wxID_ANY, wxEmptyString - , wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); - m_chat_msg_text->Bind(wxEVT_TEXT_ENTER, &NetPlayDiag::OnChat, this); - m_chat_msg_text->SetMaxLength(2000); - - wxButton* const chat_msg_btn = new wxButton(panel, wxID_ANY, _("Send")); - chat_msg_btn->Bind(wxEVT_BUTTON, &NetPlayDiag::OnChat, this); - - wxBoxSizer* const chat_msg_szr = new wxBoxSizer(wxHORIZONTAL); - chat_msg_szr->Add(m_chat_msg_text, 1); - chat_msg_szr->Add(chat_msg_btn, 0); - - wxStaticBoxSizer* const chat_szr = new wxStaticBoxSizer(wxVERTICAL, panel, _("Chat")); - chat_szr->Add(m_chat_text, 1, wxEXPAND); - chat_szr->Add(chat_msg_szr, 0, wxEXPAND | wxTOP, 5); - - m_player_lbox = new wxListBox(panel, wxID_ANY, wxDefaultPosition, wxSize(256, -1)); - - wxStaticBoxSizer* const player_szr = new wxStaticBoxSizer(wxVERTICAL, panel, _("Players")); - - // player list - if (m_is_hosting && g_TraversalClient) - { - wxBoxSizer* const host_szr = new wxBoxSizer(wxHORIZONTAL); - m_host_type_choice = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(60, -1)); - m_host_type_choice->Bind(wxEVT_COMMAND_CHOICE_SELECTED, &NetPlayDiag::OnChoice, this); - m_host_type_choice->Append(_("ID:")); - host_szr->Add(m_host_type_choice); - - m_host_label = new wxStaticText(panel, wxID_ANY, "555.555.555.555:55555", wxDefaultPosition, wxDefaultSize, wxST_NO_AUTORESIZE | wxALIGN_LEFT); - // Update() should fix this immediately. - m_host_label->SetLabel(_("")); - host_szr->Add(m_host_label, 1, wxLEFT | wxCENTER, 5); - - m_host_copy_btn = new wxButton(panel, wxID_ANY, _("Copy")); - m_host_copy_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &NetPlayDiag::OnCopyIP, this); - m_host_copy_btn->Disable(); - host_szr->Add(m_host_copy_btn, 0, wxLEFT | wxCENTER, 5); - player_szr->Add(host_szr, 0, wxEXPAND | wxBOTTOM, 5); - m_host_type_choice->Select(0); - - UpdateHostLabel(); - } - - player_szr->Add(m_player_lbox, 1, wxEXPAND); - - if (m_is_hosting) - { - m_player_lbox->Bind(wxEVT_LISTBOX, &NetPlayDiag::OnPlayerSelect, this); - m_kick_btn = new wxButton(panel, wxID_ANY, _("Kick Player")); - m_kick_btn->Bind(wxEVT_BUTTON, &NetPlayDiag::OnKick, this); - player_szr->Add(m_kick_btn, 0, wxEXPAND | wxTOP, 5); - m_kick_btn->Disable(); - - m_player_config_btn = new wxButton(panel, wxID_ANY, _("Configure Pads")); - m_player_config_btn->Bind(wxEVT_BUTTON, &NetPlayDiag::OnConfigPads, this); - player_szr->Add(m_player_config_btn, 0, wxEXPAND | wxTOP, 5); - } - - wxBoxSizer* const mid_szr = new wxBoxSizer(wxHORIZONTAL); - mid_szr->Add(chat_szr, 1, wxEXPAND | wxRIGHT, 5); - mid_szr->Add(player_szr, 0, wxEXPAND); - - // bottom crap - wxButton* const quit_btn = new wxButton(panel, wxID_ANY, _("Quit")); - quit_btn->Bind(wxEVT_BUTTON, &NetPlayDiag::OnQuit, this); - - wxBoxSizer* const bottom_szr = new wxBoxSizer(wxHORIZONTAL); - if (is_hosting) - { - m_start_btn = new wxButton(panel, wxID_ANY, _("Start")); - m_start_btn->Bind(wxEVT_BUTTON, &NetPlayDiag::OnStart, this); - bottom_szr->Add(m_start_btn); - - bottom_szr->Add(new wxStaticText(panel, wxID_ANY, _("Buffer:")), 0, wxLEFT | wxCENTER, 5); - wxSpinCtrl* const padbuf_spin = new wxSpinCtrl(panel, wxID_ANY, std::to_string(INITIAL_PAD_BUFFER_SIZE) - , wxDefaultPosition, wxSize(64, -1), wxSP_ARROW_KEYS, 0, 200, INITIAL_PAD_BUFFER_SIZE); - padbuf_spin->Bind(wxEVT_SPINCTRL, &NetPlayDiag::OnAdjustBuffer, this); - bottom_szr->Add(padbuf_spin, 0, wxCENTER); - - m_memcard_write = new wxCheckBox(panel, wxID_ANY, _("Write memcards (GC)")); - bottom_szr->Add(m_memcard_write, 0, wxCENTER); - } - - m_record_chkbox = new wxCheckBox(panel, wxID_ANY, _("Record input")); - bottom_szr->Add(m_record_chkbox, 0, wxCENTER); - - bottom_szr->AddStretchSpacer(1); - bottom_szr->Add(quit_btn); - - // main sizer - wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL); - main_szr->Add(m_game_btn, 0, wxEXPAND | wxALL, 5); - main_szr->Add(mid_szr, 1, wxEXPAND | wxLEFT | wxRIGHT, 5); - main_szr->Add(bottom_szr, 0, wxEXPAND | wxALL, 5); - - panel->SetSizerAndFit(main_szr); - - main_szr->SetSizeHints(this); - SetSize(512, 512 - 128); - - Center(); -} - -NetPlayDiag::~NetPlayDiag() -{ - if (netplay_client) - { - delete netplay_client; - netplay_client = nullptr; - } - if (netplay_server) - { - delete netplay_server; - netplay_server = nullptr; - } - npd = nullptr; -} - -void NetPlayDiag::OnChat(wxCommandEvent&) -{ - wxString text = m_chat_msg_text->GetValue(); - - if (!text.empty()) - { - netplay_client->SendChatMessage(WxStrToStr(text)); - m_chat_text->AppendText(text.Prepend(" >> ").Append('\n')); - m_chat_msg_text->Clear(); - } -} - -void NetPlayDiag::GetNetSettings(NetSettings &settings) -{ - SConfig &instance = SConfig::GetInstance(); - settings.m_CPUthread = instance.m_LocalCoreStartupParameter.bCPUThread; - settings.m_CPUcore = instance.m_LocalCoreStartupParameter.iCPUCore; - settings.m_DSPHLE = instance.m_LocalCoreStartupParameter.bDSPHLE; - settings.m_DSPEnableJIT = instance.m_DSPEnableJIT; - settings.m_WriteToMemcard = m_memcard_write->GetValue(); - settings.m_OCEnable = instance.m_OCEnable; - settings.m_OCFactor = instance.m_OCFactor; - settings.m_EXIDevice[0] = instance.m_EXIDevice[0]; - settings.m_EXIDevice[1] = instance.m_EXIDevice[1]; -} - -std::string NetPlayDiag::FindGame() -{ - // find path for selected game, sloppy.. - for (u32 i = 0; auto game = m_game_list->GetISO(i); ++i) - if (m_selected_game == BuildGameName(*game)) - return game->GetFileName(); - - WxUtils::ShowErrorDialog(_("Game not found!")); - return ""; -} - -void NetPlayDiag::OnStart(wxCommandEvent&) -{ - NetSettings settings; - GetNetSettings(settings); - netplay_server->SetNetSettings(settings); - netplay_server->StartGame(); -} - -void NetPlayDiag::BootGame(const std::string& filename) -{ - main_frame->BootGame(filename); -} - -void NetPlayDiag::StopGame() -{ - main_frame->DoStop(); -} - -// NetPlayUI methods called from ---NETPLAY--- thread -void NetPlayDiag::Update() -{ - wxThreadEvent evt(wxEVT_THREAD, 1); - GetEventHandler()->AddPendingEvent(evt); -} - -void NetPlayDiag::AppendChat(const std::string& msg) -{ - chat_msgs.Push(msg); - // silly - Update(); -} - -void NetPlayDiag::OnMsgChangeGame(const std::string& filename) -{ - wxThreadEvent* evt = new wxThreadEvent(wxEVT_THREAD, NP_GUI_EVT_CHANGE_GAME); - evt->SetString(StrToWxStr(filename)); - GetEventHandler()->QueueEvent(evt); -} - -void NetPlayDiag::OnMsgStartGame() -{ - wxThreadEvent evt(wxEVT_THREAD, NP_GUI_EVT_START_GAME); - GetEventHandler()->AddPendingEvent(evt); - if (m_is_hosting) - { - m_start_btn->Disable(); - m_memcard_write->Disable(); - m_game_btn->Disable(); - m_player_config_btn->Disable(); - } - - m_record_chkbox->Disable(); -} - -void NetPlayDiag::OnMsgStopGame() -{ - wxThreadEvent evt(wxEVT_THREAD, NP_GUI_EVT_STOP_GAME); - GetEventHandler()->AddPendingEvent(evt); - if (m_is_hosting) - { - m_start_btn->Enable(); - m_memcard_write->Enable(); - m_game_btn->Enable(); - m_player_config_btn->Enable(); - } - m_record_chkbox->Enable(); -} - -void NetPlayDiag::OnAdjustBuffer(wxCommandEvent& event) -{ - const int val = ((wxSpinCtrl*)event.GetEventObject())->GetValue(); - netplay_server->AdjustPadBufferSize(val); - - std::ostringstream ss; - ss << "< Pad Buffer: " << val << " >"; - netplay_client->SendChatMessage(ss.str()); - m_chat_text->AppendText(StrToWxStr(ss.str()).Append('\n')); -} - -void NetPlayDiag::OnQuit(wxCommandEvent&) -{ - Destroy(); -} - -// update gui -void NetPlayDiag::OnThread(wxThreadEvent& event) -{ - if (m_is_hosting && m_host_label && g_TraversalClient) - { - UpdateHostLabel(); - } - - // player list - m_playerids.clear(); - std::string tmps; - netplay_client->GetPlayerList(tmps, m_playerids); - - wxString selection; - if (m_player_lbox->GetSelection() != wxNOT_FOUND) - selection = m_player_lbox->GetString(m_player_lbox->GetSelection()); - - m_player_lbox->Clear(); - std::istringstream ss(tmps); - while (std::getline(ss, tmps)) - m_player_lbox->Append(StrToWxStr(tmps)); - - // remove ping from selection string, in case it has changed - selection.erase(selection.find_last_of("|") + 1); - - if (!selection.empty()) - { - for (unsigned int i = 0; i < m_player_lbox->GetCount(); ++i) - { - if (selection == m_player_lbox->GetString(i).Mid(0, selection.length())) - { - m_player_lbox->SetSelection(i); - break; - } - } - } - - // flash window in taskbar when someone joins if window isn't active - static u8 numPlayers = 1; - bool focus = (wxWindow::FindFocus() == this || (wxWindow::FindFocus() != nullptr && wxWindow::FindFocus()->GetParent() == this) || - (wxWindow::FindFocus() != nullptr && wxWindow::FindFocus()->GetParent() != nullptr - && wxWindow::FindFocus()->GetParent()->GetParent() == this)); - if (netplay_server != nullptr && numPlayers < m_playerids.size() && !focus) - { - RequestUserAttention(); - } - numPlayers = m_playerids.size(); - - switch (event.GetId()) - { - case NP_GUI_EVT_CHANGE_GAME: - // update selected game :/ - { - m_selected_game.assign(WxStrToStr(event.GetString())); - - wxString button_label = event.GetString(); - m_game_btn->SetLabel(button_label.Prepend(_(" Game : "))); - } - break; - case NP_GUI_EVT_START_GAME: - // client start game :/ - { - netplay_client->StartGame(FindGame()); - } - break; - case NP_GUI_EVT_STOP_GAME: - // client stop game - { - netplay_client->StopGame(); - } - break; - } - - // chat messages - while (chat_msgs.Size()) - { - std::string s; - chat_msgs.Pop(s); - //PanicAlert("message: %s", s.c_str()); - m_chat_text->AppendText(StrToWxStr(s).Append('\n')); - } -} - -void NetPlayDiag::OnChangeGame(wxCommandEvent&) -{ - wxString game_name; - ChangeGameDiag* const cgd = new ChangeGameDiag(this, m_game_list, game_name); - cgd->ShowModal(); - - if (game_name.length()) - { - m_selected_game = WxStrToStr(game_name); - netplay_server->ChangeGame(m_selected_game); - m_game_btn->SetLabel(game_name.Prepend(_(" Game : "))); - } -} - -void NetPlayDiag::OnConfigPads(wxCommandEvent&) -{ - PadMapping mapping[4]; - PadMapping wiimotemapping[4]; - std::vector player_list; - netplay_server->GetPadMapping(mapping); - netplay_server->GetWiimoteMapping(wiimotemapping); - netplay_client->GetPlayers(player_list); - PadMapDiag pmd(this, mapping, wiimotemapping, player_list); - pmd.ShowModal(); - netplay_server->SetPadMapping(mapping); - netplay_server->SetWiimoteMapping(wiimotemapping); -} - -void NetPlayDiag::OnKick(wxCommandEvent&) -{ - wxString selection = m_player_lbox->GetStringSelection(); - unsigned long player = 0; - selection.Mid(selection.find_last_of("[") + 1, selection.find_last_of("]")).ToULong(&player); - - netplay_server->KickPlayer((u8)player); - - m_player_lbox->SetSelection(wxNOT_FOUND); - wxCommandEvent event; - OnPlayerSelect(event); -} - -void NetPlayDiag::OnPlayerSelect(wxCommandEvent&) -{ - if (m_player_lbox->GetSelection() > 0) - m_kick_btn->Enable(); - else - m_kick_btn->Disable(); -} - -bool NetPlayDiag::IsRecording() -{ - return m_record_chkbox->GetValue(); -} - - -void NetPlayDiag::OnCopyIP(wxCommandEvent&) -{ - if (m_host_copy_btn_is_retry) - { - g_TraversalClient->ReconnectToServer(); - Update(); - } - else - { - if (wxTheClipboard->Open()) - { - wxTheClipboard->SetData(new wxTextDataObject(m_host_label->GetLabel())); - wxTheClipboard->Close(); - } - } -} - -void NetPlayDiag::OnChoice(wxCommandEvent& event) -{ - UpdateHostLabel(); -} - - -void NetPlayDiag::UpdateHostLabel() -{ - wxString label = _(" (internal IP)"); - auto DeLabel = [=](wxString str) { - if (str == _("Localhost")) - return std::string("!local!"); - return WxStrToStr(str.Left(str.Len() - label.Len())); - }; - auto EnLabel = [=](std::string str) -> wxString { - if (str == "!local!") - return _("Localhost"); - return StrToWxStr(str) + label; - }; - int sel = m_host_type_choice->GetSelection(); - if (sel == 0) - { - // the traversal ID - switch (g_TraversalClient->m_State) - { - case TraversalClient::Connecting: - m_host_label->SetForegroundColour(*wxLIGHT_GREY); - m_host_label->SetLabel("..."); - m_host_copy_btn->SetLabel(_("Copy")); - m_host_copy_btn->Disable(); - break; - case TraversalClient::Connected: - m_host_label->SetForegroundColour(*wxBLACK); - m_host_label->SetLabel(wxString(g_TraversalClient->m_HostId.data(), g_TraversalClient->m_HostId.size())); - m_host_copy_btn->SetLabel(_("Copy")); - m_host_copy_btn->Enable(); - m_host_copy_btn_is_retry = false; - break; - case TraversalClient::Failure: - m_host_label->SetForegroundColour(*wxBLACK); - m_host_label->SetLabel(FailureReasonStringForHostLabel(g_TraversalClient->m_FailureReason)); - m_host_copy_btn->SetLabel(_("Retry")); - m_host_copy_btn->Enable(); - m_host_copy_btn_is_retry = true; - break; - } - } - else if (sel != wxNOT_FOUND) // wxNOT_FOUND shouldn't generally happen - { - m_host_label->SetForegroundColour(*wxBLACK); - m_host_label->SetLabel(netplay_server->GetInterfaceHost(DeLabel(m_host_type_choice->GetString(sel)))); - m_host_copy_btn->SetLabel(_("Copy")); - m_host_copy_btn->Enable(); - m_host_copy_btn_is_retry = false; - } - - auto set = netplay_server->GetInterfaceSet(); - for (const std::string& iface : set) - { - wxString wxIface = EnLabel(iface); - if (m_host_type_choice->FindString(wxIface) == wxNOT_FOUND) - m_host_type_choice->Append(wxIface); - } - for (unsigned i = 1, count = m_host_type_choice->GetCount(); i != count; i++) - { - if (set.find(DeLabel(m_host_type_choice->GetString(i))) == set.end()) - { - m_host_type_choice->Delete(i); - i--; - count--; - } - } -} - -ChangeGameDiag::ChangeGameDiag(wxWindow* const parent, const CGameListCtrl* const game_list, wxString& game_name) - : wxDialog(parent, wxID_ANY, _("Change Game")) - , m_game_name(game_name) -{ - m_game_lbox = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT); - m_game_lbox->Bind(wxEVT_LISTBOX_DCLICK, &ChangeGameDiag::OnPick, this); - - FillWithGameNames(m_game_lbox, *game_list); - - wxButton* const ok_btn = new wxButton(this, wxID_OK, _("Change")); - ok_btn->Bind(wxEVT_BUTTON, &ChangeGameDiag::OnPick, this); - - wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL); - szr->Add(m_game_lbox, 1, wxLEFT | wxRIGHT | wxTOP | wxEXPAND, 5); - szr->Add(ok_btn, 0, wxALL | wxALIGN_RIGHT, 5); - - SetSizerAndFit(szr); - SetFocus(); -} - -void ChangeGameDiag::OnPick(wxCommandEvent& event) -{ - // return the selected game name - m_game_name = m_game_lbox->GetStringSelection(); - EndModal(wxID_OK); -} - -PadMapDiag::PadMapDiag(wxWindow* const parent, PadMapping map[], PadMapping wiimotemap[], std::vector& player_list) - : wxDialog(parent, wxID_ANY, _("Configure Pads")) - , m_mapping(map) - , m_wiimapping(wiimotemap) - , m_player_list(player_list) -{ - wxBoxSizer* const h_szr = new wxBoxSizer(wxHORIZONTAL); - h_szr->AddSpacer(10); - - wxArrayString player_names; - player_names.Add(_("None")); - for (auto& player : m_player_list) - player_names.Add(player->name); - - for (unsigned int i = 0; i < 4; ++i) - { - wxBoxSizer* const v_szr = new wxBoxSizer(wxVERTICAL); - v_szr->Add(new wxStaticText(this, wxID_ANY, (wxString(_("Pad ")) + (wxChar)('0' + i))), - 1, wxALIGN_CENTER_HORIZONTAL); - - m_map_cbox[i] = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, player_names); - m_map_cbox[i]->Bind(wxEVT_CHOICE, &PadMapDiag::OnAdjust, this); - if (m_mapping[i] == -1) - m_map_cbox[i]->Select(0); - else - for (unsigned int j = 0; j < m_player_list.size(); j++) - if (m_mapping[i] == m_player_list[j]->pid) - m_map_cbox[i]->Select(j + 1); - - v_szr->Add(m_map_cbox[i], 1); - - h_szr->Add(v_szr, 1, wxTOP | wxEXPAND, 20); - h_szr->AddSpacer(10); - } - - for (unsigned int i = 0; i < 4; ++i) - { - wxBoxSizer* const v_szr = new wxBoxSizer(wxVERTICAL); - v_szr->Add(new wxStaticText(this, wxID_ANY, (wxString(_("Wiimote ")) + (wxChar)('0' + i))), - 1, wxALIGN_CENTER_HORIZONTAL); - - m_map_cbox[i + 4] = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, player_names); - m_map_cbox[i + 4]->Bind(wxEVT_CHOICE, &PadMapDiag::OnAdjust, this); - if (m_wiimapping[i] == -1) - m_map_cbox[i + 4]->Select(0); - else - for (unsigned int j = 0; j < m_player_list.size(); j++) - if (m_wiimapping[i] == m_player_list[j]->pid) - m_map_cbox[i + 4]->Select(j + 1); - - v_szr->Add(m_map_cbox[i + 4], 1); - - h_szr->Add(v_szr, 1, wxTOP | wxEXPAND, 20); - h_szr->AddSpacer(10); - } - - wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL); - main_szr->Add(h_szr); - main_szr->AddSpacer(5); - main_szr->Add(CreateButtonSizer(wxOK), 0, wxEXPAND | wxLEFT | wxRIGHT, 20); - main_szr->AddSpacer(5); - SetSizerAndFit(main_szr); - SetFocus(); -} - -void PadMapDiag::OnAdjust(wxCommandEvent& event) -{ - (void)event; - for (unsigned int i = 0; i < 4; i++) - { - int player_idx = m_map_cbox[i]->GetSelection(); - if (player_idx > 0) - m_mapping[i] = m_player_list[player_idx - 1]->pid; - else - m_mapping[i] = -1; - - player_idx = m_map_cbox[i + 4]->GetSelection(); - if (player_idx > 0) - m_wiimapping[i] = m_player_list[player_idx - 1]->pid; - else - m_wiimapping[i] = -1; - } -} - -void NetPlay::StopGame() -{ - if (netplay_client != nullptr) - netplay_client->Stop(); -}