android: initial UI api

This commit is contained in:
DH 2025-04-25 03:45:53 +03:00
parent 4b66d3e6c1
commit dd9b9e75f5

View file

@ -55,6 +55,7 @@
#include <Emu/Io/pad_config.h> #include <Emu/Io/pad_config.h>
#include <Emu/RSX/GSFrameBase.h> #include <Emu/RSX/GSFrameBase.h>
#include <Emu/System.h> #include <Emu/System.h>
#include <nlohmann/json.hpp>
#include <rpcsx/fw/ps3/cellSaveData.h> #include <rpcsx/fw/ps3/cellSaveData.h>
#include <rpcsx/fw/ps3/sceNpTrophy.h> #include <rpcsx/fw/ps3/sceNpTrophy.h>
#include <rx/Version.hpp> #include <rx/Version.hpp>
@ -78,6 +79,9 @@
#include <thread> #include <thread>
#include <vector> #include <vector>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wreturn-type-c-linkage"
struct AtExit { struct AtExit {
std::function<void()> cb; std::function<void()> cb;
~AtExit() { cb(); } ~AtExit() { cb(); }
@ -611,7 +615,7 @@ public:
jlong getProgressId() const { return progressId; } jlong getProgressId() const { return progressId; }
}; };
static void sendFirmwareInstalled(JNIEnv *env, std::string version) { static void sendFirmwareInstalled(JNIEnv *env, const std::string &version) {
auto fwRepositoryClass = auto fwRepositoryClass =
ensure(env->FindClass("net/rpcsx/FirmwareRepository")); ensure(env->FindClass("net/rpcsx/FirmwareRepository"));
auto methodId = ensure(env->GetStaticMethodID( auto methodId = ensure(env->GetStaticMethodID(
@ -620,7 +624,7 @@ static void sendFirmwareInstalled(JNIEnv *env, std::string version) {
env->CallStaticVoidMethod(fwRepositoryClass, methodId, wrap(env, version)); env->CallStaticVoidMethod(fwRepositoryClass, methodId, wrap(env, version));
} }
static void sendFirmwareCompiled(JNIEnv *env, std::string version) { static void sendFirmwareCompiled(JNIEnv *env, const std::string &version) {
auto fwRepositoryClass = auto fwRepositoryClass =
ensure(env->FindClass("net/rpcsx/FirmwareRepository")); ensure(env->FindClass("net/rpcsx/FirmwareRepository"));
auto methodId = ensure(env->GetStaticMethodID( auto methodId = ensure(env->GetStaticMethodID(
@ -722,7 +726,7 @@ static void collectGamePaths(std::vector<std::string> &paths,
auto dir = std::move(workList.back()); auto dir = std::move(workList.back());
workList.pop_back(); workList.pop_back();
for (auto entry : std::filesystem::directory_iterator(dir, ec)) { for (auto &entry : std::filesystem::directory_iterator(dir, ec)) {
if (entry.is_directory()) { if (entry.is_directory()) {
if (entry.path().filename() != "C00") { if (entry.path().filename() != "C00") {
workList.push_back(entry.path()); workList.push_back(entry.path());
@ -739,9 +743,9 @@ static void collectGamePaths(std::vector<std::string> &paths,
} }
} }
static std::string locateEbootPath(const std::string &root) { static std::string locateEbootPath(std::string_view root) {
if (std::filesystem::is_regular_file(root)) { if (std::filesystem::is_regular_file(root)) {
return root; return std::string(root);
} }
for (auto suffix : { for (auto suffix : {
@ -750,7 +754,8 @@ static std::string locateEbootPath(const std::string &root) {
"/USRDIR/ISO.BIN.EDAT", "/USRDIR/ISO.BIN.EDAT",
"/PS3_GAME/USRDIR/EBOOT.BIN", "/PS3_GAME/USRDIR/EBOOT.BIN",
}) { }) {
std::string tryPath = root + suffix; auto tryPath = std::string(root);
tryPath += suffix;
if (std::filesystem::is_regular_file(tryPath)) { if (std::filesystem::is_regular_file(tryPath)) {
return tryPath; return tryPath;
@ -760,16 +765,17 @@ static std::string locateEbootPath(const std::string &root) {
return {}; return {};
} }
static std::string locateParamSfoPath(const std::string &root) { static std::string locateParamSfoPath(std::string_view root) {
if (std::filesystem::is_regular_file(root)) { if (std::filesystem::is_regular_file(root)) {
return root; return std::string(root);
} }
for (auto suffix : { for (auto suffix : {
"/PARAM.SFO", "/PARAM.SFO",
"/PS3_GAME/PARAM.SFO", "/PS3_GAME/PARAM.SFO",
}) { }) {
std::string tryPath = root + suffix; auto tryPath = std::string(root);
tryPath += suffix;
if (std::filesystem::is_regular_file(tryPath)) { if (std::filesystem::is_regular_file(tryPath)) {
return tryPath; return tryPath;
@ -874,7 +880,7 @@ fetchGameInfo(const psf::registry &psf,
} }
static void collectGameInfo(JNIEnv *env, jlong progressId, static void collectGameInfo(JNIEnv *env, jlong progressId,
std::vector<std::string> rootDirs) { const std::vector<std::string> &rootDirs) {
std::vector<std::string> paths; std::vector<std::string> paths;
for (auto &&rootDir : rootDirs) { for (auto &&rootDir : rootDirs) {
collectGamePaths(paths, rootDir); collectGamePaths(paths, rootDir);
@ -1005,7 +1011,7 @@ struct ProgressMessageDialog : MsgDialogBase {
void Close(bool success) override { void Close(bool success) override {
rpcsx_android.warning("ProgressMessageDialog::Close(%s)", success); rpcsx_android.warning("ProgressMessageDialog::Close(%s)", success);
invokeSync([this, success](JNIEnv *env) { invokeSync([this](JNIEnv *env) {
Progress progress(env, progressId); Progress progress(env, progressId);
progress.report(0, 0); progress.report(0, 0);
}); });
@ -1352,7 +1358,7 @@ private:
if (fs::is_file(workload.path)) { if (fs::is_file(workload.path)) {
if (!is_vsh) { if (!is_vsh) {
auto sfoPath = locateParamSfoPath(rootPath); auto sfoPath = locateParamSfoPath(std::string(rootPath));
if (!sfoPath.empty()) { if (!sfoPath.empty()) {
const auto psf = psf::load_object(sfoPath); const auto psf = psf::load_object(sfoPath);
@ -1384,7 +1390,8 @@ private:
std::vector<std::string> dir_queue; std::vector<std::string> dir_queue;
dir_queue.push_back(rootPath.string()); dir_queue.push_back(rootPath.string());
for (auto entry : std::filesystem::recursive_directory_iterator(rootPath)) { for (auto &entry :
std::filesystem::recursive_directory_iterator(rootPath)) {
if (entry.is_directory()) { if (entry.is_directory()) {
dir_queue.push_back(entry.path().string()); dir_queue.push_back(entry.path().string());
} }
@ -1550,14 +1557,14 @@ static void setupCallbacks() {
[](auto...) { return std::make_unique<OverlayTrophyNotification>(); }, [](auto...) { return std::make_unique<OverlayTrophyNotification>(); },
.get_localized_string = [](localized_string_id id, .get_localized_string = [](localized_string_id id,
const char *) -> std::string { const char *) -> std::string {
if (int(id) < std::size(g_strings)) { if (std::size_t(id) < std::size(g_strings)) {
return g_strings[int(id)].first; return g_strings[int(id)].first;
} }
return ""; return "";
}, },
.get_localized_u32string = [](localized_string_id id, .get_localized_u32string = [](localized_string_id id,
const char *) -> std::u32string { const char *) -> std::u32string {
if (int(id) < std::size(g_strings)) { if (std::size_t(id) < std::size(g_strings)) {
return g_strings[int(id)].second; return g_strings[int(id)].second;
} }
return U""; return U"";
@ -1664,9 +1671,9 @@ static bool initVirtualPad(const std::shared_ptr<Pad> &pad) {
return true; return true;
} }
extern "C" JNIEXPORT jboolean JNICALL Java_net_rpcsx_RPCSX_overlayPadData( extern "C" bool _rpcsx_overlayPadData(int digital1, int digital2,
JNIEnv *env, jobject, jint digital1, jint digital2, jint leftStickX, int leftStickX, int leftStickY,
jint leftStickY, jint rightStickX, jint rightStickY) { int rightStickX, int rightStickY) {
auto pad = [] { auto pad = [] {
std::shared_ptr<Pad> result; std::shared_ptr<Pad> result;
@ -1703,9 +1710,9 @@ extern "C" JNIEXPORT jboolean JNICALL Java_net_rpcsx_RPCSX_overlayPadData(
return true; return true;
} }
extern "C" JNIEXPORT jboolean JNICALL extern "C" bool _rpcsx_initialize(std::string_view rootDir,
Java_net_rpcsx_RPCSX_initialize(JNIEnv *env, jobject, jstring rootDir) { std::string_view user) {
auto rootDirStr = fix_dir_path(unwrap(env, rootDir)); auto rootDirStr = fix_dir_path(std::string(rootDir));
if (g_android_executable_dir != rootDirStr) { if (g_android_executable_dir != rootDirStr) {
g_android_executable_dir = rootDirStr; g_android_executable_dir = rootDirStr;
@ -1800,6 +1807,7 @@ Java_net_rpcsx_RPCSX_initialize(JNIEnv *env, jobject, jstring rootDir) {
virtual_pad_handler::set_on_connect_cb(initVirtualPad); virtual_pad_handler::set_on_connect_cb(initVirtualPad);
setupCallbacks(); setupCallbacks();
Emu.SetHasGui(false); Emu.SetHasGui(false);
Emu.SetUsr(std::string(user));
Emu.Init(); Emu.Init();
g_cfg_input.player1.handler.set(pad_handler::virtual_pad); g_cfg_input.player1.handler.set(pad_handler::virtual_pad);
@ -1812,40 +1820,33 @@ Java_net_rpcsx_RPCSX_initialize(JNIEnv *env, jobject, jstring rootDir) {
return true; return true;
} }
extern "C" JNIEXPORT jboolean JNICALL extern "C" bool _rpcsx_processCompilationQueue(JNIEnv *env) {
Java_net_rpcsx_RPCSX_processCompilationQueue(JNIEnv *env, jobject) {
g_compilationQueue.process(env); g_compilationQueue.process(env);
return true; return true;
} }
extern "C" JNIEXPORT jboolean JNICALL extern "C" bool _rpcsx_startMainThreadProcessor(JNIEnv *env) {
Java_net_rpcsx_RPCSX_startMainThreadProcessor(JNIEnv *env, jobject) {
g_mainThreadProcessor.process(env); g_mainThreadProcessor.process(env);
return true; return true;
} }
extern "C" JNIEXPORT jboolean JNICALL Java_net_rpcsx_RPCSX_collectGameInfo( extern "C" bool _rpcsx_collectGameInfo(JNIEnv *env, std::string_view rootDir,
JNIEnv *env, jobject, jstring jrootDir, jlong progressId) { long progressId) {
if (std::filesystem::is_regular_file(g_cfg_vfs.get_dev_flash() + if (std::filesystem::is_regular_file(g_cfg_vfs.get_dev_flash() +
"/vsh/module/vsh.self")) { "/vsh/module/vsh.self")) {
sendVshBootable(env, progressId); sendVshBootable(env, progressId);
} }
collectGameInfo(env, progressId, {unwrap(env, jrootDir)}); collectGameInfo(env, progressId, {std::string(rootDir)});
return true; return true;
} }
extern "C" JNIEXPORT void JNICALL Java_net_rpcsx_RPCSX_shutdown(JNIEnv *env, extern "C" void _rpcsx_shutdown() { Emu.Kill(); }
jobject) {
Emu.Kill();
}
extern "C" JNIEXPORT jint JNICALL Java_net_rpcsx_RPCSX_boot(JNIEnv *env, extern "C" int _rpcsx_boot(std::string_view path_) {
jobject,
jstring jpath) {
Emu.SetForceBoot(true); Emu.SetForceBoot(true);
auto path = unwrap(env, jpath); std::string path = std::string(path_);
while (path.ends_with('/')) { while (path.ends_with('/')) {
path.pop_back(); path.pop_back();
} }
@ -1853,35 +1854,21 @@ extern "C" JNIEXPORT jint JNICALL Java_net_rpcsx_RPCSX_boot(JNIEnv *env,
return static_cast<int>(Emu.BootGame(path, "", false, cfg_mode::global)); return static_cast<int>(Emu.BootGame(path, "", false, cfg_mode::global));
} }
extern "C" JNIEXPORT jint JNICALL Java_net_rpcsx_RPCSX_getState(JNIEnv *env, extern "C" int _rpcsx_getState() {
jobject) {
return static_cast<int>(Emu.GetStatus(false)); return static_cast<int>(Emu.GetStatus(false));
} }
extern "C" void _rpcsx_kill() { Emu.Kill(); }
extern "C" void _rpcsx_resume() { Emu.Resume(); }
extern "C" JNIEXPORT void JNICALL Java_net_rpcsx_RPCSX_kill(JNIEnv *env, extern "C" void _rpcsx_openHomeMenu() {
jobject) {
Emu.Kill();
}
extern "C" JNIEXPORT void JNICALL Java_net_rpcsx_RPCSX_resume(JNIEnv *env,
jobject) {
Emu.Resume();
}
extern "C" JNIEXPORT void JNICALL Java_net_rpcsx_RPCSX_openHomeMenu(JNIEnv *env,
jobject) {
if (auto padThread = pad::get_pad_thread(true)) { if (auto padThread = pad::get_pad_thread(true)) {
padThread->open_home_menu(); padThread->open_home_menu();
} }
} }
extern "C" JNIEXPORT jstring JNICALL extern "C" std::string _rpcsx_getTitleId() { return Emu.GetTitleID(); }
Java_net_rpcsx_RPCSX_getTitleId(JNIEnv *env, jobject) {
return wrap(env, Emu.GetTitleID());
}
extern "C" JNIEXPORT jboolean JNICALL Java_net_rpcsx_RPCSX_surfaceEvent( extern "C" bool _rpcsx_surfaceEvent(JNIEnv *env, jobject surface, jint event) {
JNIEnv *env, jobject, jobject surface, jint event) {
rpcsx_android.warning("surface event %p, %d", surface, event); rpcsx_android.warning("surface event %p, %d", surface, event);
if (event == 2) { if (event == 2) {
@ -1922,8 +1909,8 @@ extern "C" JNIEXPORT jboolean JNICALL Java_net_rpcsx_RPCSX_surfaceEvent(
return true; return true;
} }
extern "C" JNIEXPORT jboolean JNICALL Java_net_rpcsx_RPCSX_usbDeviceEvent( extern "C" bool _rpcsx_usbDeviceEvent(int fd, int vendorId, int productId,
JNIEnv *env, jobject, jint fd, jint vendorId, jint productId, jint event) { int event) {
rpcsx_android.warning( rpcsx_android.warning(
"usb device event %d fd: %d, vendorId: %d, productId: %d", event, fd, "usb device event %d fd: %d, vendorId: %d, productId: %d", event, fd,
vendorId, productId); vendorId, productId);
@ -2167,7 +2154,7 @@ static bool installPkg(JNIEnv *env, fs::file &&file, jlong progressId) {
while (true) { while (true) {
std::uint64_t totalProgress = 0; std::uint64_t totalProgress = 0;
for (std::size_t index = 0; auto &reader : readers) { for (auto &reader : readers) {
if (result.error != package_install_result::error_type::no_error) { if (result.error != package_install_result::error_type::no_error) {
progress.failure("Installation failed"); progress.failure("Installation failed");
for (package_reader &reader : readers) { for (package_reader &reader : readers) {
@ -2209,7 +2196,7 @@ static bool installPkg(JNIEnv *env, fs::file &&file, jlong progressId) {
} }
static bool installEdat(JNIEnv *env, fs::file &&file, jlong progressId, static bool installEdat(JNIEnv *env, fs::file &&file, jlong progressId,
std::string rootPath = {}) { std::string_view rootPath = {}) {
Progress progress(env, progressId); Progress progress(env, progressId);
NPD_HEADER npdHeader; NPD_HEADER npdHeader;
@ -2256,16 +2243,18 @@ static bool installEdat(JNIEnv *env, fs::file &&file, jlong progressId,
return false; return false;
} }
if (rootPath.empty()) { auto root = std::string(rootPath);
rootPath = rpcs3::utils::get_hdd0_dir() + "game";
if (root.empty()) {
root = rpcs3::utils::get_hdd0_dir() + "game";
} }
collectGameInfo(env, progressId, {rootPath}); collectGameInfo(env, progressId, {std::move(root)});
return true; return true;
} }
static bool installRap(JNIEnv *env, fs::file &&file, jlong progressId, static bool installRap(JNIEnv *env, fs::file &&file, jlong progressId,
const std::string &rootPath) { std::string_view rootPath) {
Progress progress(env, progressId); Progress progress(env, progressId);
auto ebootPath = locateEbootPath(rootPath); auto ebootPath = locateEbootPath(rootPath);
@ -2310,7 +2299,7 @@ static bool installRap(JNIEnv *env, fs::file &&file, jlong progressId,
return false; return false;
} }
collectGameInfo(env, -1, {rootPath}); collectGameInfo(env, -1, {std::string(rootPath)});
g_compilationQueue.push(progress, std::move(ebootPath)); g_compilationQueue.push(progress, std::move(ebootPath));
return true; return true;
} }
@ -2364,7 +2353,7 @@ static bool installIso(JNIEnv *env, fs::file &&file, jlong progressId) {
fs::dir dir; fs::dir dir;
dir.reset(iso.open_dir(path)); dir.reset(iso.open_dir(path));
for (auto entry : dir) { for (auto &entry : dir) {
if (entry.name == "." || entry.name == "..") { if (entry.name == "." || entry.name == "..") {
continue; continue;
} }
@ -2402,7 +2391,7 @@ static bool installIso(JNIEnv *env, fs::file &&file, jlong progressId) {
fs::dir dir; fs::dir dir;
dir.reset(iso.open_dir(root)); dir.reset(iso.open_dir(root));
for (auto entry : dir) { for (auto &entry : dir) {
if (entry.name == "." || entry.name == "..") { if (entry.name == "." || entry.name == "..") {
continue; continue;
} }
@ -2444,18 +2433,16 @@ static bool installIso(JNIEnv *env, fs::file &&file, jlong progressId) {
} }
collectGameInfo(env, -1, {destinationPath}); collectGameInfo(env, -1, {destinationPath});
auto ebootPath = locateEbootPath(destinationPath); auto ebootPath = locateEbootPath(destinationPath.string());
g_compilationQueue.push(progress, std::move(ebootPath)); g_compilationQueue.push(progress, std::move(ebootPath));
return true; return true;
} }
extern "C" JNIEXPORT jboolean JNICALL Java_net_rpcsx_RPCSX_installFw( extern "C" bool _rpcsx_installFw(JNIEnv *env, int fd, long progressId) {
JNIEnv *env, jobject, jint fd, jlong progressId) {
return installPup(env, fs::file::from_native_handle(fd), progressId); return installPup(env, fs::file::from_native_handle(fd), progressId);
} }
extern "C" JNIEXPORT jboolean JNICALL extern "C" bool _rpcsx_isInstallableFile(jint fd) {
Java_net_rpcsx_RPCSX_isInstallableFile(JNIEnv *env, jobject, jint fd) {
auto file = fs::file::from_native_handle(fd); auto file = fs::file::from_native_handle(fd);
AtExit atExit{[&] { file.release_handle(); }}; AtExit atExit{[&] { file.release_handle(); }};
@ -2465,8 +2452,7 @@ Java_net_rpcsx_RPCSX_isInstallableFile(JNIEnv *env, jobject, jint fd) {
type != FileType::Rap; // FIXME: implement rap preinstallation type != FileType::Rap; // FIXME: implement rap preinstallation
} }
extern "C" JNIEXPORT jstring JNICALL extern "C" jstring _rpcsx_getDirInstallPath(JNIEnv *env, jint fd) {
Java_net_rpcsx_RPCSX_getDirInstallPath(JNIEnv *env, jobject, jint fd) {
auto file = fs::file::from_native_handle(fd); auto file = fs::file::from_native_handle(fd);
AtExit atExit{[&] { file.release_handle(); }}; AtExit atExit{[&] { file.release_handle(); }};
@ -2478,8 +2464,7 @@ Java_net_rpcsx_RPCSX_getDirInstallPath(JNIEnv *env, jobject, jint fd) {
return nullptr; return nullptr;
} }
extern "C" JNIEXPORT jboolean JNICALL extern "C" bool _rpcsx_install(JNIEnv *env, int fd, long progressId) {
Java_net_rpcsx_RPCSX_install(JNIEnv *env, jobject, jint fd, jlong progressId) {
auto file = fs::file::from_native_handle(fd); auto file = fs::file::from_native_handle(fd);
AtExit atExit{[&] { file.release_handle(); }}; AtExit atExit{[&] { file.release_handle(); }};
@ -2513,8 +2498,8 @@ Java_net_rpcsx_RPCSX_install(JNIEnv *env, jobject, jint fd, jlong progressId) {
return true; return true;
} }
extern "C" JNIEXPORT jboolean JNICALL Java_net_rpcsx_RPCSX_installKey( extern "C" bool _rpcsx_installKey(JNIEnv *env, int fd, long progressId,
JNIEnv *env, jobject, jint fd, jlong progressId, jstring gamePath) { std::string_view gamePath) {
auto file = fs::file::from_native_handle(fd); auto file = fs::file::from_native_handle(fd);
AtExit atExit{[&] { file.release_handle(); }}; AtExit atExit{[&] { file.release_handle(); }};
@ -2522,19 +2507,18 @@ extern "C" JNIEXPORT jboolean JNICALL Java_net_rpcsx_RPCSX_installKey(
file.seek(0); file.seek(0);
if (type == FileType::Rap) { if (type == FileType::Rap) {
return installRap(env, std::move(file), progressId, unwrap(env, gamePath)); return installRap(env, std::move(file), progressId, gamePath);
} }
if (type == FileType::Edat) { if (type == FileType::Edat) {
return installEdat(env, std::move(file), progressId, unwrap(env, gamePath)); return installEdat(env, std::move(file), progressId, gamePath);
} }
Progress(env, progressId).failure("Unsupported key type"); Progress(env, progressId).failure("Unsupported key type");
return false; return false;
} }
extern "C" JNIEXPORT jstring JNICALL extern "C" std::string _rpcsx_systemInfo() {
Java_net_rpcsx_RPCSX_systemInfo(JNIEnv *env, jobject) {
std::string result; std::string result;
fmt::append(result, "%s\n\nLLVM CPU: %s\n\n", utils::get_system_info(), fmt::append(result, "%s\n\nLLVM CPU: %s\n\n", utils::get_system_info(),
@ -2555,7 +2539,7 @@ Java_net_rpcsx_RPCSX_systemInfo(JNIEnv *env, jobject) {
} }
} }
return wrap(env, result); return result;
} }
static cfg::_base *find_cfg_node(cfg::_base *root, std::string_view path) { static cfg::_base *find_cfg_node(cfg::_base *root, std::string_view path) {
@ -2593,38 +2577,43 @@ static cfg::_base *find_cfg_node(cfg::_base *root, std::string_view path) {
return root; return root;
} }
extern "C" JNIEXPORT jstring JNICALL extern "C" void _rpcsx_loginUser(std::string_view userId) {
Java_net_rpcsx_RPCSX_settingsGet(JNIEnv *env, jobject, jstring jpath) { Emu.SetUsr(std::string(userId));
auto root = find_cfg_node(&g_cfg, unwrap(env, jpath)); }
extern "C" std::string _rpcsx_getUser() { return Emu.GetUsr(); }
extern "C" std::string _rpcsx_settingsGet(std::string_view path) {
auto root = find_cfg_node(&g_cfg, path);
if (root == nullptr) { if (root == nullptr) {
return nullptr; return nullptr;
} }
return wrap(env, root->to_json().dump(4)); return root->to_json().dump(4);
} }
extern "C" JNIEXPORT jboolean JNICALL Java_net_rpcsx_RPCSX_settingsSet( extern "C" bool _rpcsx_settingsSet(std::string_view path,
JNIEnv *env, jobject, jstring jpath, jstring jvalue) { std::string_view valueString) {
nlohmann::json value; nlohmann::json value;
try { try {
value = nlohmann::json::parse(unwrap(env, jvalue)); value = nlohmann::json::parse(valueString);
} catch (...) { } catch (...) {
rpcsx_android.error("settingsSet: node %s passed with invalid json '%s'", rpcsx_android.error("settingsSet: node %s passed with invalid json '%s'",
unwrap(env, jpath), unwrap(env, jvalue)); path, valueString);
return false; return false;
} }
auto root = find_cfg_node(&g_cfg, unwrap(env, jpath)); auto root = find_cfg_node(&g_cfg, path);
if (root == nullptr) { if (root == nullptr) {
rpcsx_android.error("settingsSet: node %s not found", unwrap(env, jpath)); rpcsx_android.error("settingsSet: node %s not found", path);
return false; return false;
} }
if (!root->from_json(value, !Emu.IsStopped())) { if (!root->from_json(value, !Emu.IsStopped())) {
rpcsx_android.error("settingsSet: node %s not accepts value '%s'", rpcsx_android.error("settingsSet: node %s not accepts value '%s'", path,
unwrap(env, jpath), value.dump()); value.dump());
return false; return false;
} }
@ -2632,13 +2621,8 @@ extern "C" JNIEXPORT jboolean JNICALL Java_net_rpcsx_RPCSX_settingsSet(
return true; return true;
} }
extern "C" JNIEXPORT jboolean JNICALL extern "C" std::string _rpcsx_getVersion() {
Java_net_rpcsx_RPCSX_supportsCustomDriverLoading(JNIEnv *env, return rx::getVersion().toString();
jobject instance) {
return access("/dev/kgsl-3d0", F_OK) == 0;
} }
extern "C" JNIEXPORT jstring JNICALL #pragma GCC diagnostic pop
Java_net_rpcsx_RPCSX_getVersion(JNIEnv *env, jobject) {
return wrap(env, rx::getVersion().toString());
}