Merge branch 'global-user-directory'

Please read https://wiki.dolphin-emu.org/index.php?title=Controlling_the_Global_User_Directory
for documentation about this feature.

Thanks to neobrain and RachelB for their work on this change, and thanks to
everyone who helped test it.
This commit is contained in:
Pierre Bourdon 2013-09-14 19:24:27 +02:00
commit 24e9aedc14
1640 changed files with 899 additions and 872 deletions

View file

@ -40,18 +40,13 @@
#define SYSDATA_DIR "Sys"
#elif defined __APPLE__
#define SYSDATA_DIR "Contents/Resources/Sys"
#define SHARED_USER_DIR File::GetBundleDirectory() + \
DIR_SEP USERDATA_DIR DIR_SEP
#elif defined ANDROID
#define SYSDATA_DIR "/sdcard/dolphin-emu"
#define SHARED_USER_DIR SYSDATA_DIR
#else
#ifdef DATA_DIR
#define SYSDATA_DIR DATA_DIR "sys"
#define SHARED_USER_DIR DATA_DIR USERDATA_DIR DIR_SEP
#else
#define SYSDATA_DIR "sys"
#define SHARED_USER_DIR ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP
#endif
#endif
@ -64,7 +59,7 @@
#define GC_USER_DIR "GC"
#define WII_USER_DIR "Wii"
#define CONFIG_DIR "Config"
#define GAMECONFIG_DIR "GameConfig"
#define GAMESETTINGS_DIR "GameSettings"
#define MAPS_DIR "Maps"
#define CACHE_DIR "Cache"
#define SHADERCACHE_DIR "ShaderCache"

View file

@ -551,11 +551,24 @@ bool DeleteDirRecursively(const std::string &directory)
// Create directory and copy contents (does not overwrite existing files)
void CopyDir(const std::string &source_path, const std::string &dest_path)
{
#ifndef _WIN32
if (source_path == dest_path) return;
if (!File::Exists(source_path)) return;
if (!File::Exists(dest_path)) File::CreateFullPath(dest_path);
#ifdef _WIN32
WIN32_FIND_DATA ffd;
HANDLE hFind = FindFirstFile(UTF8ToTStr(source_path + "\\*").c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE)
{
FindClose(hFind);
return;
}
do
{
const std::string virtualName(TStrToUTF8(ffd.cFileName));
#else
struct dirent dirent, *result = NULL;
DIR *dirp = opendir(source_path.c_str());
if (!dirp) return;
@ -563,10 +576,9 @@ void CopyDir(const std::string &source_path, const std::string &dest_path)
while (!readdir_r(dirp, &dirent, &result) && result)
{
const std::string virtualName(result->d_name);
#endif
// check for "." and ".."
if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
((virtualName[0] == '.') && (virtualName[1] == '.') &&
(virtualName[2] == '\0')))
if (virtualName == "." || virtualName == "..")
continue;
std::string source, dest;
@ -580,6 +592,10 @@ void CopyDir(const std::string &source_path, const std::string &dest_path)
CopyDir(source, dest);
}
else if (!File::Exists(dest)) File::Copy(source, dest);
#ifdef _WIN32
} while (FindNextFile(hFind, &ffd) != 0);
FindClose(hFind);
#else
}
closedir(dirp);
#endif
@ -643,9 +659,9 @@ std::string GetSysDirectory()
std::string sysDir;
#if defined (__APPLE__)
sysDir = GetBundleDirectory();
sysDir += DIR_SEP;
sysDir += SYSDATA_DIR;
sysDir = GetBundleDirectory() + DIR_SEP + SYSDATA_DIR;
#elif defined (_WIN32)
sysDir = GetExeDirectory() + DIR_SEP + SYSDATA_DIR;
#else
sysDir = SYSDATA_DIR;
#endif
@ -665,7 +681,52 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
if (paths[D_USER_IDX].empty())
{
#ifdef _WIN32
paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
// Detect where the User directory is. There are four different cases (on top of the
// command line flag, which overrides all this):
// 1. HKCU\Software\Dolphin Emulator\LocalUserConfig exists and is true
// -> Use GetExeDirectory()\User
// 2. HKCU\Software\Dolphin Emulator\UserConfigPath exists
// -> Use this as the user directory path
// 3. My Documents exists
// -> Use My Documents\Dolphin Emulator as the User directory path
// 4. Default
// -> Use GetExeDirectory()\User
// Check our registry keys
HKEY hkey;
DWORD local = 0;
TCHAR configPath[MAX_PATH] = {0};
if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Dolphin Emulator"), NULL, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
{
DWORD size = 4;
if (RegQueryValueEx(hkey, TEXT("LocalUserConfig"), NULL, NULL, reinterpret_cast<LPBYTE>(&local), &size) != ERROR_SUCCESS)
local = 0;
size = MAX_PATH;
if (RegQueryValueEx(hkey, TEXT("UserConfigPath"), NULL, NULL, (LPBYTE)configPath, &size) != ERROR_SUCCESS)
configPath[0] = 0;
RegCloseKey(hkey);
}
// Get Program Files path in case we need it.
TCHAR my_documents[MAX_PATH];
bool my_documents_found = SUCCEEDED(SHGetFolderPath(NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, my_documents));
if (local) // Case 1
paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
else if (configPath[0]) // Case 2
paths[D_USER_IDX] = TStrToUTF8(configPath);
else if (my_documents_found) // Case 3
paths[D_USER_IDX] = TStrToUTF8(my_documents) + DIR_SEP "Dolphin Emulator" DIR_SEP;
else // Case 4
paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
// Prettify the path: it will be displayed in some places, we don't want a mix of \ and /.
paths[D_USER_IDX] = ReplaceAll(paths[D_USER_IDX], "\\", DIR_SEP);
// Make sure it ends in DIR_SEP.
if (*paths[D_USER_IDX].rbegin() != DIR_SEP_CHR)
paths[D_USER_IDX] += DIR_SEP;
#else
if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR))
paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
@ -679,7 +740,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
paths[D_WIIROOT_IDX] = paths[D_USER_IDX] + WII_USER_DIR;
paths[D_WIIUSER_IDX] = paths[D_WIIROOT_IDX] + DIR_SEP;
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
paths[D_GAMESETTINGS_IDX] = paths[D_USER_IDX] + GAMESETTINGS_DIR DIR_SEP;
paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
@ -730,37 +791,37 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
break;
case D_USER_IDX:
paths[D_GCUSER_IDX] = paths[D_USER_IDX] + GC_USER_DIR DIR_SEP;
paths[D_WIIROOT_IDX] = paths[D_USER_IDX] + WII_USER_DIR;
paths[D_WIIUSER_IDX] = paths[D_WIIROOT_IDX] + DIR_SEP;
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
paths[D_OPENCL_IDX] = paths[D_USER_IDX] + OPENCL_DIR DIR_SEP;
paths[D_HIRESTEXTURES_IDX] = paths[D_USER_IDX] + HIRES_TEXTURES_DIR DIR_SEP;
paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
paths[D_DUMPDSP_IDX] = paths[D_DUMP_IDX] + DUMP_DSP_DIR DIR_SEP;
paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
paths[D_MAILLOGS_IDX] = paths[D_LOGS_IDX] + MAIL_LOGS_DIR DIR_SEP;
paths[D_WIISYSCONF_IDX] = paths[D_WIIUSER_IDX] + WII_SYSCONF_DIR DIR_SEP;
paths[D_THEMES_IDX] = paths[D_USER_IDX] + THEMES_DIR DIR_SEP;
paths[F_DOLPHINCONFIG_IDX] = paths[D_CONFIG_IDX] + DOLPHIN_CONFIG;
paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
paths[F_WIISYSCONF_IDX] = paths[D_WIISYSCONF_IDX] + WII_SYSCONF;
paths[F_RAMDUMP_IDX] = paths[D_DUMP_IDX] + RAM_DUMP;
paths[F_ARAMDUMP_IDX] = paths[D_DUMP_IDX] + ARAM_DUMP;
paths[F_FAKEVMEMDUMP_IDX] = paths[D_DUMP_IDX] + FAKEVMEM_DUMP;
paths[F_GCSRAM_IDX] = paths[D_GCUSER_IDX] + GC_SRAM;
paths[D_GCUSER_IDX] = paths[D_USER_IDX] + GC_USER_DIR DIR_SEP;
paths[D_WIIROOT_IDX] = paths[D_USER_IDX] + WII_USER_DIR;
paths[D_WIIUSER_IDX] = paths[D_WIIROOT_IDX] + DIR_SEP;
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
paths[D_GAMESETTINGS_IDX] = paths[D_USER_IDX] + GAMESETTINGS_DIR DIR_SEP;
paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
paths[D_OPENCL_IDX] = paths[D_USER_IDX] + OPENCL_DIR DIR_SEP;
paths[D_HIRESTEXTURES_IDX] = paths[D_USER_IDX] + HIRES_TEXTURES_DIR DIR_SEP;
paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
paths[D_DUMPDSP_IDX] = paths[D_DUMP_IDX] + DUMP_DSP_DIR DIR_SEP;
paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
paths[D_MAILLOGS_IDX] = paths[D_LOGS_IDX] + MAIL_LOGS_DIR DIR_SEP;
paths[D_WIISYSCONF_IDX] = paths[D_WIIUSER_IDX] + WII_SYSCONF_DIR DIR_SEP;
paths[D_THEMES_IDX] = paths[D_USER_IDX] + THEMES_DIR DIR_SEP;
paths[F_DOLPHINCONFIG_IDX] = paths[D_CONFIG_IDX] + DOLPHIN_CONFIG;
paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
paths[F_WIISYSCONF_IDX] = paths[D_WIISYSCONF_IDX] + WII_SYSCONF;
paths[F_RAMDUMP_IDX] = paths[D_DUMP_IDX] + RAM_DUMP;
paths[F_ARAMDUMP_IDX] = paths[D_DUMP_IDX] + ARAM_DUMP;
paths[F_FAKEVMEMDUMP_IDX] = paths[D_DUMP_IDX] + FAKEVMEM_DUMP;
paths[F_GCSRAM_IDX] = paths[D_GCUSER_IDX] + GC_SRAM;
break;
case D_CONFIG_IDX:
@ -800,12 +861,10 @@ std::string GetThemeDir(const std::string& theme_name)
{
std::string dir = File::GetUserPath(D_THEMES_IDX) + theme_name + "/";
#if !defined(_WIN32)
// If theme does not exist in user's dir load from shared directory
if (!File::Exists(dir))
dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/";
#endif
dir = GetSysDirectory() + THEMES_DIR "/" + theme_name + "/";
return dir;
}

View file

@ -21,8 +21,8 @@ enum {
D_GCUSER_IDX,
D_WIIROOT_IDX,
D_WIIUSER_IDX,
D_CONFIG_IDX,
D_GAMECONFIG_IDX,
D_CONFIG_IDX, // global settings
D_GAMESETTINGS_IDX, // user-specified settings which override both the global and the default settings (per game)
D_MAPS_IDX,
D_CACHE_IDX,
D_SHADERCACHE_IDX,

View file

@ -20,7 +20,7 @@
namespace {
static void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut)
void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut)
{
if (line[0] == '#')
return;
@ -37,32 +37,15 @@ static void ParseLine(const std::string& line, std::string* keyOut, std::string*
}
std::string* IniFile::Section::GetLine(const char* key, std::string* valueOut)
{
for (std::vector<std::string>::iterator iter = lines.begin(); iter != lines.end(); ++iter)
{
std::string& line = *iter;
std::string lineKey;
ParseLine(line, &lineKey, valueOut);
if (!strcasecmp(lineKey.c_str(), key))
return &line;
}
return 0;
}
void IniFile::Section::Set(const char* key, const char* newValue)
{
std::string value;
std::string* line = GetLine(key, &value);
if (line)
{
// Change the value - keep the key and comment
*line = StripSpaces(key) + " = " + newValue;
}
auto it = values.find(key);
if (it != values.end())
it->second = newValue;
else
{
// The key did not already exist in this section - let's add it.
lines.push_back(std::string(key) + " = " + newValue);
values[key] = newValue;
keys_order.push_back(key);
}
}
@ -74,20 +57,6 @@ void IniFile::Section::Set(const char* key, const std::string& newValue, const s
Delete(key);
}
bool IniFile::Section::Get(const char* key, std::string* value, const char* defaultValue)
{
std::string* line = GetLine(key, value);
if (!line)
{
if (defaultValue)
{
*value = defaultValue;
}
return false;
}
return true;
}
void IniFile::Section::Set(const char* key, const float newValue, const float defaultValue)
{
if (newValue != defaultValue)
@ -126,7 +95,24 @@ void IniFile::Section::Set(const char* key, const std::vector<std::string>& newV
Set(key, temp.c_str());
}
bool IniFile::Section::Get(const char* key, std::vector<std::string>& values)
bool IniFile::Section::Get(const char* key, std::string* value, const char* defaultValue)
{
auto it = values.find(key);
if (it != values.end())
{
*value = it->second;
return true;
}
else if (defaultValue)
{
*value = defaultValue;
return true;
}
else
return false;
}
bool IniFile::Section::Get(const char* key, std::vector<std::string>& out)
{
std::string temp;
bool retval = Get(key, &temp, 0);
@ -145,7 +131,7 @@ bool IniFile::Section::Get(const char* key, std::vector<std::string>& values)
subEnd = temp.find_first_of(",", subStart);
if (subStart != subEnd)
// take from first char until next ,
values.push_back(StripSpaces(temp.substr(subStart, subEnd - subStart)));
out.push_back(StripSpaces(temp.substr(subStart, subEnd - subStart)));
// Find the next non , char
subStart = temp.find_first_not_of(",", subEnd);
@ -206,28 +192,18 @@ bool IniFile::Section::Get(const char* key, double* value, double defaultValue)
bool IniFile::Section::Exists(const char *key) const
{
for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter)
{
std::string lineKey;
ParseLine(*iter, &lineKey, NULL);
if (!strcasecmp(lineKey.c_str(), key))
return true;
}
return false;
return values.find(key) != values.end();
}
bool IniFile::Section::Delete(const char *key)
{
std::string* line = GetLine(key, 0);
for (std::vector<std::string>::iterator liter = lines.begin(); liter != lines.end(); ++liter)
{
if (line == &*liter)
{
lines.erase(liter);
return true;
}
}
return false;
auto it = values.find(key);
if (it == values.end())
return false;
values.erase(it);
keys_order.erase(std::find(keys_order.begin(), keys_order.end(), key));
return true;
}
// IniFile
@ -286,11 +262,7 @@ bool IniFile::Exists(const char* sectionName, const char* key) const
void IniFile::SetLines(const char* sectionName, const std::vector<std::string> &lines)
{
Section* section = GetOrCreateSection(sectionName);
section->lines.clear();
for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter)
{
section->lines.push_back(*iter);
}
section->lines = lines;
}
bool IniFile::DeleteKey(const char* sectionName, const char* key)
@ -298,16 +270,7 @@ bool IniFile::DeleteKey(const char* sectionName, const char* key)
Section* section = GetSection(sectionName);
if (!section)
return false;
std::string* line = section->GetLine(key, 0);
for (std::vector<std::string>::iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
{
if (line == &(*liter))
{
section->lines.erase(liter);
return true;
}
}
return false; //shouldn't happen
return section->Delete(key);
}
// Return a list of all keys in a section
@ -316,13 +279,7 @@ bool IniFile::GetKeys(const char* sectionName, std::vector<std::string>& keys) c
const Section* section = GetSection(sectionName);
if (!section)
return false;
keys.clear();
for (std::vector<std::string>::const_iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
{
std::string key;
ParseLine(*liter, &key, 0);
keys.push_back(key);
}
keys = section->keys_order;
return true;
}
@ -364,13 +321,13 @@ void IniFile::SortSections()
std::sort(sections.begin(), sections.end());
}
bool IniFile::Load(const char* filename)
bool IniFile::Load(const char* filename, bool keep_current_data)
{
// Maximum number of letters in a line
static const int MAX_BYTES = 1024*32;
sections.clear();
sections.push_back(Section(""));
if (!keep_current_data)
sections.clear();
// first section consists of the comments before the first real section
// Open file
@ -379,12 +336,13 @@ bool IniFile::Load(const char* filename)
if (in.fail()) return false;
Section* current_section = NULL;
while (!in.eof())
{
char templine[MAX_BYTES];
in.getline(templine, MAX_BYTES);
std::string line = templine;
#ifndef _WIN32
// Check for CRLF eol and convert it to LF
if (!line.empty() && line.at(line.size()-1) == '\r')
@ -405,12 +363,25 @@ bool IniFile::Load(const char* filename)
{
// New section!
std::string sub = line.substr(1, endpos - 1);
sections.push_back(Section(sub));
current_section = GetOrCreateSection(sub.c_str());
}
}
else
{
sections[sections.size() - 1].lines.push_back(line);
if (current_section)
{
std::string key, value;
ParseLine(line, &key, &value);
// Lines starting with '$' or '+' are kept verbatim. Kind
// of a hack, but the support for raw lines inside an INI
// is a hack anyway.
if ((key == "" && value == "")
|| (line.size() >= 1 && (line[0] == '$' || line[0] == '+')))
current_section->lines.push_back(line.c_str());
else
current_section->Set(key, value.c_str());
}
}
}
}
@ -429,27 +400,33 @@ bool IniFile::Save(const char* filename)
return false;
}
// Currently testing if dolphin community can handle the requirements of C++11 compilation
// If you get a compiler error on this line, your compiler is probably old.
// Update to g++ 4.4 or a recent version of clang (XCode 4.2 on OS X).
// If you don't want to update, complain in a google code issue, the dolphin forums or #dolphin-emu.
for (auto iter = sections.begin(); iter != sections.end(); ++iter)
{
const Section& section = *iter;
if (section.name != "")
{
if (section.keys_order.size() != 0 || section.lines.size() != 0)
out << "[" << section.name << "]" << std::endl;
}
for (std::vector<std::string>::const_iterator liter = section.lines.begin(); liter != section.lines.end(); ++liter)
if (section.keys_order.size() == 0)
{
std::string s = *liter;
out << s << std::endl;
for (auto liter = section.lines.begin(); liter != section.lines.end(); ++liter)
{
std::string s = *liter;
out << s << std::endl;
}
}
else
{
for (auto kvit = section.keys_order.begin(); kvit != section.keys_order.end(); ++kvit)
{
auto pair = section.values.find(*kvit);
out << pair->first << " = " << pair->second << std::endl;
}
}
}
out.close();
return true;
}

View file

@ -6,11 +6,21 @@
#ifndef _INIFILE_H_
#define _INIFILE_H_
#include <map>
#include <string>
#include <set>
#include <vector>
#include "StringUtil.h"
struct CaseInsensitiveStringCompare
{
bool operator() (const std::string& a, const std::string& b) const
{
return strcasecmp(a.c_str(), b.c_str()) < 0;
}
};
class IniFile
{
public:
@ -25,7 +35,6 @@ public:
bool Exists(const char *key) const;
bool Delete(const char *key);
std::string* GetLine(const char* key, std::string* valueOut);
void Set(const char* key, const char* newValue);
void Set(const char* key, const std::string& newValue, const std::string& defaultValue);
@ -68,12 +77,24 @@ public:
}
protected:
std::vector<std::string> lines;
std::string name;
std::vector<std::string> keys_order;
std::map<std::string, std::string, CaseInsensitiveStringCompare> values;
std::vector<std::string> lines;
};
bool Load(const char* filename);
bool Load(const std::string &filename) { return Load(filename.c_str()); }
/**
* Loads sections and keys.
* @param filename filename of the ini file which should be loaded
* @param keep_current_data If true, "extends" the currently loaded list of sections and keys with the loaded data (and replaces existing entries). If false, existing data will be erased.
* @warning Using any other operations than "Get*" and "Exists" is untested and will behave unexpectedly
* @todo This really is just a hack to support having two levels of gameinis (defaults and user-specified) and should eventually be replaced with a less stupid system.
*/
bool Load(const char* filename, bool keep_current_data = false);
bool Load(const std::string &filename, bool keep_current_data = false) { return Load(filename.c_str(), keep_current_data); }
bool Save(const char* filename);
bool Save(const std::string &filename) { return Save(filename.c_str()); }

View file

@ -111,115 +111,121 @@ bool CompareValues(const u32 val1, const u32 val2, const int type);
// ----------------------
// AR Remote Functions
void LoadCodes(IniFile &ini, bool forceLoad)
void LoadCodes(IniFile &globalIni, IniFile &localIni, bool forceLoad)
{
// Parses the Action Replay section of a game ini file.
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableCheats
&& !forceLoad)
return;
std::vector<std::string> lines;
std::vector<std::string> encryptedLines;
ARCode currentCode;
arCodes.clear();
if (!ini.GetLines("ActionReplay", lines))
return; // no codes found.
std::vector<std::string>::const_iterator
it = lines.begin(),
lines_end = lines.end();
for (; it != lines_end; ++it)
std::vector<std::string> enabledLines;
std::set<std::string> enabledNames;
localIni.GetLines("ActionReplay_Enabled", enabledLines);
for (auto iter = enabledLines.begin(); iter != enabledLines.end(); ++iter)
{
const std::string line = *it;
if (line.empty())
continue;
std::vector<std::string> pieces;
// Check if the line is a name of the code
if (line[0] == '+' || line[0] == '$')
const std::string& line = *iter;
if (line.size() != 0 && line[0] == '$')
{
if (currentCode.ops.size())
{
arCodes.push_back(currentCode);
currentCode.ops.clear();
}
if (encryptedLines.size())
{
DecryptARCode(encryptedLines, currentCode.ops);
arCodes.push_back(currentCode);
currentCode.ops.clear();
encryptedLines.clear();
}
if (line.size() > 1)
{
if (line[0] == '+')
{
currentCode.active = true;
currentCode.name = line.substr(2, line.size() - 2);;
if (!forceLoad)
Core::DisplayMessage("AR code active: " + currentCode.name, 5000);
}
else
{
currentCode.active = false;
currentCode.name = line.substr(1, line.size() - 1);
}
}
continue;
std::string name = line.substr(1, line.size() - 1);
enabledNames.insert(name);
}
}
SplitString(line, ' ', pieces);
IniFile* inis[] = {&globalIni, &localIni};
for (size_t i = 0; i < ArraySize(inis); ++i)
{
std::vector<std::string> lines;
std::vector<std::string> encryptedLines;
ARCode currentCode;
inis[i]->GetLines("ActionReplay", lines);
// Check if the AR code is decrypted
if (pieces.size() == 2 && pieces[0].size() == 8 && pieces[1].size() == 8)
std::vector<std::string>::const_iterator
it = lines.begin(),
lines_end = lines.end();
for (; it != lines_end; ++it)
{
AREntry op;
bool success_addr = TryParse(std::string("0x") + pieces[0], &op.cmd_addr);
bool success_val = TryParse(std::string("0x") + pieces[1], &op.value);
if (!(success_addr | success_val)) {
PanicAlertT("Action Replay Error: invalid AR code line: %s", line.c_str());
if (!success_addr) PanicAlertT("The address is invalid");
if (!success_val) PanicAlertT("The value is invalid");
const std::string line = *it;
if (line.empty())
continue;
std::vector<std::string> pieces;
// Check if the line is a name of the code
if (line[0] == '$')
{
if (currentCode.ops.size())
{
arCodes.push_back(currentCode);
currentCode.ops.clear();
}
if (encryptedLines.size())
{
DecryptARCode(encryptedLines, currentCode.ops);
arCodes.push_back(currentCode);
currentCode.ops.clear();
encryptedLines.clear();
}
currentCode.name = line.substr(1, line.size() - 1);
currentCode.active = enabledNames.find(currentCode.name) != enabledNames.end();
currentCode.user_defined = (i == 1);
}
else
{
currentCode.ops.push_back(op);
}
}
else
{
SplitString(line, '-', pieces);
if (pieces.size() == 3 && pieces[0].size() == 4 && pieces[1].size() == 4 && pieces[2].size() == 5)
{
// Encrypted AR code
// Decryption is done in "blocks", so we must push blocks into a vector,
// then send to decrypt when a new block is encountered, or if it's the last block.
encryptedLines.push_back(pieces[0]+pieces[1]+pieces[2]);
}
}
}
SplitString(line, ' ', pieces);
// Handle the last code correctly.
if (currentCode.ops.size())
{
arCodes.push_back(currentCode);
}
if (encryptedLines.size())
{
DecryptARCode(encryptedLines, currentCode.ops);
arCodes.push_back(currentCode);
// Check if the AR code is decrypted
if (pieces.size() == 2 && pieces[0].size() == 8 && pieces[1].size() == 8)
{
AREntry op;
bool success_addr = TryParse(std::string("0x") + pieces[0], &op.cmd_addr);
bool success_val = TryParse(std::string("0x") + pieces[1], &op.value);
if (!(success_addr | success_val)) {
PanicAlertT("Action Replay Error: invalid AR code line: %s", line.c_str());
if (!success_addr) PanicAlertT("The address is invalid");
if (!success_val) PanicAlertT("The value is invalid");
}
else
{
currentCode.ops.push_back(op);
}
}
else
{
SplitString(line, '-', pieces);
if (pieces.size() == 3 && pieces[0].size() == 4 && pieces[1].size() == 4 && pieces[2].size() == 5)
{
// Encrypted AR code
// Decryption is done in "blocks", so we must push blocks into a vector,
// then send to decrypt when a new block is encountered, or if it's the last block.
encryptedLines.push_back(pieces[0]+pieces[1]+pieces[2]);
}
}
}
}
// Handle the last code correctly.
if (currentCode.ops.size())
{
arCodes.push_back(currentCode);
}
if (encryptedLines.size())
{
DecryptARCode(encryptedLines, currentCode.ops);
arCodes.push_back(currentCode);
}
}
UpdateActiveList();
}
void LoadCodes(std::vector<ARCode> &_arCodes, IniFile &ini)
void LoadCodes(std::vector<ARCode> &_arCodes, IniFile &globalIni, IniFile& localIni)
{
LoadCodes(ini, true);
LoadCodes(globalIni, localIni, true);
_arCodes = arCodes;
}

View file

@ -23,12 +23,13 @@ struct ARCode
std::string name;
std::vector<AREntry> ops;
bool active;
bool user_defined;
};
void RunAllActive();
bool RunCode(const ARCode &arcode);
void LoadCodes(IniFile &ini, bool forceLoad);
void LoadCodes(std::vector<ARCode> &_arCodes, IniFile &ini);
void LoadCodes(IniFile &globalIni, IniFile &localIni, bool forceLoad);
void LoadCodes(std::vector<ARCode> &_arCodes, IniFile &globalIni, IniFile &localIni);
size_t GetCodeListSize();
ARCode GetARCode(size_t index);
void SetARCode_IsActive(bool active, size_t index);

View file

@ -71,59 +71,73 @@ void CBoot::UpdateDebugger_MapLoaded(const char *_gameID)
Host_NotifyMapLoaded();
}
std::string CBoot::GenerateMapFilename()
bool CBoot::FindMapFile(std::string* existing_map_file,
std::string* writable_map_file)
{
std::string title_id_str;
SCoreStartupParameter& _StartupPara = SConfig::GetInstance().m_LocalCoreStartupParameter;
switch (_StartupPara.m_BootType)
{
case SCoreStartupParameter::BOOT_WII_NAND:
{
const DiscIO::INANDContentLoader& Loader = DiscIO::CNANDContentManager::Access().GetNANDLoader(_StartupPara.m_strFilename);
const DiscIO::INANDContentLoader& Loader =
DiscIO::CNANDContentManager::Access().GetNANDLoader(_StartupPara.m_strFilename);
if (Loader.IsValid())
{
u64 TitleID = Loader.GetTitleID();
char tmpBuffer[32];
sprintf(tmpBuffer, "%08x_%08x", (u32)(TitleID >> 32) & 0xFFFFFFFF , (u32)TitleID & 0xFFFFFFFF );
return File::GetUserPath(D_MAPS_IDX) + std::string(tmpBuffer) + ".map";
title_id_str = StringFromFormat("%08X_%08X",
(u32)(TitleID >> 32) & 0xFFFFFFFF,
(u32)TitleID & 0xFFFFFFFF);
}
break;
}
case SCoreStartupParameter::BOOT_ELF:
case SCoreStartupParameter::BOOT_DOL:
return _StartupPara.m_strFilename.substr(0, _StartupPara.m_strFilename.size()-4) + ".map";
// Strip the .elf/.dol file extension
title_id_str = _StartupPara.m_strFilename.substr(
0, _StartupPara.m_strFilename.size() - 4);
break;
default:
return File::GetUserPath(D_MAPS_IDX) + _StartupPara.GetUniqueID() + ".map";
title_id_str = _StartupPara.GetUniqueID();
break;
}
return std::string("unknown map");
}
if (writable_map_file)
*writable_map_file = File::GetUserPath(D_MAPS_IDX) + title_id_str + ".map";
bool CBoot::LoadMapFromFilename(const std::string &_rFilename, const char *_gameID)
{
if (_rFilename.size() == 0)
return false;
std::string strMapFilename = GenerateMapFilename();
bool success = false;
if (!g_symbolDB.LoadMap(strMapFilename.c_str()))
bool found = false;
static const std::string maps_directories[] = {
File::GetUserPath(D_MAPS_IDX),
File::GetSysDirectory() + MAPS_DIR DIR_SEP
};
for (size_t i = 0; !found && i < ArraySize(maps_directories); ++i)
{
if (_gameID != NULL)
std::string path = maps_directories[i] + title_id_str + ".map";
if (File::Exists(path))
{
BuildCompleteFilename(strMapFilename, "maps", std::string(_gameID) + ".map");
success = g_symbolDB.LoadMap(strMapFilename.c_str());
found = true;
if (existing_map_file)
*existing_map_file = path;
}
}
else
return found;
}
bool CBoot::LoadMapFromFilename()
{
std::string strMapFilename;
bool found = FindMapFile(&strMapFilename, NULL);
if (found && g_symbolDB.LoadMap(strMapFilename.c_str()))
{
success = true;
UpdateDebugger_MapLoaded();
return true;
}
if (success)
UpdateDebugger_MapLoaded();
return success;
return false;
}
// If ipl.bin is not found, this function does *some* of what BS1 does:
@ -201,10 +215,6 @@ bool CBoot::BootUp()
PanicAlertT("Warning - starting ISO in wrong console mode!");
}
char gameID[7];
memcpy(gameID, pVolume->GetUniqueID().c_str(), 6);
gameID[6] = 0;
// setup the map from ISOFile ID
VolumeHandler::SetVolumeName(_StartupPara.m_strFilename);
@ -252,7 +262,7 @@ bool CBoot::BootUp()
/* Try to load the symbol map if there is one, and then scan it for
and eventually replace code */
if (LoadMapFromFilename(_StartupPara.m_strFilename, gameID))
if (LoadMapFromFilename())
HLE::PatchFunctions();
// We don't need the volume any more
@ -298,7 +308,7 @@ bool CBoot::BootUp()
PC = dolLoader.GetEntryPoint();
}
if (LoadMapFromFilename(_StartupPara.m_strFilename))
if (LoadMapFromFilename())
HLE::PatchFunctions();
break;
@ -368,7 +378,7 @@ bool CBoot::BootUp()
case SCoreStartupParameter::BOOT_WII_NAND:
Boot_WiiWAD(_StartupPara.m_strFilename.c_str());
if (LoadMapFromFilename(_StartupPara.m_strFilename))
if (LoadMapFromFilename())
HLE::PatchFunctions();
// load default image or create virtual drive from directory
@ -387,7 +397,7 @@ bool CBoot::BootUp()
DVDInterface::SetDiscInside(VolumeHandler::IsValid());
if (Load_BS2(_StartupPara.m_strBootROM))
{
if (LoadMapFromFilename(_StartupPara.m_strFilename))
if (LoadMapFromFilename())
HLE::PatchFunctions();
}
else

View file

@ -16,14 +16,26 @@ public:
static bool BootUp();
static bool IsElfWii(const char *filename);
static std::string GenerateMapFilename();
// Tries to find a map file for the current game by looking first in the
// local user directory, then in the shared user directory.
//
// If existing_map_file is not NULL and a map file exists, it is set to the
// path to the existing map file.
//
// If writable_map_file is not NULL, it is set to the path to where a map
// file should be saved.
//
// Returns true if a map file exists, false if none could be found.
static bool FindMapFile(std::string* existing_map_file,
std::string* writable_map_file);
private:
static void RunFunction(u32 _iAddr);
static void UpdateDebugger_MapLoaded(const char* _gameID = NULL);
static bool LoadMapFromFilename(const std::string& _rFilename, const char* _gameID = NULL);
static bool LoadMapFromFilename();
static bool Boot_ELF(const char *filename);
static bool Boot_WiiWAD(const char *filename);

View file

@ -68,7 +68,7 @@ bool CBoot::Boot_ELF(const char *filename)
reader.LoadInto(0x80000000);
if (!reader.LoadSymbols())
{
if (LoadMapFromFilename(filename))
if (LoadMapFromFilename())
HLE::PatchFunctions();
}
else

View file

@ -24,6 +24,7 @@
#include <vector>
#include "Common.h"
#include "CommonPaths.h"
#include "IniFile.h"
#include "BootManager.h"
#include "Volume.h"
@ -73,11 +74,16 @@ bool BootCore(const std::string& _rFilename)
return false;
// Load game specific settings
IniFile game_ini;
std::string unique_id = StartUp.GetUniqueID();
StartUp.m_strGameIni = File::GetUserPath(D_GAMECONFIG_IDX) + unique_id + ".ini";
if (unique_id.size() == 6 && game_ini.Load(StartUp.m_strGameIni.c_str()))
StartUp.m_strGameIniDefault = File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + unique_id + ".ini";
StartUp.m_strGameIniLocal = File::GetUserPath(D_GAMESETTINGS_IDX) + unique_id + ".ini";
if (unique_id.size() == 6)
{
IniFile game_ini;
game_ini.Load(StartUp.m_strGameIniDefault);
game_ini.Load(StartUp.m_strGameIniLocal, true);
config_cache.valid = true;
config_cache.bCPUThread = StartUp.bCPUThread;
config_cache.bSkipIdle = StartUp.bSkipIdle;

View file

@ -167,7 +167,7 @@ void SConfig::SaveSettings()
}
ini.Set("General", "RecursiveGCMPaths", m_RecursiveISOFolder);
ini.Set("General", "NANDRoot", m_NANDPath);
ini.Set("General", "NANDRootPath", m_NANDPath);
ini.Set("General", "WirelessMac", m_WirelessMac);
#ifdef USE_GDBSTUB
ini.Set("General", "GDBPort", m_LocalCoreStartupParameter.iGDBPort);
@ -244,8 +244,8 @@ void SConfig::SaveSettings()
ini.Set("Core", "SelectedLanguage", m_LocalCoreStartupParameter.SelectedLanguage);
ini.Set("Core", "DPL2Decoder", m_LocalCoreStartupParameter.bDPL2Decoder);
ini.Set("Core", "Latency", m_LocalCoreStartupParameter.iLatency);
ini.Set("Core", "MemcardA", m_strMemoryCardA);
ini.Set("Core", "MemcardB", m_strMemoryCardB);
ini.Set("Core", "MemcardAPath", m_strMemoryCardA);
ini.Set("Core", "MemcardBPath", m_strMemoryCardB);
ini.Set("Core", "SlotA", m_EXIDevice[0]);
ini.Set("Core", "SlotB", m_EXIDevice[1]);
ini.Set("Core", "SerialPort1", m_EXIDevice[2]);
@ -318,7 +318,7 @@ void SConfig::LoadSettings()
ini.Get("General", "RecursiveGCMPaths", &m_RecursiveISOFolder, false);
ini.Get("General", "NANDRoot", &m_NANDPath);
ini.Get("General", "NANDRootPath", &m_NANDPath);
m_NANDPath = File::GetUserPath(D_WIIROOT_IDX, m_NANDPath);
DiscIO::cUIDsys::AccessInstance().UpdateLocation();
DiscIO::CSharedContent::AccessInstance().UpdateLocation();
@ -403,8 +403,8 @@ void SConfig::LoadSettings()
ini.Get("Core", "SelectedLanguage", &m_LocalCoreStartupParameter.SelectedLanguage, 0);
ini.Get("Core", "DPL2Decoder", &m_LocalCoreStartupParameter.bDPL2Decoder, false);
ini.Get("Core", "Latency", &m_LocalCoreStartupParameter.iLatency, 2);
ini.Get("Core", "MemcardA", &m_strMemoryCardA);
ini.Get("Core", "MemcardB", &m_strMemoryCardB);
ini.Get("Core", "MemcardAPath", &m_strMemoryCardA);
ini.Get("Core", "MemcardBPath", &m_strMemoryCardB);
ini.Get("Core", "SlotA", (int*)&m_EXIDevice[0], EXIDEVICE_MEMORYCARD);
ini.Get("Core", "SlotB", (int*)&m_EXIDevice[1], EXIDEVICE_NONE);
ini.Get("Core", "SerialPort1", (int*)&m_EXIDevice[2], EXIDEVICE_NONE);

View file

@ -205,7 +205,8 @@ bool Init()
if (g_aspect_wide)
{
IniFile gameIni;
gameIni.Load(_CoreParameter.m_strGameIni.c_str());
gameIni.Load(_CoreParameter.m_strGameIniDefault.c_str());
gameIni.Load(_CoreParameter.m_strGameIniLocal.c_str(), true);
gameIni.Get("Wii", "Widescreen", &g_aspect_wide,
!!SConfig::GetInstance().m_SYSCONF->
GetData<u8>("IPL.AR"));

View file

@ -351,11 +351,7 @@ void SCoreStartupParameter::CheckMemcardPath(std::string& memcardPath, std::stri
{
// Use default memcard path if there is no user defined name
std::string defaultFilename = isSlotA ? GC_MEMCARDA : GC_MEMCARDB;
#ifdef _WIN32
memcardPath = "." + File::GetUserPath(D_GCUSER_IDX).substr(File::GetExeDirectory().size()) + defaultFilename + ext;
#else
memcardPath = File::GetUserPath(D_GCUSER_IDX) + defaultFilename + ext;
#endif
memcardPath = File::GetUserPath(D_GCUSER_IDX) + defaultFilename + ext;
}
else
{

View file

@ -198,7 +198,8 @@ struct SCoreStartupParameter
std::string m_strApploader;
std::string m_strUniqueID;
std::string m_strName;
std::string m_strGameIni;
std::string m_strGameIniDefault;
std::string m_strGameIniLocal;
// Constructor just calls LoadDefaults
SCoreStartupParameter();

View file

@ -15,6 +15,7 @@
namespace Gecko
{
// TODO: Support loading codes from default game inis.
void LoadCodes(const IniFile& inifile, std::vector<GeckoCode>& gcodes)
{
std::vector<std::string> lines;
@ -96,7 +97,7 @@ void SaveGeckoCode(std::vector<std::string>& lines, const GeckoCode& gcode)
}
lines.push_back(name);
// save all the code lines
std::vector<GeckoCode::Code>::const_iterator
codes_iter = gcode.codes.begin(),

View file

@ -20,6 +20,7 @@
#include <map>
#include <algorithm>
#include "CommonPaths.h"
#include "StringUtil.h"
#include "PatchEngine.h"
#include "HW/Memmap.h"
@ -44,22 +45,40 @@ std::vector<Patch> onFrame;
std::map<u32, int> speedHacks;
std::vector<std::string> discList;
void LoadPatchSection(const char *section, std::vector<Patch> &patches, IniFile &ini)
void LoadPatchSection(const char *section, std::vector<Patch> &patches,
IniFile &globalIni, IniFile &localIni)
{
std::vector<std::string> lines;
if (!ini.GetLines(section, lines))
return;
Patch currentPatch;
for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter)
// Load the name of all enabled patches
std::string enabledSectionName = std::string(section) + "_Enabled";
std::vector<std::string> enabledLines;
std::set<std::string> enabledNames;
localIni.GetLines(enabledSectionName.c_str(), enabledLines);
for (auto iter = enabledLines.begin(); iter != enabledLines.end(); ++iter)
{
std::string line = *iter;
if (line.size())
const std::string& line = *iter;
if (line.size() != 0 && line[0] == '$')
{
if (line[0] == '+' || line[0] == '$')
std::string name = line.substr(1, line.size() - 1);
enabledNames.insert(name);
}
}
IniFile* inis[] = {&globalIni, &localIni};
for (size_t i = 0; i < ArraySize(inis); ++i)
{
std::vector<std::string> lines;
Patch currentPatch;
inis[i]->GetLines(section, lines);
for (auto iter = lines.begin(); iter != lines.end(); ++iter)
{
std::string line = *iter;
if (line.size() == 0)
continue;
if (line[0] == '$')
{
// Take care of the previous code
if (currentPatch.name.size())
@ -67,39 +86,38 @@ void LoadPatchSection(const char *section, std::vector<Patch> &patches, IniFile
currentPatch.entries.clear();
// Set active and name
currentPatch.active = (line[0] == '+') ? true : false;
if (currentPatch.active)
currentPatch.name = line.substr(2, line.size() - 2);
else
currentPatch.name = line.substr(1, line.size() - 1);
continue;
currentPatch.name = line.substr(1, line.size() - 1);
currentPatch.active = enabledNames.find(currentPatch.name) != enabledNames.end();
currentPatch.user_defined = (i == 1);
}
std::string::size_type loc = line.find_first_of('=', 0);
if (loc != std::string::npos)
line[loc] = ':';
std::vector<std::string> items;
SplitString(line, ':', items);
if (items.size() >= 3)
else
{
PatchEntry pE;
bool success = true;
success &= TryParse(items[0], &pE.address);
success &= TryParse(items[2], &pE.value);
std::string::size_type loc = line.find_first_of('=', 0);
pE.type = PatchType(std::find(PatchTypeStrings, PatchTypeStrings + 3, items[1]) - PatchTypeStrings);
success &= (pE.type != (PatchType)3);
if (success)
currentPatch.entries.push_back(pE);
if (loc != std::string::npos)
line[loc] = ':';
std::vector<std::string> items;
SplitString(line, ':', items);
if (items.size() >= 3)
{
PatchEntry pE;
bool success = true;
success &= TryParse(items[0], &pE.address);
success &= TryParse(items[2], &pE.value);
pE.type = PatchType(std::find(PatchTypeStrings, PatchTypeStrings + 3, items[1]) - PatchTypeStrings);
success &= (pE.type != (PatchType)3);
if (success)
currentPatch.entries.push_back(pE);
}
}
}
}
if (currentPatch.name.size() && currentPatch.entries.size())
patches.push_back(currentPatch);
if (currentPatch.name.size() && currentPatch.entries.size())
patches.push_back(currentPatch);
}
}
static void LoadDiscList(const char *section, std::vector<std::string> &_discList, IniFile &ini)
@ -150,22 +168,24 @@ int GetSpeedhackCycles(const u32 addr)
void LoadPatches(const char *gameID)
{
IniFile ini;
std::string filename = File::GetUserPath(D_GAMECONFIG_IDX) + gameID + ".ini";
IniFile globalIni, localIni;
globalIni.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + gameID + ".ini");
localIni.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + gameID + ".ini", true);
if (ini.Load(filename.c_str()))
{
LoadPatchSection("OnFrame", onFrame, ini);
ActionReplay::LoadCodes(ini, false);
// lil silly
std::vector<Gecko::GeckoCode> gcodes;
Gecko::LoadCodes(ini, gcodes);
Gecko::SetActiveCodes(gcodes);
IniFile merged;
merged.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + gameID + ".ini");
merged.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + gameID + ".ini", true);
LoadSpeedhacks("Speedhacks", speedHacks, ini);
LoadDiscList("DiscList", discList, ini);
}
LoadPatchSection("OnFrame", onFrame, globalIni, localIni);
ActionReplay::LoadCodes(globalIni, localIni, false);
// lil silly
std::vector<Gecko::GeckoCode> gcodes;
Gecko::LoadCodes(localIni, gcodes);
Gecko::SetActiveCodes(gcodes);
LoadSpeedhacks("Speedhacks", speedHacks, merged);
LoadDiscList("DiscList", discList, merged);
}
void ApplyPatches(const std::vector<Patch> &patches)

View file

@ -33,10 +33,12 @@ struct Patch
std::string name;
std::vector<PatchEntry> entries;
bool active;
bool user_defined; // False if this code is shipped with Dolphin.
};
int GetSpeedhackCycles(const u32 addr);
void LoadPatchSection(const char *section, std::vector<Patch> &patches, IniFile &ini);
void LoadPatchSection(const char *section, std::vector<Patch> &patches,
IniFile &globalIni, IniFile &localIni);
void LoadPatches(const char *gameID);
void ApplyFramePatches();
void ApplyARPatches();

View file

@ -212,9 +212,6 @@ if(ANDROID)
add_custom_command(TARGET ${DOLPHIN_EXE} POST_BUILD
COMMAND cp ARGS ${CMAKE_SOURCE_DIR}/Data/Sys/GC/* ${CMAKE_SOURCE_DIR}/Source/Android/assets/
)
add_custom_command(TARGET ${DOLPHIN_EXE} POST_BUILD
COMMAND cp ARGS ${CMAKE_SOURCE_DIR}/Data/Sys/Wii/* ${CMAKE_SOURCE_DIR}/Source/Android/assets/
)
else()
add_executable(${DOLPHIN_EXE} ${SRCS})
target_link_libraries(${DOLPHIN_EXE} ${LIBS} ${WXLIBS})
@ -247,14 +244,14 @@ else()
# Copy data files into application bundle.
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/copy_data_into_bundle.cmake "
file(INSTALL ${CMAKE_SOURCE_DIR}/Data/Sys ${CMAKE_SOURCE_DIR}/Data/User
file(INSTALL ${CMAKE_SOURCE_DIR}/Data/Sys
DESTINATION ${BUNDLE_PATH}/Contents/Resources
)
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/did_copy_data_into_bundle \"\")
")
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/did_copy_data_into_bundle
COMMAND ${CMAKE_COMMAND} -P copy_data_into_bundle.cmake
DEPENDS ${CMAKE_SOURCE_DIR}/Data/Sys ${CMAKE_SOURCE_DIR}/Data/User
DEPENDS ${CMAKE_SOURCE_DIR}/Data/Sys
VERBATIM
)
add_custom_target(CopyDataIntoBundle ALL
@ -291,7 +288,7 @@ else()
add_custom_command(OUTPUT ${BUNDLE_PATH}/Contents/Resources/en.lproj
COMMAND ${CMAKE_COMMAND} -P copy_translations_into_bundle.cmake
DEPENDS ${GMO_FILES}
${CMAKE_SOURCE_DIR}/Data/Sys ${CMAKE_SOURCE_DIR}/Data/User
${CMAKE_SOURCE_DIR}/Data/Sys
VERBATIM
)
add_custom_target(CopyTranslationsIntoBundle ALL

View file

@ -5,6 +5,7 @@
#include "Globals.h"
#include "CheatsWindow.h"
#include "ActionReplay.h"
#include "CommonPaths.h"
#include "Core.h"
#include "ConfigManager.h"
#include "VolumeHandler.h"
@ -243,8 +244,10 @@ void wxCheatsWindow::OnEvent_Close(wxCloseEvent& ev)
void wxCheatsWindow::UpdateGUI()
{
// load code
m_gameini_path = File::GetUserPath(D_GAMECONFIG_IDX) + Core::g_CoreStartupParameter.GetUniqueID() + ".ini";
m_gameini.Load(m_gameini_path);
m_gameini_default_path = File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + Core::g_CoreStartupParameter.GetUniqueID() + ".ini";
m_gameini_default.Load(m_gameini_default_path);
m_gameini_local_path = File::GetUserPath(D_GAMESETTINGS_IDX) + Core::g_CoreStartupParameter.GetUniqueID() + ".ini";
m_gameini_local.Load(m_gameini_local_path, true);
Load_ARCodes();
Load_GeckoCodes();
@ -283,7 +286,7 @@ void wxCheatsWindow::Load_ARCodes()
void wxCheatsWindow::Load_GeckoCodes()
{
m_geckocode_panel->LoadCodes(m_gameini, Core::g_CoreStartupParameter.GetUniqueID(), true);
m_geckocode_panel->LoadCodes(m_gameini_local, Core::g_CoreStartupParameter.GetUniqueID(), true);
}
void wxCheatsWindow::OnEvent_CheatsList_ItemSelected(wxCommandEvent& WXUNUSED (event))
@ -338,10 +341,10 @@ void wxCheatsWindow::OnEvent_ApplyChanges_Press(wxCommandEvent& ev)
Gecko::SetActiveCodes(m_geckocode_panel->GetCodes());
// Save gameini, with changed gecko codes
if (m_gameini_path.size())
if (m_gameini_local_path.size())
{
Gecko::SaveCodes(m_gameini, m_geckocode_panel->GetCodes());
m_gameini.Save(m_gameini_path);
Gecko::SaveCodes(m_gameini_local, m_geckocode_panel->GetCodes());
m_gameini_local.Save(m_gameini_local_path);
}
ev.Skip();

View file

@ -130,8 +130,10 @@ class wxCheatsWindow : public wxDialog
std::vector<ARCodeIndex> indexList;
Gecko::CodeConfigPanel *m_geckocode_panel;
IniFile m_gameini;
std::string m_gameini_path;
IniFile m_gameini_default;
IniFile m_gameini_local;
std::string m_gameini_default_path;
std::string m_gameini_local_path;
void Init_ChildControls();

View file

@ -598,9 +598,7 @@ void CConfigMain::CreateGUIControls()
CFileSearch::XStringVector theme_dirs;
theme_dirs.push_back(File::GetUserPath(D_THEMES_IDX));
#if !defined(_WIN32)
theme_dirs.push_back(SHARED_USER_DIR THEMES_DIR);
#endif
theme_dirs.push_back(File::GetSysDirectory() + THEMES_DIR);
CFileSearch cfs(CFileSearch::XStringVector(1, "*"), theme_dirs);
auto const& sv = cfs.GetFileNames();

View file

@ -211,7 +211,9 @@ void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event)
if (Core::GetState() == Core::CORE_UNINITIALIZED) return;
std::string mapfile = CBoot::GenerateMapFilename();
std::string existing_map_file, writable_map_file;
bool map_exists = CBoot::FindMapFile(&existing_map_file,
&writable_map_file);
switch (event.GetId())
{
case IDM_CLEARSYMBOLS:
@ -238,28 +240,28 @@ void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event)
break;
}
case IDM_LOADMAPFILE:
if (!File::Exists(mapfile))
if (!map_exists)
{
g_symbolDB.Clear();
PPCAnalyst::FindFunctions(0x81300000, 0x81800000, &g_symbolDB);
SignatureDB db;
if (db.Load((File::GetSysDirectory() + TOTALDB).c_str()))
db.Apply(&g_symbolDB);
Parent->StatusBarMessage("'%s' not found, scanning for common functions instead", mapfile.c_str());
Parent->StatusBarMessage("'%s' not found, scanning for common functions instead", writable_map_file.c_str());
}
else
{
g_symbolDB.LoadMap(mapfile.c_str());
Parent->StatusBarMessage("Loaded symbols from '%s'", mapfile.c_str());
g_symbolDB.LoadMap(existing_map_file.c_str());
Parent->StatusBarMessage("Loaded symbols from '%s'", existing_map_file.c_str());
}
HLE::PatchFunctions();
NotifyMapLoaded();
break;
case IDM_SAVEMAPFILE:
g_symbolDB.SaveMap(mapfile.c_str());
g_symbolDB.SaveMap(writable_map_file.c_str());
break;
case IDM_SAVEMAPFILEWITHCODES:
g_symbolDB.SaveMap(mapfile.c_str(), true);
g_symbolDB.SaveMap(writable_map_file.c_str(), true);
break;
case IDM_RENAME_SYMBOLS:

View file

@ -115,7 +115,8 @@ GameListItem::GameListItem(const std::string& _rFileName)
if (IsValid())
{
IniFile ini;
ini.Load(File::GetUserPath(D_GAMECONFIG_IDX) + m_UniqueID + ".ini");
ini.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + m_UniqueID + ".ini");
ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + m_UniqueID + ".ini", true);
ini.Get("EmuState", "EmulationStateId", &m_emu_state);
ini.Get("EmuState", "EmulationIssues", &m_issues);
}

View file

@ -6,6 +6,8 @@
#import <Cocoa/Cocoa.h>
#endif
#include <type_traits>
#include "Common.h"
#include "CommonPaths.h"
#include "Globals.h"
@ -45,6 +47,7 @@ BEGIN_EVENT_TABLE(CISOProperties, wxDialog)
EVT_CLOSE(CISOProperties::OnClose)
EVT_BUTTON(wxID_OK, CISOProperties::OnCloseClick)
EVT_BUTTON(ID_EDITCONFIG, CISOProperties::OnEditConfig)
EVT_BUTTON(ID_SHOWDEFAULTCONFIG, CISOProperties::OnShowDefaultConfig)
EVT_CHOICE(ID_EMUSTATE, CISOProperties::SetRefresh)
EVT_CHOICE(ID_EMU_ISSUES, CISOProperties::SetRefresh)
EVT_BUTTON(ID_PHSETTINGS, CISOProperties::PHackButtonClicked)
@ -70,6 +73,7 @@ END_EVENT_TABLE()
CISOProperties::CISOProperties(const std::string fileName, wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& position, const wxSize& size, long style)
: wxDialog(parent, id, title, position, size, style)
{
// Load ISO data
OpenISO = DiscIO::CreateVolumeFromFilename(fileName);
if (DiscIO::IsVolumeWiiDisc(OpenISO))
{
@ -102,12 +106,7 @@ CISOProperties::CISOProperties(const std::string fileName, wxWindow* parent, wxW
}
}
OpenGameListItem = new GameListItem(fileName);
bRefreshList = false;
CreateGUIControls(DiscIO::IsVolumeWadFile(OpenISO));
// Load game ini
std::string _iniFilename = OpenISO->GetUniqueID();
if (!_iniFilename.length())
@ -121,34 +120,21 @@ CISOProperties::CISOProperties(const std::string fileName, wxWindow* parent, wxW
}
}
GameIniFile = File::GetUserPath(D_GAMECONFIG_IDX) + _iniFilename + ".ini";
GameIniFileDefault = File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + _iniFilename + ".ini";
GameIniFileLocal = File::GetUserPath(D_GAMESETTINGS_IDX) + _iniFilename + ".ini";
if (GameIni.Load(GameIniFile.c_str()))
{
LoadGameConfig();
}
else
{
// Will fail out if GameConfig folder doesn't exist
std::ofstream f;
OpenFStream(f, GameIniFile, std::ios_base::out);
if (f)
{
f << "# " << OpenISO->GetUniqueID() << " - " << OpenISO->GetName() << '\n'
<< "[Core] Values set here will override the main dolphin settings.\n"
<< "[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.\n"
<< "[OnFrame] Add memory patches to be applied every frame here.\n"
<< "[ActionReplay] Add action replay cheats here.\n";
f.close();
}
printf("Loading\n");
GameIniDefault.Load(GameIniFileDefault);
GameIniLocal.Load(GameIniFileLocal);
if (GameIni.Load(GameIniFile.c_str()))
LoadGameConfig();
else
wxMessageBox(wxString::Format(_("Could not create %s"),
StrToWxStr(GameIniFile).c_str()),
_("Error"), wxOK|wxICON_ERROR, this);
}
// Setup GUI
OpenGameListItem = new GameListItem(fileName);
bRefreshList = false;
CreateGUIControls(DiscIO::IsVolumeWadFile(OpenISO));
LoadGameConfig();
// Disk header and apploader
@ -280,6 +266,15 @@ size_t CISOProperties::CreateDirectoryTree(wxTreeItemId& parent,
return CurrentIndex;
}
long CISOProperties::GetElementStyle(const char* section, const char* key)
{
// Disable 3rd state if default gameini overrides the setting
if (GameIniDefault.Exists(section, key))
return 0;
return wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER;
}
void CISOProperties::CreateGUIControls(bool IsWad)
{
wxButton * const EditConfig =
@ -287,13 +282,9 @@ void CISOProperties::CreateGUIControls(bool IsWad)
EditConfig->SetToolTip(_("This will let you Manually Edit the INI config file"));
wxButton * const EditConfigDefault =
new wxButton(this, ID_EDITCONFIG, _("Show Defaults"), wxDefaultPosition, wxDefaultSize);
new wxButton(this, ID_SHOWDEFAULTCONFIG, _("Show Defaults"), wxDefaultPosition, wxDefaultSize);
EditConfigDefault->SetToolTip(_("Opens the default (read-only) configuration for this game in an external text editor."));
wxButton * const EditConfigLocal =
new wxButton(this, ID_EDITCONFIG, _("Edit Local Overrides"), wxDefaultPosition, wxDefaultSize);
EditConfigLocal->SetToolTip(_("Opens the user specified overrides in an external text editor."));
// Notebook
wxNotebook * const m_Notebook =
new wxNotebook(this, ID_NOTEBOOK, wxDefaultPosition, wxDefaultSize);
@ -314,32 +305,33 @@ void CISOProperties::CreateGUIControls(bool IsWad)
// GameConfig editing - Overrides and emulation state
wxStaticText * const OverrideText = new wxStaticText(m_GameConfig, wxID_ANY, _("These settings override core Dolphin settings.\nUndetermined means the game uses Dolphin's setting."));
// Core
CPUThread = new wxCheckBox(m_GameConfig, ID_USEDUALCORE, _("Enable Dual Core"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
SkipIdle = new wxCheckBox(m_GameConfig, ID_IDLESKIP, _("Enable Idle Skipping"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
MMU = new wxCheckBox(m_GameConfig, ID_MMU, _("Enable MMU"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
CPUThread = new wxCheckBox(m_GameConfig, ID_USEDUALCORE, _("Enable Dual Core"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "CPUThread"), wxDefaultValidator);
SkipIdle = new wxCheckBox(m_GameConfig, ID_IDLESKIP, _("Enable Idle Skipping"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "SkipIdle"), wxDefaultValidator);
MMU = new wxCheckBox(m_GameConfig, ID_MMU, _("Enable MMU"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "MMU"), wxDefaultValidator);
MMU->SetToolTip(_("Enables the Memory Management Unit, needed for some games. (ON = Compatible, OFF = Fast)"));
TLBHack = new wxCheckBox(m_GameConfig, ID_TLBHACK, _("MMU Speed Hack"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
TLBHack = new wxCheckBox(m_GameConfig, ID_TLBHACK, _("MMU Speed Hack"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "TLBHack"), wxDefaultValidator);
TLBHack->SetToolTip(_("Fast version of the MMU. Does not work for every game."));
DCBZOFF = new wxCheckBox(m_GameConfig, ID_DCBZOFF, _("Skip DCBZ clearing"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
DCBZOFF = new wxCheckBox(m_GameConfig, ID_DCBZOFF, _("Skip DCBZ clearing"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "DCBZ"), wxDefaultValidator);
DCBZOFF->SetToolTip(_("Bypass the clearing of the data cache by the DCBZ instruction. Usually leave this option disabled."));
VBeam = new wxCheckBox(m_GameConfig, ID_VBEAM, _("VBeam Speed Hack"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
VBeam = new wxCheckBox(m_GameConfig, ID_VBEAM, _("VBeam Speed Hack"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "VBeam"), wxDefaultValidator);
VBeam->SetToolTip(_("Doubles the emulated GPU clock rate. May speed up some games (ON = Fast, OFF = Compatible)"));
SyncGPU = new wxCheckBox(m_GameConfig, ID_SYNCGPU, _("Synchronize GPU thread"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
SyncGPU = new wxCheckBox(m_GameConfig, ID_SYNCGPU, _("Synchronize GPU thread"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "SyncGPU"), wxDefaultValidator);
SyncGPU->SetToolTip(_("Synchronizes the GPU and CPU threads to help prevent random freezes in Dual Core mode. (ON = Compatible, OFF = Fast)"));
FastDiscSpeed = new wxCheckBox(m_GameConfig, ID_DISCSPEED, _("Speed up Disc Transfer Rate"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
FastDiscSpeed = new wxCheckBox(m_GameConfig, ID_DISCSPEED, _("Speed up Disc Transfer Rate"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "FastDiscSpeed"), wxDefaultValidator);
FastDiscSpeed->SetToolTip(_("Enable fast disc access. Needed for a few games. (ON = Fast, OFF = Compatible)"));
BlockMerging = new wxCheckBox(m_GameConfig, ID_MERGEBLOCKS, _("Enable Block Merging"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
DSPHLE = new wxCheckBox(m_GameConfig, ID_AUDIO_DSP_HLE, _("DSP HLE emulation (fast)"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
BlockMerging = new wxCheckBox(m_GameConfig, ID_MERGEBLOCKS, _("Enable Block Merging"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "BlockMerging"), wxDefaultValidator);
DSPHLE = new wxCheckBox(m_GameConfig, ID_AUDIO_DSP_HLE, _("DSP HLE emulation (fast)"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "DSPHLE"), wxDefaultValidator);
// Wii Console
EnableWideScreen = new wxCheckBox(m_GameConfig, ID_ENABLEWIDESCREEN, _("Enable WideScreen"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
EnableWideScreen = new wxCheckBox(m_GameConfig, ID_ENABLEWIDESCREEN, _("Enable WideScreen"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Wii", "Widescreen"), wxDefaultValidator);
// Video
UseBBox = new wxCheckBox(m_GameConfig, ID_USE_BBOX, _("Enable Bounding Box Calculation"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER);
UseBBox = new wxCheckBox(m_GameConfig, ID_USE_BBOX, _("Enable Bounding Box Calculation"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Video", "UseBBox"));
UseBBox->SetToolTip(_("If checked, the bounding box registers will be updated. Used by the Paper Mario games."));
UseZTPSpeedupHack = new wxCheckBox(m_GameConfig, ID_ZTP_SPEEDUP, _("ZTP hack"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER);
UseZTPSpeedupHack = new wxCheckBox(m_GameConfig, ID_ZTP_SPEEDUP, _("ZTP hack"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Video", "ZTPSpeedupHack"));
UseZTPSpeedupHack->SetToolTip(_("Enable this to speed up The Legend of Zelda: Twilight Princess. Disable for ANY other game."));
// Hack
@ -567,10 +559,13 @@ void CISOProperties::CreateGUIControls(bool IsWad)
wxSizer* sButtons = CreateButtonSizer(wxNO_DEFAULT);
sButtons->Prepend(EditConfigDefault);
sButtons->Prepend(EditConfigLocal);
sButtons->Prepend(EditConfig);
sButtons->Add(new wxButton(this, wxID_OK, _("Close")));
// If there is no default gameini, disable the button.
if (!File::Exists(GameIniFileDefault))
EditConfigDefault->Disable();
// Add notebook and buttons to the dialog
wxBoxSizer* sMain;
sMain = new wxBoxSizer(wxVERTICAL);
@ -586,7 +581,7 @@ void CISOProperties::CreateGUIControls(bool IsWad)
void CISOProperties::OnClose(wxCloseEvent& WXUNUSED (event))
{
if (!SaveGameConfig())
PanicAlertT("Could not save %s", GameIniFile.c_str());
PanicAlertT("Could not save %s", GameIniFileLocal.c_str());
EndModal(bRefreshList ? wxID_OK : wxID_CANCEL);
}
@ -945,234 +940,193 @@ void CISOProperties::SetRefresh(wxCommandEvent& event)
EmuIssues->Enable(event.GetSelection() != 0);
}
void CISOProperties::SetCheckboxValueFromGameini(const char* section, const char* key, wxCheckBox* checkbox)
{
// Prefer local gameini value over default gameini value.
bool value;
if (GameIniLocal.Get(section, key, &value))
checkbox->Set3StateValue((wxCheckBoxState)value);
else if (GameIniDefault.Get(section, key, &value))
checkbox->Set3StateValue((wxCheckBoxState)value);
else
checkbox->Set3StateValue(wxCHK_UNDETERMINED);
}
void CISOProperties::LoadGameConfig()
{
SetCheckboxValueFromGameini("Core", "CPUThread", CPUThread);
SetCheckboxValueFromGameini("Core", "SkipIdle", SkipIdle);
SetCheckboxValueFromGameini("Core", "MMU", MMU);
SetCheckboxValueFromGameini("Core", "TLBHack", TLBHack);
SetCheckboxValueFromGameini("Core", "DCBZ", DCBZOFF);
SetCheckboxValueFromGameini("Core", "VBeam", VBeam);
SetCheckboxValueFromGameini("Core", "SyncGPU", SyncGPU);
SetCheckboxValueFromGameini("Core", "FastDiscSpeed", FastDiscSpeed);
SetCheckboxValueFromGameini("Core", "BlockMerging", BlockMerging);
SetCheckboxValueFromGameini("Core", "DSPHLE", DSPHLE);
SetCheckboxValueFromGameini("Wii", "Widescreen", EnableWideScreen);
SetCheckboxValueFromGameini("Video", "UseBBox", UseBBox);
SetCheckboxValueFromGameini("Video", "ZTPSpeedupHack", UseZTPSpeedupHack);
// First set values from default gameini, then apply values from local gameini
bool bTemp;
GameIniDefault.Get("Video", "ProjectionHack", &bTemp);
PHackEnable->SetValue(bTemp);
if (GameIniLocal.Get("Video", "ProjectionHack", &bTemp))
PHackEnable->SetValue(bTemp);
GameIniDefault.Get("Video", "PH_SZNear", &PHack_Data.PHackSZNear);
GameIniLocal.Get("Video", "PH_SZNear", &PHack_Data.PHackSZNear);
GameIniDefault.Get("Video", "PH_SZFar", &PHack_Data.PHackSZFar);
GameIniLocal.Get("Video", "PH_SZFar", &PHack_Data.PHackSZFar);
GameIniDefault.Get("Video", "PH_ExtraParam", &PHack_Data.PHackExP);
GameIniLocal.Get("Video", "PH_ExtraParam", &PHack_Data.PHackExP);
GameIniDefault.Get("Video", "PH_ZNear", &PHack_Data.PHZNear);
GameIniLocal.Get("Video", "PH_ZNear", &PHack_Data.PHZNear);
GameIniDefault.Get("Video", "PH_ZFar", &PHack_Data.PHZFar);
GameIniLocal.Get("Video", "PH_ZFar", &PHack_Data.PHZFar);
int iTemp;
std::string sTemp;
if (GameIni.Get("Core", "CPUThread", &bTemp))
CPUThread->Set3StateValue((wxCheckBoxState)bTemp);
else
CPUThread->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Core", "SkipIdle", &bTemp))
SkipIdle->Set3StateValue((wxCheckBoxState)bTemp);
else
SkipIdle->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Core", "MMU", &bTemp))
MMU->Set3StateValue((wxCheckBoxState)bTemp);
else
MMU->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Core", "TLBHack", &bTemp))
TLBHack->Set3StateValue((wxCheckBoxState)bTemp);
else
TLBHack->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Core", "DCBZ", &bTemp))
DCBZOFF->Set3StateValue((wxCheckBoxState)bTemp);
else
DCBZOFF->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Core", "VBeam", &bTemp))
VBeam->Set3StateValue((wxCheckBoxState)bTemp);
else
VBeam->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Core", "SyncGPU", &bTemp))
SyncGPU->Set3StateValue((wxCheckBoxState)bTemp);
else
SyncGPU->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Core", "FastDiscSpeed", &bTemp))
FastDiscSpeed->Set3StateValue((wxCheckBoxState)bTemp);
else
FastDiscSpeed->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Core", "BlockMerging", &bTemp))
BlockMerging->Set3StateValue((wxCheckBoxState)bTemp);
else
BlockMerging->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Core", "DSPHLE", &bTemp))
DSPHLE->Set3StateValue((wxCheckBoxState)bTemp);
else
DSPHLE->Set3StateValue(wxCHK_UNDETERMINED);
// ??
if (GameIni.Get("Wii", "Widescreen", &bTemp))
EnableWideScreen->Set3StateValue((wxCheckBoxState)bTemp);
else
EnableWideScreen->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Video", "UseBBox", &bTemp))
UseBBox->Set3StateValue((wxCheckBoxState)bTemp);
else
UseBBox->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Video", "ZTPSpeedupHack", &bTemp))
UseZTPSpeedupHack->Set3StateValue((wxCheckBoxState)bTemp);
else
UseZTPSpeedupHack->Set3StateValue(wxCHK_UNDETERMINED);
GameIni.Get("Video", "ProjectionHack", &bTemp);
PHackEnable->Set3StateValue((wxCheckBoxState)bTemp);
GameIni.Get("Video", "PH_SZNear", &PHack_Data.PHackSZNear);
GameIni.Get("Video", "PH_SZFar", &PHack_Data.PHackSZFar);
GameIni.Get("Video", "PH_ExtraParam", &PHack_Data.PHackExP);
GameIni.Get("Video", "PH_ZNear", &PHack_Data.PHZNear);
GameIni.Get("Video", "PH_ZFar", &PHack_Data.PHZFar);
GameIni.Get("EmuState", "EmulationStateId", &iTemp, 0/*Not Set*/);
GameIniDefault.Get("EmuState", "EmulationStateId", &iTemp, 0/*Not Set*/);
EmuState->SetSelection(iTemp);
if (GameIniLocal.Get("EmuState", "EmulationStateId", &iTemp, 0/*Not Set*/))
EmuState->SetSelection(iTemp);
GameIni.Get("EmuState", "EmulationIssues", &sTemp);
std::string sTemp;
GameIniDefault.Get("EmuState", "EmulationIssues", &sTemp);
if (!sTemp.empty())
{
EmuIssues->SetValue(StrToWxStr(sTemp));
}
if (GameIniLocal.Get("EmuState", "EmulationIssues", &sTemp))
EmuIssues->SetValue(StrToWxStr(sTemp));
EmuIssues->Enable(EmuState->GetSelection() != 0);
PatchList_Load();
ActionReplayList_Load();
m_geckocode_panel->LoadCodes(GameIni, OpenISO->GetUniqueID());
m_geckocode_panel->LoadCodes(GameIniLocal, OpenISO->GetUniqueID());
}
void CISOProperties::SaveGameIniValueFrom3StateCheckbox(const char* section, const char* key, wxCheckBox* checkbox)
{
// Delete any existing entries from the local gameini if checkbox is undetermined.
// Otherwise, write the current value to the local gameini if the value differs from the default gameini values.
// Delete any existing entry from the local gameini if the value does not differ from the default gameini value.
bool checkbox_val = (checkbox->Get3StateValue() == wxCHK_CHECKED);
if (checkbox->Get3StateValue() == wxCHK_UNDETERMINED)
GameIniLocal.DeleteKey(section, key);
else if (!GameIniDefault.Exists(section, key))
GameIniLocal.Set(section, key, checkbox_val);
else
{
bool default_value;
GameIniDefault.Get(section, key, &default_value);
if (default_value != checkbox_val)
GameIniLocal.Set(section, key, checkbox_val);
else
GameIniLocal.DeleteKey(section, key);
}
}
bool CISOProperties::SaveGameConfig()
{
if (CPUThread->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Core", "CPUThread");
else
GameIni.Set("Core", "CPUThread", CPUThread->Get3StateValue());
SaveGameIniValueFrom3StateCheckbox("Core", "CPUThread", CPUThread);
SaveGameIniValueFrom3StateCheckbox("Core", "SkipIdle", SkipIdle);
SaveGameIniValueFrom3StateCheckbox("Core", "MMU", MMU);
SaveGameIniValueFrom3StateCheckbox("Core", "TLBHack", TLBHack);
SaveGameIniValueFrom3StateCheckbox("Core", "DCBZ", DCBZOFF);
SaveGameIniValueFrom3StateCheckbox("Core", "VBeam", VBeam);
SaveGameIniValueFrom3StateCheckbox("Core", "SyncGPU", SyncGPU);
SaveGameIniValueFrom3StateCheckbox("Core", "FastDiscSpeed", FastDiscSpeed);
SaveGameIniValueFrom3StateCheckbox("Core", "BlockMerging", BlockMerging);
SaveGameIniValueFrom3StateCheckbox("Core", "DSPHLE", DSPHLE);
SaveGameIniValueFrom3StateCheckbox("Wii", "Widescreen", EnableWideScreen);
SaveGameIniValueFrom3StateCheckbox("Video", "UseBBox", UseBBox);
SaveGameIniValueFrom3StateCheckbox("Video", "ZTPSpeedupHack", UseZTPSpeedupHack);
if (SkipIdle->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Core", "SkipIdle");
else
GameIni.Set("Core", "SkipIdle", SkipIdle->Get3StateValue());
#define SAVE_IF_NOT_DEFAULT(section, key, val, def) do { \
if (GameIniDefault.Exists((section), (key))) { \
std::remove_reference<decltype((val))>::type tmp__; \
GameIniDefault.Get((section), (key), &tmp__); \
if ((val) != tmp__) \
GameIniLocal.Set((section), (key), (val)); \
else \
GameIniLocal.DeleteKey((section), (key)); \
} else if ((val) != (def)) \
GameIniLocal.Set((section), (key), (val)); \
else \
GameIniLocal.DeleteKey((section), (key)); \
} while (0)
if (MMU->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Core", "MMU");
else
GameIni.Set("Core", "MMU", MMU->Get3StateValue());
SAVE_IF_NOT_DEFAULT("Video", "ProjectionHack", PHackEnable->GetValue(), false);
SAVE_IF_NOT_DEFAULT("Video", "PH_SZNear", (PHack_Data.PHackSZNear ? 1 : 0), 0);
SAVE_IF_NOT_DEFAULT("Video", "PH_SZFar", (PHack_Data.PHackSZFar ? 1 : 0), 0);
SAVE_IF_NOT_DEFAULT("Video", "PH_ExtraParam", (PHack_Data.PHackExP ? 1 : 0), 0);
SAVE_IF_NOT_DEFAULT("Video", "PH_ZNear", PHack_Data.PHZNear, "");
SAVE_IF_NOT_DEFAULT("Video", "PH_ZFar", PHack_Data.PHZFar, "");
SAVE_IF_NOT_DEFAULT("EmuState", "EmulationStateId", EmuState->GetSelection(), 0);
if (TLBHack->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Core", "TLBHack");
else
GameIni.Set("Core", "TLBHack", TLBHack->Get3StateValue());
if (DCBZOFF->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Core", "DCBZ");
else
GameIni.Set("Core", "DCBZ", DCBZOFF->Get3StateValue());
if (VBeam->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Core", "VBeam");
else
GameIni.Set("Core", "VBeam", VBeam->Get3StateValue());
if (SyncGPU->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Core", "SyncGPU");
else
GameIni.Set("Core", "SyncGPU", SyncGPU->Get3StateValue());
if (FastDiscSpeed->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Core", "FastDiscSpeed");
else
GameIni.Set("Core", "FastDiscSpeed", FastDiscSpeed->Get3StateValue());
if (BlockMerging->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Core", "BlockMerging");
else
GameIni.Set("Core", "BlockMerging", BlockMerging->Get3StateValue());
if (DSPHLE->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Core", "DSPHLE");
else
GameIni.Set("Core", "DSPHLE", DSPHLE->Get3StateValue());
if (EnableWideScreen->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Wii", "Widescreen");
else
GameIni.Set("Wii", "Widescreen", EnableWideScreen->Get3StateValue());
if (UseBBox->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Video", "UseBBox");
else
GameIni.Set("Video", "UseBBox", UseBBox->Get3StateValue());
if (UseZTPSpeedupHack->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Video", "ZTPSpeedupHack");
else
GameIni.Set("Video", "ZTPSpeedupHack", UseZTPSpeedupHack->Get3StateValue());
GameIni.Set("Video", "ProjectionHack", PHackEnable->Get3StateValue());
GameIni.Set("Video", "PH_SZNear", PHack_Data.PHackSZNear ? 1 : 0);
GameIni.Set("Video", "PH_SZFar", PHack_Data.PHackSZFar ? 1 : 0);
GameIni.Set("Video", "PH_ExtraParam", PHack_Data.PHackExP ? 1 : 0);
GameIni.Set("Video", "PH_ZNear", PHack_Data.PHZNear);
GameIni.Set("Video", "PH_ZFar", PHack_Data.PHZFar);
GameIni.Set("EmuState", "EmulationStateId", EmuState->GetSelection());
std::string sTemp;
GameIni.Get("EmuState","EmulationIssues", &sTemp);
if (EmuIssues->GetValue() != sTemp)
bRefreshList = true;
GameIni.Set("EmuState", "EmulationIssues", WxStrToStr(EmuIssues->GetValue()));
std::string emu_issues = EmuIssues->GetValue().ToStdString();
SAVE_IF_NOT_DEFAULT("EmuState", "EmulationIssues", emu_issues, "");
PatchList_Save();
ActionReplayList_Save();
Gecko::SaveCodes(GameIni, m_geckocode_panel->GetCodes());
Gecko::SaveCodes(GameIniLocal, m_geckocode_panel->GetCodes());
return GameIni.Save(GameIniFile.c_str());
bool success = GameIniLocal.Save(GameIniFileLocal.c_str());
// If the resulting file is empty, delete it. Kind of a hack, but meh.
if (success && File::GetSize(GameIniFileLocal) == 0)
File::Delete(GameIniFileLocal);
return success;
}
void CISOProperties::LaunchExternalEditor(const std::string& filename)
{
#ifdef __APPLE__
// wxTheMimeTypesManager is not yet implemented for wxCocoa
[[NSWorkspace sharedWorkspace] openFile:
[NSString stringWithUTF8String: filename.c_str()]
withApplication: @"TextEdit"];
#else
wxFileType* filetype = wxTheMimeTypesManager->GetFileTypeFromExtension(_T("ini"));
if(filetype == NULL) // From extension failed, trying with MIME type now
{
filetype = wxTheMimeTypesManager->GetFileTypeFromMimeType(_T("text/plain"));
if(filetype == NULL) // MIME type failed, aborting mission
{
PanicAlertT("Filetype 'ini' is unknown! Will not open!");
return;
}
}
wxString OpenCommand;
OpenCommand = filetype->GetOpenCommand(StrToWxStr(filename));
if(OpenCommand.IsEmpty())
PanicAlertT("Couldn't find open command for extension 'ini'!");
else
if(wxExecute(OpenCommand, wxEXEC_SYNC) == -1)
PanicAlertT("wxExecute returned -1 on application run!");
#endif
bRefreshList = true; // Just in case
// Once we're done with the ini edit, give the focus back to Dolphin
SetFocus();
}
void CISOProperties::OnEditConfig(wxCommandEvent& WXUNUSED (event))
{
if (File::Exists(GameIniFile))
{
SaveGameConfig();
SaveGameConfig();
LaunchExternalEditor(GameIniFileLocal);
GameIniLocal.Load(GameIniFileLocal);
LoadGameConfig();
}
#ifdef __APPLE__
// wxTheMimeTypesManager is not yet implemented for wxCocoa
[[NSWorkspace sharedWorkspace] openFile:
[NSString stringWithUTF8String: GameIniFile.c_str()]
withApplication: @"TextEdit"];
#else
wxFileType* filetype = wxTheMimeTypesManager->GetFileTypeFromExtension(_T("ini"));
if(filetype == NULL) // From extension failed, trying with MIME type now
{
filetype = wxTheMimeTypesManager->GetFileTypeFromMimeType(_T("text/plain"));
if(filetype == NULL) // MIME type failed, aborting mission
{
PanicAlertT("Filetype 'ini' is unknown! Will not open!");
return;
}
}
wxString OpenCommand;
OpenCommand = filetype->GetOpenCommand(StrToWxStr(GameIniFile));
if(OpenCommand.IsEmpty())
PanicAlertT("Couldn't find open command for extension 'ini'!");
else
if(wxExecute(OpenCommand, wxEXEC_SYNC) == -1)
PanicAlertT("wxExecute returned -1 on application run!");
#endif
GameIni.Load(GameIniFile.c_str());
LoadGameConfig();
bRefreshList = true; // Just in case
}
// Once we're done with the ini edit, give the focus back to Dolphin
SetFocus();
void CISOProperties::OnShowDefaultConfig(wxCommandEvent& WXUNUSED (event))
{
LaunchExternalEditor(GameIniFileDefault);
}
void CISOProperties::ListSelectionChanged(wxCommandEvent& event)
@ -1180,14 +1134,26 @@ void CISOProperties::ListSelectionChanged(wxCommandEvent& event)
switch (event.GetId())
{
case ID_PATCHES_LIST:
if (Patches->GetSelection() != wxNOT_FOUND)
if (Patches->GetSelection() == wxNOT_FOUND
|| DefaultPatches.find(Patches->GetString(Patches->GetSelection()).ToStdString()) != DefaultPatches.end())
{
EditPatch->Disable();
RemovePatch->Disable();
}
else
{
EditPatch->Enable();
RemovePatch->Enable();
}
break;
case ID_CHEATS_LIST:
if (Cheats->GetSelection() != wxNOT_FOUND)
if (Cheats->GetSelection() == wxNOT_FOUND
|| DefaultCheats.find(Cheats->GetString(Cheats->GetSelection()).ToStdString()) != DefaultCheats.end())
{
EditCheat->Disable();
RemoveCheat->Disable();
}
else
{
EditCheat->Enable();
RemoveCheat->Enable();
@ -1200,14 +1166,17 @@ void CISOProperties::PatchList_Load()
{
onFrame.clear();
Patches->Clear();
PatchEngine::LoadPatchSection("OnFrame", onFrame, GameIni);
PatchEngine::LoadPatchSection("OnFrame", onFrame, GameIniDefault, GameIniLocal);
u32 index = 0;
for (std::vector<PatchEngine::Patch>::const_iterator it = onFrame.begin(); it != onFrame.end(); ++it)
for (auto it = onFrame.begin(); it != onFrame.end(); ++it)
{
PatchEngine::Patch p = *it;
Patches->Append(StrToWxStr(p.name));
Patches->Check(index, p.active);
if (!p.user_defined)
DefaultPatches.insert(p.name);
++index;
}
}
@ -1215,20 +1184,27 @@ void CISOProperties::PatchList_Load()
void CISOProperties::PatchList_Save()
{
std::vector<std::string> lines;
std::vector<std::string> enabledLines;
u32 index = 0;
for (std::vector<PatchEngine::Patch>::const_iterator onFrame_it = onFrame.begin(); onFrame_it != onFrame.end(); ++onFrame_it)
for (auto onFrame_it = onFrame.begin(); onFrame_it != onFrame.end(); ++onFrame_it)
{
lines.push_back(Patches->IsChecked(index) ? "+$" + onFrame_it->name : "$" + onFrame_it->name);
if (Patches->IsChecked(index))
enabledLines.push_back("$" + onFrame_it->name);
for (std::vector<PatchEngine::PatchEntry>::const_iterator iter2 = onFrame_it->entries.begin(); iter2 != onFrame_it->entries.end(); ++iter2)
// Do not save default patches.
if (DefaultPatches.find(onFrame_it->name) == DefaultPatches.end())
{
std::string temp = StringFromFormat("0x%08X:%s:0x%08X", iter2->address, PatchEngine::PatchTypeStrings[iter2->type], iter2->value);
lines.push_back(temp);
lines.push_back("$" + onFrame_it->name);
for (auto iter2 = onFrame_it->entries.begin(); iter2 != onFrame_it->entries.end(); ++iter2)
{
std::string temp = StringFromFormat("0x%08X:%s:0x%08X", iter2->address, PatchEngine::PatchTypeStrings[iter2->type], iter2->value);
lines.push_back(temp);
}
}
++index;
}
GameIni.SetLines("OnFrame", lines);
lines.clear();
GameIniLocal.SetLines("OnFrame_Enabled", enabledLines);
GameIniLocal.SetLines("OnFrame", lines);
}
void CISOProperties::PHackButtonClicked(wxCommandEvent& event)
@ -1282,7 +1258,7 @@ void CISOProperties::ActionReplayList_Load()
{
arCodes.clear();
Cheats->Clear();
ActionReplay::LoadCodes(arCodes, GameIni);
ActionReplay::LoadCodes(arCodes, GameIniDefault, GameIniLocal);
u32 index = 0;
for (std::vector<ActionReplay::ARCode>::const_iterator it = arCodes.begin(); it != arCodes.end(); ++it)
@ -1290,6 +1266,8 @@ void CISOProperties::ActionReplayList_Load()
ActionReplay::ARCode arCode = *it;
Cheats->Append(StrToWxStr(arCode.name));
Cheats->Check(index, arCode.active);
if (!arCode.user_defined)
DefaultCheats.insert(arCode.name);
++index;
}
}
@ -1297,20 +1275,28 @@ void CISOProperties::ActionReplayList_Load()
void CISOProperties::ActionReplayList_Save()
{
std::vector<std::string> lines;
std::vector<std::string> enabledLines;
u32 index = 0;
for (std::vector<ActionReplay::ARCode>::const_iterator iter = arCodes.begin(); iter != arCodes.end(); ++iter)
for (auto iter = arCodes.begin(); iter != arCodes.end(); ++iter)
{
ActionReplay::ARCode code = *iter;
lines.push_back(Cheats->IsChecked(index) ? "+$" + code.name : "$" + code.name);
if (Cheats->IsChecked(index))
enabledLines.push_back("$" + code.name);
for (std::vector<ActionReplay::AREntry>::const_iterator iter2 = code.ops.begin(); iter2 != code.ops.end(); ++iter2)
// Do not save default cheats.
if (DefaultCheats.find(code.name) == DefaultCheats.end())
{
lines.push_back(WxStrToStr(wxString::Format(wxT("%08X %08X"), iter2->cmd_addr, iter2->value)));
lines.push_back("$" + code.name);
for (auto iter2 = code.ops.begin(); iter2 != code.ops.end(); ++iter2)
{
lines.push_back(WxStrToStr(wxString::Format(wxT("%08X %08X"), iter2->cmd_addr, iter2->value)));
}
}
++index;
}
GameIni.SetLines("ActionReplay", lines);
GameIniLocal.SetLines("ActionReplay_Enabled", enabledLines);
GameIniLocal.SetLines("ActionReplay", lines);
}
void CISOProperties::ActionReplayButtonClicked(wxCommandEvent& event)

View file

@ -129,6 +129,7 @@ private:
ID_ENABLEPROGRESSIVESCAN,
ID_ENABLEWIDESCREEN,
ID_EDITCONFIG,
ID_SHOWDEFAULTCONFIG,
ID_EMUSTATE,
ID_EMU_ISSUES,
ID_PATCHES_LIST,
@ -163,10 +164,13 @@ private:
IDM_BNRSAVEAS
};
void LaunchExternalEditor(const std::string& filename);
void CreateGUIControls(bool);
void OnClose(wxCloseEvent& event);
void OnCloseClick(wxCommandEvent& event);
void OnEditConfig(wxCommandEvent& event);
void OnShowDefaultConfig(wxCommandEvent& event);
void ListSelectionChanged(wxCommandEvent& event);
void PatchButtonClicked(wxCommandEvent& event);
void ActionReplayButtonClicked(wxCommandEvent& event);
@ -193,13 +197,22 @@ private:
void ExportDir(const char* _rFullPath, const char* _rExportFilename,
const int partitionNum = 0);
IniFile GameIni;
std::string GameIniFile;
IniFile GameIniDefault;
IniFile GameIniLocal;
std::string GameIniFileDefault;
std::string GameIniFileLocal;
std::set<std::string> DefaultPatches;
std::set<std::string> DefaultCheats;
void LoadGameConfig();
void PatchList_Load();
void PatchList_Save();
void ActionReplayList_Save();
void ChangeBannerDetails(int lang);
long GetElementStyle(const char* section, const char* key);
void SetCheckboxValueFromGameini(const char* section, const char* key, wxCheckBox* checkbox);
void SaveGameIniValueFrom3StateCheckbox(const char* section, const char* key, wxCheckBox* checkbox);
};
#endif

View file

@ -249,37 +249,28 @@ bool DolphinApp::OnInit()
}
#endif
#ifdef _WIN32
if (!wxSetWorkingDirectory(StrToWxStr(File::GetExeDirectory())))
{
INFO_LOG(CONSOLE, "Set working directory failed");
}
#else
//create all necessary directories in user directory
//TODO : detect the revision and upgrade where necessary
File::CopyDir(std::string(SHARED_USER_DIR GAMECONFIG_DIR DIR_SEP),
File::GetUserPath(D_GAMECONFIG_IDX));
File::CopyDir(std::string(SHARED_USER_DIR MAPS_DIR DIR_SEP),
File::GetUserPath(D_MAPS_IDX));
File::CopyDir(std::string(SHARED_USER_DIR SHADERS_DIR DIR_SEP),
File::GetUserPath(D_SHADERS_IDX));
File::CopyDir(std::string(SHARED_USER_DIR WII_USER_DIR DIR_SEP),
File::GetUserPath(D_WIIUSER_IDX));
File::CopyDir(std::string(SHARED_USER_DIR OPENCL_DIR DIR_SEP),
File::GetUserPath(D_OPENCL_IDX));
#endif
File::CreateFullPath(File::GetUserPath(D_CONFIG_IDX));
File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX));
// Copy initial Wii NAND data from Sys to User.
File::CopyDir(File::GetSysDirectory() + WII_USER_DIR,
File::GetUserPath(D_WIIUSER_IDX));
File::CreateFullPath(File::GetUserPath(D_USER_IDX));
File::CreateFullPath(File::GetUserPath(D_CACHE_IDX));
File::CreateFullPath(File::GetUserPath(D_CONFIG_IDX));
File::CreateFullPath(File::GetUserPath(D_DUMPDSP_IDX));
File::CreateFullPath(File::GetUserPath(D_DUMPTEXTURES_IDX));
File::CreateFullPath(File::GetUserPath(D_HIRESTEXTURES_IDX));
File::CreateFullPath(File::GetUserPath(D_SCREENSHOTS_IDX));
File::CreateFullPath(File::GetUserPath(D_STATESAVES_IDX));
File::CreateFullPath(File::GetUserPath(D_MAILLOGS_IDX));
File::CreateFullPath(File::GetUserPath(D_GAMESETTINGS_IDX));
File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX));
File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + USA_DIR DIR_SEP);
File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + EUR_DIR DIR_SEP);
File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + JAP_DIR DIR_SEP);
File::CreateFullPath(File::GetUserPath(D_HIRESTEXTURES_IDX));
File::CreateFullPath(File::GetUserPath(D_MAILLOGS_IDX));
File::CreateFullPath(File::GetUserPath(D_MAPS_IDX));
File::CreateFullPath(File::GetUserPath(D_OPENCL_IDX));
File::CreateFullPath(File::GetUserPath(D_SCREENSHOTS_IDX));
File::CreateFullPath(File::GetUserPath(D_SHADERS_IDX));
File::CreateFullPath(File::GetUserPath(D_STATESAVES_IDX));
File::CreateFullPath(File::GetUserPath(D_THEMES_IDX));
LogManager::Init();
SConfig::Init();

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "CommonPaths.h"
#include "PHackSettings.h"
#include "ConfigManager.h"
#include "WxUtils.h"
@ -18,10 +19,9 @@ CPHackSettings::CPHackSettings(wxWindow* parent, wxWindowID id, const wxString&
{
CreateGUIControls();
std::string _iniFilename;
_iniFilename = File::GetUserPath(D_GAMECONFIG_IDX) + "PH_PRESETS.ini";
_iniFilename = File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP "PH_PRESETS.ini";
PHPresetsIni.Load(_iniFilename.c_str());
//PHPresetsIni.SortSections();
//PHPresetsIni.Save(_iniFilename.c_str());
PHPresetsIni.SortSections();
LoadPHackData();
}

View file

@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include "InputConfig.h"
#include "CommonPaths.h"
#include "../../Core/Src/ConfigManager.h"
#include "../../Core/Src/HW/Wiimote.h"
@ -37,7 +38,8 @@ bool InputPlugin::LoadConfig(bool isGC)
type = "Wiimote";
path = "Profiles/Wiimote/";
}
game_ini.Load(File::GetUserPath(D_GAMECONFIG_IDX) + SConfig::GetInstance().m_LocalCoreStartupParameter.GetUniqueID() + ".ini");
game_ini.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + SConfig::GetInstance().m_LocalCoreStartupParameter.GetUniqueID() + ".ini");
game_ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().m_LocalCoreStartupParameter.GetUniqueID() + ".ini", true);
for (int i = 0; i < 4; i++)
{
if (game_ini.Exists("Controls", (type + "Profile" + num[i]).c_str()))
@ -46,7 +48,10 @@ bool InputPlugin::LoadConfig(bool isGC)
if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + path + profile[i] + ".ini"))
useProfile[i] = true;
else
{
// TODO: Having a PanicAlert for this is dumb.
PanicAlertT("Selected controller profile does not exist");
}
}
}
}
@ -94,6 +99,6 @@ void InputPlugin::SaveConfig()
e = controllers.end();
for ( ; i!=e; ++i )
(*i)->SaveConfig(inifile.GetOrCreateSection((*i)->GetName().c_str()));
inifile.Save(ini_filename);
}

View file

@ -5,6 +5,7 @@
#include "OCLTextureDecoder.h"
#include "../OpenCL.h"
#include "CommonPaths.h"
#include "FileUtil.h"
#include <fcntl.h>
@ -138,7 +139,7 @@ void TexDecoder_OpenCL_Initialize()
if (err)
{
std::string code;
filename = File::GetUserPath(D_OPENCL_IDX) + "TextureDecoder.cl";
filename = File::GetSysDirectory() + OPENCL_DIR DIR_SEP "TextureDecoder.cl";
if (!File::ReadFileToString(true, filename.c_str(), code))
{
ERROR_LOG(VIDEO, "Failed to load OpenCL code %s - file is missing?", filename.c_str());

View file

@ -120,30 +120,45 @@ void VideoConfig::Load(const char *ini_file)
OSD::AddMessage("Warning: Shader Debugging is enabled, performance will suffer heavily", 15000);
}
void VideoConfig::GameIniLoad(const char *ini_file)
void VideoConfig::GameIniLoad(const char* default_ini_file, const char* local_ini_file)
{
bool gfx_override_exists = false;
// XXX: Again, bad place to put OSD messages at (see delroth's comment above)
// XXX: This will add an OSD message for each projection hack value... meh
#define CHECK_SETTING(section, key, var) do { \
decltype(var) temp = var; \
if (iniFile.GetIfExists(section, key, &var) && var != temp) { \
char buf[256]; \
snprintf(buf, sizeof(buf), "Note: Option \"%s\" is overridden by game ini.", key); \
OSD::AddMessage(buf, 7500); \
gfx_override_exists = true; \
} \
} while (0)
IniFile iniFile;
iniFile.Load(ini_file);
iniFile.Load(default_ini_file);
iniFile.Load(local_ini_file, true);
iniFile.GetIfExists("Video_Hardware", "VSync", &bVSync);
CHECK_SETTING("Video_Hardware", "VSync", bVSync);
iniFile.GetIfExists("Video_Settings", "wideScreenHack", &bWidescreenHack);
iniFile.GetIfExists("Video_Settings", "AspectRatio", &iAspectRatio);
iniFile.GetIfExists("Video_Settings", "Crop", &bCrop);
iniFile.GetIfExists("Video_Settings", "UseXFB", &bUseXFB);
iniFile.GetIfExists("Video_Settings", "UseRealXFB", &bUseRealXFB);
iniFile.GetIfExists("Video_Settings", "SafeTextureCacheColorSamples", &iSafeTextureCache_ColorSamples);
iniFile.GetIfExists("Video_Settings", "DLOptimize", &iCompileDLsLevel);
iniFile.GetIfExists("Video_Settings", "HiresTextures", &bHiresTextures);
iniFile.GetIfExists("Video_Settings", "AnaglyphStereo", &bAnaglyphStereo);
iniFile.GetIfExists("Video_Settings", "AnaglyphStereoSeparation", &iAnaglyphStereoSeparation);
iniFile.GetIfExists("Video_Settings", "AnaglyphFocalAngle", &iAnaglyphFocalAngle);
iniFile.GetIfExists("Video_Settings", "EnablePixelLighting", &bEnablePixelLighting);
iniFile.GetIfExists("Video_Settings", "HackedBufferUpload", &bHackedBufferUpload);
iniFile.GetIfExists("Video_Settings", "FastDepthCalc", &bFastDepthCalc);
iniFile.GetIfExists("Video_Settings", "MSAA", &iMultisampleMode);
CHECK_SETTING("Video_Settings", "wideScreenHack", bWidescreenHack);
CHECK_SETTING("Video_Settings", "AspectRatio", iAspectRatio);
CHECK_SETTING("Video_Settings", "Crop", bCrop);
CHECK_SETTING("Video_Settings", "UseXFB", bUseXFB);
CHECK_SETTING("Video_Settings", "UseRealXFB", bUseRealXFB);
CHECK_SETTING("Video_Settings", "SafeTextureCacheColorSamples", iSafeTextureCache_ColorSamples);
CHECK_SETTING("Video_Settings", "DLOptimize", iCompileDLsLevel);
CHECK_SETTING("Video_Settings", "HiresTextures", bHiresTextures);
CHECK_SETTING("Video_Settings", "AnaglyphStereo", bAnaglyphStereo);
CHECK_SETTING("Video_Settings", "AnaglyphStereoSeparation", iAnaglyphStereoSeparation);
CHECK_SETTING("Video_Settings", "AnaglyphFocalAngle", iAnaglyphFocalAngle);
CHECK_SETTING("Video_Settings", "EnablePixelLighting", bEnablePixelLighting);
CHECK_SETTING("Video_Settings", "HackedBufferUpload", bHackedBufferUpload);
CHECK_SETTING("Video_Settings", "FastDepthCalc", bFastDepthCalc);
CHECK_SETTING("Video_Settings", "MSAA", iMultisampleMode);
int tmp = -9000;
iniFile.GetIfExists("Video_Settings", "EFBScale", &tmp); // integral
CHECK_SETTING("Video_Settings", "EFBScale", tmp); // integral
if (tmp != -9000)
{
if (tmp != SCALE_FORCE_INTEGRAL)
@ -169,33 +184,36 @@ void VideoConfig::GameIniLoad(const char *ini_file)
}
}
iniFile.GetIfExists("Video_Settings", "DstAlphaPass", &bDstAlphaPass);
iniFile.GetIfExists("Video_Settings", "DisableFog", &bDisableFog);
iniFile.GetIfExists("Video_Settings", "EnableOpenCL", &bEnableOpenCL);
iniFile.GetIfExists("Video_Settings", "OMPDecoder", &bOMPDecoder);
CHECK_SETTING("Video_Settings", "DstAlphaPass", bDstAlphaPass);
CHECK_SETTING("Video_Settings", "DisableFog", bDisableFog);
CHECK_SETTING("Video_Settings", "EnableOpenCL", bEnableOpenCL);
CHECK_SETTING("Video_Settings", "OMPDecoder", bOMPDecoder);
iniFile.GetIfExists("Video_Enhancements", "ForceFiltering", &bForceFiltering);
iniFile.GetIfExists("Video_Enhancements", "MaxAnisotropy", &iMaxAnisotropy); // NOTE - this is x in (1 << x)
iniFile.GetIfExists("Video_Enhancements", "PostProcessingShader", &sPostProcessingShader);
iniFile.GetIfExists("Video_Enhancements", "Enable3dVision", &b3DVision);
CHECK_SETTING("Video_Enhancements", "ForceFiltering", bForceFiltering);
CHECK_SETTING("Video_Enhancements", "MaxAnisotropy", iMaxAnisotropy); // NOTE - this is x in (1 << x)
CHECK_SETTING("Video_Enhancements", "PostProcessingShader", sPostProcessingShader);
CHECK_SETTING("Video_Enhancements", "Enable3dVision", b3DVision);
iniFile.GetIfExists("Video_Hacks", "EFBAccessEnable", &bEFBAccessEnable);
iniFile.GetIfExists("Video_Hacks", "DlistCachingEnable", &bDlistCachingEnable);
iniFile.GetIfExists("Video_Hacks", "EFBCopyEnable", &bEFBCopyEnable);
iniFile.GetIfExists("Video_Hacks", "EFBToTextureEnable", &bCopyEFBToTexture);
iniFile.GetIfExists("Video_Hacks", "EFBScaledCopy", &bCopyEFBScaled);
iniFile.GetIfExists("Video_Hacks", "EFBCopyCacheEnable", &bEFBCopyCacheEnable);
iniFile.GetIfExists("Video_Hacks", "EFBEmulateFormatChanges", &bEFBEmulateFormatChanges);
CHECK_SETTING("Video_Hacks", "EFBAccessEnable", bEFBAccessEnable);
CHECK_SETTING("Video_Hacks", "DlistCachingEnable", bDlistCachingEnable);
CHECK_SETTING("Video_Hacks", "EFBCopyEnable", bEFBCopyEnable);
CHECK_SETTING("Video_Hacks", "EFBToTextureEnable", bCopyEFBToTexture);
CHECK_SETTING("Video_Hacks", "EFBScaledCopy", bCopyEFBScaled);
CHECK_SETTING("Video_Hacks", "EFBCopyCacheEnable", bEFBCopyCacheEnable);
CHECK_SETTING("Video_Hacks", "EFBEmulateFormatChanges", bEFBEmulateFormatChanges);
iniFile.GetIfExists("Video", "ProjectionHack", &iPhackvalue[0]);
iniFile.GetIfExists("Video", "PH_SZNear", &iPhackvalue[1]);
iniFile.GetIfExists("Video", "PH_SZFar", &iPhackvalue[2]);
iniFile.GetIfExists("Video", "PH_ExtraParam", &iPhackvalue[3]);
iniFile.GetIfExists("Video", "PH_ZNear", &sPhackvalue[0]);
iniFile.GetIfExists("Video", "PH_ZFar", &sPhackvalue[1]);
iniFile.GetIfExists("Video", "ZTPSpeedupHack", &bZTPSpeedHack);
iniFile.GetIfExists("Video", "UseBBox", &bUseBBox);
iniFile.GetIfExists("Video", "PerfQueriesEnable", &bPerfQueriesEnable);
CHECK_SETTING("Video", "ProjectionHack", iPhackvalue[0]);
CHECK_SETTING("Video", "PH_SZNear", iPhackvalue[1]);
CHECK_SETTING("Video", "PH_SZFar", iPhackvalue[2]);
CHECK_SETTING("Video", "PH_ExtraParam", iPhackvalue[3]);
CHECK_SETTING("Video", "PH_ZNear", sPhackvalue[0]);
CHECK_SETTING("Video", "PH_ZFar", sPhackvalue[1]);
CHECK_SETTING("Video", "ZTPSpeedupHack", bZTPSpeedHack);
CHECK_SETTING("Video", "UseBBox", bUseBBox);
CHECK_SETTING("Video", "PerfQueriesEnable", bPerfQueriesEnable);
if (gfx_override_exists)
OSD::AddMessage("Warning: Opening the graphics configuration will reset settings and might cause issues!", 10000);
}
void VideoConfig::VerifyValidity()
@ -262,7 +280,7 @@ void VideoConfig::Save(const char *ini_file)
iniFile.Set("Hacks", "EFBAccessEnable", bEFBAccessEnable);
iniFile.Set("Hacks", "DlistCachingEnable", bDlistCachingEnable);
iniFile.Set("Hacks", "EFBCopyEnable", bEFBCopyEnable);
iniFile.Set("Hacks", "EFBToTextureEnable", bCopyEFBToTexture);
iniFile.Set("Hacks", "EFBToTextureEnable", bCopyEFBToTexture);
iniFile.Set("Hacks", "EFBScaledCopy", bCopyEFBScaled);
iniFile.Set("Hacks", "EFBCopyCacheEnable", bEFBCopyCacheEnable);
iniFile.Set("Hacks", "EFBEmulateFormatChanges", bEFBEmulateFormatChanges);
@ -273,60 +291,6 @@ void VideoConfig::Save(const char *ini_file)
iniFile.Save(ini_file);
}
void VideoConfig::GameIniSave(const char* default_ini, const char* game_ini)
{
// wxWidgets doesn't provide us with a nice way to change 3-state checkboxes into 2-state ones
// This would allow us to make the "default config" dialog layout to be 2-state based, but the
// "game config" layout to be 3-state based (with the 3rd state being "use default")
// Since we can't do that, we instead just save anything which differs from the default config
// TODO: Make this less ugly
VideoConfig defCfg;
defCfg.Load(default_ini);
IniFile iniFile;
iniFile.Load(game_ini);
#define SET_IF_DIFFERS(section, key, member) { if ((member) != (defCfg.member)) iniFile.Set((section), (key), (member)); else iniFile.DeleteKey((section), (key)); }
SET_IF_DIFFERS("Video_Hardware", "VSync", bVSync);
SET_IF_DIFFERS("Video_Settings", "wideScreenHack", bWidescreenHack);
SET_IF_DIFFERS("Video_Settings", "AspectRatio", iAspectRatio);
SET_IF_DIFFERS("Video_Settings", "Crop", bCrop);
SET_IF_DIFFERS("Video_Settings", "UseXFB", bUseXFB);
SET_IF_DIFFERS("Video_Settings", "UseRealXFB", bUseRealXFB);
SET_IF_DIFFERS("Video_Settings", "SafeTextureCacheColorSamples", iSafeTextureCache_ColorSamples);
SET_IF_DIFFERS("Video_Settings", "DLOptimize", iCompileDLsLevel);
SET_IF_DIFFERS("Video_Settings", "HiresTextures", bHiresTextures);
SET_IF_DIFFERS("Video_Settings", "AnaglyphStereo", bAnaglyphStereo);
SET_IF_DIFFERS("Video_Settings", "AnaglyphStereoSeparation", iAnaglyphStereoSeparation);
SET_IF_DIFFERS("Video_Settings", "AnaglyphFocalAngle", iAnaglyphFocalAngle);
SET_IF_DIFFERS("Video_Settings", "EnablePixelLighting", bEnablePixelLighting);
SET_IF_DIFFERS("Video_Settings", "FastDepthCalc", bFastDepthCalc);
SET_IF_DIFFERS("Video_Settings", "MSAA", iMultisampleMode);
SET_IF_DIFFERS("Video_Settings", "EFBScale", iEFBScale); // integral
SET_IF_DIFFERS("Video_Settings", "DstAlphaPass", bDstAlphaPass);
SET_IF_DIFFERS("Video_Settings", "DisableFog", bDisableFog);
SET_IF_DIFFERS("Video_Settings", "EnableOpenCL", bEnableOpenCL);
SET_IF_DIFFERS("Video_Settings", "OMPDecoder", bOMPDecoder);
SET_IF_DIFFERS("Video_Enhancements", "ForceFiltering", bForceFiltering);
SET_IF_DIFFERS("Video_Enhancements", "MaxAnisotropy", iMaxAnisotropy); // NOTE - this is x in (1 << x)
SET_IF_DIFFERS("Video_Enhancements", "PostProcessingShader", sPostProcessingShader);
SET_IF_DIFFERS("Video_Enhancements", "Enable3dVision", b3DVision);
SET_IF_DIFFERS("Video_Hacks", "EFBAccessEnable", bEFBAccessEnable);
SET_IF_DIFFERS("Video_Hacks", "DlistCachingEnable", bDlistCachingEnable);
SET_IF_DIFFERS("Video_Hacks", "EFBCopyEnable", bEFBCopyEnable);
SET_IF_DIFFERS("Video_Hacks", "EFBToTextureEnable", bCopyEFBToTexture);
SET_IF_DIFFERS("Video_Hacks", "EFBScaledCopy", bCopyEFBScaled);
SET_IF_DIFFERS("Video_Hacks", "EFBCopyCacheEnable", bEFBCopyCacheEnable);
SET_IF_DIFFERS("Video_Hacks", "EFBEmulateFormatChanges", bEFBEmulateFormatChanges);
iniFile.Save(game_ini);
}
bool VideoConfig::IsVSync()
{
return Core::isTabPressed ? false : bVSync;

View file

@ -50,7 +50,7 @@ struct VideoConfig
{
VideoConfig();
void Load(const char *ini_file);
void GameIniLoad(const char *ini_file);
void GameIniLoad(const char* default_ini, const char* game_ini);
void VerifyValidity();
void Save(const char *ini_file);
void GameIniSave(const char* default_ini, const char* game_ini);