1- #include " nlohmann/json.hpp"
1+ #include " internal/AndroidUtils.h"
2+ #include " internal/Logger.h"
3+ #include " internal/ModManager.h"
24#include < android/native_activity.h>
35#include < dlfcn.h>
4- #include < filesystem>
5- #include < fstream>
6- #include < jni.h>
7- #include < string>
8- #include < string_view>
9-
10- #include " internal/Logger.h"
11- #include " internal/StringUtils.h"
12-
13- JNIEnv *env = nullptr ;
14-
15- jobject getGlobalContext (JNIEnv *env) {
16- jclass activity_thread = env->FindClass (" android/app/ActivityThread" );
17- if (!activity_thread)
18- return nullptr ;
19- jmethodID current_activity_thread =
20- env->GetStaticMethodID (activity_thread, " currentActivityThread" ,
21- " ()Landroid/app/ActivityThread;" );
22- if (!current_activity_thread) {
23- env->DeleteLocalRef (activity_thread);
24- return nullptr ;
25- }
26- jobject at =
27- env->CallStaticObjectMethod (activity_thread, current_activity_thread);
28- if (!at || env->ExceptionCheck ()) {
29- env->ExceptionClear ();
30- env->DeleteLocalRef (activity_thread);
31- return nullptr ;
32- }
33- jmethodID get_application = env->GetMethodID (
34- activity_thread, " getApplication" , " ()Landroid/app/Application;" );
35- jobject context = env->CallObjectMethod (at, get_application);
36- if (env->ExceptionCheck ())
37- env->ExceptionClear ();
38-
39- env->DeleteLocalRef (activity_thread);
40- env->DeleteLocalRef (at);
41- return context;
42- }
436
44- std::string getAbsolutePath (JNIEnv *env, jobject file) {
45- jclass file_class = env->GetObjectClass (file);
46- jmethodID get_abs_path =
47- env->GetMethodID (file_class, " getAbsolutePath" , " ()Ljava/lang/String;" );
48- jstring jstr = (jstring)env->CallObjectMethod (file, get_abs_path);
49- std::string result;
50-
51- if (env->ExceptionCheck () || !jstr) {
52- env->ExceptionClear ();
53- env->DeleteLocalRef (file_class);
54- return result;
55- }
56- const char *cstr = env->GetStringUTFChars (jstr, nullptr );
57- result = cstr;
58- env->ReleaseStringUTFChars (jstr, cstr);
59- env->DeleteLocalRef (jstr);
60- env->DeleteLocalRef (file_class);
61- return result;
62- }
7+ JavaVM *g_vm = nullptr ;
638
64- std::string getSelectedModsDir (JNIEnv *env, jobject context) {
65- jclass versionManagerClass =
66- env->FindClass (" org/levimc/launcher/core/versions/VersionManager" );
67- if (!versionManagerClass)
68- return " " ;
69-
70- jmethodID getSelectedModsDirMethod =
71- env->GetStaticMethodID (versionManagerClass, " getSelectedModsDir" ,
72- " (Landroid/content/Context;)Ljava/lang/String;" );
73- if (!getSelectedModsDirMethod) {
74- env->DeleteLocalRef (versionManagerClass);
75- return " " ;
76- }
77-
78- jstring modsDirPathJstr = (jstring)env->CallStaticObjectMethod (
79- versionManagerClass, getSelectedModsDirMethod, context);
80- if (!modsDirPathJstr) {
81- env->DeleteLocalRef (versionManagerClass);
82- return " " ;
83- }
84-
85- const char *chars = env->GetStringUTFChars (modsDirPathJstr, nullptr );
86- std::string modsDirPath = chars ? chars : " " ;
87- env->ReleaseStringUTFChars (modsDirPathJstr, chars);
88-
89- env->DeleteLocalRef (modsDirPathJstr);
90- env->DeleteLocalRef (versionManagerClass);
91-
92- return modsDirPath;
93- }
94-
95- namespace pl {
96- namespace fs = std::filesystem;
97-
98- static bool endsWithSo (const std::string &filename) {
99- if (filename.length () >= 3 ) {
100- return (0 == filename.compare (filename.length () - 3 , 3 , " .so" ));
101- }
102- return false ;
103- }
104-
105- static bool isModEnabled (const fs::path &json_path,
106- const std::string &mod_filename) {
107- if (!fs::exists (json_path))
108- return false ;
109- std::ifstream json_file (json_path);
110- if (!json_file)
111- return false ;
112- nlohmann::json mods_config;
113- try {
114- json_file >> mods_config;
115- } catch (...) {
116- return false ;
117- }
118- auto it = mods_config.find (mod_filename);
119- if (it != mods_config.end ())
120- return it.value ().get <bool >();
121- return false ;
122- }
123-
124- void loadPreloadNativeMods () {
125- jobject appContext = getGlobalContext (env);
126- if (!appContext)
127- return ;
128- jclass contextClass = env->GetObjectClass (appContext);
129- jmethodID get_files_dir =
130- env->GetMethodID (contextClass, " getFilesDir" , " ()Ljava/io/File;" );
131- jobject filesDir = env->CallObjectMethod (appContext, get_files_dir);
132- std::string dataDir = getAbsolutePath (env, filesDir);
133- if (!dataDir.empty () && filesDir)
134- env->DeleteLocalRef (filesDir);
135- if (contextClass)
136- env->DeleteLocalRef (contextClass);
137-
138- auto dirStr = getSelectedModsDir (env, appContext);
139- if (appContext)
140- env->DeleteLocalRef (appContext);
141- fs::path modsDir (dirStr);
142- fs::path configPath = modsDir / " mods_config.json" ;
143-
144- if (!fs::exists (modsDir))
145- return ;
146-
147- for (const auto &entry : fs::directory_iterator (modsDir)) {
148- if (entry.is_regular_file ()) {
149- auto fname = entry.path ().filename ().string ();
150- if (!endsWithSo (fname))
151- continue ;
152-
153- std::string libName =
154- pl::utils::u8str2str (entry.path ().stem ().u8string ()) + " .so" ;
155- if (!isModEnabled (configPath, libName)) {
156- pl::log::Info (" {} is not enabled, skip loading." , libName);
157- continue ;
158- }
159- fs::path destPath = fs::path (dataDir) / entry.path ().filename ();
160- try {
161- fs::copy_file (entry, destPath, fs::copy_options::overwrite_existing);
162- fs::permissions (destPath, fs::perms::owner_all | fs::perms::group_all);
163- } catch (std::exception &e) {
164- pl::log::Error (" File operation error: {}" , e.what ());
165- continue ;
166- }
167- if (void *handle = dlopen (destPath.c_str (), RTLD_NOW)) {
168- pl::log::Info (" {} Loaded." , libName);
169- } else {
170- pl::log::Error (" Can't load {}" , libName);
171- pl::log::Error (" %s" , dlerror ());
172- }
173- }
174- }
175- }
176-
177- void init () { loadPreloadNativeMods (); }
178-
179- } // namespace pl
180-
181- static void (*android_main_minecraft)(struct android_app *app) = nullptr;
1829static void (*ANativeActivity_onCreate_minecraft)(ANativeActivity *, void *,
18310 size_t ) = nullptr;
18411
185- extern " C" void android_main (struct android_app *app) {
186- if (android_main_minecraft)
187- android_main_minecraft (app);
188- pl::init ();
189- }
190-
19112extern " C" void ANativeActivity_onCreate (ANativeActivity *activity,
19213 void *savedState,
19314 size_t savedStateSize) {
194- if (ANativeActivity_onCreate_minecraft)
15+ if (ANativeActivity_onCreate_minecraft) {
19516 ANativeActivity_onCreate_minecraft (activity, savedState, savedStateSize);
17+ }
19618}
19719
19820JNIEXPORT jint JNI_OnLoad (JavaVM *vm, void *) {
21+ g_vm = vm;
22+ JNIEnv *env = nullptr ;
23+ if (vm->GetEnv (reinterpret_cast <void **>(&env), JNI_VERSION_1_4) != JNI_OK)
24+ return JNI_VERSION_1_4;
25+
26+ auto paths = AndroidUtils::FetchContextPaths (env);
27+ ModManager::LoadAndInitializeEnabledMods (paths.modsDir , paths.cacheDir , g_vm);
28+
19929 void *handle = dlopen (" libminecraftpe.so" , RTLD_LAZY);
20030 if (handle) {
201- android_main_minecraft =
202- (void (*)(struct android_app *))dlsym (handle, " android_main" );
20331 ANativeActivity_onCreate_minecraft =
20432 (void (*)(ANativeActivity *, void *, size_t ))dlsym (
20533 handle, " ANativeActivity_onCreate" );
20634 }
207- if (vm->GetEnv (reinterpret_cast <void **>(&env), JNI_VERSION_1_4) != JNI_OK) {
208- return JNI_VERSION_1_4;
209- }
21035 return JNI_VERSION_1_4;
21136}
0 commit comments