Merge pull request #5659 from shuffle2/gamelist-speedup-with-emustate

Gamelist speedup with emustate
This commit is contained in:
shuffle2 2017-06-23 17:32:15 -07:00 committed by GitHub
commit ced53e2920
29 changed files with 656 additions and 598 deletions

View File

@ -296,125 +296,3 @@ private:
*ptr += size; *ptr += size;
} }
}; };
// NOTE: this class is only used in DolphinWX/ISOFile.cpp for caching loaded
// ISO data. It will be removed when DolphinWX is, so please don't use it.
class CChunkFileReader
{
public:
// Load file template
template <class T>
static bool Load(const std::string& _rFilename, u32 _Revision, T& _class)
{
INFO_LOG(COMMON, "ChunkReader: Loading %s", _rFilename.c_str());
if (!File::Exists(_rFilename))
return false;
// Check file size
const u64 fileSize = File::GetSize(_rFilename);
static const u64 headerSize = sizeof(SChunkHeader);
if (fileSize < headerSize)
{
ERROR_LOG(COMMON, "ChunkReader: File too small");
return false;
}
File::IOFile pFile(_rFilename, "rb");
if (!pFile)
{
ERROR_LOG(COMMON, "ChunkReader: Can't open file for reading");
return false;
}
// read the header
SChunkHeader header;
if (!pFile.ReadArray(&header, 1))
{
ERROR_LOG(COMMON, "ChunkReader: Bad header size");
return false;
}
// Check revision
if (header.Revision != _Revision)
{
ERROR_LOG(COMMON, "ChunkReader: Wrong file revision, got %d expected %d", header.Revision,
_Revision);
return false;
}
// get size
const u32 sz = (u32)(fileSize - headerSize);
if (header.ExpectedSize != sz)
{
ERROR_LOG(COMMON, "ChunkReader: Bad file size, got %d expected %d", sz, header.ExpectedSize);
return false;
}
// read the state
std::vector<u8> buffer(sz);
if (!pFile.ReadArray(&buffer[0], sz))
{
ERROR_LOG(COMMON, "ChunkReader: Error reading file");
return false;
}
u8* ptr = &buffer[0];
PointerWrap p(&ptr, PointerWrap::MODE_READ);
_class.DoState(p);
INFO_LOG(COMMON, "ChunkReader: Done loading %s", _rFilename.c_str());
return true;
}
// Save file template
template <class T>
static bool Save(const std::string& _rFilename, u32 _Revision, T& _class)
{
INFO_LOG(COMMON, "ChunkReader: Writing %s", _rFilename.c_str());
File::IOFile pFile(_rFilename, "wb");
if (!pFile)
{
ERROR_LOG(COMMON, "ChunkReader: Error opening file for write");
return false;
}
// Get data
u8* ptr = nullptr;
PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
_class.DoState(p);
size_t const sz = (size_t)ptr;
std::vector<u8> buffer(sz);
ptr = &buffer[0];
p.SetMode(PointerWrap::MODE_WRITE);
_class.DoState(p);
// Create header
SChunkHeader header;
header.Revision = _Revision;
header.ExpectedSize = (u32)sz;
// Write to file
if (!pFile.WriteArray(&header, 1))
{
ERROR_LOG(COMMON, "ChunkReader: Failed writing header");
return false;
}
if (!pFile.WriteArray(&buffer[0], sz))
{
ERROR_LOG(COMMON, "ChunkReader: Failed writing data");
return false;
}
INFO_LOG(COMMON, "ChunkReader: Done writing %s", _rFilename.c_str());
return true;
}
private:
struct SChunkHeader
{
u32 Revision;
u32 ExpectedSize;
};
};

View File

@ -7,10 +7,19 @@
#include "Common/CommonPaths.h" #include "Common/CommonPaths.h"
#include "Common/FileSearch.h" #include "Common/FileSearch.h"
#ifdef _MSC_VER
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#define HAS_STD_FILESYSTEM
#else
#include "Common/FileUtil.h" #include "Common/FileUtil.h"
#endif
namespace Common namespace Common
{ {
#ifndef HAS_STD_FILESYSTEM
static std::vector<std::string> static std::vector<std::string>
FileSearchWithTest(const std::vector<std::string>& directories, bool recursive, FileSearchWithTest(const std::vector<std::string>& directories, bool recursive,
std::function<bool(const File::FSTEntry&)> callback) std::function<bool(const File::FSTEntry&)> callback)
@ -36,10 +45,10 @@ FileSearchWithTest(const std::vector<std::string>& directories, bool recursive,
return result; return result;
} }
std::vector<std::string> DoFileSearch(const std::vector<std::string>& exts, std::vector<std::string> DoFileSearchNoSTL(const std::vector<std::string>& directories,
const std::vector<std::string>& directories, bool recursive) const std::vector<std::string>& exts, bool recursive)
{ {
bool accept_all = std::find(exts.begin(), exts.end(), "") != exts.end(); bool accept_all = exts.empty();
return FileSearchWithTest(directories, recursive, [&](const File::FSTEntry& entry) { return FileSearchWithTest(directories, recursive, [&](const File::FSTEntry& entry) {
if (accept_all) if (accept_all)
return true; return true;
@ -52,11 +61,71 @@ std::vector<std::string> DoFileSearch(const std::vector<std::string>& exts,
}); });
} }
// Result includes the passed directories themselves as well as their subdirectories. std::vector<std::string> DoFileSearch(const std::vector<std::string>& directories,
std::vector<std::string> FindSubdirectories(const std::vector<std::string>& directories, const std::vector<std::string>& exts, bool recursive)
bool recursive)
{ {
return FileSearchWithTest(directories, true, return DoFileSearchNoSTL(directories, exts, recursive);
[&](const File::FSTEntry& entry) { return entry.isDirectory; });
} }
#else
std::vector<std::string> DoFileSearch(const std::vector<std::string>& directories,
const std::vector<std::string>& exts, bool recursive)
{
bool accept_all = exts.empty();
std::vector<fs::path> native_exts;
for (const auto& ext : exts)
native_exts.push_back(ext);
// N.B. This avoids doing any copies
auto ext_matches = [&native_exts](const fs::path& path) {
const auto& native_path = path.native();
return std::any_of(native_exts.cbegin(), native_exts.cend(), [&native_path](const auto& ext) {
// TODO provide cross-platform compat for the comparison function, once more platforms
// support std::filesystem
return native_path.length() >= ext.native().length() &&
_wcsicmp(&native_path.c_str()[native_path.length() - ext.native().length()],
ext.c_str()) == 0;
});
};
std::vector<std::string> result;
auto add_filtered = [&](const fs::directory_entry& entry) {
auto& path = entry.path();
if (accept_all || (ext_matches(path) && !fs::is_directory(path)))
result.emplace_back(path.u8string());
};
for (const auto& directory : directories)
{
if (recursive)
{
// TODO use fs::directory_options::follow_directory_symlink ?
for (auto& entry : fs::recursive_directory_iterator(fs::path(directory.c_str())))
add_filtered(entry);
}
else
{
for (auto& entry : fs::directory_iterator(fs::path(directory.c_str())))
add_filtered(entry);
}
}
// Remove duplicates (occurring because caller gave e.g. duplicate or overlapping directories -
// not because std::filesystem returns duplicates). Also note that this pathname-based uniqueness
// isn't as thorough as std::filesystem::equivalent.
std::sort(result.begin(), result.end());
result.erase(std::unique(result.begin(), result.end()), result.end());
// Dolphin expects to be able to use "/" (DIR_SEP) everywhere. std::filesystem uses the OS
// separator.
if (fs::path::preferred_separator != DIR_SEP_CHR)
for (auto& path : result)
std::replace(path.begin(), path.end(), '\\', DIR_SEP_CHR);
return result;
}
#endif
} // namespace Common } // namespace Common

View File

@ -9,9 +9,9 @@
namespace Common namespace Common
{ {
std::vector<std::string> DoFileSearch(const std::vector<std::string>& exts, // Callers can pass empty "exts" to indicate they want all files + directories in results
const std::vector<std::string>& directories, // Otherwise, only files matching the extensions are returned
std::vector<std::string> DoFileSearch(const std::vector<std::string>& directories,
const std::vector<std::string>& exts = {},
bool recursive = false); bool recursive = false);
std::vector<std::string> FindSubdirectories(const std::vector<std::string>& directories,
bool recursive);
} // namespace Common } // namespace Common

View File

@ -148,7 +148,7 @@ GCMemcardDirectory::GCMemcardDirectory(const std::string& directory, int slot, u
hdr_file.ReadBytes(&m_hdr, BLOCK_SIZE); hdr_file.ReadBytes(&m_hdr, BLOCK_SIZE);
} }
std::vector<std::string> filenames = Common::DoFileSearch({".gci"}, {m_save_directory}); std::vector<std::string> filenames = Common::DoFileSearch({m_save_directory}, {".gci"});
if (filenames.size() > 112) if (filenames.size() > 112)
{ {

View File

@ -365,7 +365,7 @@ QVector<QString> Settings::GetProfiles(const InputConfig* config) const
const std::string path = GetProfilesDir().toStdString() + config->GetProfileName(); const std::string path = GetProfilesDir().toStdString() + config->GetProfileName();
QVector<QString> vec; QVector<QString> vec;
for (const auto& file : Common::DoFileSearch({".ini"}, {path})) for (const auto& file : Common::DoFileSearch({path}, {".ini"}))
{ {
std::string basename; std::string basename;
SplitPath(file, nullptr, &basename, nullptr); SplitPath(file, nullptr, &basename, nullptr);

View File

@ -59,9 +59,8 @@ void InterfacePane::CreateUI()
combobox_layout->addRow(tr("&Theme:"), m_combobox_theme); combobox_layout->addRow(tr("&Theme:"), m_combobox_theme);
// List avalable themes // List avalable themes
auto file_search_results = Common::DoFileSearch( auto file_search_results =
{""}, {File::GetUserPath(D_THEMES_IDX), File::GetSysDirectory() + THEMES_DIR}, Common::DoFileSearch({File::GetUserPath(D_THEMES_IDX), File::GetSysDirectory() + THEMES_DIR});
/*recursive*/ false);
for (const std::string& filename : file_search_results) for (const std::string& filename : file_search_results)
{ {
std::string name, ext; std::string name, ext;

View File

@ -24,21 +24,21 @@
#include "DolphinWX/GameListCtrl.h" #include "DolphinWX/GameListCtrl.h"
#include "DolphinWX/WxUtils.h" #include "DolphinWX/WxUtils.h"
// Sent by child panes to signify that the game list should
// be updated when this modal dialog closes.
wxDEFINE_EVENT(wxDOLPHIN_CFG_REFRESH_LIST, wxCommandEvent); wxDEFINE_EVENT(wxDOLPHIN_CFG_REFRESH_LIST, wxCommandEvent);
wxDEFINE_EVENT(wxDOLPHIN_CFG_RESCAN_LIST, wxCommandEvent);
CConfigMain::CConfigMain(wxWindow* parent, wxWindowID id, const wxString& title, CConfigMain::CConfigMain(wxWindow* parent, wxWindowID id, const wxString& title,
const wxPoint& position, const wxSize& size, long style) const wxPoint& position, const wxSize& size, long style)
: wxDialog(parent, id, title, position, size, style) : wxDialog(parent, id, title, position, size, style)
{ {
// Control refreshing of the ISOs list // Control refreshing of the GameListCtrl
m_refresh_game_list_on_close = false; m_event_on_close = wxEVT_NULL;
Bind(wxEVT_CLOSE_WINDOW, &CConfigMain::OnClose, this); Bind(wxEVT_CLOSE_WINDOW, &CConfigMain::OnClose, this);
Bind(wxEVT_BUTTON, &CConfigMain::OnCloseButton, this, wxID_CLOSE); Bind(wxEVT_BUTTON, &CConfigMain::OnCloseButton, this, wxID_CLOSE);
Bind(wxEVT_SHOW, &CConfigMain::OnShow, this); Bind(wxEVT_SHOW, &CConfigMain::OnShow, this);
Bind(wxDOLPHIN_CFG_REFRESH_LIST, &CConfigMain::OnSetRefreshGameListOnClose, this); Bind(wxDOLPHIN_CFG_REFRESH_LIST, &CConfigMain::OnSetRefreshGameListOnClose, this);
Bind(wxDOLPHIN_CFG_RESCAN_LIST, &CConfigMain::OnSetRescanGameListOnClose, this);
wxDialog::SetExtraStyle(GetExtraStyle() & ~wxWS_EX_BLOCK_EVENTS); wxDialog::SetExtraStyle(GetExtraStyle() & ~wxWS_EX_BLOCK_EVENTS);
@ -115,8 +115,8 @@ void CConfigMain::OnClose(wxCloseEvent& WXUNUSED(event))
SConfig::GetInstance().SaveSettings(); SConfig::GetInstance().SaveSettings();
if (m_refresh_game_list_on_close) if (m_event_on_close != wxEVT_NULL)
AddPendingEvent(wxCommandEvent{DOLPHIN_EVT_RELOAD_GAMELIST}); AddPendingEvent(wxCommandEvent{m_event_on_close});
} }
void CConfigMain::OnShow(wxShowEvent& event) void CConfigMain::OnShow(wxShowEvent& event)
@ -132,5 +132,12 @@ void CConfigMain::OnCloseButton(wxCommandEvent& WXUNUSED(event))
void CConfigMain::OnSetRefreshGameListOnClose(wxCommandEvent& WXUNUSED(event)) void CConfigMain::OnSetRefreshGameListOnClose(wxCommandEvent& WXUNUSED(event))
{ {
m_refresh_game_list_on_close = true; // Don't override a rescan
if (m_event_on_close == wxEVT_NULL)
m_event_on_close = DOLPHIN_EVT_REFRESH_GAMELIST;
}
void CConfigMain::OnSetRescanGameListOnClose(wxCommandEvent& WXUNUSED(event))
{
m_event_on_close = DOLPHIN_EVT_RESCAN_GAMELIST;
} }

View File

@ -10,7 +10,10 @@
class wxNotebook; class wxNotebook;
class wxPanel; class wxPanel;
// Fast refresh - can be fulfilled from cache
wxDECLARE_EVENT(wxDOLPHIN_CFG_REFRESH_LIST, wxCommandEvent); wxDECLARE_EVENT(wxDOLPHIN_CFG_REFRESH_LIST, wxCommandEvent);
// Rescan and refresh - modifies cache
wxDECLARE_EVENT(wxDOLPHIN_CFG_RESCAN_LIST, wxCommandEvent);
class CConfigMain : public wxDialog class CConfigMain : public wxDialog
{ {
@ -41,8 +44,8 @@ private:
void OnCloseButton(wxCommandEvent& event); void OnCloseButton(wxCommandEvent& event);
void OnShow(wxShowEvent& event); void OnShow(wxShowEvent& event);
void OnSetRefreshGameListOnClose(wxCommandEvent& event); void OnSetRefreshGameListOnClose(wxCommandEvent& event);
void OnSetRescanGameListOnClose(wxCommandEvent& event);
wxNotebook* Notebook; wxNotebook* Notebook;
wxEventType m_event_on_close;
bool m_refresh_game_list_on_close;
}; };

View File

@ -196,9 +196,8 @@ void InterfaceConfigPane::LoadGUIValues()
void InterfaceConfigPane::LoadThemes() void InterfaceConfigPane::LoadThemes()
{ {
auto sv = Common::DoFileSearch( auto sv =
{""}, {File::GetUserPath(D_THEMES_IDX), File::GetSysDirectory() + THEMES_DIR}, Common::DoFileSearch({File::GetUserPath(D_THEMES_IDX), File::GetSysDirectory() + THEMES_DIR});
/*recursive*/ false);
for (const std::string& filename : sv) for (const std::string& filename : sv)
{ {
std::string name, ext; std::string name, ext;

View File

@ -163,7 +163,7 @@ void PathConfigPane::OnRecursiveISOCheckBoxChanged(wxCommandEvent& event)
{ {
SConfig::GetInstance().m_RecursiveISOFolder = m_recursive_iso_paths_checkbox->IsChecked(); SConfig::GetInstance().m_RecursiveISOFolder = m_recursive_iso_paths_checkbox->IsChecked();
AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_REFRESH_LIST)); AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_RESCAN_LIST));
} }
void PathConfigPane::OnAddISOPath(wxCommandEvent& event) void PathConfigPane::OnAddISOPath(wxCommandEvent& event)
@ -179,7 +179,7 @@ void PathConfigPane::OnAddISOPath(wxCommandEvent& event)
} }
else else
{ {
AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_REFRESH_LIST)); AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_RESCAN_LIST));
m_iso_paths_listbox->Append(dialog.GetPath()); m_iso_paths_listbox->Append(dialog.GetPath());
} }
} }
@ -189,7 +189,7 @@ void PathConfigPane::OnAddISOPath(wxCommandEvent& event)
void PathConfigPane::OnRemoveISOPath(wxCommandEvent& event) void PathConfigPane::OnRemoveISOPath(wxCommandEvent& event)
{ {
AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_REFRESH_LIST)); AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_RESCAN_LIST));
m_iso_paths_listbox->Delete(m_iso_paths_listbox->GetSelection()); m_iso_paths_listbox->Delete(m_iso_paths_listbox->GetSelection());
// This seems to not be activated on Windows when it should be. wxw bug? // This seems to not be activated on Windows when it should be. wxw bug?

View File

@ -337,7 +337,8 @@ CFrame::CFrame(wxFrame* parent, wxWindowID id, const wxString& title, wxRect geo
wxFrame::CreateToolBar(wxTB_DEFAULT_STYLE | wxTB_TEXT | wxTB_FLAT)->Realize(); wxFrame::CreateToolBar(wxTB_DEFAULT_STYLE | wxTB_TEXT | wxTB_FLAT)->Realize();
// Give it a status bar // Give it a status bar
SetStatusBar(CreateStatusBar(2, wxST_SIZEGRIP, ID_STATUSBAR)); SetStatusBar(
CreateStatusBar(2, wxSTB_SIZEGRIP | wxSTB_ELLIPSIZE_END | wxSTB_SHOW_TIPS, ID_STATUSBAR));
if (!SConfig::GetInstance().m_InterfaceStatusbar) if (!SConfig::GetInstance().m_InterfaceStatusbar)
GetStatusBar()->Hide(); GetStatusBar()->Hide();
@ -351,8 +352,9 @@ CFrame::CFrame(wxFrame* parent, wxWindowID id, const wxString& title, wxRect geo
// This panel is the parent for rendering and it holds the gamelistctrl // This panel is the parent for rendering and it holds the gamelistctrl
m_panel = new wxPanel(this, IDM_MPANEL, wxDefaultPosition, wxDefaultSize, 0); m_panel = new wxPanel(this, IDM_MPANEL, wxDefaultPosition, wxDefaultSize, 0);
m_game_list_ctrl = new CGameListCtrl(m_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_game_list_ctrl =
wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT); new GameListCtrl(m_batch_mode, m_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT);
m_game_list_ctrl->Bind(wxEVT_LIST_ITEM_ACTIVATED, &CFrame::OnGameListCtrlItemActivated, this); m_game_list_ctrl->Bind(wxEVT_LIST_ITEM_ACTIVATED, &CFrame::OnGameListCtrlItemActivated, this);
wxBoxSizer* sizerPanel = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* sizerPanel = new wxBoxSizer(wxHORIZONTAL);
@ -490,7 +492,8 @@ void CFrame::BindEvents()
BindMenuBarEvents(); BindMenuBarEvents();
Bind(DOLPHIN_EVT_RELOAD_THEME_BITMAPS, &CFrame::OnReloadThemeBitmaps, this); Bind(DOLPHIN_EVT_RELOAD_THEME_BITMAPS, &CFrame::OnReloadThemeBitmaps, this);
Bind(DOLPHIN_EVT_RELOAD_GAMELIST, &CFrame::OnReloadGameList, this); Bind(DOLPHIN_EVT_REFRESH_GAMELIST, &CFrame::OnRefreshGameList, this);
Bind(DOLPHIN_EVT_RESCAN_GAMELIST, &CFrame::OnRescanGameList, this);
Bind(DOLPHIN_EVT_UPDATE_LOAD_WII_MENU_ITEM, &CFrame::OnUpdateLoadWiiMenuItem, this); Bind(DOLPHIN_EVT_UPDATE_LOAD_WII_MENU_ITEM, &CFrame::OnUpdateLoadWiiMenuItem, this);
Bind(DOLPHIN_EVT_BOOT_SOFTWARE, &CFrame::OnPlay, this); Bind(DOLPHIN_EVT_BOOT_SOFTWARE, &CFrame::OnPlay, this);
Bind(DOLPHIN_EVT_STOP_SOFTWARE, &CFrame::OnStop, this); Bind(DOLPHIN_EVT_STOP_SOFTWARE, &CFrame::OnStop, this);
@ -876,7 +879,7 @@ void CFrame::OnGameListCtrlItemActivated(wxListEvent& WXUNUSED(event))
// 1. Boot the selected iso // 1. Boot the selected iso
// 2. Boot the default or last loaded iso. // 2. Boot the default or last loaded iso.
// 3. Call BrowseForDirectory if the gamelist is empty // 3. Call BrowseForDirectory if the gamelist is empty
if (!m_game_list_ctrl->GetISO(0) && CGameListCtrl::IsHidingItems()) if (!m_game_list_ctrl->GetISO(0) && GameListCtrl::IsHidingItems())
{ {
SConfig::GetInstance().m_ListGC = SConfig::GetInstance().m_ListWii = SConfig::GetInstance().m_ListGC = SConfig::GetInstance().m_ListWii =
SConfig::GetInstance().m_ListWad = SConfig::GetInstance().m_ListElfDol = SConfig::GetInstance().m_ListWad = SConfig::GetInstance().m_ListElfDol =
@ -909,7 +912,7 @@ void CFrame::OnGameListCtrlItemActivated(wxListEvent& WXUNUSED(event))
GetMenuBar()->FindItem(IDM_LIST_WORLD)->Check(true); GetMenuBar()->FindItem(IDM_LIST_WORLD)->Check(true);
GetMenuBar()->FindItem(IDM_LIST_UNKNOWN)->Check(true); GetMenuBar()->FindItem(IDM_LIST_UNKNOWN)->Check(true);
UpdateGameList(); GameListRefresh();
} }
else if (!m_game_list_ctrl->GetISO(0)) else if (!m_game_list_ctrl->GetISO(0))
{ {

View File

@ -33,7 +33,7 @@
struct BootParameters; struct BootParameters;
// Class declarations // Class declarations
class CGameListCtrl; class GameListCtrl;
class CCodeWindow; class CCodeWindow;
class CConfigMain; class CConfigMain;
class CLogWindow; class CLogWindow;
@ -98,10 +98,11 @@ public:
void DoStop(); void DoStop();
void UpdateGUI(); void UpdateGUI();
void UpdateGameList(); void GameListRefresh();
void GameListRescan();
void ToggleLogWindow(bool bShow); void ToggleLogWindow(bool bShow);
void ToggleLogConfigWindow(bool bShow); void ToggleLogConfigWindow(bool bShow);
void StatusBarMessage(const char* Text, ...); void StatusBarMessage(const char* format, ...);
void ClearStatusBar(); void ClearStatusBar();
void BootGame(const std::string& filename); void BootGame(const std::string& filename);
bool RendererHasFocus(); bool RendererHasFocus();
@ -143,7 +144,7 @@ private:
ADD_PANE_CENTER ADD_PANE_CENTER
}; };
CGameListCtrl* m_game_list_ctrl = nullptr; GameListCtrl* m_game_list_ctrl = nullptr;
CConfigMain* m_main_config_dialog = nullptr; CConfigMain* m_main_config_dialog = nullptr;
wxPanel* m_panel = nullptr; wxPanel* m_panel = nullptr;
CRenderFrame* m_render_frame = nullptr; CRenderFrame* m_render_frame = nullptr;
@ -267,7 +268,8 @@ private:
void OnHelp(wxCommandEvent& event); void OnHelp(wxCommandEvent& event);
void OnReloadThemeBitmaps(wxCommandEvent& event); void OnReloadThemeBitmaps(wxCommandEvent& event);
void OnReloadGameList(wxCommandEvent& event); void OnRefreshGameList(wxCommandEvent& event);
void OnRescanGameList(wxCommandEvent& event);
void OnUpdateInterpreterMenuItem(wxUpdateUIEvent& event); void OnUpdateInterpreterMenuItem(wxUpdateUIEvent& event);

View File

@ -511,8 +511,7 @@ void CFrame::OnPerspectiveMenu(wxCommandEvent& event)
return; return;
} }
SaveIniPerspectives(); SaveIniPerspectives();
GetStatusBar()->SetStatusText( StatusBarMessage("Saved %s", m_perspectives[m_active_perspective].name.c_str());
StrToWxStr(std::string("Saved " + m_perspectives[m_active_perspective].name)), 0);
break; break;
case IDM_PERSPECTIVES_ADD_PANE_TOP: case IDM_PERSPECTIVES_ADD_PANE_TOP:
AddPane(ADD_PANE_TOP); AddPane(ADD_PANE_TOP);

View File

@ -774,7 +774,7 @@ void CFrame::OnBootDrive(wxCommandEvent& event)
void CFrame::OnRefresh(wxCommandEvent& WXUNUSED(event)) void CFrame::OnRefresh(wxCommandEvent& WXUNUSED(event))
{ {
UpdateGameList(); GameListRescan();
} }
void CFrame::OnScreenshot(wxCommandEvent& WXUNUSED(event)) void CFrame::OnScreenshot(wxCommandEvent& WXUNUSED(event))
@ -1097,12 +1097,17 @@ void CFrame::OnReloadThemeBitmaps(wxCommandEvent& WXUNUSED(event))
reload_event.SetEventObject(this); reload_event.SetEventObject(this);
wxPostEvent(GetToolBar(), reload_event); wxPostEvent(GetToolBar(), reload_event);
UpdateGameList(); GameListRefresh();
} }
void CFrame::OnReloadGameList(wxCommandEvent& WXUNUSED(event)) void CFrame::OnRefreshGameList(wxCommandEvent& WXUNUSED(event))
{ {
UpdateGameList(); GameListRefresh();
}
void CFrame::OnRescanGameList(wxCommandEvent& WXUNUSED(event))
{
GameListRescan();
} }
void CFrame::OnUpdateInterpreterMenuItem(wxUpdateUIEvent& event) void CFrame::OnUpdateInterpreterMenuItem(wxUpdateUIEvent& event)
@ -1128,18 +1133,16 @@ void CFrame::ClearStatusBar()
} }
} }
void CFrame::StatusBarMessage(const char* Text, ...) void CFrame::StatusBarMessage(const char* format, ...)
{ {
const int MAX_BYTES = 1024 * 10; va_list args;
char Str[MAX_BYTES]; va_start(args, format);
va_list ArgPtr; std::string msg = StringFromFormatV(format, args);
va_start(ArgPtr, Text); va_end(args);
vsnprintf(Str, MAX_BYTES, Text, ArgPtr);
va_end(ArgPtr);
if (this->GetStatusBar()->IsEnabled()) if (this->GetStatusBar()->IsEnabled())
{ {
this->GetStatusBar()->SetStatusText(StrToWxStr(Str), 0); this->GetStatusBar()->SetStatusText(StrToWxStr(msg), 0);
} }
} }
@ -1605,9 +1608,16 @@ void CFrame::UpdateGUI()
} }
} }
void CFrame::UpdateGameList() void CFrame::GameListRefresh()
{ {
wxCommandEvent event{DOLPHIN_EVT_RELOAD_GAMELIST, GetId()}; wxCommandEvent event{DOLPHIN_EVT_REFRESH_GAMELIST, GetId()};
event.SetEventObject(this);
wxPostEvent(m_game_list_ctrl, event);
}
void CFrame::GameListRescan()
{
wxCommandEvent event{DOLPHIN_EVT_RESCAN_GAMELIST, GetId()};
event.SetEventObject(this); event.SetEventObject(this);
wxPostEvent(m_game_list_ctrl, event); wxPostEvent(m_game_list_ctrl, event);
} }
@ -1674,17 +1684,19 @@ void CFrame::GameListChanged(wxCommandEvent& event)
SConfig::GetInstance().m_ListDrives = event.IsChecked(); SConfig::GetInstance().m_ListDrives = event.IsChecked();
break; break;
case IDM_PURGE_GAME_LIST_CACHE: case IDM_PURGE_GAME_LIST_CACHE:
std::vector<std::string> rFilenames = std::vector<std::string> filenames =
Common::DoFileSearch({".cache"}, {File::GetUserPath(D_CACHE_IDX)}); Common::DoFileSearch({File::GetUserPath(D_CACHE_IDX)}, {".cache"});
for (const std::string& rFilename : rFilenames) for (const std::string& filename : filenames)
{ {
File::Delete(rFilename); File::Delete(filename);
} }
break; // Do rescan after cache has been cleared
GameListRescan();
return;
} }
UpdateGameList(); GameListRefresh();
} }
// Enable and disable the toolbar // Enable and disable the toolbar
@ -1743,6 +1755,6 @@ void CFrame::OnChangeColumnsVisible(wxCommandEvent& event)
default: default:
return; return;
} }
UpdateGameList(); GameListRefresh();
SConfig::GetInstance().SaveSettings(); SConfig::GetInstance().SaveSettings();
} }

File diff suppressed because it is too large Load Diff

View File

@ -7,11 +7,15 @@
#include <cstddef> #include <cstddef>
#include <memory> #include <memory>
#include <string> #include <string>
#include <thread>
#include <vector> #include <vector>
#include <wx/listctrl.h> #include <wx/listctrl.h>
#include <wx/tipwin.h> #include <wx/tipwin.h>
#include "Common/ChunkFile.h"
#include "Common/Event.h"
#include "Common/Flag.h"
#include "DolphinWX/ISOFile.h" #include "DolphinWX/ISOFile.h"
class wxEmuStateTip : public wxTipWindow class wxEmuStateTip : public wxTipWindow
@ -31,26 +35,27 @@ public:
} }
}; };
wxDECLARE_EVENT(DOLPHIN_EVT_RELOAD_GAMELIST, wxCommandEvent); wxDECLARE_EVENT(DOLPHIN_EVT_REFRESH_GAMELIST, wxCommandEvent);
wxDECLARE_EVENT(DOLPHIN_EVT_RESCAN_GAMELIST, wxCommandEvent);
class CGameListCtrl : public wxListCtrl class GameListCtrl : public wxListCtrl
{ {
public: public:
CGameListCtrl(wxWindow* parent, const wxWindowID id, const wxPoint& pos, const wxSize& size, GameListCtrl(bool disable_scanning, wxWindow* parent, const wxWindowID id, const wxPoint& pos,
long style); const wxSize& size, long style);
~CGameListCtrl(); ~GameListCtrl();
void BrowseForDirectory(); void BrowseForDirectory();
const GameListItem* GetISO(size_t index) const; const GameListItem* GetISO(size_t index) const;
const GameListItem* GetSelectedISO() const; const GameListItem* GetSelectedISO() const;
std::vector<const GameListItem*> GetAllSelectedISOs() const;
static bool IsHidingItems(); static bool IsHidingItems();
enum enum
{ {
COLUMN_DUMMY = 0, COLUMN_DUMMY = 0,
COLUMN_PLATFORM, FIRST_COLUMN_WITH_CONTENT,
COLUMN_PLATFORM = FIRST_COLUMN_WITH_CONTENT,
COLUMN_BANNER, COLUMN_BANNER,
COLUMN_TITLE, COLUMN_TITLE,
COLUMN_MAKER, COLUMN_MAKER,
@ -69,17 +74,19 @@ public:
private: private:
struct ColumnInfo; struct ColumnInfo;
void ReloadList();
void ClearIsoFiles() { m_ISOFiles.clear(); }
void InitBitmaps(); void InitBitmaps();
void UpdateItemAtColumn(long _Index, int column); void UpdateItemAtColumn(long index, int column);
void InsertItemInReportView(long _Index); void InsertItemInReportView(long index);
void SetColors(); void SetColors();
void ScanForISOs(); void RefreshList();
void RescanList();
void DoState(PointerWrap* p, u32 size = 0);
bool SyncCacheFile(bool write);
std::vector<const GameListItem*> GetAllSelectedISOs() const;
// events // events
void OnReloadGameList(wxCommandEvent& event); void OnRefreshGameList(wxCommandEvent& event);
void OnRescanGameList(wxCommandEvent& event);
void OnLeftClick(wxMouseEvent& event); void OnLeftClick(wxMouseEvent& event);
void OnRightClick(wxMouseEvent& event); void OnRightClick(wxMouseEvent& event);
void OnMouseMotion(wxMouseEvent& event); void OnMouseMotion(wxMouseEvent& event);
@ -109,16 +116,27 @@ private:
static bool MultiCompressCB(const std::string& text, float percent, void* arg); static bool MultiCompressCB(const std::string& text, float percent, void* arg);
static bool WiiCompressWarning(); static bool WiiCompressWarning();
std::vector<int> m_FlagImageIndex; struct
std::vector<int> m_PlatformImageIndex; {
std::vector<int> m_EmuStateImageIndex; std::vector<int> flag;
std::vector<int> m_utility_game_banners; std::vector<int> platform;
std::vector<std::unique_ptr<GameListItem>> m_ISOFiles; std::vector<int> utility_banner;
std::vector<int> emu_state;
} m_image_indexes;
int last_column; // Actual backing GameListItems are maintained in a background thread and cached to file
int last_sort; static constexpr u32 CACHE_REVISION = 0;
wxSize lastpos; std::list<std::shared_ptr<GameListItem>> m_cached_files;
wxEmuStateTip* toolTip; std::thread m_scan_thread;
Common::Event m_scan_trigger;
Common::Flag m_scan_exiting;
// UI thread's view into the cache
std::vector<std::shared_ptr<GameListItem>> m_shown_files;
int m_last_column;
int m_last_sort;
wxSize m_lastpos;
wxEmuStateTip* m_tooltip;
std::vector<ColumnInfo> m_columns; std::vector<ColumnInfo> m_columns;
}; };

View File

@ -38,8 +38,6 @@
#include "DolphinWX/ISOFile.h" #include "DolphinWX/ISOFile.h"
#include "DolphinWX/WxUtils.h" #include "DolphinWX/WxUtils.h"
static const u32 CACHE_REVISION = 0x129; // Last changed in PR 5102
static std::string GetLanguageString(DiscIO::Language language, static std::string GetLanguageString(DiscIO::Language language,
std::map<DiscIO::Language, std::string> strings) std::map<DiscIO::Language, std::string> strings)
{ {
@ -69,26 +67,8 @@ GameListItem::GameListItem(const std::string& _rFileName, const Core::TitleDatab
m_Revision(0), m_Valid(false), m_ImageWidth(0), m_ImageHeight(0), m_disc_number(0), m_Revision(0), m_Valid(false), m_ImageWidth(0), m_ImageHeight(0), m_disc_number(0),
m_has_custom_name(false) m_has_custom_name(false)
{ {
if (LoadFromCache())
{
m_Valid = true;
// Wii banners can only be read if there is a savefile,
// so sometimes caches don't contain banners. Let's check
// if a banner has become available after the cache was made.
if (m_pImage.empty())
{
std::vector<u32> buffer =
DiscIO::Volume::GetWiiBanner(&m_ImageWidth, &m_ImageHeight, m_title_id);
ReadVolumeBanner(buffer, m_ImageWidth, m_ImageHeight);
if (!m_pImage.empty())
SaveToCache();
}
}
else
{ {
std::unique_ptr<DiscIO::Volume> volume(DiscIO::CreateVolumeFromFilename(_rFileName)); std::unique_ptr<DiscIO::Volume> volume(DiscIO::CreateVolumeFromFilename(_rFileName));
if (volume != nullptr) if (volume != nullptr)
{ {
m_Platform = volume->GetVolumeType(); m_Platform = volume->GetVolumeType();
@ -116,7 +96,6 @@ GameListItem::GameListItem(const std::string& _rFileName, const Core::TitleDatab
ReadVolumeBanner(buffer, m_ImageWidth, m_ImageHeight); ReadVolumeBanner(buffer, m_ImageWidth, m_ImageHeight);
m_Valid = true; m_Valid = true;
SaveToCache();
} }
} }
@ -138,37 +117,28 @@ GameListItem::GameListItem(const std::string& _rFileName, const Core::TitleDatab
m_FileSize = File::GetSize(_rFileName); m_FileSize = File::GetSize(_rFileName);
m_Platform = DiscIO::Platform::ELF_DOL; m_Platform = DiscIO::Platform::ELF_DOL;
m_blob_type = DiscIO::BlobType::DIRECTORY; m_blob_type = DiscIO::BlobType::DIRECTORY;
std::string path, name;
SplitPath(m_FileName, &path, &name, nullptr);
// A bit like the Homebrew Channel icon, except there can be multiple files
// in a folder with their own icons. Useful for those who don't want to have
// a Homebrew Channel-style folder structure.
if (SetWxBannerFromPngFile(path + name + ".png"))
return;
// Homebrew Channel icon. Typical for DOLs and ELFs,
// but can be also used with volumes.
if (SetWxBannerFromPngFile(path + "icon.png"))
return;
} }
else
std::string path, name;
SplitPath(m_FileName, &path, &name, nullptr);
// A bit like the Homebrew Channel icon, except there can be multiple files
// in a folder with their own icons. Useful for those who don't want to have
// a Homebrew Channel-style folder structure.
if (ReadPNGBanner(path + name + ".png"))
return;
// Homebrew Channel icon. Typical for DOLs and ELFs,
// but can be also used with volumes.
if (ReadPNGBanner(path + "icon.png"))
return;
// Volume banner. Typical for everything that isn't a DOL or ELF.
if (!m_pImage.empty())
{ {
// Need to make explicit copy as wxImage uses reference counting for copies combined with only // Volume banner. Typical for everything that isn't a DOL or ELF.
// taking a pointer, not the content, when given a buffer to its constructor. SetWxBannerFromRaw();
m_image.Create(m_ImageWidth, m_ImageHeight, false);
std::memcpy(m_image.GetData(), m_pImage.data(), m_pImage.size());
return;
} }
} }
GameListItem::~GameListItem()
{
}
bool GameListItem::IsValid() const bool GameListItem::IsValid() const
{ {
if (!m_Valid) if (!m_Valid)
@ -198,37 +168,35 @@ void GameListItem::ReloadINI()
} }
} }
bool GameListItem::LoadFromCache()
{
return CChunkFileReader::Load<GameListItem>(CreateCacheFilename(), CACHE_REVISION, *this);
}
void GameListItem::SaveToCache()
{
if (!File::IsDirectory(File::GetUserPath(D_CACHE_IDX)))
File::CreateDir(File::GetUserPath(D_CACHE_IDX));
CChunkFileReader::Save<GameListItem>(CreateCacheFilename(), CACHE_REVISION, *this);
}
void GameListItem::DoState(PointerWrap& p) void GameListItem::DoState(PointerWrap& p)
{ {
p.Do(m_FileName);
p.Do(m_names); p.Do(m_names);
p.Do(m_descriptions); p.Do(m_descriptions);
p.Do(m_company); p.Do(m_company);
p.Do(m_game_id); p.Do(m_game_id);
p.Do(m_title_id); p.Do(m_title_id);
p.Do(m_issues);
p.Do(m_emu_state);
p.Do(m_FileSize); p.Do(m_FileSize);
p.Do(m_VolumeSize); p.Do(m_VolumeSize);
p.Do(m_region); p.Do(m_region);
p.Do(m_Country); p.Do(m_Country);
p.Do(m_Platform);
p.Do(m_blob_type); p.Do(m_blob_type);
p.Do(m_Revision);
p.Do(m_pImage); p.Do(m_pImage);
p.Do(m_Valid);
p.Do(m_ImageWidth); p.Do(m_ImageWidth);
p.Do(m_ImageHeight); p.Do(m_ImageHeight);
p.Do(m_Platform);
p.Do(m_disc_number); p.Do(m_disc_number);
p.Do(m_Revision); p.Do(m_custom_name_titles_txt);
p.Do(m_custom_name);
p.Do(m_has_custom_name);
if (p.GetMode() == PointerWrap::MODE_READ)
{
SetWxBannerFromRaw();
}
} }
bool GameListItem::IsElfOrDol() const bool GameListItem::IsElfOrDol() const
@ -241,27 +209,6 @@ bool GameListItem::IsElfOrDol() const
return name_end == ".elf" || name_end == ".dol"; return name_end == ".elf" || name_end == ".dol";
} }
std::string GameListItem::CreateCacheFilename() const
{
std::string Filename, LegalPathname, extension;
SplitPath(m_FileName, &LegalPathname, &Filename, &extension);
if (Filename.empty())
return Filename; // Disc Drive
// Filename.extension_HashOfFolderPath_Size.cache
// Append hash to prevent ISO name-clashing in different folders.
Filename.append(
StringFromFormat("%s_%x_%" PRIx64 ".cache", extension.c_str(),
HashFletcher((const u8*)LegalPathname.c_str(), LegalPathname.size()),
File::GetSize(m_FileName)));
std::string fullname(File::GetUserPath(D_CACHE_IDX));
fullname += Filename;
return fullname;
}
// Outputs to m_pImage
void GameListItem::ReadVolumeBanner(const std::vector<u32>& buffer, int width, int height) void GameListItem::ReadVolumeBanner(const std::vector<u32>& buffer, int width, int height)
{ {
m_pImage.resize(width * height * 3); m_pImage.resize(width * height * 3);
@ -273,8 +220,7 @@ void GameListItem::ReadVolumeBanner(const std::vector<u32>& buffer, int width, i
} }
} }
// Outputs to m_Bitmap bool GameListItem::SetWxBannerFromPngFile(const std::string& path)
bool GameListItem::ReadPNGBanner(const std::string& path)
{ {
if (!File::Exists(path)) if (!File::Exists(path))
return false; return false;
@ -287,6 +233,37 @@ bool GameListItem::ReadPNGBanner(const std::string& path)
return true; return true;
} }
void GameListItem::SetWxBannerFromRaw()
{
// Need to make explicit copy as wxImage uses reference counting for copies combined with only
// taking a pointer, not the content, when given a buffer to its constructor.
if (!m_pImage.empty())
{
m_image.Create(m_ImageWidth, m_ImageHeight, false);
std::memcpy(m_image.GetData(), m_pImage.data(), m_pImage.size());
}
}
bool GameListItem::ReloadBannerIfNeeded()
{
// Wii banners can only be read if there is a savefile,
// so sometimes caches don't contain banners. Let's check
// if a banner has become available after the cache was made.
if ((m_Platform == DiscIO::Platform::WII_DISC || m_Platform == DiscIO::Platform::WII_WAD) &&
m_pImage.empty())
{
std::vector<u32> buffer =
DiscIO::Volume::GetWiiBanner(&m_ImageWidth, &m_ImageHeight, m_title_id);
if (buffer.size())
{
ReadVolumeBanner(buffer, m_ImageWidth, m_ImageHeight);
SetWxBannerFromRaw();
return true;
}
}
return false;
}
std::string GameListItem::GetDescription(DiscIO::Language language) const std::string GameListItem::GetDescription(DiscIO::Language language) const
{ {
return GetLanguageString(language, m_descriptions); return GetLanguageString(language, m_descriptions);

View File

@ -32,8 +32,9 @@ class PointerWrap;
class GameListItem class GameListItem
{ {
public: public:
GameListItem() = default;
GameListItem(const std::string& file_name, const Core::TitleDatabase& title_database); GameListItem(const std::string& file_name, const Core::TitleDatabase& title_database);
~GameListItem(); ~GameListItem() = default;
// Reload settings after INI changes // Reload settings after INI changes
void ReloadINI(); void ReloadINI();
@ -65,8 +66,20 @@ public:
// to display it // to display it
const wxImage& GetBannerImage() const { return m_image; } const wxImage& GetBannerImage() const { return m_image; }
void DoState(PointerWrap& p); void DoState(PointerWrap& p);
bool ReloadBannerIfNeeded();
private: private:
bool IsElfOrDol() const;
// Outputs to m_pImage
void ReadVolumeBanner(const std::vector<u32>& buffer, int width, int height);
// Outputs to m_image
bool SetWxBannerFromPngFile(const std::string& path);
void SetWxBannerFromRaw();
// IMPORTANT: All data members must be save/restored in DoState.
// If anything is changed, make sure DoState handles it properly and
// GameListCtrl::CACHE_REVISION is incremented.
std::string m_FileName; std::string m_FileName;
std::map<DiscIO::Language, std::string> m_names; std::map<DiscIO::Language, std::string> m_names;
@ -97,15 +110,4 @@ private:
std::string m_custom_name_titles_txt; // Custom title from titles.txt std::string m_custom_name_titles_txt; // Custom title from titles.txt
std::string m_custom_name; // Custom title from INI or titles.txt std::string m_custom_name; // Custom title from INI or titles.txt
bool m_has_custom_name; bool m_has_custom_name;
bool LoadFromCache();
void SaveToCache();
bool IsElfOrDol() const;
std::string CreateCacheFilename() const;
// Outputs to m_pImage
void ReadVolumeBanner(const std::vector<u32>& buffer, int width, int height);
// Outputs to m_Bitmap
bool ReadPNGBanner(const std::string& path);
}; };

View File

@ -264,7 +264,7 @@ void InputConfigDialog::UpdateProfileComboBox()
pname += PROFILES_PATH; pname += PROFILES_PATH;
pname += m_config.GetProfileName(); pname += m_config.GetProfileName();
std::vector<std::string> sv = Common::DoFileSearch({".ini"}, {pname}); std::vector<std::string> sv = Common::DoFileSearch({pname}, {".ini"});
wxArrayString strs; wxArrayString strs;
for (const std::string& filename : sv) for (const std::string& filename : sv)

View File

@ -208,9 +208,6 @@ void DolphinApp::MacOpenFile(const wxString& fileName)
void DolphinApp::AfterInit() void DolphinApp::AfterInit()
{ {
if (!m_batch_mode)
main_frame->UpdateGameList();
#if defined(USE_ANALYTICS) && USE_ANALYTICS #if defined(USE_ANALYTICS) && USE_ANALYTICS
if (!SConfig::GetInstance().m_analytics_permission_asked) if (!SConfig::GetInstance().m_analytics_permission_asked)
{ {
@ -481,7 +478,7 @@ void Host_SetWiiMoteConnectionState(int _State)
event.SetString(_("Wii Remote Connected")); event.SetString(_("Wii Remote Connected"));
break; break;
} }
// Update field 1 or 2 // The second field is used for auxiliary info such as this
event.SetInt(1); event.SetInt(1);
NOTICE_LOG(WIIMOTE, "%s", static_cast<const char*>(event.GetString().c_str())); NOTICE_LOG(WIIMOTE, "%s", static_cast<const char*>(event.GetString().c_str()));

View File

@ -9,7 +9,7 @@
#include "DolphinWX/NetPlay/ChangeGameDialog.h" #include "DolphinWX/NetPlay/ChangeGameDialog.h"
#include "DolphinWX/NetPlay/NetWindow.h" #include "DolphinWX/NetPlay/NetWindow.h"
ChangeGameDialog::ChangeGameDialog(wxWindow* parent, const CGameListCtrl* const game_list) ChangeGameDialog::ChangeGameDialog(wxWindow* parent, const GameListCtrl* const game_list)
: wxDialog(parent, wxID_ANY, _("Select Game")) : wxDialog(parent, wxID_ANY, _("Select Game"))
{ {
const int space5 = FromDIP(5); const int space5 = FromDIP(5);

View File

@ -6,13 +6,13 @@
#include <wx/dialog.h> #include <wx/dialog.h>
class CGameListCtrl; class GameListCtrl;
class wxListBox; class wxListBox;
class ChangeGameDialog final : public wxDialog class ChangeGameDialog final : public wxDialog
{ {
public: public:
ChangeGameDialog(wxWindow* parent, const CGameListCtrl* const game_list); ChangeGameDialog(wxWindow* parent, const GameListCtrl* const game_list);
wxString GetChosenGameName() const; wxString GetChosenGameName() const;

View File

@ -8,7 +8,7 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/IniFile.h" #include "Common/IniFile.h"
class CGameListCtrl; class GameListCtrl;
class wxRect; class wxRect;
class wxWindow; class wxWindow;
@ -24,7 +24,7 @@ public:
const wxRect window_defaults{wxDefaultCoord, wxDefaultCoord, 768, 768 - 128}; const wxRect window_defaults{wxDefaultCoord, wxDefaultCoord, 768, 768 - 128};
std::string player_name; std::string player_name;
const CGameListCtrl* game_list_ctrl; const GameListCtrl* game_list_ctrl;
wxWindow* parent_window; wxWindow* parent_window;
bool use_traversal; bool use_traversal;
std::string traversal_host; std::string traversal_host;

View File

@ -36,7 +36,7 @@ wxString GetTraversalLabelText(IniFile::Section& section)
} }
} // Anonymous namespace } // Anonymous namespace
NetPlaySetupFrame::NetPlaySetupFrame(wxWindow* const parent, const CGameListCtrl* const game_list) NetPlaySetupFrame::NetPlaySetupFrame(wxWindow* const parent, const GameListCtrl* const game_list)
: wxFrame(parent, wxID_ANY, _("Dolphin NetPlay Setup")), m_game_list(game_list) : wxFrame(parent, wxID_ANY, _("Dolphin NetPlay Setup")), m_game_list(game_list)
{ {
IniFile inifile; IniFile inifile;

View File

@ -8,7 +8,7 @@
#include <string> #include <string>
#include <wx/frame.h> #include <wx/frame.h>
class CGameListCtrl; class GameListCtrl;
class wxCheckBox; class wxCheckBox;
class wxChoice; class wxChoice;
class wxListBox; class wxListBox;
@ -20,7 +20,7 @@ class wxTextCtrl;
class NetPlaySetupFrame final : public wxFrame class NetPlaySetupFrame final : public wxFrame
{ {
public: public:
NetPlaySetupFrame(wxWindow* const parent, const CGameListCtrl* const game_list); NetPlaySetupFrame(wxWindow* const parent, const GameListCtrl* const game_list);
~NetPlaySetupFrame(); ~NetPlaySetupFrame();
private: private:
@ -66,5 +66,5 @@ private:
#endif #endif
wxString m_traversal_string; wxString m_traversal_string;
const CGameListCtrl* const m_game_list; const GameListCtrl* const m_game_list;
}; };

View File

@ -58,13 +58,13 @@ NetPlayServer* NetPlayDialog::netplay_server = nullptr;
NetPlayClient* NetPlayDialog::netplay_client = nullptr; NetPlayClient* NetPlayDialog::netplay_client = nullptr;
NetPlayDialog* NetPlayDialog::npd = nullptr; NetPlayDialog* NetPlayDialog::npd = nullptr;
void NetPlayDialog::FillWithGameNames(wxListBox* game_lbox, const CGameListCtrl& game_list) void NetPlayDialog::FillWithGameNames(wxListBox* game_lbox, const GameListCtrl& game_list)
{ {
for (u32 i = 0; auto game = game_list.GetISO(i); ++i) for (u32 i = 0; auto game = game_list.GetISO(i); ++i)
game_lbox->Append(StrToWxStr(game->GetUniqueIdentifier())); game_lbox->Append(StrToWxStr(game->GetUniqueIdentifier()));
} }
NetPlayDialog::NetPlayDialog(wxWindow* const parent, const CGameListCtrl* const game_list, NetPlayDialog::NetPlayDialog(wxWindow* const parent, const GameListCtrl* const game_list,
const std::string& game, const bool is_hosting) const std::string& game, const bool is_hosting)
: wxFrame(parent, wxID_ANY, _("Dolphin NetPlay")), m_selected_game(game), m_start_btn(nullptr), : 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_label(nullptr), m_host_type_choice(nullptr), m_host_copy_btn(nullptr),

View File

@ -25,7 +25,7 @@
#include <wx/msw/winundef.h> #include <wx/msw/winundef.h>
#endif #endif
class CGameListCtrl; class GameListCtrl;
class MD5Dialog; class MD5Dialog;
class wxButton; class wxButton;
class wxCheckBox; class wxCheckBox;
@ -78,7 +78,7 @@ enum class MD5Target
class NetPlayDialog : public wxFrame, public NetPlayUI class NetPlayDialog : public wxFrame, public NetPlayUI
{ {
public: public:
NetPlayDialog(wxWindow* parent, const CGameListCtrl* const game_list, const std::string& game, NetPlayDialog(wxWindow* parent, const GameListCtrl* const game_list, const std::string& game,
const bool is_hosting = false); const bool is_hosting = false);
~NetPlayDialog(); ~NetPlayDialog();
@ -107,7 +107,7 @@ public:
static NetPlayDialog*& GetInstance() { return npd; } static NetPlayDialog*& GetInstance() { return npd; }
static NetPlayClient*& GetNetPlayClient() { return netplay_client; } static NetPlayClient*& GetNetPlayClient() { return netplay_client; }
static NetPlayServer*& GetNetPlayServer() { return netplay_server; } static NetPlayServer*& GetNetPlayServer() { return netplay_server; }
static void FillWithGameNames(wxListBox* game_lbox, const CGameListCtrl& game_list); static void FillWithGameNames(wxListBox* game_lbox, const GameListCtrl& game_list);
bool IsRecording() override; bool IsRecording() override;
@ -163,7 +163,7 @@ private:
std::vector<int> m_playerids; std::vector<int> m_playerids;
Common::FifoQueue<std::string> m_chat_msgs; Common::FifoQueue<std::string> m_chat_msgs;
const CGameListCtrl* const m_game_list; const GameListCtrl* const m_game_list;
static NetPlayDialog* npd; static NetPlayDialog* npd;
static NetPlayServer* netplay_server; static NetPlayServer* netplay_server;

View File

@ -97,7 +97,7 @@ void HiresTexture::Update()
}; };
std::vector<std::string> filenames = std::vector<std::string> filenames =
Common::DoFileSearch(extensions, {texture_directory}, /*recursive*/ true); Common::DoFileSearch({texture_directory}, extensions, /*recursive*/ true);
const std::string code = game_id + "_"; const std::string code = game_id + "_";

View File

@ -31,8 +31,9 @@ PostProcessingShaderImplementation::~PostProcessingShaderImplementation()
static std::vector<std::string> GetShaders(const std::string& sub_dir = "") static std::vector<std::string> GetShaders(const std::string& sub_dir = "")
{ {
std::vector<std::string> paths = std::vector<std::string> paths =
Common::DoFileSearch({".glsl"}, {File::GetUserPath(D_SHADERS_IDX) + sub_dir, Common::DoFileSearch({File::GetUserPath(D_SHADERS_IDX) + sub_dir,
File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir}); File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir},
{".glsl"});
std::vector<std::string> result; std::vector<std::string> result;
for (std::string path : paths) for (std::string path : paths)
{ {