diff --git a/vita3k/compat/src/compat.cpp b/vita3k/compat/src/compat.cpp index ec511c434b..7ed8436bbf 100644 --- a/vita3k/compat/src/compat.cpp +++ b/vita3k/compat/src/compat.cpp @@ -157,8 +157,10 @@ bool load_app_compat_db(GuiState &gui, EmuEnvState &emuenv) { } // Update compatibility status of all user apps - for (auto &app : gui.app_selector.user_apps) - app.compat = gui.compat.app_compat_db.contains(app.title_id) ? gui.compat.app_compat_db[app.title_id].state : CompatibilityState::UNKNOWN; + for (auto &apps : gui.app_selector.vita_apps) { + for (auto &app : apps.second) + app.compat = gui.compat.app_compat_db.contains(app.title_id) ? gui.compat.app_compat_db[app.title_id].state : CompatibilityState::UNKNOWN; + } return !gui.compat.app_compat_db.empty(); } diff --git a/vita3k/config/include/config/state.h b/vita3k/config/include/config/state.h index 4ce3e4c10f..9e71cbd008 100644 --- a/vita3k/config/include/config/state.h +++ b/vita3k/config/include/config/state.h @@ -84,6 +84,7 @@ struct Config : YamlLoader { fullscreen = rhs.fullscreen; console = rhs.console; app_args = rhs.app_args; + app_device = rhs.app_device; load_app_list = rhs.load_app_list; self_path = rhs.self_path; } @@ -101,6 +102,7 @@ struct Config : YamlLoader { // Setting not present in the YAML file fs::path config_path = {}; std::string app_args; + std::string app_device; std::string self_path; bool overwrite_config = true; bool load_config = false; diff --git a/vita3k/config/src/config.cpp b/vita3k/config/src/config.cpp index 8b006e648e..f9a2642287 100644 --- a/vita3k/config/src/config.cpp +++ b/vita3k/config/src/config.cpp @@ -145,12 +145,14 @@ ExitCode init_config(Config &cfg, int argc, char **argv, const Root &root_paths) ->default_val(false)->group("Input"); input->add_option("--app-args,-Z", command_line.app_args, "Argument for app, use ', ' to separate arguments.") ->default_str("")->group("Input"); + input->add_option("--app-device,-D", command_line.app_device, "App device") + ->default_val("ux0")->group("Input"); input->add_option("--load-app-list,-a", command_line.load_app_list, "Starts the emulator with load app list.") ->default_val(false)->group("Input"); input->add_option("--self,-S", command_line.self_path, "Path to the self to run inside Title ID") ->default_str("eboot.bin")->group("Input"); input->add_option("--installed-path,-r", command_line.run_app_path, "Path to the installed app to run") - ->default_str({})->check(CLI::IsMember(get_file_set(cfg.get_pref_path() / "ux0/app")))->group("Input"); + ->default_str({})->group("Input"); input->add_option("--recompile-shader,-s", command_line.recompile_shader_path, "Recompile the given PS Vita shader (GXP format) to SPIR_V / GLSL and quit") ->default_str({})->group("Input"); input->add_option("--deleted-id,-d", command_line.delete_title_id, "Title ID of installed app to delete") @@ -208,7 +210,27 @@ ExitCode init_config(Config &cfg, int argc, char **argv, const Root &root_paths) std::cout << window_title << std::endl; return QuitRequested; } - + if (command_line.run_app_path.has_value()) { + const std::string app_path = command_line.run_app_path.value(); + if ((app_path.find("vsh") != std::string::npos)) { + if (!fs::exists(fs::path(cfg.pref_path) / "vs0/vsh/shell/shell.self")) { + std::cout << "--installed-path: " << app_path << " not found" << std::endl; + return InitConfigFailed; + } + } else { + std::set exist_apps = get_file_set(fs::path(cfg.pref_path) / command_line.app_device / "app"); + if (exist_apps.find(app_path) == exist_apps.end()) { + std::cout << "--installed-path: " << app_path << " no in {"; + for (auto &app : exist_apps) { + std::cout << app; + if (app != *exist_apps.rbegin()) + std::cout << ", "; + } + std::cout << "}" << std::endl; + return InitConfigFailed; + } + } + } if (command_line.recompile_shader_path.has_value()) { cfg.recompile_shader_path = std::move(command_line.recompile_shader_path); return QuitRequested; diff --git a/vita3k/emuenv/include/emuenv/state.h b/vita3k/emuenv/include/emuenv/state.h index 5378ec304d..d9f76a455b 100644 --- a/vita3k/emuenv/include/emuenv/state.h +++ b/vita3k/emuenv/include/emuenv/state.h @@ -120,6 +120,7 @@ struct EmuEnvState { fs::path static_assets_path{}; fs::path shared_path{}; bool load_exec{}; + std::string load_app_device{}; std::string load_app_path{}; std::string load_exec_argv{}; std::string load_exec_path{}; @@ -128,6 +129,7 @@ struct EmuEnvState { Config &cfg; std::unique_ptr cpu_protocol{}; SceUID main_thread_id{}; + SceUID main_modid{}; size_t frame_count = 0; uint32_t sdl_ticks = 0; uint32_t fps = 0; diff --git a/vita3k/gui/include/gui/functions.h b/vita3k/gui/include/gui/functions.h index 4c2dd832d9..3db2007bca 100644 --- a/vita3k/gui/include/gui/functions.h +++ b/vita3k/gui/include/gui/functions.h @@ -41,7 +41,7 @@ void browse_live_area_apps_list(GuiState &gui, EmuEnvState &emuenv, const uint32 void browse_pages_manual(GuiState &gui, EmuEnvState &emuenv, const uint32_t button); void browse_save_data_dialog(GuiState &gui, EmuEnvState &emuenv, const uint32_t button); void browse_users_management(GuiState &gui, EmuEnvState &emuenv, const uint32_t button); -void close_and_run_new_app(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path); +void close_and_run_new_app(EmuEnvState &emuenv, const std::string &app_path); void close_live_area_app(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path); void close_system_app(GuiState &gui, EmuEnvState &emuenv); void delete_app(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path); @@ -69,12 +69,13 @@ std::string get_sys_lang_name(uint32_t lang_id); void init(GuiState &gui, EmuEnvState &emuenv); void init_app_background(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path); void init_app_icon(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path); -void init_apps_icon(GuiState &gui, EmuEnvState &emuenv, const std::vector &app_list); +void init_apps_icon(GuiState &gui, EmuEnvState &emuenv, const std::vector &apps_list); bool init_bgm(EmuEnvState &emuenv, const std::pair path_bgm); void init_bgm_player(const float vol); void init_config(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path); void init_content_manager(GuiState &gui, EmuEnvState &emuenv); vfs::FileBuffer init_default_icon(GuiState &gui, EmuEnvState &emuenv); +void init_fw_apps(GuiState &gui, EmuEnvState &emuenv); void init_home(GuiState &gui, EmuEnvState &emuenv); void init_live_area(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path); bool init_manual(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path); @@ -85,11 +86,11 @@ void init_last_time_apps(GuiState &gui, EmuEnvState &emuenv); void init_trophy_collection(GuiState &gui, EmuEnvState &emuenv); void init_user(GuiState &gui, EmuEnvState &emuenv, const std::string &user_id); void init_user_app(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path); -void init_user_apps(GuiState &gui, EmuEnvState &emuenv); bool init_user_background(GuiState &gui, EmuEnvState &emuenv, const std::string &background_path); bool init_user_backgrounds(GuiState &gui, EmuEnvState &emuenv); void init_user_management(GuiState &gui, EmuEnvState &emuenv); bool init_user_start_background(GuiState &gui, const std::string &image_path); +void init_vita_apps(GuiState &gui, EmuEnvState &emuenv); void load_and_update_compat_user_apps(GuiState &gui, EmuEnvState &emuenv); void open_live_area(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path); void open_manual(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path); diff --git a/vita3k/gui/include/gui/state.h b/vita3k/gui/include/gui/state.h index 8cad431e45..5f422f18e2 100644 --- a/vita3k/gui/include/gui/state.h +++ b/vita3k/gui/include/gui/state.h @@ -99,13 +99,13 @@ struct IconAsyncLoader { }; struct AppsSelector { - std::vector sys_apps; - std::vector user_apps; + std::vector emu_apps; + std::map> vita_apps; uint32_t apps_cache_lang; AppInfo app_info; std::optional icon_async_loader; - std::map sys_apps_icon; - std::map user_apps_icon; + std::map emu_apps_icon; + std::map vita_apps_icon; bool is_app_list_sorted{ false }; std::map app_list_sorted; }; diff --git a/vita3k/gui/src/app_context_menu.cpp b/vita3k/gui/src/app_context_menu.cpp index 68c6e4e8d2..547681680a 100644 --- a/vita3k/gui/src/app_context_menu.cpp +++ b/vita3k/gui/src/app_context_menu.cpp @@ -19,11 +19,16 @@ #include #include + #include #include + #include #include + +#include #include + #include #include @@ -97,7 +102,7 @@ static bool get_update_history(GuiState &gui, EmuEnvState &emuenv, const std::st std::vector::iterator get_time_app_index(GuiState &gui, EmuEnvState &emuenv, const std::string &app) { const auto time_app_index = std::find_if(gui.time_apps[emuenv.io.user_id].begin(), gui.time_apps[emuenv.io.user_id].end(), [&](const TimeApp &t) { - return t.app == app; + return t.app == fs::path(app).stem().string(); }); return time_app_index; @@ -205,7 +210,7 @@ void update_last_time_app_used(GuiState &gui, EmuEnvState &emuenv, const std::st if (time_app_index != gui.time_apps[emuenv.io.user_id].end()) time_app_index->last_time_used = std::time(nullptr); else - gui.time_apps[emuenv.io.user_id].push_back({ app, std::time(nullptr), 0 }); + gui.time_apps[emuenv.io.user_id].push_back({ fs::path(app).stem().string(), std::time(nullptr), 0 }); get_app_index(gui, app)->last_time = std::time(nullptr); if (gui.users[emuenv.io.user_id].sort_apps_type == LAST_TIME) @@ -216,11 +221,12 @@ void update_last_time_app_used(GuiState &gui, EmuEnvState &emuenv, const std::st void delete_app(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path) { const auto APP_INDEX = get_app_index(gui, app_path); + const auto &APP = fs::path(app_path).stem().string(); const auto &title_id = APP_INDEX->title_id; try { - fs::remove_all(emuenv.pref_path / "ux0/app" / app_path); + fs::remove_all(emuenv.pref_path / "ux0/app" / APP); - const auto CUSTOM_CONFIG_PATH{ emuenv.config_path / "config" / fmt::format("config_{}.xml", app_path) }; + const auto CUSTOM_CONFIG_PATH{ emuenv.config_path / "config" / fmt::format("config_{}.xml", APP) }; if (fs::exists(CUSTOM_CONFIG_PATH)) fs::remove_all(CUSTOM_CONFIG_PATH); const auto ADDCONT_PATH{ emuenv.pref_path / "ux0/addcont" / APP_INDEX->addcont }; @@ -251,9 +257,9 @@ void delete_app(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path) if (fs::exists(IMPORT_TEXTURES_PATH)) fs::remove_all(IMPORT_TEXTURES_PATH); - if (gui.app_selector.user_apps_icon.contains(app_path)) { - gui.app_selector.user_apps_icon[app_path] = {}; - gui.app_selector.user_apps_icon.erase(app_path); + if (gui.app_selector.vita_apps_icon.contains(app_path)) { + gui.app_selector.vita_apps_icon[app_path] = {}; + gui.app_selector.vita_apps_icon.erase(app_path); } const auto time_app_index = get_time_app_index(gui, emuenv, app_path); @@ -267,7 +273,7 @@ void delete_app(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path) LOG_INFO("Application successfully deleted '{} [{}]'.", title_id, APP_INDEX->title); - gui.app_selector.user_apps.erase(gui.app_selector.user_apps.begin() + (APP_INDEX - &gui.app_selector.user_apps[0])); + gui.app_selector.vita_apps["ux0"].erase(gui.app_selector.vita_apps["ux0"].begin() + (APP_INDEX - gui.app_selector.vita_apps["ux0"].data())); save_apps_cache(gui, emuenv); } catch (std::exception &e) { @@ -299,8 +305,8 @@ void draw_app_context_menu(GuiState &gui, EmuEnvState &emuenv, const std::string const auto APP_INDEX = get_app_index(gui, app_path); const auto &title_id = APP_INDEX->title_id; - const auto APP_PATH{ emuenv.pref_path / "ux0/app" / app_path }; - const auto CUSTOM_CONFIG_PATH{ emuenv.config_path / "config" / fmt::format("config_{}.xml", app_path) }; + const auto APP_PATH{ emuenv.pref_path / convert_path(app_path) }; + const auto CUSTOM_CONFIG_PATH{ emuenv.config_path / "config" / fmt::format("config_{}.xml", fs::path(app_path).stem().string()) }; const auto ADDCONT_PATH{ emuenv.pref_path / "ux0/addcont" / APP_INDEX->addcont }; const auto LICENSE_PATH{ emuenv.pref_path / "ux0/license" / title_id }; const auto MANUAL_PATH{ APP_PATH / "sce_sys/manual" }; @@ -571,11 +577,11 @@ void draw_app_context_menu(GuiState &gui, EmuEnvState &emuenv, const std::string } else { // Delete Data const auto ICON_MARGIN = 24.f * SCALE.y; - if (gui.app_selector.user_apps_icon.contains(title_id)) { + if (gui.app_selector.vita_apps_icon.contains(title_id)) { ImGui::SetCursorPos(ImVec2((WINDOW_SIZE.x / 2.f) - (PUPOP_ICON_SIZE.x / 2.f), ICON_MARGIN)); const auto POS_MIN = ImGui::GetCursorScreenPos(); const ImVec2 POS_MAX(POS_MIN.x + PUPOP_ICON_SIZE.x, POS_MIN.y + PUPOP_ICON_SIZE.y); - ImGui::GetWindowDrawList()->AddImageRounded(gui.app_selector.user_apps_icon[title_id], POS_MIN, POS_MAX, ImVec2(0, 0), ImVec2(1, 1), IM_COL32_WHITE, PUPOP_ICON_SIZE.x * SCALE.x, ImDrawFlags_RoundCornersAll); + ImGui::GetWindowDrawList()->AddImageRounded(gui.app_selector.vita_apps_icon[title_id], POS_MIN, POS_MAX, ImVec2(0, 0), ImVec2(1, 1), IM_COL32_WHITE, PUPOP_ICON_SIZE.x * SCALE.x, ImDrawFlags_RoundCornersAll); } ImGui::SetWindowFontScale(1.6f * RES_SCALE.x); ImGui::SetCursorPos(ImVec2((WINDOW_SIZE.x / 2.f) - (ImGui::CalcTextSize(APP_INDEX->stitle.c_str()).x / 2.f), ICON_MARGIN + PUPOP_ICON_SIZE.y + (4.f * SCALE.y))); diff --git a/vita3k/gui/src/common_dialog.cpp b/vita3k/gui/src/common_dialog.cpp index 5c02e4efd4..e6e1805815 100644 --- a/vita3k/gui/src/common_dialog.cpp +++ b/vita3k/gui/src/common_dialog.cpp @@ -51,7 +51,7 @@ static void draw_ime_dialog(EmuEnvState &emuenv, DialogState &common_dialog, flo } ImGui::SameLine(); auto &common = common_dialog.lang.common; - if (ImGui::Button(common["submit"].c_str()) || ImGui::IsKeyPressed(static_cast(emuenv.cfg.keyboard_button_cross))) { + if (ImGui::Button(common["submit"].c_str())) { common_dialog.ime.status = SCE_IME_DIALOG_BUTTON_ENTER; common_dialog.status = SCE_COMMON_DIALOG_STATUS_FINISHED; common_dialog.result = SCE_COMMON_DIALOG_RESULT_OK; diff --git a/vita3k/gui/src/compile_shaders.cpp b/vita3k/gui/src/compile_shaders.cpp index 6d591bd12f..60e15f744c 100644 --- a/vita3k/gui/src/compile_shaders.cpp +++ b/vita3k/gui/src/compile_shaders.cpp @@ -42,7 +42,7 @@ void draw_pre_compiling_shaders_progress(GuiState &gui, EmuEnvState &emuenv, con ImGui::SetWindowFontScale(1.1f * RES_SCALE.x); // Check if icon exist - if (gui.app_selector.user_apps_icon.contains(emuenv.io.app_path)) { + if (gui.app_selector.vita_apps_icon.contains(emuenv.io.app_path)) { ImGui::SetCursorPos(ImVec2(54.f * SCALE.x, 32.f * SCALE.y)); ImGui::Image(get_app_icon(gui, emuenv.io.app_path)->second, ICON_SIZE_SCALE); } diff --git a/vita3k/gui/src/content_manager.cpp b/vita3k/gui/src/content_manager.cpp index 1ce82d7d44..be93305ec1 100644 --- a/vita3k/gui/src/content_manager.cpp +++ b/vita3k/gui/src/content_manager.cpp @@ -47,7 +47,7 @@ auto get_recursive_directory_size(const T &path) { } // namespace void get_app_info(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path) { - const auto APP_PATH{ emuenv.pref_path / "ux0/app" / app_path }; + const auto APP_PATH{ emuenv.pref_path / convert_path(app_path) }; gui.app_selector.app_info = {}; if (fs::exists(APP_PATH) && !fs::is_empty(APP_PATH)) { @@ -60,7 +60,7 @@ void get_app_info(GuiState &gui, EmuEnvState &emuenv, const std::string &app_pat } size_t get_app_size(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path) { - const auto APP_PATH{ emuenv.pref_path / "ux0/app" / app_path }; + const auto APP_PATH{ emuenv.pref_path / convert_path(app_path) }; boost::uintmax_t app_size = 0; if (fs::exists(APP_PATH) && !fs::is_empty(APP_PATH)) { app_size += get_recursive_directory_size(APP_PATH); @@ -129,7 +129,7 @@ void init_content_manager(GuiState &gui, EmuEnvState &emuenv) { space["free"] = get_unit_size(free_size); const auto query_app = [&gui, &emuenv] { - const auto &directory_list = gui.app_selector.user_apps; + const auto &directory_list = gui.app_selector.vita_apps["ux0"]; const auto pred = [&](const auto acc, const auto &app) { apps_size[app.path] = get_app_size(gui, emuenv, app.path); return acc + apps_size[app.path]; @@ -194,13 +194,14 @@ struct AddCont { static std::map addcont_info; static void get_content_info(GuiState &gui, EmuEnvState &emuenv) { - const auto APP_PATH{ emuenv.pref_path / "ux0/app" / app_selected }; + const auto &APP = fs::path(app_selected).stem().string(); + const auto APP_PATH{ emuenv.pref_path / "ux0/app" / APP }; if (fs::exists(APP_PATH) && !fs::is_empty(APP_PATH)) { gui.app_selector.app_info.size = get_recursive_directory_size(APP_PATH); } addcont_info.clear(); - const auto ADDCONT_PATH{ emuenv.pref_path / "ux0/addcont" / app_selected }; + const auto ADDCONT_PATH{ emuenv.pref_path / "ux0/addcont" / APP }; if (fs::exists(ADDCONT_PATH) && !fs::is_empty(ADDCONT_PATH)) { for (const auto &addcont : fs::directory_iterator(ADDCONT_PATH)) { const auto content_id = addcont.path().stem().string(); @@ -211,7 +212,7 @@ static void get_content_info(GuiState &gui, EmuEnvState &emuenv) { const auto addcont_size = get_recursive_directory_size(addcont); addcont_info[content_id].size = get_unit_size(addcont_size); - const auto content_path{ fs::path("addcont") / app_selected / content_id }; + const auto content_path{ fs::path("addcont") / APP / content_id }; vfs::FileBuffer params; if (vfs::read_file(VitaIoDevice::ux0, params, emuenv.pref_path, content_path / "sce_sys/param.sfo")) { SfoFile sfo_handle; @@ -249,7 +250,7 @@ void draw_content_manager(GuiState &gui, EmuEnvState &emuenv) { const auto POPUP_SIZE = ImVec2(756.0f * SCALE.x, 436.0f * SCALE.y); - const auto has_background = gui.apps_background.contains("NPXS10026"); + const auto BG_PATH = "vs0:app/NPXS10026"; const auto is_12_hour_format = emuenv.cfg.sys_time_format == SCE_SYSTEM_PARAM_TIME_FORMAT_12HOUR; ImGui::SetNextWindowPos(WINDOW_POS, ImGuiCond_Always); @@ -262,8 +263,8 @@ void draw_content_manager(GuiState &gui, EmuEnvState &emuenv) { const auto draw_list = ImGui::GetBackgroundDrawList(); const ImVec2 VIEWPORT_POS_MAX(VIEWPORT_POS.x + VIEWPORT_SIZE.x, VIEWPORT_POS.y + VIEWPORT_SIZE.y); - if (has_background) - draw_list->AddImage(gui.apps_background["NPXS10026"], VIEWPORT_POS, VIEWPORT_POS_MAX); + if (gui.apps_background.contains(BG_PATH)) + draw_list->AddImage(gui.apps_background[BG_PATH], VIEWPORT_POS, VIEWPORT_POS_MAX); else draw_list->AddRectFilled(VIEWPORT_POS, VIEWPORT_POS_MAX, IM_COL32(53.f, 54.f, 70.f, 255.f), 0.f, ImDrawFlags_RoundCornersAll); @@ -277,7 +278,7 @@ void draw_content_manager(GuiState &gui, EmuEnvState &emuenv) { if (menu == "info") { ImGui::SetCursorPos(ImVec2(90.f * SCALE.x, 10.f * SCALE.y)); - ImGui::Image(gui.app_selector.user_apps_icon[app_selected], SIZE_ICON_DETAIL); + ImGui::Image(gui.app_selector.vita_apps_icon[app_selected], SIZE_ICON_DETAIL); const auto CALC_NAME = ImGui::CalcTextSize(get_app_index(gui, app_selected)->title.c_str(), nullptr, false, SIZE_INFO.x - SIZE_ICON_DETAIL.x).y / 2.f; ImGui::SetCursorPos(ImVec2((110.f * SCALE.x) + SIZE_ICON_DETAIL.x, (SIZE_ICON_DETAIL.y / 2.f) - CALC_NAME + (10.f * SCALE.y))); ImGui::PushTextWrapPos(SIZE_INFO.x); @@ -290,7 +291,7 @@ void draw_content_manager(GuiState &gui, EmuEnvState &emuenv) { ImGui::TextColored(GUI_COLOR_TEXT, "%s", title.c_str()); ImGui::PopTextWrapPos(); if (!menu.empty()) { - if (((menu == "app") && !gui.app_selector.user_apps.empty()) || ((menu == "save") && !save_data_list.empty())) { + if (((menu == "app") && !gui.app_selector.vita_apps["ux0"].empty()) || ((menu == "save") && !save_data_list.empty())) { // Search Bar ImGui::SetCursorPos(ImVec2(VIEWPORT_POS.x + (10.f * SCALE.x), VIEWPORT_POS.y + (32.f * SCALE.y) - (ImGui::CalcTextSize(common["search"].c_str()).y / 2.f))); ImGui::TextColored(GUI_COLOR_TEXT, "%s", common["search"].c_str()); @@ -338,7 +339,7 @@ void draw_content_manager(GuiState &gui, EmuEnvState &emuenv) { ImGui::Separator(); ImGui::SetWindowFontScale(1.2f); if (ImGui::Selectable(lang.main["theme"].c_str(), false, ImGuiSelectableFlags_SpanAllColumns, ImVec2(0.f, SIZE_SELECT))) - pre_run_app(gui, emuenv, "NPXS10015"); + pre_run_app(gui, emuenv, "vs0:app/NPXS10015"); ImGui::NextColumn(); ImGui::SetWindowFontScale(0.8f); ImGui::Selectable(space["themes"].c_str(), false, ImGuiSelectableFlags_SpanAllColumns, ImVec2(0.f, SIZE_SELECT)); @@ -361,13 +362,14 @@ void draw_content_manager(GuiState &gui, EmuEnvState &emuenv) { if (content_delete) { for (const auto &content : contents_selected) { if (content.second) { + const auto &APP = fs::path(content.first).stem().string(); if (menu == "app") { - fs::remove_all(emuenv.pref_path / "ux0/app" / content.first); - fs::remove_all(emuenv.pref_path / "ux0/addcont" / content.first); - gui.app_selector.user_apps.erase(gui.app_selector.user_apps.begin() + (get_app_index(gui, content.first) - &gui.app_selector.user_apps[0])); - gui.app_selector.user_apps_icon.erase(content.first); + fs::remove_all(emuenv.pref_path / "ux0/app" / APP); + fs::remove_all(emuenv.pref_path / "ux0/addcont" / APP); + gui.app_selector.vita_apps["ux0"].erase(gui.app_selector.vita_apps["ux0"].begin() + (get_app_index(gui, content.first) - gui.app_selector.vita_apps["ux0"].data())); + gui.app_selector.vita_apps_icon.erase(content.first); } - const auto SAVE_PATH{ emuenv.pref_path / "ux0/user" / emuenv.io.user_id / "savedata" / content.first }; + const auto SAVE_PATH{ emuenv.pref_path / "ux0/user" / emuenv.io.user_id / "savedata" / APP }; fs::remove_all(SAVE_PATH); } } @@ -408,7 +410,7 @@ void draw_content_manager(GuiState &gui, EmuEnvState &emuenv) { // Apps Menu if (menu == "app") { title = application["title"]; - if (gui.app_selector.user_apps.empty()) { + if (gui.app_selector.vita_apps["ux0"].empty()) { ImGui::SetWindowFontScale(1.2f); auto no_item_str = application["no_item"].c_str(); const auto calc_text = ImGui::CalcTextSize(no_item_str); @@ -425,7 +427,7 @@ void draw_content_manager(GuiState &gui, EmuEnvState &emuenv) { ImGui::SetColumnWidth(0, 60 * SCALE.x); ImGui::SetColumnWidth(1, 75 * SCALE.x); ImGui::SetColumnWidth(2, 580.f * SCALE.x); - for (const auto &app : gui.app_selector.user_apps) { + for (const auto &app : gui.app_selector.vita_apps["ux0"]) { if (!search_bar.PassFilter(app.title.c_str()) && !search_bar.PassFilter(app.stitle.c_str()) && !search_bar.PassFilter(app.title_id.c_str())) continue; ImGui::PushID(app.path.c_str()); @@ -434,7 +436,7 @@ void draw_content_manager(GuiState &gui, EmuEnvState &emuenv) { ImGui::Checkbox("##selected", &contents_selected[app.path]); ImGui::NextColumn(); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (8.f * SCALE.y)); - ImGui::Image(gui.app_selector.user_apps_icon[app.path], SIZE_ICON_LIST); + ImGui::Image(gui.app_selector.vita_apps_icon[app.path], SIZE_ICON_LIST); ImGui::NextColumn(); const auto Title_POS = ImGui::GetCursorPosY(); ImGui::SetWindowFontScale(1.1f); @@ -483,7 +485,7 @@ void draw_content_manager(GuiState &gui, EmuEnvState &emuenv) { ImGui::Checkbox("##selected", &contents_selected[save.title_id]); ImGui::NextColumn(); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (8.f * SCALE.y)); - ImGui::Image(gui.app_selector.user_apps_icon[save.title_id], SIZE_ICON_LIST); + ImGui::Image(gui.app_selector.vita_apps_icon[save.title_id], SIZE_ICON_LIST); ImGui::NextColumn(); const auto Title_POS = ImGui::GetCursorPosY(); ImGui::SetWindowFontScale(1.1f); @@ -561,7 +563,7 @@ void draw_content_manager(GuiState &gui, EmuEnvState &emuenv) { ImGui::SetWindowFontScale(1.2f * RES_SCALE.x); ImGui::SetCursorPos(ImVec2(10.f * SCALE.x, WINDOW_SIZE.y - (56.f * SCALE.y))); - const auto is_empty = ((menu == "app") && gui.app_selector.user_apps.empty()) || ((menu == "save") && save_data_list.empty()); + const auto is_empty = ((menu == "app") && gui.app_selector.vita_apps["ux0"].empty()) || ((menu == "save") && save_data_list.empty()); if (menu.empty() || (menu == "info") || is_empty) { // Back if (ImGui::Button("Back", ImVec2(64.f * SCALE.x, 40.f * SCALE.y)) || ImGui::IsKeyPressed(static_cast(emuenv.cfg.keyboard_button_circle))) { diff --git a/vita3k/gui/src/gui.cpp b/vita3k/gui/src/gui.cpp index 70132a7b33..47e4e5418f 100644 --- a/vita3k/gui/src/gui.cpp +++ b/vita3k/gui/src/gui.cpp @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include #include @@ -320,7 +322,7 @@ static IconData load_app_icon(GuiState &gui, EmuEnvState &emuenv, const std::str void init_app_icon(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path) { IconData data = load_app_icon(gui, emuenv, app_path); if (data.data) { - gui.app_selector.user_apps_icon[app_path].init(gui.imgui_state.get(), data.data.get(), data.width, data.height); + gui.app_selector.vita_apps_icon[app_path].init(gui.imgui_state.get(), data.data.get(), data.width, data.height); } } @@ -332,7 +334,7 @@ void IconAsyncLoader::commit(GuiState &gui) { for (const auto &pair : icon_data) { if (pair.second.data) { - gui.app_selector.user_apps_icon[pair.first].init(gui.imgui_state.get(), pair.second.data.get(), pair.second.width, pair.second.height); + gui.app_selector.vita_apps_icon[pair.first].init(gui.imgui_state.get(), pair.second.data.get(), pair.second.width, pair.second.height); } } @@ -372,8 +374,8 @@ IconAsyncLoader::~IconAsyncLoader() { thread.join(); } -void init_apps_icon(GuiState &gui, EmuEnvState &emuenv, const std::vector &app_list) { - gui.app_selector.icon_async_loader.emplace(gui, emuenv, app_list); +void init_apps_icon(GuiState &gui, EmuEnvState &emuenv, const std::vector &apps_list) { + gui.app_selector.icon_async_loader.emplace(gui, emuenv, apps_list); } void init_app_background(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path) { @@ -385,16 +387,12 @@ void init_app_background(GuiState &gui, EmuEnvState &emuenv, const std::string & int32_t height = 0; vfs::FileBuffer buffer; - const auto is_sys = app_path.starts_with("NPXS") && (app_path != "NPXS10007"); - if (is_sys) - vfs::read_file(VitaIoDevice::vs0, buffer, emuenv.pref_path, "app/" + app_path + "/sce_sys/pic0.png"); - else - vfs::read_app_file(buffer, emuenv.pref_path, app_path, "sce_sys/pic0.png"); + vfs::read_app_file(buffer, emuenv.pref_path, app_path, "sce_sys/pic0.png"); const auto &title = APP_INDEX ? APP_INDEX->title : app_path; if (buffer.empty()) { - LOG_WARN("Background not found for application {} [{}].", title, app_path); + LOG_WARN("Background not found for application {} in path [{}].", title, app_path); return; } @@ -419,15 +417,14 @@ static bool get_user_apps(GuiState &gui, EmuEnvState &emuenv) { const auto apps_cache_path{ emuenv.pref_path / "ux0/temp/apps.dat" }; fs::ifstream apps_cache(apps_cache_path, std::ios::in | std::ios::binary); if (apps_cache.is_open()) { - gui.app_selector.user_apps.clear(); // Read size of apps list - size_t size; + uint32_t size; apps_cache.read((char *)&size, sizeof(size)); // Check version of cache uint32_t versionInFile; apps_cache.read((char *)&versionInFile, sizeof(uint32_t)); - if (versionInFile != 1) { + if (versionInFile != 2) { LOG_WARN("Current version of cache: {}, is outdated, recreate it.", versionInFile); return false; } @@ -465,14 +462,14 @@ static bool get_user_apps(GuiState &gui, EmuEnvState &emuenv) { app.title_id = read(); app.path = read(); - gui.app_selector.user_apps.push_back(app); + gui.app_selector.vita_apps["ux0"].push_back(app); } - init_apps_icon(gui, emuenv, gui.app_selector.user_apps); + init_apps_icon(gui, emuenv, gui.app_selector.vita_apps["ux0"]); load_and_update_compat_user_apps(gui, emuenv); } - return !gui.app_selector.user_apps.empty(); + return !gui.app_selector.vita_apps["ux0"].empty(); } void save_apps_cache(GuiState &gui, EmuEnvState &emuenv) { @@ -482,11 +479,11 @@ void save_apps_cache(GuiState &gui, EmuEnvState &emuenv) { fs::ofstream apps_cache(temp_path / "apps.dat", std::ios::out | std::ios::binary); if (apps_cache.is_open()) { // Write Size of apps list - const auto size = gui.app_selector.user_apps.size(); + const uint32_t size = gui.app_selector.vita_apps["ux0"].size(); apps_cache.write((char *)&size, sizeof(size)); // Write version of cache - const uint32_t versionInFile = 1; + const uint32_t versionInFile = 2; apps_cache.write((const char *)&versionInFile, sizeof(uint32_t)); // Write language of cache @@ -494,7 +491,7 @@ void save_apps_cache(GuiState &gui, EmuEnvState &emuenv) { apps_cache.write((char *)&gui.app_selector.apps_cache_lang, sizeof(uint32_t)); // Write Apps list - for (const App &app : gui.app_selector.user_apps) { + for (const App &app : gui.app_selector.vita_apps["ux0"]) { auto write = [&apps_cache](const std::string &i) { const auto size = i.length(); @@ -517,13 +514,50 @@ void save_apps_cache(GuiState &gui, EmuEnvState &emuenv) { } } +void init_fw_apps(GuiState &gui, EmuEnvState &emuenv) { + // Add preinstalled apps working here + static std::vector preinst_apps_paths = { + "pd0:app/NPXS10007", + "vs0:app/NPXS10000", // Near + "vs0:app/NPXS10001", // Party + "vs0:app/NPXS10002", // Ps Store + "vs0:app/NPXS10003", // Web Browser + "vs0:app/NPXS10004", + "vs0:app/NPXS10006", + "vs0:app/NPXS10008", + "vs0:app/NPXS10009", + "vs0:app/NPXS10010", + "vs0:app/NPXS10012", + "vs0:app/NPXS10013", + "vs0:app/NPXS10014", + "vs0:app/NPXS10015", + "vs0:app/NPXS10018", + "vs0:app/NPXS10021", + "vs0:app/NPXS10026", // Content Manager + "vs0:app/NPXS10031", + "vs0:app/NPXS10072", + "vs0:app/NPXS10078", + "vs0:app/NPXS10091", + "vs0:app/NPXS10094", + "vs0:app/NPXS10095", + "vs0:app/NPXS10098", + }; + + for (const auto &app_path : preinst_apps_paths) { + if (fs::exists(emuenv.pref_path / convert_path(app_path) / "eboot.bin")) + init_user_app(gui, emuenv, app_path); + else + LOG_WARN("Preinstalled app not found in path [{}].", app_path); + } +} + void init_home(GuiState &gui, EmuEnvState &emuenv) { - if (gui.app_selector.user_apps.empty() && (emuenv.cfg.load_app_list || !emuenv.cfg.run_app_path)) { + init_fw_apps(gui, emuenv); + if (gui.app_selector.vita_apps["ux0"].empty() && (emuenv.cfg.load_app_list || !emuenv.cfg.run_app_path)) { if (!get_user_apps(gui, emuenv)) - init_user_apps(gui, emuenv); + init_vita_apps(gui, emuenv); } - - init_app_background(gui, emuenv, "NPXS10015"); + init_app_background(gui, emuenv, "vs0:app/NPXS10015"); regmgr::init_regmgr(emuenv.regmgr, emuenv.pref_path); @@ -539,13 +573,14 @@ void init_home(GuiState &gui, EmuEnvState &emuenv) { } void init_user_app(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path) { - auto &user_apps = gui.app_selector.user_apps; + const auto device = device::get_device(app_path)._to_string(); + auto &user_apps = gui.app_selector.vita_apps[device]; auto it = std::find_if(user_apps.begin(), user_apps.end(), [&](const App &a) { return a.path == app_path; }); if (it != user_apps.end()) { user_apps.erase(it); - gui.app_selector.user_apps_icon.erase(app_path); + gui.app_selector.vita_apps_icon.erase(app_path); } get_app_param(gui, emuenv, app_path); @@ -559,7 +594,7 @@ void init_user_app(GuiState &gui, EmuEnvState &emuenv, const std::string &app_pa } std::map::const_iterator get_app_icon(GuiState &gui, const std::string &app_path) { - const auto &app_type = app_path.starts_with("NPXS") && (app_path != "NPXS10007") ? gui.app_selector.sys_apps_icon : gui.app_selector.user_apps_icon; + const auto &app_type = app_path.starts_with("emu") ? gui.app_selector.emu_apps_icon : gui.app_selector.vita_apps_icon; const auto app_icon = std::find_if(app_type.begin(), app_type.end(), [&](const auto &i) { return i.first == app_path; }); @@ -568,7 +603,8 @@ std::map::const_iterator get_app_icon(GuiState &gui, } App *get_app_index(GuiState &gui, const std::string &app_path) { - auto &app_type = app_path.starts_with("NPXS") && (app_path != "NPXS10007") ? gui.app_selector.sys_apps : gui.app_selector.user_apps; + const auto device = device::get_device(app_path)._to_string(); + auto &app_type = app_path.starts_with("emu") ? gui.app_selector.emu_apps : gui.app_selector.vita_apps[device]; const auto app_index = std::find_if(app_type.begin(), app_type.end(), [&](const App &a) { return a.path == app_path; }); @@ -582,23 +618,23 @@ void get_app_param(GuiState &gui, EmuEnvState &emuenv, const std::string &app_pa if (vfs::read_app_file(param, emuenv.pref_path, app_path, "sce_sys/param.sfo")) { sfo::get_param_info(emuenv.app_info, param, emuenv.cfg.sys_lang); } else { - emuenv.app_info.app_addcont = emuenv.app_info.app_savedata = emuenv.app_info.app_short_title = emuenv.app_info.app_title = emuenv.app_info.app_title_id = emuenv.app_path; // Use app path as TitleID, addcont, Savedata, Short title and Title + emuenv.app_info.app_addcont = emuenv.app_info.app_savedata = emuenv.app_info.app_short_title = emuenv.app_info.app_title = emuenv.app_info.app_title_id = fs::path(emuenv.app_path).stem().string(); // Use app path as TitleID, addcont, Savedata, Short title and Title emuenv.app_info.app_version = emuenv.app_info.app_category = emuenv.app_info.app_parental_level = "N/A"; } - gui.app_selector.user_apps.push_back({ emuenv.app_info.app_version, emuenv.app_info.app_category, emuenv.app_info.app_content_id, emuenv.app_info.app_addcont, emuenv.app_info.app_savedata, emuenv.app_info.app_parental_level, emuenv.app_info.app_short_title, emuenv.app_info.app_title, emuenv.app_info.app_title_id, emuenv.app_path }); + const auto device = device::get_device(app_path)._to_string(); + gui.app_selector.vita_apps[device].push_back({ emuenv.app_info.app_version, emuenv.app_info.app_category, emuenv.app_info.app_content_id, emuenv.app_info.app_addcont, emuenv.app_info.app_savedata, emuenv.app_info.app_parental_level, emuenv.app_info.app_short_title, emuenv.app_info.app_title, emuenv.app_info.app_title_id, emuenv.app_path }); } void get_user_apps_title(GuiState &gui, EmuEnvState &emuenv) { - const fs::path app_path{ emuenv.pref_path / "ux0/app" }; - if (!fs::exists(app_path)) + const fs::path apps_path{ emuenv.pref_path / "ux0/app" }; + if (!fs::exists(apps_path)) return; - gui.app_selector.user_apps.clear(); - for (const auto &app : fs::directory_iterator(app_path)) { + for (const auto &app : fs::directory_iterator(apps_path)) { if (!app.path().empty() && fs::is_directory(app.path()) && !app.path().filename_is_dot() && !app.path().filename_is_dot_dot()) { const auto app_path = app.path().stem().generic_string(); - get_app_param(gui, emuenv, app_path); + get_app_param(gui, emuenv, "ux0:app/" + app_path); } } @@ -606,41 +642,52 @@ void get_user_apps_title(GuiState &gui, EmuEnvState &emuenv) { } void get_sys_apps_title(GuiState &gui, EmuEnvState &emuenv) { - gui.app_selector.sys_apps.clear(); - constexpr std::array sys_apps_list = { "NPXS10003", "NPXS10008", "NPXS10015", "NPXS10026" }; + gui.app_selector.emu_apps.clear(); + constexpr std::array sys_apps_list = { "NPXS10003", "NPXS10008", "NPXS10015", "NPXS10026", "NPXS19999" }; for (const auto &app : sys_apps_list) { - vfs::FileBuffer params; - if (vfs::read_file(VitaIoDevice::vs0, params, emuenv.pref_path, fmt::format("app/{}/sce_sys/param.sfo", app))) { - SfoFile sfo_handle; - sfo::load(sfo_handle, params); - sfo::get_data_by_key(emuenv.app_info.app_version, sfo_handle, "APP_VER"); - if (emuenv.app_info.app_version[0] == '0') - emuenv.app_info.app_version.erase(emuenv.app_info.app_version.begin()); - sfo::get_data_by_key(emuenv.app_info.app_category, sfo_handle, "CATEGORY"); - sfo::get_data_by_key(emuenv.app_info.app_short_title, sfo_handle, fmt::format("STITLE_{:0>2d}", emuenv.cfg.sys_lang)); - sfo::get_data_by_key(emuenv.app_info.app_title, sfo_handle, fmt::format("TITLE_{:0>2d}", emuenv.cfg.sys_lang)); - boost::trim(emuenv.app_info.app_title); - sfo::get_data_by_key(emuenv.app_info.app_title_id, sfo_handle, "TITLE_ID"); + if (app == "NPXS19999") { + if (fs::exists(fs::path(emuenv.pref_path) / "vs0/vsh/shell")) { + emuenv.app_path = "emu:vsh/shell"; + emuenv.app_info.app_title_id = app; + emuenv.app_info.app_short_title = "PS Vita OS"; + emuenv.app_info.app_title = "PlayStation Vita OS"; + } else + continue; } else { - auto &lang = gui.lang.sys_apps_title; - emuenv.app_info.app_version = "1.00"; - emuenv.app_info.app_category = "gda"; - emuenv.app_info.app_title_id = app; - if (app == "NPXS10003") { - emuenv.app_info.app_short_title = lang["browser"]; - emuenv.app_info.app_title = lang["internet_browser"]; - } else if (app == "NPXS10008") { - emuenv.app_info.app_short_title = lang["trophies"]; - emuenv.app_info.app_title = lang["trophy_collection"]; - } else if (app == "NPXS10015") - emuenv.app_info.app_short_title = emuenv.app_info.app_title = lang["settings"]; - else - emuenv.app_info.app_short_title = emuenv.app_info.app_title = lang["content_manager"]; + emuenv.app_path = fmt::format("emu:app/{}", app); + vfs::FileBuffer params; + if (vfs::read_file(VitaIoDevice::vs0, params, emuenv.pref_path, fmt::format("app/{}/sce_sys/param.sfo", app))) { + SfoFile sfo_handle; + sfo::load(sfo_handle, params); + sfo::get_data_by_key(emuenv.app_info.app_version, sfo_handle, "APP_VER"); + if (emuenv.app_info.app_version[0] == '0') + emuenv.app_info.app_version.erase(emuenv.app_info.app_version.begin()); + sfo::get_data_by_key(emuenv.app_info.app_category, sfo_handle, "CATEGORY"); + sfo::get_data_by_key(emuenv.app_info.app_short_title, sfo_handle, fmt::format("STITLE_{:0>2d}", emuenv.cfg.sys_lang)); + sfo::get_data_by_key(emuenv.app_info.app_title, sfo_handle, fmt::format("TITLE_{:0>2d}", emuenv.cfg.sys_lang)); + boost::trim(emuenv.app_info.app_title); + sfo::get_data_by_key(emuenv.app_info.app_title_id, sfo_handle, "TITLE_ID"); + } else { + auto &lang = gui.lang.sys_apps_title; + emuenv.app_info.app_version = "1.00"; + emuenv.app_info.app_category = "gda"; + emuenv.app_info.app_title_id = app; + if (app == "NPXS10003") { + emuenv.app_info.app_short_title = lang["browser"]; + emuenv.app_info.app_title = lang["internet_browser"]; + } else if (app == "NPXS10008") { + emuenv.app_info.app_short_title = lang["trophies"]; + emuenv.app_info.app_title = lang["trophy_collection"]; + } else if (app == "NPXS10015") + emuenv.app_info.app_short_title = emuenv.app_info.app_title = lang["settings"]; + else + emuenv.app_info.app_short_title = emuenv.app_info.app_title = lang["content_manager"]; + } } - gui.app_selector.sys_apps.push_back({ emuenv.app_info.app_version, emuenv.app_info.app_category, {}, {}, {}, {}, emuenv.app_info.app_short_title, emuenv.app_info.app_title, emuenv.app_info.app_title_id, app.data() }); + gui.app_selector.emu_apps.push_back({ emuenv.app_info.app_version, emuenv.app_info.app_category, {}, {}, {}, {}, emuenv.app_info.app_short_title, emuenv.app_info.app_title, emuenv.app_info.app_title_id, emuenv.app_path }); } - std::sort(gui.app_selector.sys_apps.begin(), gui.app_selector.sys_apps.end(), [](const App &lhs, const App &rhs) { + std::sort(gui.app_selector.emu_apps.begin(), gui.app_selector.emu_apps.end(), [](const App &lhs, const App &rhs) { return string_utils::toupper(lhs.title) < string_utils::toupper(rhs.title); }); } diff --git a/vita3k/gui/src/home_screen.cpp b/vita3k/gui/src/home_screen.cpp index 057262eef2..0ece23cb8f 100644 --- a/vita3k/gui/src/home_screen.cpp +++ b/vita3k/gui/src/home_screen.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -35,9 +36,9 @@ using namespace std::string_literals; namespace gui { -void init_user_apps(GuiState &gui, EmuEnvState &emuenv) { +void init_vita_apps(GuiState &gui, EmuEnvState &emuenv) { gui.apps_background.clear(); - gui.app_selector.user_apps_icon.clear(); + gui.app_selector.vita_apps_icon.clear(); gui.live_area_app_current_open = -1; gui.live_area_current_open_apps_list.clear(); gui.live_area_contents.clear(); @@ -46,30 +47,31 @@ void init_user_apps(GuiState &gui, EmuEnvState &emuenv) { gui.app_selector.icon_async_loader->quit = true; std::thread init_apps([&gui, &emuenv]() { - auto app_list_size = gui.app_selector.user_apps.size(); - gui.app_selector.user_apps.clear(); + auto apps_list_size = gui.app_selector.vita_apps["ux0"].size(); + gui.app_selector.vita_apps.clear(); + + init_fw_apps(gui, emuenv); get_user_apps_title(gui, emuenv); - if (gui.app_selector.user_apps.empty()) + if (gui.app_selector.vita_apps["ux0"].empty()) return false; gui.app_selector.is_app_list_sorted = false; init_last_time_apps(gui, emuenv); load_and_update_compat_user_apps(gui, emuenv); - init_apps_icon(gui, emuenv, gui.app_selector.user_apps); + const auto new_apps_list_size = gui.app_selector.vita_apps["ux0"].size(); + init_apps_icon(gui, emuenv, gui.app_selector.vita_apps["ux0"]); - if (app_list_size == gui.app_selector.user_apps.size()) + if (apps_list_size == new_apps_list_size) return false; std::string change_app_list = "new application(s) added"; - if (app_list_size > gui.app_selector.user_apps.size()) { + if (apps_list_size > new_apps_list_size) { change_app_list = "application(s) removed"; - app_list_size -= gui.app_selector.user_apps.size(); + apps_list_size -= new_apps_list_size; } else - app_list_size = gui.app_selector.user_apps.size() - app_list_size; - - LOG_INFO("{} {}", app_list_size, change_app_list); + apps_list_size = new_apps_list_size - apps_list_size; return true; }); @@ -87,8 +89,9 @@ void init_last_time_apps(GuiState &gui, EmuEnvState &emuenv) { } }; - last_time_apps(gui.app_selector.sys_apps); - last_time_apps(gui.app_selector.user_apps); + last_time_apps(gui.app_selector.emu_apps); + for (auto &[_, apps] : gui.app_selector.vita_apps) + last_time_apps(apps); gui.app_selector.is_app_list_sorted = false; } @@ -132,10 +135,9 @@ void open_live_area(GuiState &gui, EmuEnvState &emuenv, const std::string &app_p } void pre_load_app(GuiState &gui, EmuEnvState &emuenv, bool live_area, const std::string &app_path) { - if (app_path == "NPXS10003") { - update_last_time_app_used(gui, emuenv, app_path); + if (app_path == "emu:app/NPXS10003") open_path("https://Vita3k.org"); - } else { + else { if (live_area) open_live_area(gui, emuenv, app_path); else @@ -145,8 +147,8 @@ void pre_load_app(GuiState &gui, EmuEnvState &emuenv, bool live_area, const std: void pre_run_app(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path) { switch_bgm_state(true); - const auto is_sys = app_path.starts_with("NPXS") && (app_path != "NPXS10007"); - if (!is_sys) { + const auto is_emu = app_path.starts_with("emu"); + if (!is_emu || (app_path == "emu:vsh/shell")) { if (emuenv.io.app_path != app_path) { if (!emuenv.io.app_path.empty()) gui.vita_area.app_close = true; @@ -162,16 +164,15 @@ void pre_run_app(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path emuenv.app_path = app_path; gui.vita_area.home_screen = false; gui.vita_area.live_area_screen = false; - init_app_background(gui, emuenv, app_path); - update_last_time_app_used(gui, emuenv, app_path); + init_app_background(gui, emuenv, "vs0:app/" + fs::path(app_path).stem().string()); - if (app_path == "NPXS10008") { + if (app_path == "emu:app/NPXS10008") { init_trophy_collection(gui, emuenv); gui.vita_area.trophy_collection = true; - } else if (app_path == "NPXS10015") { + } else if (app_path == "emu:app/NPXS10015") { if (gui.vita_area.content_manager) { - emuenv.app_path = "NPXS10026"; - update_time_app_used(gui, emuenv, "NPXS10026"); + emuenv.app_path = "emu:app/NPXS10026"; + update_time_app_used(gui, emuenv, emuenv.app_path); gui.vita_area.content_manager = false; } @@ -184,10 +185,9 @@ void pre_run_app(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path } void close_system_app(GuiState &gui, EmuEnvState &emuenv) { - if (gui.vita_area.content_manager) { + if (gui.vita_area.content_manager) gui.vita_area.content_manager = false; - update_time_app_used(gui, emuenv, "NPXS10026"); - } else if (gui.vita_area.manual) { + else if (gui.vita_area.manual) { gui.vita_area.manual = false; // Free manual textures from memory when manual is closed @@ -196,15 +196,12 @@ void close_system_app(GuiState &gui, EmuEnvState &emuenv) { gui.manuals.clear(); } else if (gui.vita_area.settings) { gui.vita_area.settings = false; - update_time_app_used(gui, emuenv, "NPXS10015"); - if (emuenv.app_path == "NPXS10026") { - pre_run_app(gui, emuenv, "NPXS10026"); + if (emuenv.app_path == "emu:app/NPXS10026") { + pre_run_app(gui, emuenv, "emu:app/NPXS10026"); return; } - } else { + } else gui.vita_area.trophy_collection = false; - update_time_app_used(gui, emuenv, "NPXS10008"); - } if ((gui::get_live_area_current_open_apps_list_index(gui, emuenv.app_path) != gui.live_area_current_open_apps_list.end()) && (gui.live_area_current_open_apps_list[gui.live_area_app_current_open] == emuenv.app_path)) { gui.vita_area.live_area_screen = true; @@ -218,9 +215,16 @@ void close_system_app(GuiState &gui, EmuEnvState &emuenv) { switch_bgm_state(false); } -void close_and_run_new_app(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path) { +void close_and_run_new_app(EmuEnvState &emuenv, const std::string &app_path) { emuenv.kernel.exit_delete_all_threads(); - emuenv.load_app_path = app_path; + if (app_path == "emu:vsh/shell") { + emuenv.load_app_device = "vs0"; + emuenv.load_app_path = "vsh/shell"; + emuenv.load_exec_path = "shell.self"; + } else { + emuenv.load_app_device = device::get_device(app_path)._to_string(); + emuenv.load_app_path = fs::path(app_path).stem().string(); + } emuenv.load_exec = true; } @@ -247,7 +251,7 @@ void draw_app_close(GuiState &gui, EmuEnvState &emuenv) { ImGui::SetWindowFontScale(1.4f * RES_SCALE.x); ImGui::SetCursorPos(ImVec2(50.f * SCALE.x, 108.f * SCALE.y)); ImGui::TextColored(GUI_COLOR_TEXT, "%s", gui.lang.game_data["app_close"].c_str()); - if (gui.app_selector.user_apps_icon.contains(emuenv.io.app_path)) { + if (gui.app_selector.vita_apps_icon.contains(emuenv.io.app_path)) { const auto ICON_POS_SCALE = ImVec2(50.f * SCALE.x, (WINDOW_SIZE.y / 2.f) - (ICON_SIZE.y / 2.f) - (10.f * SCALE.y)); ImGui::SetCursorPos(ICON_POS_SCALE); const auto POS_MIN = ImGui::GetCursorScreenPos(); @@ -261,7 +265,7 @@ void draw_app_close(GuiState &gui, EmuEnvState &emuenv) { ImGui::SameLine(0, 20.f * SCALE.x); if (ImGui::Button(common["ok"].c_str(), BUTTON_SIZE)) { const auto &app_path = gui.vita_area.live_area_screen ? gui.live_area_current_open_apps_list[gui.live_area_app_current_open] : emuenv.app_path; - close_and_run_new_app(gui, emuenv, app_path); + close_and_run_new_app(emuenv, app_path); } ImGui::PopStyleVar(); ImGui::EndChild(); @@ -345,7 +349,7 @@ static void sort_app_list(GuiState &gui, EmuEnvState &emuenv, const SortType &ty gui.app_selector.is_app_list_sorted = true; } - std::sort(gui.app_selector.user_apps.begin(), gui.app_selector.user_apps.end(), [&](const App &lhs, const App &rhs) { + std::sort(gui.app_selector.vita_apps["ux0"].begin(), gui.app_selector.vita_apps["ux0"].end(), [&](const App &lhs, const App &rhs) { switch (type) { case APP_VER: switch (sorted) { @@ -422,7 +426,7 @@ static std::string get_label_name(GuiState &gui, const SortType &type) { return label; } -static constexpr int32_t INVALID_APP_INDEX = -5; +static constexpr int32_t INVALID_APP_INDEX = -6; static int32_t first_visible_app_index = INVALID_APP_INDEX, current_selected_app_index = INVALID_APP_INDEX; static std::vector apps_list_filtered; @@ -461,6 +465,13 @@ void browse_home_apps_list(GuiState &gui, EmuEnvState &emuenv, const uint32_t bu } }; + const auto has_preinst_app = gui.app_selector.vita_apps.contains("pd0"); + const auto &preinst_app = gui.app_selector.vita_apps["pd0"][0]; + const auto &user_app = gui.app_selector.vita_apps["ux0"]; + const auto &sys_app = gui.app_selector.vita_apps["vs0"]; + const auto emu_apps_size = gui.app_selector.emu_apps.size(); + const auto &selected_app = current_selected_app_index < 0 ? gui.app_selector.emu_apps[current_selected_app_index + emu_apps_size] : (has_preinst_app ? (current_selected_app_index == 0 ? preinst_app : user_app[current_selected_app_index - 1]) : user_app[current_selected_app_index]); + switch (button) { case SCE_CTRL_UP: if (emuenv.cfg.apps_list_grid) { @@ -495,16 +506,12 @@ void browse_home_apps_list(GuiState &gui, EmuEnvState &emuenv, const uint32_t bu gui.vita_area.home_screen = !gui.vita_area.live_area_screen; break; case SCE_CTRL_CIRCLE: - if (emuenv.cfg.sys_button == 0) { - const auto &selected_app = current_selected_app_index < 0 ? gui.app_selector.sys_apps[current_selected_app_index + 4] : gui.app_selector.user_apps[current_selected_app_index]; + if (emuenv.cfg.sys_button == 0) pre_load_app(gui, emuenv, emuenv.cfg.show_live_area_screen, selected_app.path); - } break; case SCE_CTRL_CROSS: - if (emuenv.cfg.sys_button == 1) { - const auto &selected_app = current_selected_app_index < 0 ? gui.app_selector.sys_apps[current_selected_app_index + 4] : gui.app_selector.user_apps[current_selected_app_index]; + if (emuenv.cfg.sys_button == 1) pre_load_app(gui, emuenv, emuenv.cfg.show_live_area_screen, selected_app.path); - } break; default: break; } @@ -513,14 +520,14 @@ void browse_home_apps_list(GuiState &gui, EmuEnvState &emuenv, const uint32_t bu static int selected_app_index = INVALID_APP_INDEX; void select_app(GuiState &gui, const std::string &title_id) { // Find the app in the user apps list - auto app_it = std::find_if(gui.app_selector.user_apps.begin(), gui.app_selector.user_apps.end(), [&](const App &app) { + auto app_it = std::find_if(gui.app_selector.vita_apps["ux0"].begin(), gui.app_selector.vita_apps["ux0"].end(), [&](const App &app) { return app.title_id == title_id; }); // Check if the app was found - if (app_it != gui.app_selector.user_apps.end()) { + if (app_it != gui.app_selector.vita_apps["ux0"].end()) { // Set the selected app index - current_selected_app_index = selected_app_index = std::distance(gui.app_selector.user_apps.begin(), app_it); + current_selected_app_index = selected_app_index = std::distance(gui.app_selector.vita_apps["ux0"].begin(), app_it); gui.is_nav_button = true; } else LOG_ERROR("App with title id {} not found", title_id); @@ -723,7 +730,7 @@ void draw_home_screen(GuiState &gui, EmuEnvState &emuenv) { const auto search_bar_size = 120.f * VIEWPORT_SCALE.x; ImGui::SameLine(ImGui::GetColumnWidth() - ImGui::CalcTextSize(lang["refresh"].c_str()).x - search_bar_size - (78 * VIEWPORT_SCALE.x)); if (ImGui::Button(lang["refresh"].c_str())) - init_user_apps(gui, emuenv); + init_vita_apps(gui, emuenv); ImGui::SameLine(); ImGui::PushStyleColor(ImGuiCol_Text, GUI_COLOR_SEARCH_BAR_TEXT); ImGui::PushStyleColor(ImGuiCol_FrameBg, GUI_COLOR_SEARCH_BAR_BG); @@ -779,9 +786,9 @@ void draw_home_screen(GuiState &gui, EmuEnvState &emuenv) { const auto display_app = [&](const std::vector &apps_list, std::map &apps_icon) { for (const auto &app : apps_list) { - const auto is_sys = app.path.starts_with("NPXS") && (app.path != "NPXS10007"); + const auto is_emu_app = app.path.starts_with("emu"); - if (!is_sys) { + if (!is_emu_app) { // Filter app by region and type if (app_filter(app.title_id)) continue; @@ -804,9 +811,24 @@ void draw_home_screen(GuiState &gui, EmuEnvState &emuenv) { if (emuenv.cfg.apps_list_grid) ImGui::SetCursorPosX(GRID_ICON_POS); + const auto is_preinst_app = app.path.starts_with("pd0"); + const auto is_user_app = app.path.starts_with("ux0"); + const auto is_sys_app = app.path.starts_with("vs0"); + const auto emu_app_size = gui.app_selector.emu_apps.size(); + const auto sys_app_size = gui.app_selector.vita_apps["vs0"].size(); + // Get the current app index off the apps list. const auto app_index = static_cast(&app - apps_list.data()); - const auto current_app_index = !is_sys ? app_index : app_index - 4; + /*auto current_app_index = app_index - emu_app_size; + if (!is_emu_app) { + if (is_preinst_app) + current_app_index = app_index; + else if (is_sys_app) + current_app_index = app_index + 1; + else + current_app_index = app_index + sys_app_size + 1; + }*/ + const auto current_app_index = !is_emu_app ? (is_preinst_app ? app_index : (is_sys_app ? app_index + 1 : app_index + sys_app_size + 1)) : app_index - emu_app_size; apps_list_filtered.push_back(current_app_index); // Check if the current app is selected. @@ -888,7 +910,7 @@ void draw_home_screen(GuiState &gui, EmuEnvState &emuenv) { ImGui::NextColumn(); // Draw the compatibility badge for commercial apps when they are within the visible area. - if (element_is_within_visible_area && (app.title_id.starts_with("PCS") || (app.title_id == "NPXS10007"))) { + if (element_is_within_visible_area && (app.path.starts_with("pd0") || app.title_id.starts_with("PCS"))) { const auto compat_state = (gui.compat.compat_db_loaded ? gui.compat.app_compat_db.contains(app.title_id) : false) ? gui.compat.app_compat_db[app.title_id].state : compat::UNKNOWN; const auto &compat_state_vec4 = gui.compat.compat_color[compat_state]; const ImU32 compat_state_color = IM_COL32((int)(compat_state_vec4.x * 255.0f), (int)(compat_state_vec4.y * 255.0f), (int)(compat_state_vec4.z * 255.0f), (int)(compat_state_vec4.w * 255.0f)); @@ -940,10 +962,12 @@ void draw_home_screen(GuiState &gui, EmuEnvState &emuenv) { // Draw System Applications if (emuenv.cfg.display_system_apps) - display_app(gui.app_selector.sys_apps, gui.app_selector.sys_apps_icon); + display_app(gui.app_selector.emu_apps, gui.app_selector.emu_apps_icon); - // Draw User Applications - display_app(gui.app_selector.user_apps, gui.app_selector.user_apps_icon); + // Draw Vita Applications + display_app(gui.app_selector.vita_apps["pd0"], gui.app_selector.vita_apps_icon); + display_app(gui.app_selector.vita_apps["vs0"], gui.app_selector.vita_apps_icon); + display_app(gui.app_selector.vita_apps["ux0"], gui.app_selector.vita_apps_icon); ImGui::PopStyleColor(); ImGui::Columns(1); diff --git a/vita3k/gui/src/information_bar.cpp b/vita3k/gui/src/information_bar.cpp index 3ba3907d60..7b71bc5d81 100644 --- a/vita3k/gui/src/information_bar.cpp +++ b/vita3k/gui/src/information_bar.cpp @@ -456,11 +456,11 @@ static void draw_notice_info(GuiState &gui, EmuEnvState &emuenv) { save_notice_list(emuenv); if (notice.type == "content") { if (notice.group == "theme") - pre_load_app(gui, emuenv, false, "NPXS10015"); + pre_load_app(gui, emuenv, false, "vs0:app/NPXS10015"); else select_app(gui, notice.id); } else { - pre_load_app(gui, emuenv, false, "NPXS10008"); + pre_load_app(gui, emuenv, false, "vs0:app/NPXS10008"); open_trophy_unlocked(gui, emuenv, notice.id, notice.content_id); } notice_info_state = false; @@ -599,7 +599,7 @@ void draw_information_bar(GuiState &gui, EmuEnvState &emuenv) { const ImVec2 ICON_POS_MAX(ICON_POS_MIN.x + ICON_SIZE_SCALE, ICON_POS_MIN.y + ICON_SIZE_SCALE); const ImVec2 ICON_CENTER_POS(ICON_POS_MIN.x + (ICON_SIZE_SCALE / 2.f), ICON_POS_MIN.y + (ICON_SIZE_SCALE / 2.f)); const auto &APPS_OPENED = gui.live_area_current_open_apps_list[a]; - auto &APP_ICON_TYPE = APPS_OPENED.starts_with("NPXS") && (APPS_OPENED != "NPXS10007") ? gui.app_selector.sys_apps_icon : gui.app_selector.user_apps_icon; + auto &APP_ICON_TYPE = APPS_OPENED.starts_with("emu") ? gui.app_selector.emu_apps_icon : gui.app_selector.vita_apps_icon; // Check if icon exist if (APP_ICON_TYPE.contains(APPS_OPENED)) diff --git a/vita3k/gui/src/live_area.cpp b/vita3k/gui/src/live_area.cpp index 85f9cf7db4..478228474f 100644 --- a/vita3k/gui/src/live_area.cpp +++ b/vita3k/gui/src/live_area.cpp @@ -21,7 +21,11 @@ #include #include #include + +#include +#include #include + #include #include #include @@ -152,31 +156,33 @@ static std::map items_styles = { void init_live_area(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path) { const auto &live_area_lang = gui.lang.user_lang[LIVE_AREA]; - const auto is_sys_app = app_path.starts_with("NPXS") && (app_path != "NPXS10007"); - const auto is_ps_app = app_path.starts_with("PCS") || (app_path == "NPXS10007"); - const VitaIoDevice app_device = is_sys_app ? VitaIoDevice::vs0 : VitaIoDevice::ux0; + const auto is_emu_app = app_path.starts_with("emu"); const auto APP_INDEX = get_app_index(gui, app_path); + const auto is_com_app = APP_INDEX->title_id.starts_with("PCS"); + const auto is_fw_app = app_path.starts_with("vs0"); + const auto is_ps_vita_os = app_path == "emu:vsh/shell"; - if (is_ps_app && !sku_flag.contains(app_path)) + if (is_com_app && !sku_flag.contains(app_path)) sku_flag[app_path] = get_license_sku_flag(emuenv, APP_INDEX->content_id); if (!gui.live_area_contents.contains(app_path)) { auto default_contents = false; const auto fw_path{ emuenv.pref_path / "vs0" }; const auto default_fw_contents{ fw_path / "data/internal/livearea/default/sce_sys/livearea/contents/template.xml" }; - const auto APP_PATH{ emuenv.pref_path / app_device._to_string() / "app" / app_path }; - const auto live_area_path{ fs::path("sce_sys") / ((sku_flag[app_path] == 3) && fs::exists(APP_PATH / "sce_sys/retail/livearea") ? "retail/livearea" : "livearea") }; - auto template_xml{ APP_PATH / live_area_path / "contents/template.xml" }; + const auto real_app_path = app_path.starts_with("emu") ? "vs0:app/" + fs::path(app_path).stem().string() : app_path; + const auto APP_PATH{ emuenv.pref_path / convert_path(real_app_path) }; + const auto live_area_contents_path{ fs::path("sce_sys") / ((sku_flag[app_path] == 3) && fs::exists(APP_PATH / "sce_sys/retail/livearea") ? "retail/livearea" : "livearea") / "contents" }; + auto template_xml{ APP_PATH / live_area_contents_path / "template.xml" }; pugi::xml_document doc; if (!doc.load_file(template_xml.c_str())) { - if (is_ps_app || is_sys_app) + if (!is_ps_vita_os && (is_com_app || is_fw_app || is_emu_app)) LOG_WARN("Live Area Contents is corrupted or missing for title: {} '{}' in path: {}.", APP_INDEX->title_id, APP_INDEX->title, template_xml); if (doc.load_file(default_fw_contents.c_str())) { template_xml = default_fw_contents; default_contents = true; - LOG_INFO("Using default firmware contents."); + LOG_INFO_IF(!is_ps_vita_os, "Using default firmware contents."); } else { type[app_path] = "a1"; LOG_WARN("Default firmware contents is corrupted or missing, install firmware for fix it."); @@ -253,17 +259,15 @@ void init_live_area(GuiState &gui, EmuEnvState &emuenv, const std::string &app_p if (default_contents) vfs::read_file(VitaIoDevice::vs0, buffer, emuenv.pref_path, "data/internal/livearea/default/sce_sys/livearea/contents/" + contents.second); - else if (app_device == VitaIoDevice::vs0) - vfs::read_file(VitaIoDevice::vs0, buffer, emuenv.pref_path, "app/" + app_path + "/sce_sys/livearea/contents/" + contents.second); else - vfs::read_app_file(buffer, emuenv.pref_path, app_path, live_area_path / "contents" / contents.second); + vfs::read_app_file(buffer, emuenv.pref_path, real_app_path, live_area_contents_path / contents.second); if (buffer.empty()) { - if (is_ps_app || is_sys_app) + if (is_com_app || is_fw_app) LOG_WARN("Contents {} '{}' Not found for title {} [{}].", contents.first, contents.second, app_path, APP_INDEX->title); continue; } - stbi_uc *data = stbi_load_from_memory(&buffer[0], static_cast(buffer.size()), &width, &height, nullptr, STBI_rgb_alpha); + stbi_uc *data = stbi_load_from_memory(buffer.data(), static_cast(buffer.size()), &width, &height, nullptr, STBI_rgb_alpha); if (!data) { LOG_ERROR("Invalid Live Area Contents for title {} [{}].", app_path, APP_INDEX->title); continue; @@ -441,17 +445,14 @@ void init_live_area(GuiState &gui, EmuEnvState &emuenv, const std::string &app_p int32_t height = 0; vfs::FileBuffer buffer; - if (app_device == VitaIoDevice::vs0) - vfs::read_file(VitaIoDevice::vs0, buffer, emuenv.pref_path, fmt::format("app/{}/sce_sys/livearea/contents/{}", app_path, bg_name)); - else - vfs::read_app_file(buffer, emuenv.pref_path, app_path, live_area_path / "contents" / bg_name); + vfs::read_app_file(buffer, emuenv.pref_path, real_app_path, live_area_contents_path / bg_name); if (buffer.empty()) { - if (is_ps_app || is_sys_app) + if (is_com_app || is_fw_app || is_emu_app) LOG_WARN("background, Id: {}, Name: '{}', Not found for title: {} [{}].", item.first, bg_name, app_path, APP_INDEX->title); continue; } - stbi_uc *data = stbi_load_from_memory(&buffer[0], static_cast(buffer.size()), &width, &height, nullptr, STBI_rgb_alpha); + stbi_uc *data = stbi_load_from_memory(buffer.data(), static_cast(buffer.size()), &width, &height, nullptr, STBI_rgb_alpha); if (!data) { LOG_ERROR("Frame: {}, Invalid Live Area Contents for title: {} [{}].", item.first, app_path, APP_INDEX->title); continue; @@ -473,17 +474,14 @@ void init_live_area(GuiState &gui, EmuEnvState &emuenv, const std::string &app_p int32_t height = 0; vfs::FileBuffer buffer; - if (app_device == VitaIoDevice::vs0) - vfs::read_file(VitaIoDevice::vs0, buffer, emuenv.pref_path, fmt::format("app/{}/sce_sys/livearea/contents/{}", app_path, img_name)); - else - vfs::read_app_file(buffer, emuenv.pref_path, app_path, live_area_path / "contents" / img_name); + vfs::read_app_file(buffer, emuenv.pref_path, real_app_path, live_area_contents_path / img_name); if (buffer.empty()) { - if (is_ps_app || is_sys_app) + if (is_com_app || is_fw_app || is_emu_app) LOG_WARN("Image, Id: {} Name: '{}', Not found for title {} [{}].", item.first, img_name, app_path, APP_INDEX->title); continue; } - stbi_uc *data = stbi_load_from_memory(&buffer[0], static_cast(buffer.size()), &width, &height, nullptr, STBI_rgb_alpha); + stbi_uc *data = stbi_load_from_memory(buffer.data(), static_cast(buffer.size()), &width, &height, nullptr, STBI_rgb_alpha); if (!data) { LOG_ERROR("Frame: {}, Invalid Live Area Contents for title: {} [{}].", item.first, app_path, APP_INDEX->title); continue; @@ -554,7 +552,8 @@ static constexpr ImU32 ARROW_COLOR = 0xFFFFFFFF; // White static LiveAreaType live_area_type_selected = GATE; void browse_live_area_apps_list(GuiState &gui, EmuEnvState &emuenv, const uint32_t button) { - const auto manual_path{ emuenv.pref_path / "ux0/app" / gui.live_area_current_open_apps_list[gui.live_area_app_current_open] / "sce_sys/manual/" }; + const auto &APP_PATH = gui.live_area_current_open_apps_list[gui.live_area_app_current_open]; + const auto manual_path{ emuenv.pref_path / convert_path(APP_PATH) / "sce_sys/manual" }; const auto manual_found = fs::exists(manual_path) && !fs::is_empty(manual_path); if (!gui.is_nav_button) { @@ -567,18 +566,18 @@ void browse_live_area_apps_list(GuiState &gui, EmuEnvState &emuenv, const uint32 const auto live_area_current_open_apps_list_size = static_cast(gui.live_area_current_open_apps_list.size() - 1); const auto cancel = [&]() { - close_live_area_app(gui, emuenv, gui.live_area_current_open_apps_list[gui.live_area_app_current_open]); + close_live_area_app(gui, emuenv, APP_PATH); }; const auto confirm = [&]() { switch (live_area_type_selected) { case GATE: - pre_run_app(gui, emuenv, gui.live_area_current_open_apps_list[gui.live_area_app_current_open]); + pre_run_app(gui, emuenv, APP_PATH); break; case SEARCH: - open_search(get_app_index(gui, gui.live_area_current_open_apps_list[gui.live_area_app_current_open])->title); + open_search(get_app_index(gui, APP_PATH)->title); break; case MANUAL: - open_manual(gui, emuenv, gui.live_area_current_open_apps_list[gui.live_area_app_current_open]); + open_manual(gui, emuenv, APP_PATH); break; default: break; @@ -638,7 +637,7 @@ void draw_live_area_screen(GuiState &gui, EmuEnvState &emuenv) { const auto SCALE = ImVec2(RES_SCALE.x * emuenv.dpi_scale, RES_SCALE.y * emuenv.dpi_scale); const auto &app_path = gui.live_area_current_open_apps_list[gui.live_area_app_current_open]; - const VitaIoDevice app_device = app_path.starts_with("NPXS") ? VitaIoDevice::vs0 : VitaIoDevice::ux0; + const VitaIoDevice app_device = device::get_device(app_path); const auto INFO_BAR_HEIGHT = 32.f * SCALE.y; @@ -1078,7 +1077,7 @@ void draw_live_area_screen(GuiState &gui, EmuEnvState &emuenv) { const auto ICON_POS_MAX_SCALE = ImVec2(ICON_POS_MINI_SCALE.x + ICON_SIZE_SCALE, ICON_POS_MINI_SCALE.y + ICON_SIZE_SCALE); // check if app icon exist - auto &APP_ICON_TYPE = app_path.starts_with("NPXS") && (app_path != "NPXS10007") ? gui.app_selector.sys_apps_icon : gui.app_selector.user_apps_icon; + auto &APP_ICON_TYPE = app_path.starts_with("emu") ? gui.app_selector.emu_apps_icon : gui.app_selector.vita_apps_icon; if (APP_ICON_TYPE.contains(app_path)) { window_draw_list->AddImageRounded(APP_ICON_TYPE[app_path], ICON_POS_MINI_SCALE, ICON_POS_MAX_SCALE, ImVec2(0, 0), ImVec2(1, 1), IM_COL32_WHITE, 75.f * SCALE.x, ImDrawFlags_RoundCornersAll); @@ -1097,7 +1096,7 @@ void draw_live_area_screen(GuiState &gui, EmuEnvState &emuenv) { if (app_device == VitaIoDevice::ux0) { const auto widget_scal_size = ImVec2(80.0f * SCALE.x, 80.f * SCALE.y); - const auto manual_path{ emuenv.pref_path / "ux0/app" / app_path / "sce_sys/manual/" }; + const auto manual_path{ emuenv.pref_path / convert_path(app_path) / "sce_sys/manual/" }; const auto scal_widget_font_size = 23.0f / ImGui::GetFontSize(); const auto manual_exist = fs::exists(manual_path) && !fs::is_empty(manual_path); diff --git a/vita3k/gui/src/main_menubar.cpp b/vita3k/gui/src/main_menubar.cpp index 855847987b..7346960703 100644 --- a/vita3k/gui/src/main_menubar.cpp +++ b/vita3k/gui/src/main_menubar.cpp @@ -94,7 +94,7 @@ static void draw_emulation_menu(GuiState &gui, EmuEnvState &emuenv) { } if (!emuenv.cfg.display_system_apps) { ImGui::Separator(); - for (const auto &app : gui.app_selector.sys_apps) + for (const auto &app : gui.app_selector.emu_apps) draw_app(app); } ImGui::EndMenu(); diff --git a/vita3k/gui/src/manual.cpp b/vita3k/gui/src/manual.cpp index 21665bc020..b3ac453c30 100644 --- a/vita3k/gui/src/manual.cpp +++ b/vita3k/gui/src/manual.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -82,8 +83,8 @@ bool init_manual(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path height_manual_pages.clear(); const auto APP_INDEX = get_app_index(gui, app_path); - const auto APP_PATH{ emuenv.pref_path / "ux0/app" / app_path }; - auto manual_path{ fs::path("sce_sys/manual/") }; + const auto APP_PATH{ emuenv.pref_path / convert_path(app_path) }; + auto manual_path{ fs::path("sce_sys/manual") }; const auto lang = fmt::format("{:0>2d}", emuenv.cfg.sys_lang); if (fs::exists(APP_PATH / manual_path / lang)) diff --git a/vita3k/gui/src/settings.cpp b/vita3k/gui/src/settings.cpp index 8654458be7..69ebd15082 100644 --- a/vita3k/gui/src/settings.cpp +++ b/vita3k/gui/src/settings.cpp @@ -224,8 +224,8 @@ void draw_settings(GuiState &gui, EmuEnvState &emuenv) { const auto SIZE_MINI_PACKAGE = ImVec2(170.f * SCALE.x, 96.f * SCALE.y); const auto POPUP_SIZE = ImVec2(756.0f * SCALE.x, 436.0f * SCALE.y); - const auto is_background = gui.apps_background.contains("NPXS10015"); auto &common = emuenv.common_dialog.lang.common; + const auto BG_PATH = "vs0:app/NPXS10015"; ImGui::SetNextWindowPos(WINDOW_POS, ImGuiCond_Always); ImGui::SetNextWindowSize(WINDOW_SIZE, ImGuiCond_Always); @@ -237,8 +237,8 @@ void draw_settings(GuiState &gui, EmuEnvState &emuenv) { const auto draw_list = ImGui::GetBackgroundDrawList(); const ImVec2 BG_POS_MAX(VIEWPORT_POS.x + VIEWPORT_SIZE.x, VIEWPORT_POS.y + VIEWPORT_SIZE.y); - if (is_background) - draw_list->AddImage(gui.apps_background["NPXS10015"], VIEWPORT_POS, BG_POS_MAX); + if (gui.apps_background.contains(BG_PATH)) + draw_list->AddImage(gui.apps_background[BG_PATH], VIEWPORT_POS, BG_POS_MAX); else draw_list->AddRectFilled(VIEWPORT_POS, BG_POS_MAX, IM_COL32(36.f, 120.f, 12.f, 255.f), 0.f, ImDrawFlags_RoundCornersAll); diff --git a/vita3k/gui/src/settings_dialog.cpp b/vita3k/gui/src/settings_dialog.cpp index fb3703caf2..bbba781c7c 100644 --- a/vita3k/gui/src/settings_dialog.cpp +++ b/vita3k/gui/src/settings_dialog.cpp @@ -96,7 +96,7 @@ static void reset_emulator(GuiState &gui, EmuEnvState &emuenv) { config::serialize_config(emuenv.cfg, emuenv.cfg.config_path); // Clean User apps list - gui.app_selector.user_apps.clear(); + gui.app_selector.vita_apps.clear(); get_modules_list(gui, emuenv); get_sys_apps_title(gui, emuenv); @@ -1027,7 +1027,7 @@ void draw_settings_dialog(GuiState &gui, EmuEnvState &emuenv) { gui.users[emuenv.io.user_id].start_type = "default"; save_user(gui, emuenv, emuenv.io.user_id); init_theme_start_background(gui, emuenv, "default"); - init_apps_icon(gui, emuenv, gui.app_selector.sys_apps); + init_apps_icon(gui, emuenv, gui.app_selector.emu_apps); } ImGui::SameLine(); } diff --git a/vita3k/gui/src/themes.cpp b/vita3k/gui/src/themes.cpp index 76336cb7d9..7179815027 100644 --- a/vita3k/gui/src/themes.cpp +++ b/vita3k/gui/src/themes.cpp @@ -222,11 +222,12 @@ bool init_theme(GuiState &gui, EmuEnvState &emuenv, const std::string &content_i { "NPXS10003", {} }, { "NPXS10008", {} }, { "NPXS10015", {} }, - { "NPXS10026", {} } + { "NPXS10026", {} }, + { "NPXS19999", {} } }; // Clear the current theme - gui.app_selector.sys_apps_icon.clear(); + gui.app_selector.emu_apps_icon.clear(); gui.current_theme_bg = 0; gui.information_bar_color = {}; gui.theme_backgrounds.clear(); @@ -254,6 +255,8 @@ bool init_theme(GuiState &gui, EmuEnvState &emuenv, const std::string &content_i theme_icon_name["NPXS10015"] = home_property.child("m_settings").child("m_iconFilePath").text().as_string(); if (!home_property.child("m_hostCollabo").child("m_iconFilePath").text().empty()) theme_icon_name["NPXS10026"] = home_property.child("m_hostCollabo").child("m_iconFilePath").text().as_string(); + if (!home_property.child("m_power").child("m_iconFilePath").text().empty()) + theme_icon_name["NPXS19999"] = home_property.child("m_power").child("m_iconFilePath").text().as_string(); // Bgm theme if (!home_property.child("m_bgmFilePath").text().empty()) @@ -342,9 +345,11 @@ bool init_theme(GuiState &gui, EmuEnvState &emuenv, const std::string &content_i const auto &title_id = icon.first; const auto &name = icon.second; - if (name.empty()) - vfs::read_file(VitaIoDevice::vs0, buffer, emuenv.pref_path, "app/" + title_id + "/sce_sys/icon0.png"); - else + const auto is_shell = title_id == "NPXS19999"; + if (name.empty()) { + const auto basic_icon_path = is_shell ? fs::path("data/internal/icon/power.png") : fs::path("app") / title_id / "sce_sys/icon0.png"; + vfs::read_file(VitaIoDevice::vs0, buffer, emuenv.pref_path, basic_icon_path); + } else vfs::read_file(VitaIoDevice::ux0, buffer, emuenv.pref_path, fs::path("theme") / content_id_path / name); if (buffer.empty()) { @@ -361,7 +366,8 @@ bool init_theme(GuiState &gui, EmuEnvState &emuenv, const std::string &content_i continue; } - gui.app_selector.sys_apps_icon[title_id].init(gui.imgui_state.get(), data, width, height); + const auto app_path = "emu:" + (is_shell ? "vsh/shell" : "app/" + title_id); + gui.app_selector.emu_apps_icon[app_path].init(gui.imgui_state.get(), data, width, height); stbi_image_free(data); } diff --git a/vita3k/gui/src/trophy_collection.cpp b/vita3k/gui/src/trophy_collection.cpp index 3a90ef3c71..617b45dfaa 100644 --- a/vita3k/gui/src/trophy_collection.cpp +++ b/vita3k/gui/src/trophy_collection.cpp @@ -413,7 +413,7 @@ void draw_trophy_collection(GuiState &gui, EmuEnvState &emuenv) { const auto TROPHY_PATH{ emuenv.pref_path / "ux0/user" / emuenv.io.user_id / "trophy" }; - const auto is_background = gui.apps_background.contains("NPXS10008"); + const auto BG_PATH = "vs0:app/NPXS10008"; const auto is_12_hour_format = emuenv.cfg.sys_time_format == SCE_SYSTEM_PARAM_TIME_FORMAT_12HOUR; ImGui::SetNextWindowPos(WINDOW_POS, ImGuiCond_Always); @@ -426,8 +426,8 @@ void draw_trophy_collection(GuiState &gui, EmuEnvState &emuenv) { const auto draw_list = ImGui::GetBackgroundDrawList(); const ImVec2 BG_POS_MAX(VIEWPORT_POS.x + VIEWPORT_SIZE.x, VIEWPORT_POS.y + VIEWPORT_SIZE.y); - if (is_background) - draw_list->AddImage(gui.apps_background["NPXS10008"], VIEWPORT_POS, BG_POS_MAX); + if (gui.apps_background.contains(BG_PATH)) + draw_list->AddImage(gui.apps_background[BG_PATH], VIEWPORT_POS, BG_POS_MAX); else draw_list->AddRectFilled(VIEWPORT_POS, BG_POS_MAX, IM_COL32(31.f, 12.f, 0.f, 255.f), 0.f, ImDrawFlags_RoundCornersAll); diff --git a/vita3k/gui/src/user_management.cpp b/vita3k/gui/src/user_management.cpp index 43d8abb60c..f0c906b645 100644 --- a/vita3k/gui/src/user_management.cpp +++ b/vita3k/gui/src/user_management.cpp @@ -204,7 +204,7 @@ static uint32_t current_user_id_selected = 0; static UserMenu menu_selected = SELECT, menu = SELECT; void init_user_management(GuiState &gui, EmuEnvState &emuenv) { - init_app_background(gui, emuenv, "NPXS10013"); + init_app_background(gui, emuenv, "vs0:app/NPXS10013"); gui.vita_area.home_screen = false; gui.vita_area.information_bar = false; gui.vita_area.user_management = true; @@ -485,8 +485,8 @@ void draw_user_management(GuiState &gui, EmuEnvState &emuenv) { ImGui::GetBackgroundDrawList()->AddRectFilled(ImVec2(0.f, 0.f), ImGui::GetIO().DisplaySize, IM_COL32(0.f, 0.f, 0.f, 255.f), 0.f, ImDrawFlags_RoundCornersAll); const ImVec2 WINDOW_POS_MAX(WINDOW_POS.x + WINDOW_SIZE.x, WINDOW_POS.y + WINDOW_SIZE.y); - if (gui.apps_background.contains("NPXS10013")) - ImGui::GetBackgroundDrawList()->AddImage(gui.apps_background["NPXS10013"], WINDOW_POS, WINDOW_POS_MAX); + if (gui.apps_background.contains("vs0:app/NPXS10013")) + ImGui::GetBackgroundDrawList()->AddImage(gui.apps_background["vs0:app/NPXS10013"], WINDOW_POS, WINDOW_POS_MAX); else ImGui::GetBackgroundDrawList()->AddRectFilled(WINDOW_POS, WINDOW_POS_MAX, IM_COL32(10.f, 50.f, 140.f, 255.f), 0.f, ImDrawFlags_RoundCornersAll); diff --git a/vita3k/interface.cpp b/vita3k/interface.cpp index f72f2bbfa3..9391caa38c 100644 --- a/vita3k/interface.cpp +++ b/vita3k/interface.cpp @@ -220,7 +220,7 @@ bool install_archive_content(EmuEnvState &emuenv, GuiState *gui, const ZipPtr &z if (!gui->file_menu.archive_install_dialog && (emuenv.app_info.app_category != "theme")) { gui::update_notice_info(*gui, emuenv, "content"); if ((emuenv.app_info.app_category.find("gd") != std::string::npos) || (emuenv.app_info.app_category.find("gp") != std::string::npos)) { - gui::init_user_app(*gui, emuenv, emuenv.app_info.app_title_id); + gui::init_user_app(*gui, emuenv, "ux0:app/" + emuenv.app_info.app_title_id); gui::save_apps_cache(*gui, emuenv); } } @@ -363,7 +363,7 @@ static bool install_content(EmuEnvState &emuenv, GuiState *gui, const fs::path & LOG_INFO("{} [{}] installed successfully!", emuenv.app_info.app_title, emuenv.app_info.app_title_id); if ((emuenv.app_info.app_category.find("gd") != std::string::npos) || (emuenv.app_info.app_category.find("gp") != std::string::npos)) { - gui::init_user_app(*gui, emuenv, emuenv.app_info.app_title_id); + gui::init_user_app(*gui, emuenv, "ux0:app/" + emuenv.app_info.app_title_id); gui::save_apps_cache(*gui, emuenv); } @@ -446,8 +446,11 @@ static ExitCode load_app_impl(SceUID &main_module_id, EmuEnvState &emuenv) { } // Load main executable - emuenv.self_path = !emuenv.cfg.self_path.empty() ? emuenv.cfg.self_path : EBOOT_PATH; - main_module_id = load_module(emuenv, "app0:" + emuenv.self_path); + if (emuenv.io.app_path == "emu:vsh/shell") + emuenv.self_path = "vs0:vsh/shell/shell.self"; + else + emuenv.self_path = (fs::path(emuenv.io.app_path) / (!emuenv.cfg.self_path.empty() ? emuenv.cfg.self_path : EBOOT_PATH)).string(); + main_module_id = load_module(emuenv, emuenv.self_path); if (main_module_id >= 0) { const auto module = emuenv.kernel.loaded_modules[main_module_id]; LOG_INFO("Main executable {} ({}) loaded", module->info.module_name, emuenv.self_path); @@ -465,7 +468,7 @@ static ExitCode load_app_impl(SceUID &main_module_id, EmuEnvState &emuenv) { process_preload_disabled = *preload_disabled_ptr.get(emuenv.mem); } } - const auto module_app_path{ emuenv.pref_path / "ux0/app" / emuenv.io.app_path / "sce_module" }; + const auto module_app_path{ emuenv.pref_path / convert_path(emuenv.io.app_path) / "sce_module" }; std::vector lib_load_list = {}; // todo: check if module is imported @@ -474,7 +477,7 @@ static ExitCode load_app_impl(SceUID &main_module_id, EmuEnvState &emuenv) { if (is_lle_module(name, emuenv)) { const auto module_name_file = fmt::format("{}.suprx", name); if (load_from_app && fs::exists(module_app_path / module_name_file)) - lib_load_list.emplace_back(fmt::format("app0:sce_module/{}", module_name_file)); + lib_load_list.emplace_back(fmt::format("{}/sce_module/{}.suprx", emuenv.io.app_path, name)); else if (fs::exists(emuenv.pref_path / "vs0/sys/external" / module_name_file)) lib_load_list.emplace_back(fmt::format("vs0:sys/external/{}", module_name_file)); } @@ -574,8 +577,8 @@ bool handle_events(EmuEnvState &emuenv, GuiState &gui) { gui.vita_area.app_close = false; }; const auto confirm = [&gui, &emuenv]() { - const auto app_path = gui.vita_area.live_area_screen ? gui.live_area_current_open_apps_list[gui.live_area_app_current_open] : emuenv.app_path; - gui::close_and_run_new_app(gui, emuenv, app_path); + const auto &app_path = gui.vita_area.live_area_screen ? gui.live_area_current_open_apps_list[gui.live_area_app_current_open] : emuenv.app_path; + gui::close_and_run_new_app(emuenv, app_path); }; switch (sce_ctrl_btn) { case SCE_CTRL_CIRCLE: @@ -848,6 +851,7 @@ ExitCode run_app(EmuEnvState &emuenv, int32_t main_module_id) { return InitThreadFailed; } emuenv.main_thread_id = main_thread->id; + emuenv.main_modid = main_module_id; // Run `module_start` export (entry point) of loaded libraries for (auto &[_, module] : emuenv.kernel.loaded_modules) { diff --git a/vita3k/io/include/io/VitaIoDevice.h b/vita3k/io/include/io/VitaIoDevice.h index cc32ecaf3c..d9c4864dfe 100644 --- a/vita3k/io/include/io/VitaIoDevice.h +++ b/vita3k/io/include/io/VitaIoDevice.h @@ -23,7 +23,6 @@ BETTER_ENUM(VitaIoDevice, int, addcont0 = 0, app0, host0, - gro0, grw0, imc0, music0, diff --git a/vita3k/io/include/io/functions.h b/vita3k/io/include/io/functions.h index 52ad284eda..d0583d5830 100644 --- a/vita3k/io/include/io/functions.h +++ b/vita3k/io/include/io/functions.h @@ -41,7 +41,8 @@ bool find_case_isens_path(IOState &io, VitaIoDevice &device, const fs::path &tra fs::path find_in_cache(IOState &io, const std::string &system_path); fs::path expand_path(IOState &io, const char *path, const fs::path &pref_path); -std::string translate_path(const char *path, VitaIoDevice &device, const IOState::DevicePaths &device_paths); +std::string convert_path(const std::string &path); +std::string translate_path(const char *path, VitaIoDevice &device, const IOState &io); /** * @brief Copy all directories and files from one location into another diff --git a/vita3k/io/src/io.cpp b/vita3k/io/src/io.cpp index d05a1e296c..c0446c3536 100644 --- a/vita3k/io/src/io.cpp +++ b/vita3k/io/src/io.cpp @@ -78,7 +78,8 @@ bool read_file(const VitaIoDevice device, FileBuffer &buf, const fs::path &pref_ } bool read_app_file(FileBuffer &buf, const fs::path &pref_path, const std::string &app_path, const fs::path &vfs_file_path) { - return read_file(VitaIoDevice::ux0, buf, pref_path, fs::path("app") / app_path / vfs_file_path); + const auto app_device = device::get_device(app_path); + return read_file(app_device, buf, pref_path, device::remove_device_from_path(app_path, app_device) / vfs_file_path); } SpaceInfo get_space_info(const VitaIoDevice device, const std::string &vfs_path, const fs::path &pref_path) { @@ -134,7 +135,7 @@ bool init(IOState &io, const fs::path &cache_path, const fs::path &log_path, con void init_device_paths(IOState &io) { io.device_paths.savedata0 = "user/" + io.user_id + "/savedata/" + io.savedata; - io.device_paths.app0 = "app/" + io.app_path; + io.device_paths.app0 = device::remove_device_from_path(io.app_path, device::get_device(io.app_path)); io.device_paths.addcont0 = "addcont/" + io.addcont; } @@ -195,7 +196,16 @@ fs::path find_in_cache(IOState &io, const std::string &system_path) { } } -std::string translate_path(const char *path, VitaIoDevice &device, const IOState::DevicePaths &device_paths) { +std::string convert_path(const std::string &path) { + auto convert_path = path; + + // replace colon with slash + string_utils::replace(convert_path, ":", "/"); + + return convert_path; +} + +std::string translate_path(const char *path, VitaIoDevice &device, const IOState &io) { auto relative_path = device::remove_duplicate_device(path, device); // replace invalid slashes with proper forward slash @@ -207,17 +217,17 @@ std::string translate_path(const char *path, VitaIoDevice &device, const IOState switch (device) { case +VitaIoDevice::savedata0: // Redirect savedata0: to ux0:user/00/savedata/ case +VitaIoDevice::savedata1: { - relative_path = device::remove_device_from_path(relative_path, device, device_paths.savedata0); + relative_path = device::remove_device_from_path(relative_path, device, io.device_paths.savedata0); device = VitaIoDevice::ux0; break; } case +VitaIoDevice::app0: { // Redirect app0: to ux0:app/ - relative_path = device::remove_device_from_path(relative_path, device, device_paths.app0); - device = VitaIoDevice::ux0; + relative_path = device::remove_device_from_path(relative_path, device, io.device_paths.app0); + device = device::get_device(io.app_path); break; } case +VitaIoDevice::addcont0: { // Redirect addcont0: to ux0:addcont/ - relative_path = device::remove_device_from_path(relative_path, device, device_paths.addcont0); + relative_path = device::remove_device_from_path(relative_path, device, io.device_paths.addcont0); device = VitaIoDevice::ux0; break; } @@ -238,7 +248,6 @@ std::string translate_path(const char *path, VitaIoDevice &device, const IOState } case +VitaIoDevice::host0: - case +VitaIoDevice::gro0: case +VitaIoDevice::grw0: case +VitaIoDevice::imc0: case +VitaIoDevice::os0: @@ -279,7 +288,7 @@ std::string translate_path(const char *path, VitaIoDevice &device, const IOState fs::path expand_path(IOState &io, const char *path, const fs::path &pref_path) { auto device = device::get_device(path); - const auto translated_path = translate_path(path, device, io.device_paths); + const auto translated_path = translate_path(path, device, io); return device::construct_emulated_path(device, translated_path, pref_path, io.redirect_stdio).string(); } @@ -307,7 +316,7 @@ SceUID open_file(IOState &io, const char *path, const int flags, const fs::path return fd; } - const auto translated_path = translate_path(path, device, io.device_paths); + const auto translated_path = translate_path(path, device, io); if (translated_path.empty()) { LOG_ERROR("Cannot translate path: {}", path); return IO_ERROR(SCE_ERROR_ERRNO_ENOENT); @@ -496,7 +505,7 @@ int stat_file(IOState &io, const char *file, SceIoStat *statp, const fs::path &p return IO_ERROR(SCE_ERROR_ERRNO_ENOENT); } - const auto translated_path = translate_path(file, device, io.device_paths); + const auto translated_path = translate_path(file, device, io); file_path = device::construct_emulated_path(device, translated_path, pref_path, io.redirect_stdio); if (!fs::exists(file_path)) { @@ -608,7 +617,7 @@ int remove_file(IOState &io, const char *file, const fs::path &pref_path, const return IO_ERROR(SCE_ERROR_ERRNO_ENOENT); } - const auto translated_path = translate_path(file, device, io.device_paths); + const auto translated_path = translate_path(file, device, io); if (translated_path.empty()) { LOG_ERROR("Cannot translate path: {}", translated_path); return IO_ERROR(SCE_ERROR_ERRNO_ENOENT); @@ -640,13 +649,13 @@ int rename(IOState &io, const char *old_name, const char *new_name, const fs::pa return IO_ERROR(SCE_ERROR_ERRNO_ENOENT); } - const auto translated_old_path = translate_path(old_name, device, io.device_paths); + const auto translated_old_path = translate_path(old_name, device, io); if (translated_old_path.empty()) { LOG_ERROR("Cannot translate path: {}", translated_old_path); return IO_ERROR(SCE_ERROR_ERRNO_ENOENT); } - const auto translated_new_path = translate_path(new_name, device, io.device_paths); + const auto translated_new_path = translate_path(new_name, device, io); if (translated_new_path.empty()) { LOG_ERROR("Cannot translate path: {}", translated_new_path); return IO_ERROR(SCE_ERROR_ERRNO_ENOENT); @@ -677,7 +686,7 @@ int rename(IOState &io, const char *old_name, const char *new_name, const fs::pa SceUID open_dir(IOState &io, const char *path, const fs::path &pref_path, const char *export_name) { auto device = device::get_device(path); auto device_for_icase = device; - const auto translated_path = translate_path(path, device, io.device_paths); + const auto translated_path = translate_path(path, device, io); auto dir_path = device::construct_emulated_path(device, translated_path, pref_path, io.redirect_stdio) / ""; if (!fs::exists(dir_path)) { @@ -794,7 +803,7 @@ bool copy_path(const fs::path &src_path, const fs::path &pref_path, const std::s int create_dir(IOState &io, const char *dir, int mode, const fs::path &pref_path, const char *export_name, const bool recursive) { auto device = device::get_device(dir); - const auto translated_path = translate_path(dir, device, io.device_paths); + const auto translated_path = translate_path(dir, device, io); if (translated_path.empty()) { LOG_ERROR("Failed to translate path: {}", dir); return IO_ERROR(SCE_ERROR_ERRNO_ENOENT); @@ -841,7 +850,7 @@ int remove_dir(IOState &io, const char *dir, const fs::path &pref_path, const ch return IO_ERROR(SCE_ERROR_ERRNO_ENOENT); } - const auto translated_path = translate_path(dir, device, io.device_paths); + const auto translated_path = translate_path(dir, device, io); if (translated_path.empty()) { LOG_ERROR("Cannot translate path: {}", dir); return IO_ERROR(SCE_ERROR_ERRNO_ENOENT); diff --git a/vita3k/kernel/src/load_self.cpp b/vita3k/kernel/src/load_self.cpp index aa2a064a9a..16a7780d18 100644 --- a/vita3k/kernel/src/load_self.cpp +++ b/vita3k/kernel/src/load_self.cpp @@ -627,8 +627,9 @@ SceUID load_self(KernelState &kernel, MemState &mem, const void *self, const std unsigned long dest_bytes = seg_header.p_filesz; const uint8_t *const compressed_segment_bytes = self_bytes + seg_infos[seg_index].offset; - int res = mz_uncompress(seg_ptr.get(mem), &dest_bytes, compressed_segment_bytes, static_cast(seg_infos[seg_index].length)); - assert(res == MZ_OK); + int res = MZ_OK; + if (seg_infos[seg_index].length > 0) + res = mz_uncompress(seg_ptr.get(mem), &dest_bytes, compressed_segment_bytes, static_cast(seg_infos[seg_index].length)); } else { memcpy(seg_ptr.get(mem), seg_bytes, seg_header.p_filesz); } diff --git a/vita3k/main.cpp b/vita3k/main.cpp index fdeb2c241b..8f8589cc03 100644 --- a/vita3k/main.cpp +++ b/vita3k/main.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -56,30 +57,31 @@ #include static void run_execv(char *argv[], EmuEnvState &emuenv) { - char const *args[10]; + char const *args[12]; args[0] = argv[0]; args[1] = "-a"; args[2] = "true"; if (!emuenv.load_app_path.empty()) { - args[3] = "-r"; - args[4] = emuenv.load_app_path.data(); + args[3] = "--app-device"; + args[4] = emuenv.load_app_device.data(); + args[5] = "-r"; + args[6] = emuenv.load_app_path.data(); if (!emuenv.load_exec_path.empty()) { - args[5] = "--self"; - args[6] = emuenv.load_exec_path.data(); + args[7] = "--self"; + args[8] = emuenv.load_exec_path.data(); if (!emuenv.load_exec_argv.empty()) { - args[7] = "--app-args"; - args[8] = emuenv.load_exec_argv.data(); - args[9] = nullptr; + args[9] = "--app-args"; + args[10] = emuenv.load_exec_argv.data(); + args[11] = nullptr; } else - args[7] = nullptr; + args[9] = nullptr; } else - args[5] = nullptr; + args[7] = nullptr; } else args[3] = nullptr; // Execute the emulator again with some arguments #ifdef _WIN32 - FreeConsole(); _execv(argv[0], args); #elif defined(__unix__) || defined(__APPLE__) && defined(__MACH__) execv(argv[0], const_cast(args)); @@ -266,7 +268,10 @@ int main(int argc, char *argv[]) { } if (run_type == app::AppRunType::Extracted) { - emuenv.io.app_path = cfg.run_app_path ? *cfg.run_app_path : emuenv.app_info.app_title_id; + if (std::string(*cfg.run_app_path).find("vsh") != std::string::npos) + emuenv.io.app_path = cfg.app_device + ":" + *cfg.run_app_path; + else + emuenv.io.app_path = cfg.app_device + ":app/" + (cfg.run_app_path ? *cfg.run_app_path : emuenv.app_info.app_title_id); gui::init_user_app(gui, emuenv, emuenv.io.app_path); if (emuenv.cfg.run_app_path.has_value()) emuenv.cfg.run_app_path.reset(); @@ -324,14 +329,15 @@ int main(int argc, char *argv[]) { // When backend render is changed before boot app, reboot emu in new backend render and run app if (emuenv.renderer->current_backend != emuenv.backend_renderer) { - emuenv.load_app_path = emuenv.io.app_path; + emuenv.load_app_device = device::get_device(emuenv.io.app_path)._to_string(); + emuenv.load_app_path = fs::path(emuenv.io.app_path).stem().string(); run_execv(argv, emuenv); return Success; } gui::set_config(gui, emuenv, emuenv.io.app_path); - const auto APP_INDEX = gui::get_app_index(gui, emuenv.io.app_path); + const auto APP_INDEX = gui::get_app_index(gui, emuenv.io.app_path.find("vsh") != std::string::npos ? "emu:vsh/shell" : emuenv.io.app_path); emuenv.app_info.app_version = APP_INDEX->app_ver; emuenv.app_info.app_category = APP_INDEX->category; emuenv.app_info.app_content_id = APP_INDEX->content_id; @@ -357,7 +363,8 @@ int main(int argc, char *argv[]) { } gui::switch_bgm_state(true); - gui::init_app_background(gui, emuenv, emuenv.io.app_path); + if (emuenv.io.app_path.find("vsh") == std::string::npos) + gui::init_app_background(gui, emuenv, emuenv.io.app_path); gui::update_last_time_app_used(gui, emuenv, emuenv.io.app_path); if (!app::late_init(emuenv)) { diff --git a/vita3k/module/src/load_module.cpp b/vita3k/module/src/load_module.cpp index e0b7634631..20f3a26c58 100644 --- a/vita3k/module/src/load_module.cpp +++ b/vita3k/module/src/load_module.cpp @@ -130,6 +130,7 @@ static SysmoduleInternalPaths init_sysmodule_internal_paths() { p[SCE_SYSMODULE_INTERNAL_DB_RECOVERY_UTILITY] = { "dbrecovery_utility" }; p[SCE_SYSMODULE_INTERNAL_DRM_PSM_KDC] = { "psmkdc" }; p[SCE_SYSMODULE_INTERNAL_LOCATION_INTERNAL] = { "liblocation_internal" }; + p[SCE_SYSMODULE_INTERNAL_PROMOTER_UTIL] = { "libScePromoterUtil" }; return p; } diff --git a/vita3k/modules/SceAppMgr/SceAppMgr.cpp b/vita3k/modules/SceAppMgr/SceAppMgr.cpp index f2d6972149..e831948ce4 100644 --- a/vita3k/modules/SceAppMgr/SceAppMgr.cpp +++ b/vita3k/modules/SceAppMgr/SceAppMgr.cpp @@ -17,6 +17,7 @@ #include "SceAppMgr.h" +#include #include #include #include @@ -389,17 +390,14 @@ EXPORT(SceInt32, _sceAppMgrLoadExec, const char *appPath, Ptr const argv[] return RET_ERROR(SCE_APPMGR_ERROR_INVALID); // Create exec path - auto exec_path = static_cast(appPath); - if (exec_path.find("app0:/") != std::string::npos) - exec_path.erase(0, 6); - else - exec_path.erase(0, 5); + const auto app_device = device::get_device(appPath); + auto exec_path = device::remove_device_from_path(appPath, app_device); LOG_INFO("sceAppMgrLoadExec run self: {}", appPath); // Load exec executable vfs::FileBuffer exec_buffer; - if (vfs::read_app_file(exec_buffer, emuenv.pref_path, emuenv.io.app_path, exec_path)) { + if (vfs::read_file(app_device, exec_buffer, emuenv.pref_path, exec_path)) { if (argv && argv->get(emuenv.mem)) { size_t args = 0; emuenv.load_exec_argv = "\""; @@ -417,9 +415,12 @@ EXPORT(SceInt32, _sceAppMgrLoadExec, const char *appPath, Ptr const argv[] } emuenv.kernel.exit_delete_all_threads(); + const auto self_path = fs::path(exec_path).filename().string(); + exec_path = fs::path(exec_path).parent_path().string(); - emuenv.load_app_path = emuenv.io.app_path; - emuenv.load_exec_path = exec_path; + emuenv.load_app_device = app_device._to_string(); + emuenv.load_app_path = exec_path; + emuenv.load_exec_path = self_path; emuenv.load_exec = true; // make sure we are not stuck waiting for a gpu command emuenv.renderer->should_display = true; diff --git a/vita3k/modules/SceCommonDialog/SceCommonDialog.cpp b/vita3k/modules/SceCommonDialog/SceCommonDialog.cpp index f4a3eb53cf..38be9510ce 100644 --- a/vita3k/modules/SceCommonDialog/SceCommonDialog.cpp +++ b/vita3k/modules/SceCommonDialog/SceCommonDialog.cpp @@ -825,7 +825,7 @@ static void check_empty_param(EmuEnvState &emuenv, const SceAppUtilSaveDataSlotE vfs::FileBuffer thumbnail_buffer; if (iconPath) { auto device = device::get_device(empty_param->iconPath.get(emuenv.mem)); - auto thumbnail_path = translate_path(empty_param->iconPath.get(emuenv.mem), device, emuenv.io.device_paths); + auto thumbnail_path = translate_path(empty_param->iconPath.get(emuenv.mem), device, emuenv.io); vfs::read_file(VitaIoDevice::ux0, thumbnail_buffer, emuenv.pref_path, thumbnail_path); emuenv.common_dialog.savedata.icon_buffer[idx] = thumbnail_buffer; } else if (iconBuf && iconBufSize != 0) { @@ -853,7 +853,7 @@ static void check_save_file(const uint32_t index, EmuEnvState &emuenv, const cha emuenv.common_dialog.savedata.date[index] = slot_param.modifiedTime; emuenv.common_dialog.savedata.has_date[index] = true; auto device = device::get_device(slot_param.iconPath); - auto thumbnail_path = translate_path(slot_param.iconPath, device, emuenv.io.device_paths); + auto thumbnail_path = translate_path(slot_param.iconPath, device, emuenv.io); vfs::read_file(device, thumbnail_buffer, emuenv.pref_path, thumbnail_path); emuenv.common_dialog.savedata.icon_buffer[index] = thumbnail_buffer; emuenv.common_dialog.savedata.icon_texture[index] = {}; diff --git a/vita3k/modules/SceDisplay/SceDisplay.h b/vita3k/modules/SceDisplay/SceDisplay.h index 3db9a546f3..c3f701e2fd 100644 --- a/vita3k/modules/SceDisplay/SceDisplay.h +++ b/vita3k/modules/SceDisplay/SceDisplay.h @@ -68,6 +68,6 @@ struct SceDisplayFrameBuf2 : public SceDisplayFrameBuf { DECL_EXPORT(SceInt32, _sceDisplayGetFrameBuf, SceDisplayFrameBuf *pFrameBuf, SceDisplaySetBufSync sync, uint32_t *pFrameBuf_size); DECL_EXPORT(SceInt32, _sceDisplaySetFrameBuf, const SceDisplayFrameBuf *pFrameBuf, SceDisplaySetBufSync sync, uint32_t *pFrameBuf_size); +DECL_EXPORT(SceInt32, sceDisplayRegisterVblankStartCallback, SceUID uid); DECL_EXPORT(SceInt32, _sceDisplayGetMaximumFrameBufResolution, SceInt32 *width, SceInt32 *height); DECL_EXPORT(SceInt32, sceDisplayRegisterVblankStartCallback, SceUID uid); - diff --git a/vita3k/modules/SceDriverUser/SceAppMgrUser.cpp b/vita3k/modules/SceDriverUser/SceAppMgrUser.cpp index c2e0872703..cc45c703ea 100644 --- a/vita3k/modules/SceDriverUser/SceAppMgrUser.cpp +++ b/vita3k/modules/SceDriverUser/SceAppMgrUser.cpp @@ -246,8 +246,22 @@ EXPORT(int, sceAppMgrGetCurrentBgmState) { return UNIMPLEMENTED(); } -EXPORT(int, sceAppMgrGetCurrentBgmState2) { +struct BgmState { + uint32_t unk_0; + uint32_t unk2; + int unk3; + int unk4; + int unk5; + int unk6; + int unk7; + int unk8; +}; + +EXPORT(int, sceAppMgrGetCurrentBgmState2, BgmState *state) { TRACY_FUNC(sceAppMgrGetCurrentBgmState2); + memset(state, 0, sizeof(BgmState)); + state->unk_0 = 130; + // state->unk2 = 130; return UNIMPLEMENTED(); } @@ -354,6 +368,30 @@ EXPORT(int, sceAppMgrGetSaveDataInfoForSpecialExport) { return UNIMPLEMENTED(); } +struct SceAppMgrAppStatus { // size is 0x80 + SceUInt32 unk_0; // 0x0 + SceUInt32 launchMode; // 0x4 + SceUInt32 bgm_priority_or_status; // 0x8 + char appName[32]; // 0xC + SceUInt32 unk_2c; // 0x2C + SceUID appId; // 0x30 - Application ID + SceUID processId; // 0x34 - Process ID + SceUInt32 status_related_1; // 0x38 + SceUInt32 status_related_2; // 0x3C + SceUInt32 unk_40; + SceUInt32 unk_44; + SceUInt32 unk_48; + SceUInt32 unk_4c; + char name_02[32]; + char unk_70; + uint8_t unk_71; + char unk_72; + char unk_73; + uint32_t unk_74; + uint32_t unk_78; + uint32_t unk_7c; +}; + EXPORT(int, sceAppMgrGetStatusByAppId) { TRACY_FUNC(sceAppMgrGetStatusByAppId); return UNIMPLEMENTED(); @@ -364,9 +402,33 @@ EXPORT(int, sceAppMgrGetStatusById) { return UNIMPLEMENTED(); } -EXPORT(int, sceAppMgrGetStatusByName) { +EXPORT(int, sceAppMgrGetStatusByName, const char *appName, SceAppMgrAppStatus *appStatus) { TRACY_FUNC(sceAppMgrGetStatusByName); - return UNIMPLEMENTED(); + LOG_DEBUG_IF(appName, "name: {}", appName); + // LOG_DEBUG("Called"); + if (appStatus) { + memset(appStatus, 0, sizeof(SceAppMgrAppStatus)); + appStatus->unk_71 = 2; + appStatus->unk_74 = 1; + appStatus->status_related_1 = 2; + + appStatus->launchMode = 2; + appStatus->unk_0 = 2; + appStatus->unk_2c = 2; + appStatus->bgm_priority_or_status = 1; + strncpy(appStatus->appName, emuenv.io.title_id.c_str(), sizeof(appStatus->appName)); + appStatus->status_related_2 = 2; + appStatus->unk_40 = 2; + appStatus->unk_44 = 2; + appStatus->unk_48 = 2; + appStatus->unk_4c = 2; + strncpy(appStatus->name_02, emuenv.io.title_id.c_str(), sizeof(appStatus->name_02)); + appStatus->unk_70 = 1; + appStatus->unk_78 = 2; + appStatus->unk_7c = 2; + } + + return 0; } EXPORT(int, sceAppMgrGetSystemDataFilePlayReady) { @@ -437,9 +499,11 @@ EXPORT(int, sceAppMgrLaunchAppByNameForShell) { return UNIMPLEMENTED(); } -EXPORT(int, sceAppMgrLaunchAppByPath4) { +EXPORT(int, sceAppMgrLaunchAppByPath4, const char *path, const char *titleid, int a3, Ptr const app_param[], int a5, void *opt) { TRACY_FUNC(sceAppMgrLaunchAppByPath4); - return UNIMPLEMENTED(); + LOG_DEBUG("path: {}, titleid: {}, a3: {}, app param: {}, a5: {}", path, titleid, a3, app_param ? app_param->get(emuenv.mem) : "null", a5); + + return CALL_EXPORT(_sceAppMgrLoadExec, path, app_param, nullptr); } EXPORT(int, sceAppMgrLaunchAppByUri) { @@ -477,9 +541,23 @@ EXPORT(int, sceAppMgrLoopBackMount) { return UNIMPLEMENTED(); } -EXPORT(int, sceAppMgrMmsMount) { - TRACY_FUNC(sceAppMgrMmsMount); - return UNIMPLEMENTED(); +EXPORT(int, sceAppMgrMmsMount, int id, char *mount_point) { + TRACY_FUNC(sceAppMgrMmsMount, id, mount_point); + switch (id) { + case 0x190: + strcpy(mount_point, "ux0:mms/photo/"); + break; + case 0x191: + strcpy(mount_point, "ux0:mms/music"); + break; + case 0x192: + strcpy(mount_point, "ux0:mms/video"); + break; + default: + LOG_WARN("Unknown id: {}", log_hex(id)); + break; + } + return STUBBED("using strcpy"); } EXPORT(int, sceAppMgrOverwriteLaunchParamForShell) { @@ -533,7 +611,9 @@ EXPORT(int, sceAppMgrReceiveEventNum, SceUInt32 *eventNum) { EXPORT(int, sceAppMgrReceiveNotificationRequestForShell) { TRACY_FUNC(sceAppMgrReceiveNotificationRequestForShell); - return UNIMPLEMENTED(); + STUBBED("STUBBED"); + + return 0x80802024; } EXPORT(int, sceAppMgrReceiveShellEvent) { diff --git a/vita3k/modules/SceKernelModulemgr/SceModulemgr.cpp b/vita3k/modules/SceKernelModulemgr/SceModulemgr.cpp index ae4b9433a1..101eb8a19a 100644 --- a/vita3k/modules/SceKernelModulemgr/SceModulemgr.cpp +++ b/vita3k/modules/SceKernelModulemgr/SceModulemgr.cpp @@ -75,9 +75,10 @@ EXPORT(SceUID, _sceKernelLoadStartModule, const char *moduleFileName, SceSize ar return kernel_start_module(emuenv, module_id, args, argp, pRes); } -EXPORT(int, _sceKernelOpenModule) { - TRACY_FUNC(_sceKernelOpenModule); - return UNIMPLEMENTED(); +EXPORT(SceUID, _sceKernelOpenModule, const char *moduleFileName, SceSize args, const Ptr argp, SceUInt32 flags, const SceKernelLMOption *pOpt, int *pRes) { + TRACY_FUNC(_sceKernelOpenModule, moduleFileName, args, argp, flags, pOpt, pRes); + + return CALL_EXPORT(_sceKernelLoadStartModule, moduleFileName, args, argp, flags, pOpt, pRes); } EXPORT(int, _sceKernelStartModule, SceUID uid, SceSize args, Ptr argp, SceUInt32 flags, const SceKernelStartModuleOpt *pOpt, int *pRes) { diff --git a/vita3k/modules/SceKernelThreadMgr/SceThreadmgr.cpp b/vita3k/modules/SceKernelThreadMgr/SceThreadmgr.cpp index da60ab9ad1..58569df057 100644 --- a/vita3k/modules/SceKernelThreadMgr/SceThreadmgr.cpp +++ b/vita3k/modules/SceKernelThreadMgr/SceThreadmgr.cpp @@ -1038,7 +1038,8 @@ EXPORT(SceUID, sceKernelCreateCallback, char *name, SceUInt32 attr, Ptrcpu_affinity_mask & ~SCE_KERNEL_CPU_MASK_USER_ALL) { + if (options->cpu_affinity_mask & ~(SCE_KERNEL_CPU_MASK_USER_ALL | 0x80000)) { + LOG_DEBUG("cpu_affinity_mask: {}", options->cpu_affinity_mask); return RET_ERROR(SCE_KERNEL_ERROR_INVALID_CPU_AFFINITY); } diff --git a/vita3k/modules/SceLibKernel/SceLibKernel.cpp b/vita3k/modules/SceLibKernel/SceLibKernel.cpp index 568c49bb6f..29d6d4ffec 100644 --- a/vita3k/modules/SceLibKernel/SceLibKernel.cpp +++ b/vita3k/modules/SceLibKernel/SceLibKernel.cpp @@ -1574,9 +1574,9 @@ EXPORT(SceInt32, sceKernelLockWriteRWLockCB, SceUID lock_id, SceUInt32 *timeout) return CALL_EXPORT(_sceKernelLockWriteRWLockCB, lock_id, timeout); } -EXPORT(int, sceKernelOpenModule) { - TRACY_FUNC(sceKernelOpenModule); - return UNIMPLEMENTED(); +EXPORT(SceUID, sceKernelOpenModule, const char *moduleFileName, SceSize args, const Ptr argp, SceUInt32 flags, const SceKernelLMOption *pOpt, int *pRes) { + TRACY_FUNC(sceKernelOpenModule, moduleFileName, args, argp, flags, pOpt, pRes); + return CALL_EXPORT(_sceKernelLoadStartModule, moduleFileName, args, argp, flags, pOpt, pRes); } EXPORT(int, sceKernelPMonThreadGetCounter) { diff --git a/vita3k/modules/SceNetInternal/SceNetInternal.cpp b/vita3k/modules/SceNetInternal/SceNetInternal.cpp index f21cd302a9..64b826f222 100644 --- a/vita3k/modules/SceNetInternal/SceNetInternal.cpp +++ b/vita3k/modules/SceNetInternal/SceNetInternal.cpp @@ -31,3 +31,11 @@ EXPORT(int, sceNetInternalIcmConnect, int sid, int flags) { // call sceNetSyscallIcmConnect(sid, flags) return UNIMPLEMENTED(); } + +EXPORT(Ptr, SceNetInternal_F3917021, int unk) { + TRACY_FUNC(SceNetInternal_F3917021); + LOG_DEBUG("SceNetInternal_F3917021, {}", unk); + Ptr rep = Ptr(alloc(emuenv.mem, 0x10, "ip_field")); + strcpy(rep.get(emuenv.mem), "127.0.0.1"); + return rep; +} diff --git a/vita3k/modules/SceSblUpdateMgr/SceSblSsUpdateMgr.cpp b/vita3k/modules/SceSblUpdateMgr/SceSblSsUpdateMgr.cpp index 397cbba79e..44402e8f4f 100644 --- a/vita3k/modules/SceSblUpdateMgr/SceSblSsUpdateMgr.cpp +++ b/vita3k/modules/SceSblUpdateMgr/SceSblSsUpdateMgr.cpp @@ -37,8 +37,18 @@ EXPORT(int, sceSblUsGetExtractSpackage) { return UNIMPLEMENTED(); } -EXPORT(int, sceSblUsGetSpkgInfo) { - return UNIMPLEMENTED(); +struct SceSblUsSpkgInfo { // Size is 0x10 on FW 0.931-0.990 + SceSize size; // size of this structure + int version; + int reserved1; + int reserved2; +}; + +EXPORT(int, sceSblUsGetSpkgInfo, int package_type, SceSblUsSpkgInfo *pInfo) { + LOG_DEBUG("package type: {}", package_type); + pInfo->version = 0x3000011; + + return STUBBED("Set to 3.00"); } EXPORT(int, sceSblUsGetStatus) { diff --git a/vita3k/modules/include/modules/module_parent.h b/vita3k/modules/include/modules/module_parent.h index 318a162c1e..af31576ab8 100644 --- a/vita3k/modules/include/modules/module_parent.h +++ b/vita3k/modules/include/modules/module_parent.h @@ -36,6 +36,7 @@ void call_import(EmuEnvState &emuenv, CPUState &cpu, uint32_t nid, SceUID thread */ SceUID load_module(EmuEnvState &emuenv, const std::string &module_path); int unload_module(EmuEnvState &emuenv, SceUID module_id); +SceUID load_app_by_path(EmuEnvState &emuenv, const std::string &self_path, const char *titleid, const char *app_param); uint32_t start_module(EmuEnvState &emuenv, const SceKernelModuleInfo &module, SceSize args = 0, Ptr argp = Ptr{}); uint32_t stop_module(EmuEnvState &emuenv, const SceKernelModuleInfo &module, SceSize args = 0, Ptr argp = Ptr{}); diff --git a/vita3k/modules/module_parent.cpp b/vita3k/modules/module_parent.cpp index 29092915f5..45b840e6a7 100644 --- a/vita3k/modules/module_parent.cpp +++ b/vita3k/modules/module_parent.cpp @@ -190,6 +190,53 @@ void call_import(EmuEnvState &emuenv, CPUState &cpu, uint32_t nid, SceUID thread } } +SceUID load_app_by_path(EmuEnvState &emuenv, const std::string &self_path, const char *titleid, const char *app_param) { + vfs::FileBuffer self_buffer; + const auto device = device::get_device(self_path); + const auto relative_path = device::remove_device_from_path(self_path, device); + LOG_DEBUG("device: {}, relative_path: {}", device._to_string(), relative_path); + const auto res = vfs::read_file(device, self_buffer, emuenv.pref_path, relative_path); + if (res) { + SceUID module_id = load_self(emuenv.kernel, emuenv.mem, self_buffer.data(), self_path, emuenv.log_path); + if (module_id >= 0) { + const auto module = emuenv.kernel.loaded_modules[module_id]; + Ptr entry_point = module->info.start_entry; + const ThreadStatePtr thread = emuenv.kernel.create_thread(emuenv.mem, titleid, entry_point, SCE_KERNEL_DEFAULT_PRIORITY_USER, SCE_KERNEL_THREAD_CPU_AFFINITY_MASK_DEFAULT, static_cast(SCE_KERNEL_STACK_SIZE_USER_MAIN), nullptr); + const SceUID self_thread_id = thread->id; + + LOG_INFO("Self executable {} ({}) loaded", module->info.module_name, self_path); + + if (entry_point) { + LOG_DEBUG("Running module_start of module: {}", module->info.module_name); + SceKernelThreadOptParam param{ 0, 0 }; + if (app_param) { + std::vector buf; + buf.insert(buf.end(), app_param, app_param + strlen(app_param) + 1); + auto arr = Ptr(alloc(emuenv.mem, static_cast(buf.size()), "arg")); + memcpy(arr.get(emuenv.mem), buf.data(), buf.size()); + param.size = SceSize(buf.size()); + param.attr = arr.address(); + } + const ThreadStatePtr self_thread = util::find(self_thread_id, emuenv.kernel.threads); + if (self_thread->start(param.size, Ptr(param.attr)) < 0) { + LOG_ERROR("Error when starting main thread of module at \"{}\"", self_path); + return -1; + } + return self_thread_id; + } else { + LOG_ERROR("Error when loading self executable at \"{}\"", self_path); + return -1; + } + } else { + LOG_ERROR("Executable at \"{}\" not present", self_path); + return -1; + } + } else { + LOG_ERROR("Error when reading executable at \"{}\"", self_path); + return -1; + } +} + SceUID load_module(EmuEnvState &emuenv, const std::string &module_path) { // Check if module is already loaded { @@ -206,12 +253,10 @@ SceUID load_module(EmuEnvState &emuenv, const std::string &module_path) { LOG_INFO("Loading module \"{}\"", module_path); vfs::FileBuffer module_buffer; - bool res; VitaIoDevice device = device::get_device(module_path); auto device_for_icase = device; - fs::path translated_module_path = translate_path(module_path.c_str(), device, emuenv.io.device_paths); + fs::path translated_module_path = translate_path(module_path.c_str(), device, emuenv.io); auto system_path = device::construct_emulated_path(device, translated_module_path, emuenv.pref_path, emuenv.io.redirect_stdio); - if (emuenv.io.case_isens_find_enabled && !fs::exists(system_path)) { // Attempt a case-insensitive file search. const auto original_translated_module_path = translated_module_path; @@ -233,11 +278,7 @@ SceUID load_module(EmuEnvState &emuenv, const std::string &module_path) { } } - if (device == VitaIoDevice::app0) - res = vfs::read_app_file(module_buffer, emuenv.pref_path, emuenv.io.app_path, translated_module_path); - else - res = vfs::read_file(device, module_buffer, emuenv.pref_path, translated_module_path); - if (!res) { + if (!vfs::read_file(device, module_buffer, emuenv.pref_path, translated_module_path)) { LOG_ERROR("Failed to read module file {}", module_path); return SCE_ERROR_ERRNO_ENOENT; } diff --git a/vita3k/nids/include/nids/nids.inc b/vita3k/nids/include/nids/nids.inc index 2ea08fddd5..f7b48249bf 100644 --- a/vita3k/nids/include/nids/nids.inc +++ b/vita3k/nids/include/nids/nids.inc @@ -5091,6 +5091,7 @@ NID(sceNetTerm, 0xEA3CC286) // Library "SceNetInternal" NID(sceNetInternalIcmConnect, 0x93F2FF08) NID(sceNetInternalInetPton, 0x916EA798) +NID(SceNetInternal_F3917021, 0xF3917021) // Module "SceNetAdhocMatching" // Library "SceNetAdhocMatching" NID(sceNetAdhocMatchingAbortSendData, 0xFE77831E)