mirror of
https://github.com/wiiu-env/AutobootModule.git
synced 2024-11-25 12:06:58 +01:00
Add support for custom boot entries (either vWii or Wiiu)
(cherry picked from commit 74316bd54d4d873d9bb453eb12747f84be5ae0d8)
This commit is contained in:
parent
2d023be0a2
commit
1711a30cf7
@ -12,6 +12,7 @@
|
||||
#include <nn/act.h>
|
||||
#include <nn/cmpt/cmpt.h>
|
||||
#include <padscore/kpad.h>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <sysapp/launch.h>
|
||||
#include <sysapp/title.h>
|
||||
@ -39,6 +40,18 @@ void bootHomebrewLauncher() {
|
||||
_SYSLaunchTitleWithStdArgsInNoSplash(titleId, nullptr);
|
||||
}
|
||||
|
||||
void bootWiiuTitle(const std::string &hexId) {
|
||||
uint64_t titleId;
|
||||
std::stringstream ss;
|
||||
ss << std::hex << hexId;
|
||||
ss >> titleId;
|
||||
|
||||
handleAccountSelection();
|
||||
|
||||
titleId = _SYSGetSystemApplicationTitleId(static_cast<SYSTEM_APP_ID>(titleId));
|
||||
_SYSLaunchTitleWithStdArgsInNoSplash(titleId, nullptr);
|
||||
}
|
||||
|
||||
void handleAccountSelection() {
|
||||
nn::act::Initialize();
|
||||
nn::act::SlotNo defaultSlot = nn::act::GetDefaultAccount();
|
||||
@ -83,7 +96,7 @@ void handleAccountSelection() {
|
||||
nn::act::Finalize();
|
||||
}
|
||||
|
||||
static void launchvWiiTitle(uint64_t titleId) {
|
||||
void launchvWiiTitle(uint64_t titleId) {
|
||||
// we need to init kpad for cmpt
|
||||
KPADInit();
|
||||
|
||||
@ -114,7 +127,7 @@ void bootvWiiMenu() {
|
||||
launchvWiiTitle(0);
|
||||
}
|
||||
|
||||
uint64_t getVWiiHBLTitleId() {
|
||||
uint64_t getVWiiTitleId(const std::string& hexId) {
|
||||
// fall back to booting the vWii system menu if anything fails
|
||||
uint64_t titleId = 0;
|
||||
|
||||
@ -126,13 +139,15 @@ uint64_t getVWiiHBLTitleId() {
|
||||
if (FSAMount(client, "/dev/slccmpt01", "/vol/storage_slccmpt01", FSA_MOUNT_FLAG_GLOBAL_MOUNT, nullptr, 0) >= 0) {
|
||||
FSStat stat;
|
||||
|
||||
// test if the OHBC or HBC is installed
|
||||
if (FSAGetStat(client, "/vol/storage_slccmpt01/title/00010001/4f484243/content/00000000.app", &stat) >= 0) {
|
||||
titleId = 0x000100014F484243L; // 'OHBC'
|
||||
} else if (FSAGetStat(client, "/vol/storage_slccmpt01/title/00010001/4c554c5a/content/00000000.app", &stat) >= 0) {
|
||||
titleId = 0x000100014C554C5AL; // 'LULZ'
|
||||
const std::string hexValue{ hexId.size() > 2 ? hexId.substr(2) : hexId };
|
||||
const std::string titleString{ "/vol/storage_slccmpt01/title/00010001/" + hexValue + "/content/00000000.app" };
|
||||
if (FSAGetStat(client, titleString.c_str(), &stat) >= 0) {
|
||||
std::stringstream ss;
|
||||
ss << std::hex << hexId;
|
||||
ss >> titleId;
|
||||
titleId |= 0x0001000100000000L;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Cannot find HBC");
|
||||
DEBUG_FUNCTION_LINE("Cannot find title 0x%s", hexId.c_str());
|
||||
}
|
||||
FSAUnmount(client, "/vol/storage_slccmpt01", static_cast<FSAUnmountFlags>(2));
|
||||
} else {
|
||||
@ -145,6 +160,17 @@ uint64_t getVWiiHBLTitleId() {
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to add FSAClient");
|
||||
}
|
||||
|
||||
return titleId;
|
||||
}
|
||||
|
||||
uint64_t getVWiiHBLTitleId() {
|
||||
// Try 'OHBC' first and if it fails, try 'LULZ'
|
||||
uint64_t titleId = getVWiiTitleId("4f484243");
|
||||
if (titleId == 0) {
|
||||
titleId = getVWiiTitleId("4c554c5a");
|
||||
}
|
||||
|
||||
return titleId;
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
void launchvWiiTitle(uint64_t titleId);
|
||||
|
||||
void bootWiiUMenu();
|
||||
|
||||
void bootHomebrewLauncher();
|
||||
|
||||
void bootWiiuTitle(const std::string& hexId);
|
||||
|
||||
void bootvWiiMenu();
|
||||
|
||||
void bootHomebrewChannel();
|
||||
|
||||
uint64_t getVWiiTitleId(const std::string& hexId);
|
||||
|
||||
uint64_t getVWiiHBLTitleId();
|
@ -11,18 +11,17 @@
|
||||
#include <malloc.h>
|
||||
#include <memory>
|
||||
#include <nn/act/client_cpp.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <vpad/input.h>
|
||||
|
||||
#define AUTOBOOT_MODULE_VERSION "v0.1.2"
|
||||
|
||||
const char *autoboot_config_strings[] = {
|
||||
"wiiu_menu",
|
||||
"homebrew_launcher",
|
||||
"vwii_system_menu",
|
||||
"vwii_homebrew_channel",
|
||||
};
|
||||
// Initialize with the autoboot_base_config_strings data
|
||||
std::vector<std::string> autoboot_config_strings = { autoboot_base_config_strings.begin(), autoboot_base_config_strings.end() };
|
||||
std::vector<BootOption> custom_boot_options;
|
||||
|
||||
template<typename... Args>
|
||||
std::string string_format(const std::string &format, Args... args) {
|
||||
@ -33,36 +32,90 @@ std::string string_format(const std::string &format, Args... args) {
|
||||
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
|
||||
}
|
||||
|
||||
int32_t readAutobootOption(std::string &configPath) {
|
||||
FILE *f = fopen(configPath.c_str(), "r");
|
||||
if (f) {
|
||||
char buf[128]{};
|
||||
fgets(buf, sizeof(buf), f);
|
||||
fclose(f);
|
||||
std::string trim(const std::string& str) {
|
||||
std::string result;
|
||||
for (auto& ch : str) {
|
||||
if (!std::isspace(ch)) {
|
||||
result += ch;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < sizeof(autoboot_config_strings) / sizeof(char *); i++) {
|
||||
if (strncmp(autoboot_config_strings[i], buf, strlen(autoboot_config_strings[i])) == 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void readBootOptionsFromSD(const std::string &configPath) {
|
||||
std::ifstream fileStream(configPath.c_str(), std::ios::in);
|
||||
if (fileStream.is_open()) {
|
||||
DEBUG_FUNCTION_LINE("bootOptions.cfg open");
|
||||
|
||||
constexpr size_t bufSize{ 256 };
|
||||
for (char line[bufSize]; fileStream.getline(line, bufSize);) {
|
||||
DEBUG_FUNCTION_LINE(" Line \"%s\"", line);
|
||||
std::istringstream parsingLine{std::string{line}};
|
||||
memset(line, 0, bufSize);
|
||||
|
||||
std::vector<std::string> tokens;
|
||||
for (char tmp[bufSize]; parsingLine.getline(tmp, bufSize, ',');) {
|
||||
DEBUG_FUNCTION_LINE(" Token \"%s\"", tmp);
|
||||
tokens.push_back(trim(tmp));
|
||||
memset(tmp, 0, bufSize);
|
||||
}
|
||||
|
||||
if (tokens.size() == 3)
|
||||
{
|
||||
const std::string subSystem{ tokens[2] };
|
||||
const std::string vWiiStr{ "vwii" };
|
||||
const bool vWii{ std::equal(subSystem.begin(), subSystem.end(),
|
||||
vWiiStr.begin(), vWiiStr.end(), [](unsigned char a, unsigned char b) {
|
||||
return std::tolower(a) == std::tolower(b);
|
||||
})
|
||||
};
|
||||
|
||||
custom_boot_options.push_back(BootOption{tokens[0], tokens[1], vWii});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Failed to open bootOptions.cfg");
|
||||
}
|
||||
}
|
||||
|
||||
int32_t readAutobootOption(const std::string &configPath) {
|
||||
std::ifstream fileStream(configPath.c_str(), std::ios::in);
|
||||
if (fileStream.is_open()) {
|
||||
std::string readOption;
|
||||
fileStream >> readOption;
|
||||
|
||||
for (size_t i = 0; i < autoboot_config_strings.size(); ++i) {
|
||||
if (autoboot_config_strings[i] == readOption) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < custom_boot_options.size(); ++i) {
|
||||
if (custom_boot_options[i].title == readOption) {
|
||||
return BOOT_OPTION_MAX_OPTIONS + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void writeAutobootOption(std::string &configPath, int32_t autobootOption) {
|
||||
FILE *f = fopen(configPath.c_str(), "w");
|
||||
if (f) {
|
||||
if (autobootOption >= 0) {
|
||||
fputs(autoboot_config_strings[autobootOption], f);
|
||||
void writeAutobootOption(const std::string &configPath, int32_t autobootOption) {
|
||||
const int32_t customAutoBootOption{ autobootOption - BOOT_OPTION_MAX_OPTIONS };
|
||||
std::ofstream outStream(configPath.c_str(), std::ios::out);
|
||||
if (outStream.is_open()) {
|
||||
if (customAutoBootOption >= 0) {
|
||||
outStream << custom_boot_options[customAutoBootOption].title;
|
||||
} else if (autobootOption >= 0) {
|
||||
outStream << autoboot_config_strings[autobootOption];
|
||||
} else {
|
||||
fputs("none", f);
|
||||
outStream << "none";
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t handleMenuScreen(std::string &configPath, int32_t autobootOptionInput, const std::map<uint32_t, std::string> &menu) {
|
||||
int32_t handleMenuScreen(const std::string &configPath, int32_t autobootOptionInput, const std::map<uint32_t, std::string> &menu) {
|
||||
auto screenBuffer = DrawUtils::InitOSScreen();
|
||||
if (!screenBuffer) {
|
||||
OSFatal("Failed to alloc memory for screen");
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "ACTAccountInfo.h"
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@ -20,18 +21,38 @@
|
||||
#define COLOR_BORDER Color(204, 204, 204, 255)
|
||||
#define COLOR_BORDER_HIGHLIGHTED Color(0x3478e4ff)
|
||||
|
||||
struct BootOption {
|
||||
std::string title;
|
||||
std::string hexId;
|
||||
bool vWii;
|
||||
};
|
||||
|
||||
enum {
|
||||
BOOT_OPTION_WII_U_MENU,
|
||||
BOOT_OPTION_WII_U_MENU = 0,
|
||||
BOOT_OPTION_HOMEBREW_LAUNCHER,
|
||||
BOOT_OPTION_VWII_SYSTEM_MENU,
|
||||
BOOT_OPTION_VWII_HOMEBREW_CHANNEL,
|
||||
|
||||
BOOT_OPTION_MAX_OPTIONS
|
||||
};
|
||||
|
||||
int32_t readAutobootOption(std::string &configPath);
|
||||
constexpr std::array<const char*, BOOT_OPTION_MAX_OPTIONS> autoboot_base_config_strings{
|
||||
"wiiu_menu",
|
||||
"homebrew_launcher",
|
||||
"vwii_system_menu",
|
||||
"vwii_homebrew_channel",
|
||||
};
|
||||
|
||||
void writeAutobootOption(std::string &configPath, int32_t autobootOption);
|
||||
extern std::vector<std::string> autoboot_config_strings;
|
||||
extern std::vector<BootOption> custom_boot_options;
|
||||
|
||||
int32_t handleMenuScreen(std::string &configPath, int32_t autobootOptionInput, const std::map<uint32_t, std::string> &menu);
|
||||
void readBootOptionsFromSD(const std::string &configPath);
|
||||
|
||||
int32_t readAutobootOption(const std::string &configPath);
|
||||
|
||||
void writeAutobootOption(const std::string &configPath, int32_t autobootOption);
|
||||
|
||||
int32_t handleMenuScreen(const std::string &configPath, int32_t autobootOptionInput, const std::map<uint32_t, std::string> &menu);
|
||||
|
||||
nn::act::SlotNo handleAccountSelectScreen(const std::vector<std::shared_ptr<AccountInfo>> &data);
|
||||
|
||||
|
@ -81,6 +81,10 @@ int32_t main(int32_t argc, char **argv) {
|
||||
if (stat(hblInstallerPath.c_str(), &st) >= 0) {
|
||||
showHBL = true;
|
||||
}
|
||||
|
||||
readBootOptionsFromSD(std::string(argv[0]) + "/bootOptions.cfg");
|
||||
} else {
|
||||
readBootOptionsFromSD("fs:/vol/external01/wiiu/bootOptions.cfg");
|
||||
}
|
||||
|
||||
int32_t bootSelection = readAutobootOption(configPath);
|
||||
@ -95,6 +99,11 @@ int32_t main(int32_t argc, char **argv) {
|
||||
menu[BOOT_OPTION_VWII_HOMEBREW_CHANNEL] = "vWii Homebrew Channel";
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < custom_boot_options.size(); ++i) {
|
||||
const BootOption& option{ custom_boot_options[i] };
|
||||
menu[BOOT_OPTION_MAX_OPTIONS + i] = option.title + " (" + (option.vWii ? "vWii" : "WiiU") + " " + option.hexId + ")";
|
||||
}
|
||||
|
||||
if ((bootSelection == -1) ||
|
||||
(bootSelection == BOOT_OPTION_HOMEBREW_LAUNCHER && !showHBL) ||
|
||||
(bootSelection == BOOT_OPTION_VWII_HOMEBREW_CHANNEL && !showvHBL) ||
|
||||
@ -102,7 +111,22 @@ int32_t main(int32_t argc, char **argv) {
|
||||
bootSelection = handleMenuScreen(configPath, bootSelection, menu);
|
||||
}
|
||||
|
||||
if (bootSelection >= 0) {
|
||||
const int32_t customBootSelection{bootSelection - BOOT_OPTION_MAX_OPTIONS};
|
||||
if (customBootSelection >= 0) {
|
||||
if (static_cast<size_t>(customBootSelection) < custom_boot_options.size()) {
|
||||
const BootOption &selectedOption{custom_boot_options[customBootSelection]};
|
||||
if (selectedOption.vWii) {
|
||||
const uint64_t titleId = getVWiiTitleId(selectedOption.hexId);
|
||||
DEBUG_FUNCTION_LINE("Launching vWii title %016llx", titleId);
|
||||
launchvWiiTitle(titleId);
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Launching WiiU title %s", selectedOption.hexId);
|
||||
bootWiiuTitle(selectedOption.hexId);
|
||||
}
|
||||
} else {
|
||||
bootWiiUMenu();
|
||||
}
|
||||
} else if (bootSelection >= 0) {
|
||||
switch (bootSelection) {
|
||||
case BOOT_OPTION_WII_U_MENU:
|
||||
bootWiiUMenu();
|
||||
|
Loading…
Reference in New Issue
Block a user