mirror of
https://github.com/wiiu-env/AutobootModule.git
synced 2024-11-25 12:06:58 +01:00
Merge pull request #2 from wiiu-env/account_selection
Show a Account Selection screen when no default account has been set
This commit is contained in:
commit
ce99c9e5f2
13
source/ACTAccountInfo.h
Normal file
13
source/ACTAccountInfo.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
class AccountInfo {
|
||||
public:
|
||||
AccountInfo() = default;
|
||||
|
||||
nn::act::SlotNo slot{};
|
||||
std::string name;
|
||||
char accountId[nn::act::AccountIdSize];
|
||||
bool isNetworkAccount = false;
|
||||
uint8_t miiImageBuffer[65554];
|
||||
uint32_t miiImageSize = 0;
|
||||
};
|
@ -1,12 +1,29 @@
|
||||
#include <malloc.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <locale>
|
||||
#include <vector>
|
||||
#include <codecvt>
|
||||
#include <memory>
|
||||
|
||||
#include "BootUtils.h"
|
||||
#include "logger.h"
|
||||
#include "DrawUtils.h"
|
||||
#include "MenuUtils.h"
|
||||
#include "ACTAccountInfo.h"
|
||||
|
||||
#include <coreinit/debug.h>
|
||||
#include <coreinit/screen.h>
|
||||
#include <nn/cmpt/cmpt.h>
|
||||
#include <nn/act.h>
|
||||
#include <sysapp/launch.h>
|
||||
#include <sysapp/title.h>
|
||||
#include <padscore/kpad.h>
|
||||
#include <vpad/input.h>
|
||||
#include <gx2/state.h>
|
||||
|
||||
|
||||
void handleAccountSelection();
|
||||
|
||||
void bootWiiUMenu() {
|
||||
nn::act::Initialize();
|
||||
@ -22,10 +39,53 @@ void bootWiiUMenu() {
|
||||
}
|
||||
|
||||
void bootHomebrewLauncher() {
|
||||
handleAccountSelection();
|
||||
|
||||
uint64_t titleId = _SYSGetSystemApplicationTitleId(SYSTEM_APP_ID_MII_MAKER);
|
||||
_SYSLaunchTitleWithStdArgsInNoSplash(titleId, nullptr);
|
||||
}
|
||||
|
||||
void handleAccountSelection() {
|
||||
nn::act::Initialize();
|
||||
nn::act::SlotNo defaultSlot = nn::act::GetDefaultAccount();
|
||||
|
||||
if (!defaultSlot) { // No default account is set.
|
||||
std::vector<std::shared_ptr<AccountInfo>> accountInfoList;
|
||||
for (int32_t i = 0; i < 13; i++) {
|
||||
if (!nn::act::IsSlotOccupied(i)) {
|
||||
continue;
|
||||
}
|
||||
char16_t nameOut[nn::act::MiiNameSize];
|
||||
std::shared_ptr<AccountInfo> accountInfo = std::make_shared<AccountInfo>();
|
||||
accountInfo->slot = i;
|
||||
auto result = nn::act::GetMiiNameEx(reinterpret_cast<int16_t *>(nameOut), i);
|
||||
if (result.IsSuccess()) {
|
||||
std::u16string source;
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
|
||||
accountInfo->name = convert.to_bytes((char16_t *) nameOut);
|
||||
} else {
|
||||
accountInfo->name = "[UNKNOWN]";
|
||||
}
|
||||
accountInfo->isNetworkAccount = nn::act::IsNetworkAccountEx(i);
|
||||
if (accountInfo->isNetworkAccount) {
|
||||
nn::act::GetAccountIdEx(accountInfo->accountId, i);
|
||||
}
|
||||
|
||||
uint32_t imageSize = 0;
|
||||
result = nn::act::GetMiiImageEx(&imageSize, accountInfo->miiImageBuffer, sizeof(accountInfo->miiImageBuffer), 0, i);
|
||||
if (result.IsSuccess()) {
|
||||
accountInfo->miiImageSize = imageSize;
|
||||
}
|
||||
accountInfoList.push_back(accountInfo);
|
||||
}
|
||||
auto slot = handleAccountSelectScreen(accountInfoList);
|
||||
|
||||
DEBUG_FUNCTION_LINE("Load slot %d", slot);
|
||||
nn::act::LoadConsoleAccount(slot, 0, nullptr, false);
|
||||
}
|
||||
nn::act::Finalize();
|
||||
}
|
||||
|
||||
static void launchvWiiTitle(uint32_t titleId_low, uint32_t titleId_high) {
|
||||
// we need to init kpad for cmpt
|
||||
KPADInit();
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include <vector>
|
||||
#include "MenuUtils.h"
|
||||
#include "DrawUtils.h"
|
||||
|
||||
@ -10,8 +10,12 @@
|
||||
#include <coreinit/debug.h>
|
||||
#include <vpad/input.h>
|
||||
#include <gx2/state.h>
|
||||
#include <nn/act/client_cpp.h>
|
||||
#include <memory>
|
||||
|
||||
#include "icon_png.h"
|
||||
#include "ACTAccountInfo.h"
|
||||
#include "logger.h"
|
||||
|
||||
const char *menu_options[] = {
|
||||
"Wii U Menu",
|
||||
@ -27,6 +31,14 @@ const char *autoboot_config_strings[] = {
|
||||
"vwii_homebrew_channel",
|
||||
};
|
||||
|
||||
template<typename ... Args>
|
||||
std::string string_format(const std::string &format, Args ... args) {
|
||||
int size_s = std::snprintf(nullptr, 0, format.c_str(), args ...) + 1; // Extra space for '\0'
|
||||
auto size = static_cast<size_t>( size_s );
|
||||
auto buf = std::make_unique<char[]>(size);
|
||||
std::snprintf(buf.get(), size, format.c_str(), 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");
|
||||
@ -154,3 +166,135 @@ int32_t handleMenuScreen(std::string &configPath, int32_t autobootOptionInput) {
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
|
||||
nn::act::SlotNo handleAccountSelectScreen(const std::vector<std::shared_ptr<AccountInfo>> &data) {
|
||||
auto screenBuffer = DrawUtils::InitOSScreen();
|
||||
if (!screenBuffer) {
|
||||
OSFatal("Failed to alloc memory for screen");
|
||||
}
|
||||
|
||||
uint32_t tvBufferSize = OSScreenGetBufferSizeEx(SCREEN_TV);
|
||||
uint32_t drcBufferSize = OSScreenGetBufferSizeEx(SCREEN_DRC);
|
||||
|
||||
DrawUtils::initBuffers(screenBuffer, tvBufferSize, (void *) ((uint32_t) screenBuffer + tvBufferSize), drcBufferSize);
|
||||
DrawUtils::initFont();
|
||||
|
||||
int32_t selected = 0;
|
||||
bool redraw = true;
|
||||
while (true) {
|
||||
VPADStatus vpad{};
|
||||
VPADRead(VPAD_CHAN_0, &vpad, 1, nullptr);
|
||||
|
||||
if (vpad.trigger & VPAD_BUTTON_UP) {
|
||||
if (selected > 0) {
|
||||
selected--;
|
||||
redraw = true;
|
||||
}
|
||||
} else if (vpad.trigger & VPAD_BUTTON_DOWN) {
|
||||
if (selected < data.size() - 1) {
|
||||
selected++;
|
||||
redraw = true;
|
||||
}
|
||||
} else if (vpad.trigger & VPAD_BUTTON_A) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (redraw) {
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
|
||||
// draw buttons
|
||||
uint32_t index = 8 + 24 + 8 + 4;
|
||||
int32_t start = (selected / 5) * 5;
|
||||
auto end = start + 5 < data.size() ? start + 5 : data.size();
|
||||
for (int i = start; i < end; i++) {
|
||||
auto &val = data[i];
|
||||
if (val->miiImageSize > 0) {
|
||||
// Draw Mii
|
||||
auto width = 128;
|
||||
auto height = 128;
|
||||
auto target_height = 64;
|
||||
auto target_width = 64;
|
||||
auto xOffset = 20;
|
||||
auto yOffset = index;
|
||||
for (uint32_t y = 0; y < target_height; y++) {
|
||||
for (uint32_t x = 0; x < target_width; x++) {
|
||||
uint32_t col = (((x) * width / target_width) + ((target_height - y - 1) * height / target_height) * width) * 4;
|
||||
uint32_t colVal = ((uint32_t *) &val->miiImageBuffer[col + 1])[0];
|
||||
if (colVal == 0x00808080) { // Remove the green background.
|
||||
DrawUtils::drawPixel(x + xOffset, y + yOffset, COLOR_BACKGROUND.r, COLOR_BACKGROUND.g, COLOR_BACKGROUND.b, COLOR_BACKGROUND.a);
|
||||
} else {
|
||||
DrawUtils::drawPixel(x + xOffset, y + yOffset, val->miiImageBuffer[col + 1], val->miiImageBuffer[col + 2], val->miiImageBuffer[col + 3], val->miiImageBuffer[col]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i == selected) {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 64, 4, COLOR_BORDER_HIGHLIGHTED);
|
||||
}
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
std::string finalStr = val->name + (val->isNetworkAccount ? (std::string(" (NNID: ") + val->accountId + ")") : "");
|
||||
DrawUtils::print(72 + 16 * 2, index + 8 + 32, finalStr.c_str());
|
||||
|
||||
index += 72 + 8;
|
||||
}
|
||||
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, "Select your Account");
|
||||
auto curPage = (selected / 5) + 1;
|
||||
auto totalPages = data.size() % 5 == 0 ? data.size() / 5 : data.size() / 5 + 1;
|
||||
DrawUtils::print(SCREEN_WIDTH - 50, 6 + 24, string_format("%d/%d", curPage, totalPages).c_str());
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_WHITE);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_WHITE);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 8, "\ue07d Navigate ");
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 8, "\ue000 Choose", true);
|
||||
|
||||
if (start > 0) {
|
||||
DrawUtils::setFontSize(36);
|
||||
DrawUtils::print(SCREEN_WIDTH - 30, 68, "\uE01B", true);
|
||||
}
|
||||
|
||||
if (end < data.size()) {
|
||||
DrawUtils::setFontSize(36);
|
||||
DrawUtils::print(SCREEN_WIDTH - 30, SCREEN_HEIGHT - 40, "\uE01C", true);
|
||||
}
|
||||
|
||||
DrawUtils::endDraw();
|
||||
|
||||
redraw = false;
|
||||
}
|
||||
}
|
||||
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BLACK);
|
||||
DrawUtils::endDraw();
|
||||
|
||||
DrawUtils::deinitFont();
|
||||
|
||||
// Call GX2Init to shut down OSScreen
|
||||
GX2Init(nullptr);
|
||||
|
||||
free(screenBuffer);
|
||||
|
||||
auto i = 0;
|
||||
nn::act::SlotNo resultSlot = 0;
|
||||
for (auto const &val: data) {
|
||||
if (i == selected) {
|
||||
resultSlot = val->slot;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return resultSlot;
|
||||
}
|
@ -1,7 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <nn/act.h>
|
||||
#include <vector>
|
||||
#include "ACTAccountInfo.h"
|
||||
|
||||
#define COLOR_WHITE Color(0xffffffff)
|
||||
#define COLOR_BLACK Color(0, 0, 0, 255)
|
||||
@ -24,3 +28,5 @@ int32_t readAutobootOption(std::string &configPath);
|
||||
void writeAutobootOption(std::string &configPath, int32_t autobootOption);
|
||||
|
||||
int32_t handleMenuScreen(std::string &configPath, int32_t autobootOptionInput);
|
||||
|
||||
nn::act::SlotNo handleAccountSelectScreen(const std::vector<std::shared_ptr<AccountInfo>> &data);
|
@ -135,7 +135,7 @@ void initExternalStorage() {
|
||||
tries++;
|
||||
}
|
||||
if (!found) {
|
||||
DEBUG_FUNCTION_LINE("USB Storage is connected but either it's not connected or we ran into a timeout.");
|
||||
DEBUG_FUNCTION_LINE("USB Storage is connected but either it doesn't have a WFS partition or we ran into a timeout.");
|
||||
InitEmptyExternalStorage();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user