mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-12 17:19:28 +01:00
Merge pull request #22900 from hrydgard/gamebutton-cleanup
sceReg: Sync registry settings with the config, match category_version to the firmware
This commit is contained in:
15 files changed
+399
-156
No files matched your search
@@ -23,7 +23,7 @@ static void TextToImage(std::string_view buttonText, ImageID *image) {
|
||||
if (buttonText == di->T("Delete") || buttonText == di->T("Move to trash")) {
|
||||
*image = ImageID("I_TRASHCAN");
|
||||
} else if (buttonText == di->T("Back")) {
|
||||
*image = ImageID("I_NAVIGATE_BACK");
|
||||
*image = ImageID("I_CHEVRON_LEFT");
|
||||
} else if (buttonText == di->T("Add")) {
|
||||
*image = ImageID("I_PLUS");
|
||||
} else if (buttonText == di->T("OK")) {
|
||||
|
||||
+9
-1
@@ -1470,10 +1470,12 @@ static constexpr const char *paramDateFormatNames[] = { "YYYYMMDD", "MMDDYYYY",
|
||||
|
||||
static constexpr const char *paramTimeFormatNames[] = { "24HR", "12HR" };
|
||||
|
||||
// Most of this is just registry settings, stored in our ini format. sceReg reads/writes here.
|
||||
static constexpr ConfigSetting systemParamSettings[] = {
|
||||
ConfigSetting("PSPModel", SETTING(g_Config, iPSPModel), PSP_MODEL_SLIM, CfgFlag::PER_GAME | CfgFlag::REPORT)
|
||||
.Label(I18NCat::SYSTEM, "PSP Model").Choices(pSPModelNames),
|
||||
ConfigSetting("PSPFirmwareVersion", SETTING(g_Config, iFirmwareVersion), PSP_DEFAULT_FIRMWARE, CfgFlag::PER_GAME | CfgFlag::REPORT),
|
||||
ConfigSetting("SceRegCategoryVersion", SETTING(g_Config, iSceRegCategoryVersion), 1, CfgFlag::DEFAULT),
|
||||
ConfigSetting("NickName", SETTING(g_Config, sNickName), "PPSSPP", CfgFlag::PER_GAME),
|
||||
ConfigSetting("MacAddress", SETTING(g_Config, sMACAddress), "", CfgFlag::PER_GAME),
|
||||
ConfigSetting("GameLanguage", SETTING(g_Config, iLanguage), -1, CfgFlag::PER_GAME | CfgFlag::REPORT)
|
||||
@@ -1482,7 +1484,8 @@ static constexpr ConfigSetting systemParamSettings[] = {
|
||||
.Label(I18NCat::SYSTEM, "Time Format").Choices(paramTimeFormatNames),
|
||||
ConfigSetting("ParamDateFormat", SETTING(g_Config, iDateFormat), PSP_SYSTEMPARAM_DATE_FORMAT_YYYYMMDD, CfgFlag::PER_GAME)
|
||||
.Label(I18NCat::SYSTEM, "Date Format").Choices(paramDateFormatNames),
|
||||
ConfigSetting("TimeZone", SETTING(g_Config, iTimeZone), 0, CfgFlag::PER_GAME),
|
||||
ConfigSetting("TimeZone", SETTING(g_Config, iTimeZoneOffset), 0, CfgFlag::PER_GAME),
|
||||
ConfigSetting("TimeZoneArea", SETTING(g_Config, sTimeZoneArea), "sweden", CfgFlag::PER_GAME), // This doesn't really do much. Just cosmetic in the XMB
|
||||
ConfigSetting("DayLightSavings", SETTING(g_Config, bDayLightSavings), (bool) PSP_SYSTEMPARAM_DAYLIGHTSAVINGS_STD, CfgFlag::PER_GAME)
|
||||
.Label(I18NCat::SYSTEM, "Daylight savings"),
|
||||
ConfigSetting("ButtonPreference", SETTING(g_Config, iButtonPreference), PSP_SYSTEMPARAM_BUTTON_CROSS, CfgFlag::PER_GAME | CfgFlag::REPORT)
|
||||
@@ -1495,6 +1498,11 @@ static constexpr ConfigSetting systemParamSettings[] = {
|
||||
ConfigSetting("WlanPowerSave", SETTING(g_Config, bWlanPowerSave), (bool) PSP_SYSTEMPARAM_WLAN_POWERSAVE_OFF, CfgFlag::PER_GAME),
|
||||
ConfigSetting("EncryptSave", SETTING(g_Config, bEncryptSave), true, CfgFlag::PER_GAME | CfgFlag::REPORT),
|
||||
ConfigSetting("VshUmdAutoboot", SETTING(g_Config, bVshUmdAutoboot), false, CfgFlag::DEFAULT),
|
||||
ConfigSetting("XmbThemeType", SETTING(g_Config, iXmbThemeType), 0, CfgFlag::DEFAULT),
|
||||
ConfigSetting("XmbThemeColorMode", SETTING(g_Config, iXmbThemeColorMode), 0, CfgFlag::DEFAULT),
|
||||
ConfigSetting("XmbThemeWallpaperMode", SETTING(g_Config, iXmbThemeWallpaperMode), 0, CfgFlag::DEFAULT),
|
||||
ConfigSetting("XmbThemeSystemColor", SETTING(g_Config, iXmbThemeSystemColor), 0, CfgFlag::DEFAULT),
|
||||
ConfigSetting("XmbThemeCustomThemeMode", SETTING(g_Config, iXmbThemeCustomThemeMode), 0, CfgFlag::DEFAULT),
|
||||
ConfigSetting("MemStickSize", SETTING(g_Config, iMemStickSizeGB), 16, CfgFlag::DEFAULT)
|
||||
.Label(I18NCat::SYSTEM, "Memory Stick size").Range(1, 32).Units("GB"),
|
||||
ConfigSetting("FuseID", SETTING(g_Config, sFuseID), "", CfgFlag::DEFAULT),
|
||||
|
||||
+12
-2
@@ -601,7 +601,10 @@ public:
|
||||
// Risky JIT optimizations
|
||||
bool bDiscardRegsOnJRRA;
|
||||
|
||||
// SystemParam
|
||||
// SystemParam settings - well, they are queries by systemparam but they're actually stored in the registry.
|
||||
// So now, we mirror these out into the actual registry.
|
||||
int iSceRegCategoryVersion; // The version of the registry. Resets to 1 if you install an older firmware. The system will reject too-new regs and rewrite too-old ones.
|
||||
|
||||
std::string sNickName; // AdHoc and system nickname
|
||||
std::string sMACAddress;
|
||||
// The Fuse ID of the PSP a game patch was installed on (12 hex digits), to decrypt it with.
|
||||
@@ -610,13 +613,20 @@ public:
|
||||
int iLanguage;
|
||||
int iTimeFormat;
|
||||
int iDateFormat;
|
||||
int iTimeZone;
|
||||
int iTimeZoneOffset;
|
||||
std::string sTimeZoneArea;
|
||||
bool bDayLightSavings;
|
||||
int iButtonPreference;
|
||||
int iLockParentalLevel;
|
||||
bool bEncryptSave;
|
||||
// /CONFIG/SYSTEM/umd_autoboot: whether the VSH starts an inserted disc by itself.
|
||||
bool bVshUmdAutoboot;
|
||||
// /CONFIG/SYSTEM/XMB (language and button_assign are iLanguage and iButtonPreference).
|
||||
int iXmbThemeType;
|
||||
int iXmbThemeColorMode;
|
||||
int iXmbThemeWallpaperMode;
|
||||
int iXmbThemeSystemColor;
|
||||
int iXmbThemeCustomThemeMode;
|
||||
|
||||
// Networking
|
||||
bool bEnableAdhocServer;
|
||||
|
||||
@@ -403,3 +403,51 @@ void ConfigSetting::ReportSetting(const ConfigBlock *configBlock, UrlEncoder &da
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int ConfigSettingRef::GetIntValue() const {
|
||||
_dbg_assert_(setting);
|
||||
const void *ptr = setting->GetVoidPtr(block);
|
||||
switch (setting->GetType()) {
|
||||
case ConfigSetting::Type::TYPE_INT:
|
||||
return *(const int *)ptr;
|
||||
case ConfigSetting::Type::TYPE_BOOL:
|
||||
return *(const bool *)ptr ? 1 : 0;
|
||||
default:
|
||||
ERROR_LOG(Log::Config, "ConfigSettingRef::GetIntValue: %.*s is not an int or bool", STR_VIEW(setting->IniKey()));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigSettingRef::SetIntValue(int value) const {
|
||||
_dbg_assert_(setting);
|
||||
void *ptr = setting->VoidPtr(block);
|
||||
switch (setting->GetType()) {
|
||||
case ConfigSetting::Type::TYPE_INT:
|
||||
*(int *)ptr = value;
|
||||
break;
|
||||
case ConfigSetting::Type::TYPE_BOOL:
|
||||
*(bool *)ptr = value != 0;
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(Log::Config, "ConfigSettingRef::SetIntValue: %.*s is not an int or bool", STR_VIEW(setting->IniKey()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string *ConfigSettingRef::GetStringPtr() const {
|
||||
_dbg_assert_(setting);
|
||||
if (setting->GetType() != ConfigSetting::Type::TYPE_STRING) {
|
||||
ERROR_LOG(Log::Config, "ConfigSettingRef::GetStringPtr: %.*s is not a string", STR_VIEW(setting->IniKey()));
|
||||
return nullptr;
|
||||
}
|
||||
return (const std::string *)setting->GetVoidPtr(block);
|
||||
}
|
||||
|
||||
void ConfigSettingRef::SetStringValue(std::string_view value) const {
|
||||
_dbg_assert_(setting);
|
||||
if (setting->GetType() != ConfigSetting::Type::TYPE_STRING) {
|
||||
ERROR_LOG(Log::Config, "ConfigSettingRef::SetStringValue: %.*s is not a string", STR_VIEW(setting->IniKey()));
|
||||
return;
|
||||
}
|
||||
*(std::string *)setting->VoidPtr(block) = std::string(value);
|
||||
}
|
||||
@@ -251,6 +251,9 @@ struct ConfigSetting {
|
||||
_dbg_assert_(type_ == Type::TYPE_FLOAT);
|
||||
return defaultCallback_.f ? defaultCallback_.f() : default_.f;
|
||||
}
|
||||
Type GetType() const {
|
||||
return type_;
|
||||
}
|
||||
|
||||
constexpr const ConfigSettingInfo &Info() const {
|
||||
return info_;
|
||||
@@ -274,6 +277,10 @@ struct ConfigSetting {
|
||||
const char *configBlockBase = (const char *)configBlock;
|
||||
return (const void *)(configBlockBase + offset_);
|
||||
}
|
||||
void *VoidPtr(const ConfigBlock *configBlock) const {
|
||||
const char *configBlockBase = (const char *)configBlock;
|
||||
return (void *)(configBlockBase + offset_);
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr void Check(bool ok) {
|
||||
@@ -300,4 +307,10 @@ struct ConfigSettingRef {
|
||||
ConfigBlock *block;
|
||||
const ConfigSetting *setting;
|
||||
std::string_view section;
|
||||
|
||||
// Easy accessors. The int ones also handle bools, as 0 or 1.
|
||||
int GetIntValue() const;
|
||||
void SetIntValue(int value) const;
|
||||
const std::string *GetStringPtr() const; // nullptr if not a string setting.
|
||||
void SetStringValue(std::string_view value) const;
|
||||
};
|
||||
+10
-13
@@ -923,7 +923,7 @@ static bool KirkOutputFits(const KIRK_CMD1_ECDSA_HEADER *header, u32 size) {
|
||||
}
|
||||
|
||||
static int pspDecryptType0(KirkState *kirk, const u8 *inbuf, u8 *outbuf, u32 size) {
|
||||
DEBUG_LOG(Log::Loader, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]);
|
||||
DEBUG_LOG(Log::Loader, "Decrypting tag %02X (type 0)", (u32)*(u32_le *)&inbuf[0xD0]);
|
||||
const auto decryptSize = *(s32_le*)&inbuf[0xB0];
|
||||
const auto pti = GetTagInfo((u32)*(u32_le *)&inbuf[0xD0]);
|
||||
|
||||
@@ -985,9 +985,8 @@ static int pspDecryptType0(KirkState *kirk, const u8 *inbuf, u8 *outbuf, u32 siz
|
||||
return decryptSize;
|
||||
}
|
||||
|
||||
static int pspDecryptType1(KirkState *kirk, const u8 *inbuf, u8 *outbuf, u32 size)
|
||||
{
|
||||
INFO_LOG(Log::Loader, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]);
|
||||
static int pspDecryptType1(KirkState *kirk, const u8 *inbuf, u8 *outbuf, u32 size) {
|
||||
DEBUG_LOG(Log::Loader, "Decrypting tag %02X (type 1)", (u32)*(u32_le *)&inbuf[0xD0]);
|
||||
const auto decryptSize = *(s32_le*)&inbuf[0xB0];
|
||||
const auto pti = GetTagInfo((u32)*(u32_le *)&inbuf[0xD0]);
|
||||
|
||||
@@ -1045,9 +1044,8 @@ static int pspDecryptType1(KirkState *kirk, const u8 *inbuf, u8 *outbuf, u32 siz
|
||||
return decryptSize;
|
||||
}
|
||||
|
||||
static int pspDecryptType2(KirkState *kirk, const u8 *inbuf, u8 *outbuf, u32 size)
|
||||
{
|
||||
INFO_LOG(Log::Loader, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]);
|
||||
static int pspDecryptType2(KirkState *kirk, const u8 *inbuf, u8 *outbuf, u32 size) {
|
||||
DEBUG_LOG(Log::Loader, "Decrypting tag %02X (type 2)", (u32)*(u32_le *)&inbuf[0xD0]);
|
||||
const auto decryptSize = *(s32_le*)&inbuf[0xB0];
|
||||
const auto pti = GetTagInfo2((u32)*(u32_le *)&inbuf[0xD0]);
|
||||
|
||||
@@ -1165,9 +1163,8 @@ static int pspFinishType5(KirkState *kirk, const u8 *inbuf, u8 *outbuf, u32 size
|
||||
return decryptSize;
|
||||
}
|
||||
|
||||
static int pspDecryptType5(KirkState *kirk, const u8 *inbuf, u8 *outbuf, u32 size, const u8 *seed)
|
||||
{
|
||||
INFO_LOG(Log::Loader, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]);
|
||||
static int pspDecryptType5(KirkState *kirk, const u8 *inbuf, u8 *outbuf, u32 size, const u8 *seed) {
|
||||
DEBUG_LOG(Log::Loader, "Decrypting tag %02X (type 5)", (u32)*(u32_le *)&inbuf[0xD0]);
|
||||
const auto pti = GetTagInfo2((u32)*(u32_le *)&inbuf[0xD0]);
|
||||
|
||||
if (!pti)
|
||||
@@ -1206,7 +1203,7 @@ static int pspDecryptType3(KirkState *kirk, const u8 *inbuf, u8 *outbuf, u32 siz
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
INFO_LOG(Log::Loader, "Decrypting tag %08X", (u32)*(u32_le *)&inbuf[0xD0]);
|
||||
DEBUG_LOG(Log::Loader, "Decrypting tag %08X (type 3)", (u32)*(u32_le *)&inbuf[0xD0]);
|
||||
|
||||
auto xorbuf = expandSeed(pti->key, pti->code, secureId);
|
||||
PRXType5 type5(inbuf);
|
||||
@@ -1221,7 +1218,7 @@ static int pspDecryptType3(KirkState *kirk, const u8 *inbuf, u8 *outbuf, u32 siz
|
||||
|
||||
static int pspDecryptType6(KirkState *kirk, const u8 *inbuf, u8 *outbuf, u32 size)
|
||||
{
|
||||
INFO_LOG(Log::Loader, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]);
|
||||
DEBUG_LOG(Log::Loader, "Decrypting tag %02X (type 6)", (u32)*(u32_le *)&inbuf[0xD0]);
|
||||
const auto decryptSize = *(s32_le*)&inbuf[0xB0];
|
||||
const auto pti = GetTagInfo2((u32)*(u32_le *)&inbuf[0xD0]);
|
||||
|
||||
@@ -1297,7 +1294,7 @@ static int pspDecryptType6(KirkState *kirk, const u8 *inbuf, u8 *outbuf, u32 siz
|
||||
// type 6 writes its tail there.
|
||||
static int pspDecryptType9(KirkState *kirk, const u8 *inbuf, u8 *outbuf, u32 size)
|
||||
{
|
||||
INFO_LOG(Log::Loader, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]);
|
||||
DEBUG_LOG(Log::Loader, "Decrypting tag %02X (type 9)", (u32)*(u32_le *)&inbuf[0xD0]);
|
||||
const auto decryptSize = *(s32_le*)&inbuf[0xB0];
|
||||
const auto pti = GetTagInfo2((u32)*(u32_le *)&inbuf[0xD0]);
|
||||
|
||||
|
||||
@@ -293,6 +293,10 @@ const HLEFunction sceImpose_driver[] = {
|
||||
{0X01EF0650, &WrapI_I<sceImposeSetStatus>, "sceImposeSetStatus", 'i', "i" },
|
||||
{0X2462EFE4, &WrapI_I<sceImposeSetStatus>, "sceImposeSetStatus", 'i', "i" },
|
||||
{0XC10C3D39, &WrapI_I<sceImposeSetStatus>, "sceImposeSetStatus", 'i', "i" },
|
||||
|
||||
// Unknown, spams in older firmwares (3.80). Probably aliases for Get something.
|
||||
{0x21d3ea22, 0, "sceImpose_21D3EA22", '?', ""},
|
||||
{0xd4fda428, 0, "sceImpose_d4fda428", '?', ""},
|
||||
};
|
||||
|
||||
void Register_sceImpose_driver() {
|
||||
|
||||
@@ -850,7 +850,7 @@ void ImportVarSymbol(WriteVarSymbolState &state, const VarSymbolImport &var) {
|
||||
}
|
||||
|
||||
// It hasn't been exported yet, but hopefully it will later.
|
||||
INFO_LOG(Log::Loader, "Variable (%s,%08x) unresolved, storing for later resolving", var.moduleName, var.nid);
|
||||
DEBUG_LOG(Log::Loader, "Variable (%s,%08x) unresolved, storing for later resolving", var.moduleName, var.nid);
|
||||
}
|
||||
|
||||
void ExportVarSymbol(const VarSymbolExport &var) {
|
||||
@@ -945,7 +945,7 @@ void ImportFuncSymbol(const FuncSymbolImport &func, bool reimporting, const char
|
||||
// We used to report this, but I don't think it's very interesting anymore.
|
||||
WARN_LOG(Log::Loader, "Unknown syscall from known HLE module '%s': 0x%08x (import for '%s')", func.moduleName, func.nid, importingModule);
|
||||
} else {
|
||||
INFO_LOG(Log::Loader, "Function (%s,%08x) unresolved in '%s', storing for later resolving", func.moduleName, func.nid, importingModule);
|
||||
DEBUG_LOG(Log::Loader, "Function (%s,%08x) unresolved in '%s', storing for later resolving", func.moduleName, func.nid, importingModule);
|
||||
}
|
||||
|
||||
if (shouldHLE || !reimporting) {
|
||||
|
||||
+205
-99
@@ -5,21 +5,54 @@
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/HLE/FunctionWrappers.h"
|
||||
#include "Core/HLE/ErrorCodes.h"
|
||||
#include "Core/HLE/sceUtility.h"
|
||||
#include "Common/Serialize/Serializer.h"
|
||||
#include "Common/Serialize/SerializeMap.h"
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/ConfigSettings.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#define SYSTEM_REGISTRY "/system"
|
||||
#define REG_KEYNAME_SIZE 27
|
||||
|
||||
enum RegKeyTypes {
|
||||
REG_TYPE_DIR = 1,
|
||||
REG_TYPE_INT = 2,
|
||||
REG_TYPE_STR = 3,
|
||||
REG_TYPE_BIN = 4,
|
||||
};
|
||||
// Mapping to PPSSPP settings
|
||||
// Bools are stored as 4-byte INT registry keys, 0 or 1.
|
||||
//
|
||||
// CONFIG/SYSTEM/owner_name <-> g_Config.sNickName
|
||||
// CONFIG/SYSTEM/XMB/language <-> g_Config.iLanguage (-1 means auto, and reads as what GetPSPLanguage() picks)
|
||||
// CONFIG/SYSTEM/umd_autoboot <-> g_Config.bVshUmdAutoboot - and in addition, auto-controlled when booting UMD VIDEO.
|
||||
// CONFIG/SYSTEM/umd_cache <-> (unmapped, ignore)
|
||||
// CONFIG/SYSTEM/usb_autoconnect <-> (unmapped, ignore)
|
||||
// CONFIG/DATE/date_format <-> g_Config.iDateFormat
|
||||
// CONFIG/DATE/time_format <-> g_Config.iTimeFormat
|
||||
// CONFIG/DATE/time_zone_area <-> g_Config.sTimeZoneArea
|
||||
// CONFIG/DATE/time_zone_offset <-> g_Config.iTimeZoneOffset
|
||||
// CONFIG/DATE/summer_time <-> g_Config.bDayLightSavings
|
||||
// CONFIG/SYSTEM/LOCK/parental_level <-> g_Config.iLockParentalLevel, int
|
||||
// CONFIG/DISPLAY/screensaver_start_time <-> (unmapped, int seconds)
|
||||
// CONFIG/SYSTEM/POWER_SAVING/backlight_off_interval <-> (unmapped, int seconds)
|
||||
// CONFIG/SYSTEM/POWER_SAVING/suspend_interval_interval <-> (unmapped, int seconds)
|
||||
// CONFIG/SYSTEM/POWER_SAVING/wlan_mode <-> (unmapped, bool, "WLAN power save")
|
||||
// CONFIG/SYSTEM/SOUND/avls <-> (unmapped, bool)
|
||||
// CONFIG/SYSTEM/SOUND/dynamic_normalizer <-> (unmapped, bool)
|
||||
// CONFIG/SYSTEM/SOUND/operation_sound_mode <-> (unmapped, bool) (click sound when navigating the XMB)
|
||||
// CONFIG/RSS/download_items (unmapped, int)
|
||||
// CONFIG/SYSTEM/XMB/button_assign <-> g_Config.iButtonPreference
|
||||
// CONFIG/SYSTEM/XMB/theme_type <-> g_Config.iXmbThemeType
|
||||
// CONFIG/SYSTEM/XMB/THEME/color_mode <-> g_Config.iXmbThemeColorMode
|
||||
// CONFIG/SYSTEM/XMB/THEME/system_color <-> g_Config.iXmbThemeSystemColor
|
||||
// CONFIG/SYSTEM/XMB/THEME/wallpaper_mode <-> g_Config.iXmbThemeWallpaperMode
|
||||
// CONFIG/SYSTEM/XMB/THEME/custom_theme_mode <-> g_Config.iXmbThemeCustomThemeMode
|
||||
//
|
||||
// UMD video stuff
|
||||
// CONFIG/VIDEO/appended_volume (unmapped, int, 0-2) << TODO
|
||||
// CONFIG/VIDEO/menu_language (unmapped, 2 byte binary) << TODO
|
||||
// CONFIG/VIDEO/sound_language (unmapped, 2 byte binary) << TODO
|
||||
// CONFIG/VIDEO/subtitle_language (unmapped, 2 byte binary) << TODO
|
||||
// CONFIG/VIDEO/lr_button_enable (unmapped, bool) << TODO
|
||||
// CONFIG/VIDEO/list_play_mode (unmapped, bool) << TODO
|
||||
// CONFIG/VIDEO/title_display_mode (int, 0-1) << TODO
|
||||
|
||||
typedef unsigned int REGHANDLE;
|
||||
|
||||
@@ -57,17 +90,21 @@ enum class ValueType {
|
||||
struct KeyValue {
|
||||
std::string name;
|
||||
ValueType type;
|
||||
// Fixed values.
|
||||
const char *strValue; // also can be used for bin. Note: can't be std::string/string_view, will cut off the length.
|
||||
int intValue;
|
||||
const KeyValue *dirContents; // intValue is the count.
|
||||
// If set, an INT key reads this setting (as 0 or 1), even after the guest writes it: the VSH
|
||||
// rewrites every key with its default at each boot, since category_version is below its schema.
|
||||
bool (*boolSetting)() = nullptr;
|
||||
// If set, the key is synced both ways with this g_Config member (looked up by pointer): reads
|
||||
// return the setting and guest writes go to it. INT keys map to int or bool settings, STR keys
|
||||
// to std::string ones.
|
||||
void *configSetting;
|
||||
// If set, reads of an INT key return this instead, while writes still go to configSetting.
|
||||
int (*readOverride)();
|
||||
};
|
||||
|
||||
static bool UmdAutoboot() {
|
||||
static int UmdAutoboot() {
|
||||
// Forced on when a UMD Video disc picked from the game list boots the XMB.
|
||||
return PSP_CoreParameter().umdAutoboot.value_or(g_Config.bVshUmdAutoboot);
|
||||
return PSP_CoreParameter().umdAutoboot.value_or(g_Config.bVshUmdAutoboot) ? 1 : 0;
|
||||
}
|
||||
|
||||
// Guest-written registry values (sceRegCreateKey / sceRegSetKeyValue), keyed by category path
|
||||
@@ -664,7 +701,7 @@ static const KeyValue tree_CONFIG_PREMO[] = {
|
||||
{ "custom_video_buffer1", ValueType::INT, "", (int)0x0 }, // decimal: 0
|
||||
{ "custom_video_buffer2", ValueType::INT, "", (int)0x0 }, // decimal: 0
|
||||
{ "setting_internet", ValueType::INT, "", (int)0x0 }, // decimal: 0
|
||||
{ "button_assign", ValueType::INT, "", (int)0x0 }, // decimal: 0
|
||||
{ "button_assign", ValueType::INT, "", (int)0x0 }, // decimal: 0 NOTE: This is not the "real" button_assign, this is something else.
|
||||
{ "flags", ValueType::INT, "", (int)0x0 }, // decimal: 0
|
||||
{ "account_id", ValueType::BIN, "", 16 }, // (all zero)
|
||||
{ "login_id", ValueType::STR, "", 1 },
|
||||
@@ -725,17 +762,17 @@ static const KeyValue tree_CONFIG_ONESEG[] = {
|
||||
|
||||
// Dump of /CONFIG/SYSTEM/XMB/THEME
|
||||
static const KeyValue tree_CONFIG_SYSTEM_XMB_THEME[] = {
|
||||
{ "color_mode", ValueType::INT, "", (int)0x0 }, // decimal: 0
|
||||
{ "wallpaper_mode", ValueType::INT, "", (int)0x0 }, // decimal: 0
|
||||
{ "system_color", ValueType::INT, "", (int)0x0 }, // decimal: 0
|
||||
{ "custom_theme_mode", ValueType::INT, "", (int)0x0 }, // decimal: 0
|
||||
{ "color_mode", ValueType::INT, "", (int)0x0, nullptr, &g_Config.iXmbThemeColorMode }, // decimal: 0
|
||||
{ "wallpaper_mode", ValueType::INT, "", (int)0x0, nullptr, &g_Config.iXmbThemeWallpaperMode }, // decimal: 0
|
||||
{ "system_color", ValueType::INT, "", (int)0x0, nullptr, &g_Config.iXmbThemeSystemColor }, // decimal: 0
|
||||
{ "custom_theme_mode", ValueType::INT, "", (int)0x0, nullptr, &g_Config.iXmbThemeCustomThemeMode }, // decimal: 0
|
||||
};
|
||||
|
||||
// Dump of /CONFIG/SYSTEM/XMB
|
||||
static const KeyValue tree_CONFIG_SYSTEM_XMB[] = {
|
||||
{ "theme_type", ValueType::INT, "", (int)0x0 }, // decimal: 0
|
||||
{ "language", ValueType::INT, "", (int)0x1 }, // decimal: 1
|
||||
{ "button_assign", ValueType::INT, "", (int)0x1 }, // decimal: 1
|
||||
{ "theme_type", ValueType::INT, "", (int)0x0, nullptr, &g_Config.iXmbThemeType }, // decimal: 0
|
||||
{ "language", ValueType::INT, "", (int)0x1, nullptr, &g_Config.iLanguage, &GetPSPLanguage }, // decimal: 1
|
||||
{ "button_assign", ValueType::INT, "", (int)0x1, nullptr, &g_Config.iButtonPreference },
|
||||
{ "THEME", ValueType::DIR, "", ARRAY_SIZE(tree_CONFIG_SYSTEM_XMB_THEME), tree_CONFIG_SYSTEM_XMB_THEME },
|
||||
};
|
||||
|
||||
@@ -760,7 +797,7 @@ static const KeyValue tree_CONFIG_SYSTEM_POWER_SAVING[] = {
|
||||
// Dump of /CONFIG/SYSTEM/LOCK
|
||||
static const KeyValue tree_CONFIG_SYSTEM_LOCK[] = {
|
||||
{ "password", ValueType::BIN, "0000", 4 },
|
||||
{ "parental_level", ValueType::INT, "", (int)0x0 }, // decimal: 0
|
||||
{ "parental_level", ValueType::INT, "", (int)0x0, nullptr, &g_Config.iLockParentalLevel }, // decimal: 0
|
||||
{ "browser_start", ValueType::INT, "", (int)0x0 }, // decimal: 0
|
||||
};
|
||||
|
||||
@@ -772,9 +809,9 @@ static const KeyValue tree_CONFIG_SYSTEM_CHARACTER_SET[] = {
|
||||
|
||||
// Dump of /CONFIG/SYSTEM
|
||||
static const KeyValue tree_CONFIG_SYSTEM[] = {
|
||||
{ "owner_name", ValueType::STR, "P939", 5 },
|
||||
{ "owner_name", ValueType::STR, "P939", 5, nullptr, &g_Config.sNickName },
|
||||
{ "backlight_brightness", ValueType::INT, "", (int)0x3 }, // decimal: 3
|
||||
{ "umd_autoboot", ValueType::INT, "", (int)0x1, nullptr, &UmdAutoboot }, // decimal: 1
|
||||
{ "umd_autoboot", ValueType::INT, "", (int)0x1, nullptr, &g_Config.bVshUmdAutoboot, &UmdAutoboot }, // decimal: 1
|
||||
{ "usb_charge", ValueType::INT, "", (int)0x1 }, // decimal: 1
|
||||
{ "umd_cache", ValueType::INT, "", (int)0x1 }, // decimal: 1
|
||||
{ "usb_auto_connect", ValueType::INT, "", (int)0x1 }, // decimal: 1
|
||||
@@ -793,11 +830,11 @@ static const KeyValue tree_CONFIG_SYSTEM[] = {
|
||||
|
||||
// Dump of /CONFIG/DATE
|
||||
static const KeyValue tree_CONFIG_DATE[] = {
|
||||
{ "time_format", ValueType::INT, "", (int)0x0 }, // decimal: 0
|
||||
{ "date_format", ValueType::INT, "", (int)0x2 }, // decimal: 2
|
||||
{ "summer_time", ValueType::INT, "", (int)0x0 }, // decimal: 0
|
||||
{ "time_zone_offset", ValueType::INT, "", (int)0x3c }, // decimal: 60
|
||||
{ "time_zone_area", ValueType::STR, "sweden", 7 },
|
||||
{ "time_format", ValueType::INT, "", (int)0x0, nullptr, &g_Config.iTimeFormat }, // decimal: 0
|
||||
{ "date_format", ValueType::INT, "", (int)0x2, nullptr, &g_Config.iDateFormat }, // decimal: 2
|
||||
{ "summer_time", ValueType::INT, "", (int)0x0, nullptr, &g_Config.bDayLightSavings }, // decimal: 0
|
||||
{ "time_zone_offset", ValueType::INT, "", (int)0x3c, nullptr, &g_Config.iTimeZoneOffset }, // decimal: 60
|
||||
{ "time_zone_area", ValueType::STR, "sweden", 7, nullptr, &g_Config.sTimeZoneArea },
|
||||
};
|
||||
|
||||
// Dump of /CONFIG/NETWORK/ADHOC
|
||||
@@ -990,7 +1027,7 @@ static const KeyValue tree_REGISTRY[] = {
|
||||
// A real 6.6x PSP has 0x66 here, which is what this tree was dumped from - but the VSH treats a
|
||||
// category_version higher than the schema it knows as a corrupt registry and offers to reset your
|
||||
// settings instead of booting. So we go very low.
|
||||
{ "category_version", ValueType::INT, "", 1 },
|
||||
{ "category_version", ValueType::INT, "", 1, nullptr, &g_Config.iSceRegCategoryVersion },
|
||||
};
|
||||
|
||||
// There might be more categories.
|
||||
@@ -1056,10 +1093,45 @@ static const KeyValue *LookupStaticCategory(const std::string &path, int *count)
|
||||
return curDir;
|
||||
}
|
||||
|
||||
// Points the config-mapped keys at the current g_Config values. Done on every lookup, since the
|
||||
// settings can change outside the registry (in our UI, or a per-game config being loaded).
|
||||
static void ApplyConfigValues(MergedCategory &merged) {
|
||||
for (KeyValue &kv : merged.keyvals) {
|
||||
if (kv.readOverride && kv.type == ValueType::INT) {
|
||||
kv.intValue = kv.readOverride();
|
||||
continue;
|
||||
}
|
||||
if (!kv.configSetting) {
|
||||
continue;
|
||||
}
|
||||
const ConfigSettingRef *ref = g_Config.FindSetting(kv.configSetting);
|
||||
if (!ref) {
|
||||
continue;
|
||||
}
|
||||
if (kv.type == ValueType::INT) {
|
||||
kv.intValue = ref->GetIntValue();
|
||||
} else if (kv.type == ValueType::STR) {
|
||||
const std::string *str = ref->GetStringPtr();
|
||||
if (!str) {
|
||||
continue;
|
||||
}
|
||||
// Like the static dump, the length includes the null terminator.
|
||||
const int len = (int)str->size() + 1;
|
||||
if (kv.strValue && kv.intValue == len && memcmp(kv.strValue, str->c_str(), len) == 0) {
|
||||
continue;
|
||||
}
|
||||
merged.strStorage.push_back(*str);
|
||||
kv.strValue = merged.strStorage.back().c_str();
|
||||
kv.intValue = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Merges the static dump entries for path with the overlay entries written by the guest.
|
||||
static const MergedCategory &GetMergedCategory(const std::string &path) {
|
||||
auto cached = g_mergedCache.find(path);
|
||||
if (cached != g_mergedCache.end()) {
|
||||
ApplyConfigValues(cached->second);
|
||||
return cached->second;
|
||||
}
|
||||
|
||||
@@ -1100,12 +1172,7 @@ static const MergedCategory &GetMergedCategory(const std::string &path) {
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &kv : merged.keyvals) {
|
||||
if (kv.boolSetting) {
|
||||
kv.intValue = kv.boolSetting() ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
ApplyConfigValues(merged);
|
||||
return merged;
|
||||
}
|
||||
|
||||
@@ -1143,6 +1210,21 @@ static const KeyValue *LookupCategory(std::string_view path, int *count) {
|
||||
return cur->keyvals.data();
|
||||
}
|
||||
|
||||
static const KeyValue *LookupCategoryKey(const KeyValue *keyvals, const char *name, int count, int *index = nullptr) {
|
||||
if (!keyvals || !count) {
|
||||
return nullptr;
|
||||
}
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (equals(keyvals[i].name, name)) {
|
||||
if (index) {
|
||||
*index = i;
|
||||
}
|
||||
return &keyvals[i];
|
||||
}
|
||||
};
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void __RegDoState(PointerWrap &p) {
|
||||
auto s = p.Section("sceReg", 0, 4);
|
||||
if (!s) {
|
||||
@@ -1347,31 +1429,31 @@ int sceRegGetKeyInfo(int catHandle, const char *name, u32 outKeyHandleAddr, u32
|
||||
return hleLogWarning(Log::sceReg, SCE_REG_ERROR_CATEGORY_NOT_FOUND);
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (equals(keyvals[i].name, name)) {
|
||||
// Found it!
|
||||
if (Memory::IsValid4AlignedAddress(outKeyHandleAddr)) {
|
||||
// Let's just make the index the key handle.
|
||||
Memory::WriteUnchecked_U32(i, outKeyHandleAddr);
|
||||
}
|
||||
if (Memory::IsValid4AlignedAddress(outTypeAddr)) {
|
||||
// Let's just make the index the key handle.
|
||||
Memory::WriteUnchecked_U32((int)keyvals[i].type, outTypeAddr);
|
||||
}
|
||||
int size = 0;
|
||||
if (Memory::IsValid4AlignedAddress(outSizeAddr)) {
|
||||
switch (keyvals[i].type) {
|
||||
case ValueType::BIN: size = (int)keyvals[i].intValue; break;
|
||||
case ValueType::STR: size = (int)keyvals[i].intValue; break;
|
||||
case ValueType::DIR: size = 0; break;
|
||||
case ValueType::INT: size = 4; break;
|
||||
default: break;
|
||||
}
|
||||
// Let's just make the index the key handle.
|
||||
Memory::WriteUnchecked_U32(size, outSizeAddr);
|
||||
}
|
||||
return hleLogDebug(Log::sceReg, 0, "handle: %d type: %d size: %d", i, (int)keyvals[i].type, size);
|
||||
int index = 0;
|
||||
const KeyValue *keyval = LookupCategoryKey(keyvals, name, count, &index);
|
||||
if (keyval) {
|
||||
// Found it!
|
||||
if (Memory::IsValid4AlignedAddress(outKeyHandleAddr)) {
|
||||
// Let's just make the index the key handle.
|
||||
Memory::WriteUnchecked_U32(index, outKeyHandleAddr);
|
||||
}
|
||||
if (Memory::IsValid4AlignedAddress(outTypeAddr)) {
|
||||
// Let's just make the index the key handle.
|
||||
Memory::WriteUnchecked_U32((int)keyval->type, outTypeAddr);
|
||||
}
|
||||
int size = 0;
|
||||
if (Memory::IsValid4AlignedAddress(outSizeAddr)) {
|
||||
switch (keyval->type) {
|
||||
case ValueType::BIN: size = (int)keyval->intValue; break;
|
||||
case ValueType::STR: size = (int)keyval->intValue; break;
|
||||
case ValueType::DIR: size = 0; break;
|
||||
case ValueType::INT: size = 4; break;
|
||||
default: break;
|
||||
}
|
||||
// Let's just make the index the key handle.
|
||||
Memory::WriteUnchecked_U32(size, outSizeAddr);
|
||||
}
|
||||
return hleLogDebug(Log::sceReg, 0, "type: %d size: %d", (int)keyval->type, size);
|
||||
}
|
||||
|
||||
return hleLogWarning(Log::sceReg, -1, "key with name '%s' not found", name);
|
||||
@@ -1393,24 +1475,23 @@ int sceRegGetKeyInfoByName(int catHandle, const char *name, u32 typeAddr, u32 si
|
||||
return hleLogWarning(Log::sceReg, SCE_REG_ERROR_CATEGORY_NOT_FOUND);
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (equals(keyvals[i].name, name)) {
|
||||
int size = 0;
|
||||
if (Memory::IsValid4AlignedAddress(typeAddr)) {
|
||||
Memory::WriteUnchecked_U32((int)keyvals[i].type, typeAddr);
|
||||
}
|
||||
if (Memory::IsValid4AlignedAddress(sizeAddr)) {
|
||||
switch (keyvals[i].type) {
|
||||
case ValueType::BIN: size = (int)keyvals[i].intValue; break;
|
||||
case ValueType::STR: size = (int)keyvals[i].intValue; break;
|
||||
case ValueType::DIR: size = 0; break;
|
||||
case ValueType::INT: size = 4; break;
|
||||
default: break;
|
||||
}
|
||||
Memory::WriteUnchecked_U32(size, sizeAddr);
|
||||
}
|
||||
return hleLogDebug(Log::sceReg, 0, "type: %d size: %d", (int)keyvals[i].type, size);
|
||||
const KeyValue *keyval = LookupCategoryKey(keyvals, name, count);
|
||||
if (keyval) {
|
||||
int size = 0;
|
||||
if (Memory::IsValid4AlignedAddress(typeAddr)) {
|
||||
Memory::WriteUnchecked_U32((int)keyval->type, typeAddr);
|
||||
}
|
||||
if (Memory::IsValid4AlignedAddress(sizeAddr)) {
|
||||
switch (keyval->type) {
|
||||
case ValueType::BIN: size = (int)keyval->intValue; break;
|
||||
case ValueType::STR: size = (int)keyval->intValue; break;
|
||||
case ValueType::DIR: size = 0; break;
|
||||
case ValueType::INT: size = 4; break;
|
||||
default: break;
|
||||
}
|
||||
Memory::WriteUnchecked_U32(size, sizeAddr);
|
||||
}
|
||||
return hleLogDebug(Log::sceReg, 0, "type: %d size: %d", (int)keyval->type, size);
|
||||
}
|
||||
|
||||
return hleLogWarning(Log::sceReg, -1, "key with name '%s' not found", name);
|
||||
@@ -1421,7 +1502,7 @@ int sceRegGetKeyValue(int catHandle, int keyHandle, u32 bufAddr, u32 size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto iter = g_openCategories.find(catHandle);
|
||||
const auto iter = g_openCategories.find(catHandle);
|
||||
if (iter == g_openCategories.end()) {
|
||||
return hleLogError(Log::sceReg, 0, "Not found");
|
||||
}
|
||||
@@ -1440,14 +1521,14 @@ int sceRegGetKeyValue(int catHandle, int keyHandle, u32 bufAddr, u32 size) {
|
||||
switch (keyval.type) {
|
||||
case ValueType::BIN:
|
||||
Memory::MemcpyUnchecked(bufAddr, keyval.strValue, std::min(size, (u32)keyval.intValue));
|
||||
return hleLogDebug(Log::sceReg, 0);
|
||||
return hleLogDebug(Log::sceReg, 0, "%s/%s: value: <binary data>", iter->second.path.c_str(), keyval.name.c_str());
|
||||
case ValueType::STR:
|
||||
Memory::MemcpyUnchecked(bufAddr, keyval.strValue, std::min(size, (u32)keyval.intValue));
|
||||
return hleLogDebug(Log::sceReg, 0, "value: '%s'", keyval.strValue);
|
||||
return hleLogDebug(Log::sceReg, 0, "%s/%s: value: '%s'", iter->second.path.c_str(), keyval.name.c_str(), keyval.strValue);
|
||||
case ValueType::INT:
|
||||
if (size >= sizeof(u32))
|
||||
Memory::WriteUnchecked_U32(keyval.intValue, bufAddr);
|
||||
return hleLogDebug(Log::sceReg, 0, "value: %d (0x%08x)", keyval.intValue, keyval.intValue);
|
||||
return hleLogInfo(Log::sceReg, 0, "%s/%s: value: %d (0x%08x)", iter->second.path.c_str(), keyval.name.c_str(), keyval.intValue, keyval.intValue);
|
||||
case ValueType::DIR:
|
||||
case ValueType::FAIL:
|
||||
default:
|
||||
@@ -1456,6 +1537,7 @@ int sceRegGetKeyValue(int catHandle, int keyHandle, u32 bufAddr, u32 size) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This one seems to ignore overlays?
|
||||
int sceRegGetKeyValueByName(int catHandle, const char *name, u32 bufAddr, u32 size) {
|
||||
if (!name) {
|
||||
return hleLogError(Log::sceReg, -1, "Invalid name pointer");
|
||||
@@ -1482,14 +1564,17 @@ int sceRegGetKeyValueByName(int catHandle, const char *name, u32 bufAddr, u32 si
|
||||
const KeyValue &keyval = keyvals[i];
|
||||
switch (keyval.type) {
|
||||
case ValueType::BIN:
|
||||
Memory::MemcpyUnchecked(bufAddr, keyval.strValue, std::min(size, (u32)keyval.intValue));
|
||||
return hleLogDebug(Log::sceReg, 0);
|
||||
case ValueType::STR:
|
||||
Memory::MemcpyUnchecked(bufAddr, keyval.strValue, std::min(size, (u32)keyval.intValue));
|
||||
return hleLogDebug(Log::sceReg, 0, "value: '%s'", keyval.strValue);
|
||||
if (keyval.type == ValueType::BIN) {
|
||||
return hleLogDebug(Log::sceReg, 0, "value: <binary data>");
|
||||
} else {
|
||||
return hleLogDebug(Log::sceReg, 0, "value: '%s'", keyval.strValue);
|
||||
}
|
||||
case ValueType::INT:
|
||||
if (size >= sizeof(u32))
|
||||
if (size >= sizeof(u32)) {
|
||||
Memory::WriteUnchecked_U32(keyval.intValue, bufAddr);
|
||||
}
|
||||
return hleLogDebug(Log::sceReg, 0, "value: %d (0x%08x)", keyval.intValue, keyval.intValue);
|
||||
case ValueType::DIR:
|
||||
case ValueType::FAIL:
|
||||
@@ -1520,9 +1605,13 @@ int sceRegSetKeyValue(int catHandle, const char *name, u32 bufAddr, u32 size) {
|
||||
// registry upgrade rewrites BIN keys like /CONFIG/NP/account_id, and reports the settings as
|
||||
// corrupted if they read back as anything else.
|
||||
ValueType type = ValueType::FAIL;
|
||||
const ConfigSettingRef *configRef = nullptr;
|
||||
for (const auto &kv : GetMergedCategory(path).keyvals) {
|
||||
if (equals(kv.name, name)) {
|
||||
type = kv.type;
|
||||
if (kv.configSetting) {
|
||||
configRef = g_Config.FindSetting(kv.configSetting);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1552,6 +1641,13 @@ int sceRegSetKeyValue(int catHandle, const char *name, u32 bufAddr, u32 size) {
|
||||
return hleLogError(Log::sceReg, -1, "bad input addr");
|
||||
}
|
||||
value.intValue = (int)Memory::ReadUnchecked_U32(bufAddr);
|
||||
if (configRef) {
|
||||
configRef->SetIntValue(value.intValue);
|
||||
}
|
||||
|
||||
g_overlay[path][name] = value;
|
||||
InvalidateMergedCache();
|
||||
return hleLogInfo(Log::sceReg, 0, "set %s/%s to %d", path.c_str(), name, value.intValue);
|
||||
} else if (Memory::IsValidRange(bufAddr, size)) {
|
||||
const char *str = (const char *)Memory::GetPointerUnchecked(bufAddr);
|
||||
value.str.assign(str, size);
|
||||
@@ -1560,13 +1656,25 @@ int sceRegSetKeyValue(int catHandle, const char *name, u32 bufAddr, u32 size) {
|
||||
value.str.push_back('\0');
|
||||
}
|
||||
value.intValue = (int)value.str.size();
|
||||
if (configRef && type == ValueType::STR) {
|
||||
// Up to the terminator, if the guest included one.
|
||||
configRef->SetStringValue(std::string_view(value.str.c_str()));
|
||||
}
|
||||
g_overlay[path][name] = value;
|
||||
InvalidateMergedCache();
|
||||
if (type == ValueType::STR) {
|
||||
return hleLogInfo(Log::sceReg, 0, "set %s/%s to '%.*s'", path.c_str(), name, (int)value.str.size(), value.str.c_str());
|
||||
} else {
|
||||
if (value.str.size() == 2) {
|
||||
// This is probably one of the languages.
|
||||
return hleLogInfo(Log::sceReg, 0, "set %s/%s to binary data of size 2: '%c%c'", path.c_str(), name, value.str[0], value.str[1]);
|
||||
} else {
|
||||
return hleLogInfo(Log::sceReg, 0, "set %s/%s to binary data of size %d", path.c_str(), name, (int)value.str.size());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return hleLogError(Log::sceReg, -1, "bad input addr");
|
||||
}
|
||||
|
||||
g_overlay[path][name] = value;
|
||||
InvalidateMergedCache();
|
||||
return hleLogDebug(Log::sceReg, 0, "set %s/%s", path.c_str(), name);
|
||||
}
|
||||
|
||||
int sceRegCreateKey(int catHandle, const char *name, int type, u32 size) {
|
||||
@@ -1580,19 +1688,15 @@ int sceRegCreateKey(int catHandle, const char *name, int type, u32 size) {
|
||||
}
|
||||
|
||||
OverlayValue value;
|
||||
switch (type) {
|
||||
case REG_TYPE_DIR:
|
||||
value.isDir = true;
|
||||
switch ((ValueType)type) {
|
||||
case ValueType::DIR:
|
||||
value.type = ValueType::DIR;
|
||||
value.isDir = true;
|
||||
break;
|
||||
case REG_TYPE_INT:
|
||||
value.type = ValueType::INT;
|
||||
break;
|
||||
case REG_TYPE_STR:
|
||||
value.type = ValueType::STR;
|
||||
break;
|
||||
case REG_TYPE_BIN:
|
||||
value.type = ValueType::BIN;
|
||||
case ValueType::INT:
|
||||
case ValueType::STR:
|
||||
case ValueType::BIN:
|
||||
value.type = (ValueType)type;
|
||||
break;
|
||||
default:
|
||||
return hleLogError(Log::sceReg, -1, "bad type %d", type);
|
||||
@@ -1612,8 +1716,10 @@ int sceRegCreateKey(int catHandle, const char *name, int type, u32 size) {
|
||||
|
||||
g_overlay[path][name] = value;
|
||||
InvalidateMergedCache();
|
||||
return hleLogDebug(Log::sceReg, 0, "create %s/%s (type %d)", path.c_str(), name, type);
|
||||
|
||||
return hleLogInfo(Log::sceReg, 0, "create %s/%s (type %d)", path.c_str(), name, type);
|
||||
}
|
||||
|
||||
// Speculated signature
|
||||
int sceRegRemoveKey(int catHandle, int key) {
|
||||
return hleLogError(Log::sceReg, 0);
|
||||
|
||||
@@ -1577,7 +1577,7 @@ static u32 sceUtilityGetSystemParamInt(u32 id, u32 destaddr) {
|
||||
param = PSP_SYSTEMPARAM_TIME_FORMAT_24HR;
|
||||
break;
|
||||
case PSP_SYSTEMPARAM_ID_INT_TIMEZONE:
|
||||
param = g_Config.iTimeZone;
|
||||
param = g_Config.iTimeZoneOffset;
|
||||
break;
|
||||
case PSP_SYSTEMPARAM_ID_INT_DAYLIGHTSAVINGS:
|
||||
param = g_Config.bDayLightSavings?PSP_SYSTEMPARAM_DAYLIGHTSAVINGS_SAVING:PSP_SYSTEMPARAM_DAYLIGHTSAVINGS_STD;
|
||||
|
||||
@@ -1337,9 +1337,39 @@ bool EraseInstalledFirmware(const Path &nandRoot, std::string *error) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Also reset the category version.
|
||||
g_Config.iSceRegCategoryVersion = 1;
|
||||
return success;
|
||||
}
|
||||
|
||||
int SceRegCategoryVersionForFirmware(std::string_view version) {
|
||||
// The default of /REGISTRY/category_version in each firmware's registry schema, a table of
|
||||
// { name, type, size, default } entries in vsh/module/vshmain.prx (common_util.prx before 2.00).
|
||||
// When the stored version is below this, the shell writes the default of every key added since
|
||||
// that version (from 1, that includes umd_autoboot). One above it means a corrupt registry.
|
||||
static const struct {
|
||||
int firmware; // The first firmware with this version, as FirmwareVersionToInt() gives it.
|
||||
int categoryVersion;
|
||||
} versions[] = {
|
||||
{ 100, 0x00 }, { 150, 0x01 }, { 200, 0x06 }, { 250, 0x13 }, { 260, 0x14 }, { 270, 0x1b },
|
||||
{ 280, 0x20 }, { 300, 0x26 }, { 310, 0x2c }, { 330, 0x31 }, { 350, 0x35 }, { 360, 0x36 },
|
||||
{ 370, 0x3b }, { 380, 0x3e }, { 395, 0x40 }, { 405, 0x43 }, { 420, 0x46 }, { 500, 0x4c },
|
||||
{ 550, 0x58 }, { 570, 0x61 }, { 600, 0x63 }, { 620, 0x64 }, { 630, 0x66 },
|
||||
};
|
||||
const int fw = FirmwareVersionToInt(version);
|
||||
if (fw < versions[0].firmware) {
|
||||
return 1;
|
||||
}
|
||||
int categoryVersion = versions[0].categoryVersion;
|
||||
for (const auto &v : versions) {
|
||||
if (fw >= v.firmware) {
|
||||
categoryVersion = v.categoryVersion;
|
||||
}
|
||||
}
|
||||
return categoryVersion;
|
||||
}
|
||||
|
||||
int FirmwareVersionToInt(std::string_view version) {
|
||||
const size_t dot = version.find('.');
|
||||
if (dot == std::string_view::npos || dot == 0 || dot + 1 >= version.size()) {
|
||||
@@ -1671,6 +1701,11 @@ bool InstallFirmware(const Path &updater, const Path &nandRoot, const PSARUnpack
|
||||
if (ok) {
|
||||
ok = SwapStagingIntoPlace(nandRoot, staging, error);
|
||||
}
|
||||
if (ok) {
|
||||
// Match the registry to the new firmware's schema, so its shell doesn't reset the
|
||||
// settings (which sceReg maps to our config) to its defaults at first boot.
|
||||
g_Config.iSceRegCategoryVersion = SceRegCategoryVersionForFirmware(stats->firmwareVersion);
|
||||
}
|
||||
|
||||
// Whether it worked or not, don't leave the staging copy behind.
|
||||
if (File::Exists(staging) && !File::DeleteDirRecursively(staging)) {
|
||||
|
||||
@@ -181,6 +181,9 @@ bool EraseInstalledFirmware(const Path &nandRoot, std::string *error);
|
||||
// makes the result safe to compare with: an unknown version is older than every real one.
|
||||
int FirmwareVersionToInt(std::string_view version);
|
||||
|
||||
// The /REGISTRY/category_version the shell of this firmware expects. 1 for an unknown version.
|
||||
int SceRegCategoryVersionForFirmware(std::string_view version);
|
||||
|
||||
// The firmware versions we can actually boot the VSH (XMB) on. Every other version loads, but
|
||||
// the module patches it needs are version-specific, so it won't get anywhere.
|
||||
bool FirmwareVersionSupportsVSH(std::string_view version);
|
||||
|
||||
+43
-36
@@ -204,7 +204,6 @@ void GameButton::Draw(UIContext &dc) {
|
||||
}
|
||||
}
|
||||
|
||||
u32 color = 0, shadowColor = 0;
|
||||
using namespace UI;
|
||||
|
||||
UI::Style style = dc.GetTheme().itemStyle;
|
||||
@@ -232,71 +231,79 @@ void GameButton::Draw(UIContext &dc) {
|
||||
}
|
||||
const float textX = ListTextX(viewMode_);
|
||||
|
||||
if (texture && ginfo) {
|
||||
color = whiteAlpha(ease((time_now_d() - ginfo->icon.timeLoaded) * 2));
|
||||
shadowColor = blackAlpha(ease((time_now_d() - ginfo->icon.timeLoaded) * 2));
|
||||
float tw = texture->Width();
|
||||
float th = texture->Height();
|
||||
|
||||
// Adjust position so we don't stretch the image vertically or horizontally.
|
||||
// Make sure it's not wider than 144 (like Doom Legacy homebrew), ugly in the grid mode.
|
||||
float nw = std::min(iconBounds.h * tw / th, (float)iconBounds.w);
|
||||
iconBounds.x += (iconBounds.w - nw) / 2.0f;
|
||||
iconBounds.w = nw;
|
||||
}
|
||||
|
||||
int txOffset = down_ ? 4 : 0;
|
||||
if (viewMode_ != GameBrowserViewMode::GRID) {
|
||||
txOffset = 0;
|
||||
int iconYOffset = 0;
|
||||
if (viewMode_ == GameBrowserViewMode::GRID && down_) {
|
||||
iconYOffset = 4;
|
||||
}
|
||||
|
||||
Bounds overlayBounds = bounds_;
|
||||
|
||||
// Render the icon, all modes have this.
|
||||
int dropsize = 10;
|
||||
if (texture) {
|
||||
float alpha = 1.0f;
|
||||
float dropsize = 10;
|
||||
|
||||
if (ginfo) {
|
||||
float loadPhase = ease((time_now_d() - ginfo->icon.timeLoaded) * 2);
|
||||
|
||||
loadPhase = 0.0f;
|
||||
|
||||
alpha = loadPhase;
|
||||
|
||||
float tw = texture->Width();
|
||||
float th = texture->Height();
|
||||
// Adjust position so we don't stretch the image vertically or horizontally.
|
||||
// Make sure it's not wider than 144 (like Doom Legacy homebrew), ugly in the grid mode.
|
||||
float nw = std::min(iconBounds.h * tw / th, (float)iconBounds.w);
|
||||
iconBounds.x += (iconBounds.w - nw) / 2.0f;
|
||||
iconBounds.w = nw;
|
||||
}
|
||||
|
||||
if (viewMode_ == GameBrowserViewMode::LIST) {
|
||||
iconBounds.x += 4;
|
||||
}
|
||||
if (txOffset) {
|
||||
|
||||
if (iconYOffset) {
|
||||
// Button pressed, move the icon down a bit and reduce the shadow.
|
||||
dropsize = 3;
|
||||
iconBounds.y += txOffset * 2;
|
||||
overlayBounds.y += txOffset * 2;
|
||||
iconBounds.y += iconYOffset * 2;
|
||||
overlayBounds.y += iconYOffset * 2;
|
||||
}
|
||||
|
||||
if (HasFocus()) {
|
||||
dc.Draw()->Flush();
|
||||
dc.RebindTexture();
|
||||
float pulse = sin(time_now_d() * 7.0) * 0.25 + 0.8;
|
||||
|
||||
dc.DrawRectDropShadow(iconBounds, 10.0f, pulse, alphaMul(color, pulse));
|
||||
dc.DrawRectDropShadow(iconBounds, 10.0f, pulse, style.fgColor);
|
||||
dc.Draw()->Flush();
|
||||
} else {
|
||||
dc.Draw()->Flush();
|
||||
dc.RebindTexture();
|
||||
dc.DrawRectDropShadow(iconBounds, 8.0f, 0.7f, shadowColor);
|
||||
// dc.Draw()->DrawImage4Grid(dc.GetTheme().dropShadow4Grid, x - dropsize, y - dropsize * 0.5f, x + w + dropsize, y + h + dropsize * 1.5, alphaMul(shadowColor, 0.5f), 1.0f);
|
||||
dc.DrawRectDropShadow(iconBounds, 8.0f, 0.7f, 0);
|
||||
dc.Draw()->Flush();
|
||||
}
|
||||
|
||||
dc.Draw()->Flush();
|
||||
dc.GetDrawContext()->BindTexture(0, texture);
|
||||
dc.Draw()->DrawTexRect(iconBounds, 0, 0, 1, 1, color);
|
||||
dc.Draw()->DrawTexRect(iconBounds, 0, 0, 1, 1, 0xFFFFFFFF);
|
||||
dc.Draw()->Flush();
|
||||
}
|
||||
|
||||
if (viewMode_ == GameBrowserViewMode::GRID && g_Config.bShowIDOnGameIcon && fileType != IdentifiedFileType::PSP_ELF && !id_version.empty()) {
|
||||
std::string_view idStr = id_version;
|
||||
if (fileType == IdentifiedFileType::PSP_SAVEDATA_DIRECTORY) {
|
||||
auto ga = GetI18NCategory(I18NCat::GAME);
|
||||
idStr = ga->T("SaveData");
|
||||
}
|
||||
dc.SetFontScale(0.5f * g_Config.fGameGridScale, 0.5f * g_Config.fGameGridScale);
|
||||
dc.DrawText(idStr, bounds_.x + 5, iconBounds.y + 1, 0xFF000000, ALIGN_TOPLEFT);
|
||||
dc.DrawText(idStr, bounds_.x + 4, iconBounds.y, dc.GetTheme().infoStyle.fgColor, ALIGN_TOPLEFT);
|
||||
dc.SetFontScale(1.0f, 1.0f);
|
||||
}
|
||||
|
||||
if (viewMode_ == GameBrowserViewMode::GRID) {
|
||||
if (g_Config.bShowIDOnGameIcon && fileType != IdentifiedFileType::PSP_ELF && !id_version.empty()) {
|
||||
std::string_view idStr = id_version;
|
||||
if (fileType == IdentifiedFileType::PSP_SAVEDATA_DIRECTORY) {
|
||||
auto ga = GetI18NCategory(I18NCat::GAME);
|
||||
idStr = ga->T("SaveData");
|
||||
}
|
||||
dc.SetFontScale(0.5f * g_Config.fGameGridScale, 0.5f * g_Config.fGameGridScale);
|
||||
dc.DrawText(idStr, bounds_.x + 5, iconBounds.y + 1, 0xFF000000, ALIGN_TOPLEFT);
|
||||
dc.DrawText(idStr, bounds_.x + 4, iconBounds.y, dc.GetTheme().infoStyle.fgColor, ALIGN_TOPLEFT);
|
||||
dc.SetFontScale(1.0f, 1.0f);
|
||||
}
|
||||
|
||||
if (imageIcon.isValid()) {
|
||||
Bounds bounds = bounds_;
|
||||
|
||||
|
||||
+11
-1
@@ -941,6 +941,8 @@ int main(int argc, const char* argv[]) {
|
||||
#endif
|
||||
PROFILE_INIT();
|
||||
TimeInit();
|
||||
// Builds the pointer to setting lookup, which sceReg's registry mapping uses.
|
||||
g_Config.Init();
|
||||
#if PPSSPP_PLATFORM(WINDOWS)
|
||||
if (!IsDebuggerPresent()) {
|
||||
SetCleanExitOnAssert();
|
||||
@@ -1180,7 +1182,7 @@ int main(int argc, const char* argv[]) {
|
||||
g_Config.iTimeFormat = PSP_SYSTEMPARAM_TIME_FORMAT_24HR;
|
||||
g_Config.bEncryptSave = true;
|
||||
g_Config.sNickName = "shadow";
|
||||
g_Config.iTimeZone = 60;
|
||||
g_Config.iTimeZoneOffset = 60;
|
||||
g_Config.iDateFormat = PSP_SYSTEMPARAM_DATE_FORMAT_DDMMYYYY;
|
||||
g_Config.iButtonPreference = PSP_SYSTEMPARAM_BUTTON_CROSS;
|
||||
g_Config.iLockParentalLevel = 9;
|
||||
@@ -1445,6 +1447,14 @@ int main(int argc, const char* argv[]) {
|
||||
coreParameter.nandRoot = nand;
|
||||
}
|
||||
|
||||
// Headless doesn't keep a config, so set the registry version that installing this firmware
|
||||
// in the app would have stored.
|
||||
{
|
||||
InstalledFirmwareInfo firmwareInfo;
|
||||
ReadInstalledFirmwareInfo(g_Config.nandRootDirectory, &firmwareInfo, false);
|
||||
g_Config.iSceRegCategoryVersion = SceRegCategoryVersionForFirmware(firmwareInfo.version);
|
||||
}
|
||||
|
||||
// Placed here rather than with the other early-exit subcommands above, because resolving a
|
||||
// "flash0:/kd/foo.prx" module path needs nandRootDirectory, which is only settled just above.
|
||||
if (cmdLineOptions.reDecrypt.has_value()) {
|
||||
|
||||
@@ -1225,6 +1225,8 @@ void retro_init(void)
|
||||
if (environ_cb(RETRO_ENVIRONMENT_GET_INPUT_BITMASKS, NULL))
|
||||
libretro_supports_bitmasks = true;
|
||||
|
||||
// Builds the pointer to setting lookup, which sceReg's registry mapping uses.
|
||||
g_Config.Init();
|
||||
g_Config.Load("", "");
|
||||
g_Config.iInternalResolution = 0;
|
||||
|
||||
|
||||
Reference in new issue
Block a user