Files

313 lines
10 KiB
C++

#include "Common.h"
#include "Settings_Menu.h"
#include "RemoteCaller.h"
#include "UI.h"
#include "Debug_Features.h"
#include "Game_Overlay.h"
#include "Build_Overlay.h"
#include "Config.h"
//Embedded xmls
extern uint8_t settings_root[];
extern int32_t settings_root_Size;
extern uint8_t orbis_toolbox[];
extern int32_t orbis_toolbox_Size;
extern uint8_t external_hdd[];
extern int32_t external_hdd_Size;
//Detours
Detour* Settings_Menu::Detour_GetManifestResourceStream = nullptr;
Detour* Settings_Menu::Detour_OnCheckVisible = nullptr;
Detour* Settings_Menu::Detour_OnPreCreate = nullptr;
Detour* Settings_Menu::Detour_OnPageActivating = nullptr;
Detour* Settings_Menu::Detour_OnPress = nullptr;
Detour* Settings_Menu::Detour_OnRender = nullptr;
//Patches
Patcher* Settings_Menu::Patch_IsDevkit;
Patcher* Settings_Menu::Patch_IsDebugMenuEnable;
Patcher* Settings_Menu::Patch_AllowDebugMenu;
Patcher* Settings_Menu::Patch_MainThreadCheck;
/*
GetManifestResourceStream:
This is the method I hook that loads internal packed resources
from the mono UI. I intercept the uri and force it to return a
new memory stream of the bytes for our custom xml.
*/
uint64_t Settings_Menu::GetManifestResourceStream_Hook(uint64_t inst, MonoString* FileName)
{
char* str = mono_string_to_utf8(FileName);
//klog("****\nFileName: %s\n****\n", str);
if (!strcmp(str, "Sce.Vsh.ShellUI.src.Sce.Vsh.ShellUI.Settings.Plugins.SettingsRoot.data.settings_root.xml"))
return (uint64_t)UI::Utilities::MemoryStream(settings_root, settings_root_Size);
else if (!strcmp(str, "Sce.Vsh.ShellUI.src.Sce.Vsh.ShellUI.Settings.Plugins.orbis_toolbox.xml"))
return (uint64_t)UI::Utilities::MemoryStream(orbis_toolbox, orbis_toolbox_Size);
else if (!strcmp(str, "Sce.Vsh.ShellUI.src.Sce.Vsh.ShellUI.Settings.Plugins.external_hdd.xml"))
return (uint64_t)UI::Utilities::MemoryStream(external_hdd, external_hdd_Size);
else
return Detour_GetManifestResourceStream->Stub<uint64_t>(inst, FileName);
}
/*
Settings Root Hooks:
I set my custom menu as the plugin of the root settings page
this allows me to hook all the call backs from inside this
page and run my own code.
Note: in the xml "plugin="settings_root_plugin""
*/
/*
OnCheckVisible:
This could allow us to show and hide elements on each page
much like the id_message which is a loading symbol.
*/
void Settings_Menu::OnCheckVisible_Hook(MonoObject* Instance, MonoObject* element, MonoObject* e)
{
if (Instance && element)
{
char* Id = mono_string_to_utf8(Mono::Get_Property<MonoString*>(Mono::App_exe, "Sce.Vsh.ShellUI.Settings.Core", "SettingElement", element, "Id"));
MenuOption* Cur = Menu::Get_Option(Id);
if (Cur)
{
//Show or hide Menu Options on the fly.
Mono::Set_Property(Mono::App_exe, "Sce.Vsh.ShellUI.Settings.Core", "SettingElement", element, "Visible", Cur->Visible);
}
}
Detour_OnCheckVisible->Stub<void>(Instance, element, e);
}
/*
OnPreCreate:
This Hook allows us to set values of each menu element
depending on what is set prior. For example I use this
to set the check boxes to match the previously selected
values.
*/
void Settings_Menu::OnPreCreate_Hook(MonoObject* Instance, MonoObject* element, MonoObject* e)
{
if (Instance && element)
{
MonoClass* SettingElement = Mono::Get_Class(Mono::App_exe, "Sce.Vsh.ShellUI.Settings.Core", "SettingElement");
char* Id = mono_string_to_utf8(Mono::Get_Property<MonoString*>(SettingElement, element, "Id"));
MenuOption* Cur = Menu::Get_Option(Id);
if (Cur)
{
//Update the shown value of the option.
if (Cur->Type == Type_Boolean)
Mono::Set_Property(SettingElement, element, "Value", (*(bool*)Cur->Data) ? Mono::New_String("1") : Mono::New_String("0"));
/*else if (Cur->Type == Type_Integer)
Mono::Set_Property(SettingElement, element, "Value", Mono::New_String(std::to_string(*(int*)Cur->Data).c_str()));
else if (Cur->Type == Type_Float)
Mono::Set_Property(SettingElement, element, "Value", Mono::New_String(std::to_string(*(float*)Cur->Data).c_str()));*/
else if (Cur->Type == Type_String)
Mono::Set_Property(SettingElement, element, "Value", Mono::New_String((const char*)Cur->Data));
//Call the OnPreCreate call back.
if (Cur->OnPreCreate != nullptr)
Cur->OnPreCreate();
}
}
Detour_OnPreCreate->Stub<void>(Instance, element, e);
}
/*
OnPageActivating:
Hooking this allows us to add custom elements when a
page is loading like for example how I will be using
it to parse the payloads from the HDD and display
them to be loaded.
*/
void Settings_Menu::OnPageActivating_Hook(MonoObject* Instance, MonoObject* page, MonoObject* e)
{
if (Instance && page)
{
MonoClass* SettingElement = Mono::Get_Class(Mono::App_exe, "Sce.Vsh.ShellUI.Settings.Core", "SettingElement");
char* Id = mono_string_to_utf8(Mono::Get_Property<MonoString*>(Mono::App_exe, "Sce.Vsh.ShellUI.Settings.Core", "SettingPage", page, "Id"));
MenuOption* Cur = Menu::Get_Option(Id);
if (Cur)
{
if(Cur->OnPageActivating != nullptr)
Cur->OnPageActivating();
}
}
Detour_OnPageActivating->Stub<void>(Instance, page, e);
}
/*
OnPress:
This Hook allows us to catch when a element is selected
or its value is changed.
*/
void Settings_Menu::OnPress_Hook(MonoObject* Instance, MonoObject* element, MonoObject* e)
{
if (Instance && element)
{
MonoClass* SettingElement = Mono::Get_Class(Mono::App_exe, "Sce.Vsh.ShellUI.Settings.Core", "SettingElement");
char* Id = mono_string_to_utf8(Mono::Get_Property<MonoString*>(SettingElement, element, "Id"));
char* Value = mono_string_to_utf8(Mono::Get_Property<MonoString*>(SettingElement, element, "Value"));
if (!strcmp(Id, "_option"))
Id = Value;
MenuOption* Cur = Menu::Get_Option(Id);
if (Cur)
{
//Update the local value of the option.
if (Cur->Type == Type_Boolean)
*(bool*)Cur->Data = (atoi(Value) >= 1);
else if (Cur->Type == Type_Integer)
*Cur->Data = atoi(Value);
else if (Cur->Type == Type_Float)
*Cur->Data = atof(Value);
else if (Cur->Type == Type_String)
strcpy((char*)Cur->Data, Value);
//Call the OnPress call back.
if (Cur->OnPress != nullptr)
Cur->OnPress();
}
}
Detour_OnPress->Stub<void>(Instance, element, e);
}
void Settings_Menu::OnRender_Hook(MonoObject* Instance)
{
static bool Do_Once = false;
if (!Do_Once)
{
Log("Init Game Overlay");
Game_Overlay::Init();
Log("Init Build Overlay");
Build_Overlay::Init();
if (Config::Read(SETTIN_DIR) && Config::Data->Auto_Load_Settings)
{
Config::Parse(SETTIN_DIR);
//Call functions to reflect update
Debug_Feature::DebugTitleIdLabel::Update();
Debug_Feature::DevkitPanel::Update();
UI::Utilities::ReloadItemList();
Build_Overlay::Update();
Game_Overlay::Update_Location();
Game_Overlay::Update();
}
else
{
Build_Overlay::Draw = true;
Build_Overlay::Update();
}
Do_Once = true;
}
CallInMonoThread->DoRemoteCalls();
Config::UpdateSettings();
Game_Overlay::OnRender();
Detour_OnRender->Stub<void>(Instance);
}
void Settings_Menu::Log(const char* fmt, ...)
{
char va_Buffer[0x200];
//Create full string from va list.
va_list args;
va_start(args, fmt);
vsprintf(va_Buffer, fmt, args);
va_end(args);
klog("[Settings Menu] %s\n", va_Buffer);
}
void Settings_Menu::Init()
{
Log("Init");
Log(ORBIS_TOOLBOX_BUILDSTRING);
Config::Init();
//Debug Settings Patch
Patch_IsDevkit = new Patcher();
Patch_IsDebugMenuEnable = new Patcher();
Patch_AllowDebugMenu = new Patcher();
Patch_MainThreadCheck = new Patcher();
Log("Install Patches");
Patch_IsDevkit->Install_Method_Patch(Mono::KernelSysWrapper, "Sce.Vsh", "KernelSysWrapper", "IsDevKit", 0, 0, "\x48\xc7\xc0\x01\x00\x00\x00\xC3", 8);
Patch_IsDebugMenuEnable->Install_Method_Patch(Mono::App_exe, "Sce.Vsh.ShellUI.DebugSystem", "KeyMonitorTask", "IsDebugMenuEnable", 0, 0, "\x48\xc7\xc0\x01\x00\x00\x00\xC3", 8);
Patch_AllowDebugMenu->Install_Method_Patch(Mono::platform_dll, "Sce.Vsh.ShellUI.Settings.Sbl", "SblWrapper", "SblRcMgrIsAllowDebugMenuForSettings", 0, 0, "\x48\xc7\xc0\x01\x00\x00\x00\xC3", 8);
Patch_MainThreadCheck->Install_Method_Patch(Mono::PlayStation_Core, "Sce.PlayStation.Core.Runtime", "Diagnostics", "CheckRunningOnMainThread", 0, 0, "\xC3", 1);
Debug_Feature::DevkitPanel::Init();
Debug_Feature::DebugTitleIdLabel::Init();
Debug_Feature::Custom_Content::Init();
Log("Init Menu");
Menu::Init();
Log("Init Detours");
Detour_GetManifestResourceStream = new Detour();
Detour_OnCheckVisible = new Detour();
Detour_OnPreCreate = new Detour();
Detour_OnPageActivating = new Detour();
Detour_OnPress = new Detour();
Detour_OnRender = new Detour();
Log("Detour Methods");
Detour_GetManifestResourceStream->DetourMethod(Mono::mscorlib, "System.Reflection", "Assembly", "GetManifestResourceStream", 1, (void*)GetManifestResourceStream_Hook);
Detour_OnCheckVisible->DetourMethod(Mono::App_exe, "Sce.Vsh.ShellUI.Settings.SettingsRoot", "SettingsRootHandler", "OnCheckVisible", 2, (void*)OnCheckVisible_Hook);
Detour_OnPreCreate->DetourMethod(Mono::App_exe, "Sce.Vsh.ShellUI.Settings.SettingsRoot", "SettingsRootHandler", "OnPreCreate", 2, (void*)OnPreCreate_Hook);
Detour_OnPageActivating->DetourMethod(Mono::App_exe, "Sce.Vsh.ShellUI.Settings.SettingsRoot", "SettingsRootHandler", "OnPageActivating", 2, (void*)OnPageActivating_Hook);
Detour_OnPress->DetourMethod(Mono::App_exe, "Sce.Vsh.ShellUI.Settings.SettingsRoot", "SettingsRootHandler", "OnPress", 2, (void*)OnPress_Hook);
Detour_OnRender->DetourMethod(Mono::UI_dll, Mono::PUI, "Application", "Update", 0, (void*)OnRender_Hook);
Log("Init Complete");
}
void Settings_Menu::Term()
{
Config::Term();
Debug_Feature::DevkitPanel::Term();
Debug_Feature::DebugTitleIdLabel::Term();
Debug_Feature::Custom_Content::Term();
Game_Overlay::Term();
Build_Overlay::Term();
//Remove Denug Settings Patch
delete Patch_IsDevkit;
delete Patch_IsDebugMenuEnable;
delete Patch_AllowDebugMenu;
delete Patch_MainThreadCheck;
//Clean up detours
delete Detour_GetManifestResourceStream;
delete Detour_OnCheckVisible;
delete Detour_OnPreCreate;
delete Detour_OnPageActivating;
delete Detour_OnPress;
delete Detour_OnRender;
//Clean up menu
Menu::Term();
}