diff options
author | WlodekM <[email protected]> | 2024-06-16 10:35:45 +0300 |
---|---|---|
committer | WlodekM <[email protected]> | 2024-06-16 10:35:45 +0300 |
commit | abef6da56913f1c55528103e60a50451a39628b1 (patch) | |
tree | b3c8092471ecbb73e568cd0d336efa0e7871ee8d /src/Platform_Android.c |
initial commit
Diffstat (limited to 'src/Platform_Android.c')
-rw-r--r-- | src/Platform_Android.c | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/src/Platform_Android.c b/src/Platform_Android.c new file mode 100644 index 0000000..e3b3a74 --- /dev/null +++ b/src/Platform_Android.c @@ -0,0 +1,253 @@ +#include "Core.h" +#if defined CC_BUILD_ANDROID +#include "Chat.h" +#include "Constants.h" +#include "Errors.h" +#include "Funcs.h" +#include "String.h" +#include "Platform.h" +#include <errno.h> +#include <unistd.h> +#include <android/log.h> + + +/*########################################################################################################################* +*------------------------------------------------------Logging/Time-------------------------------------------------------* +*#########################################################################################################################*/ +void Platform_Log(const char* msg, int len) { + char tmp[2048 + 1]; + len = min(len, 2048); + + Mem_Copy(tmp, msg, len); tmp[len] = '\0'; + /* log using logchat */ + __android_log_write(ANDROID_LOG_DEBUG, "ClassiCube", tmp); +} + + +/*########################################################################################################################* +*-----------------------------------------------------Process/Module------------------------------------------------------* +*#########################################################################################################################*/ +cc_result Process_StartOpen(const cc_string* args) { + JavaCall_String_Void("startOpen", args); + return 0; +} + + +/*########################################################################################################################* +*--------------------------------------------------------Updater----------------------------------------------------------* +*#########################################################################################################################*/ +const struct UpdaterInfo Updater_Info = { + "&eRedownload and reinstall to update", 0 +}; +cc_bool Updater_Clean(void) { return true; } + +cc_result Updater_GetBuildTime(cc_uint64* t) { + JNIEnv* env; + JavaGetCurrentEnv(env); + *t = JavaCallLong(env, "getApkUpdateTime", "()J", NULL); + return 0; +} + +cc_result Updater_Start(const char** action) { *action = "Updating game"; return ERR_NOT_SUPPORTED; } +cc_result Updater_MarkExecutable(void) { return 0; } +cc_result Updater_SetNewBuildTime(cc_uint64 t) { return ERR_NOT_SUPPORTED; } + + +/*########################################################################################################################* +*--------------------------------------------------------Platform---------------------------------------------------------* +*#########################################################################################################################*/ +void Platform_TryLogJavaError(void) { + JNIEnv* env; + jthrowable err; + JavaGetCurrentEnv(env); + + err = (*env)->ExceptionOccurred(env); + if (!err) return; + + Platform_LogConst("PANIC"); + (*env)->ExceptionDescribe(env); + (*env)->ExceptionClear(env); + /* TODO actually do something */ +} + +void Platform_ShareScreenshot(const cc_string* filename) { + cc_string path; char pathBuffer[FILENAME_SIZE]; + String_InitArray(path, pathBuffer); + + JavaCall_String_String("shareScreenshot", filename, &path); + if (!path.length) return; + + Chat_AddRaw("&cError sharing screenshot"); + Chat_Add1(" &c%s", &path); +} + +void Directory_GetCachePath(cc_string* path) { + // TODO cache method ID + JavaCall_Void_String("getGameCacheDirectory", path); +} + + +/*########################################################################################################################* +*-----------------------------------------------------Configuration-------------------------------------------------------* +*#########################################################################################################################*/ +#include "Window.h" +cc_result Platform_SetDefaultCurrentDirectory(int argc, char **argv) { + cc_string dir; char dirBuffer[FILENAME_SIZE + 1]; + String_InitArray_NT(dir, dirBuffer); + + JavaCall_Void_String("getGameDataDirectory", &dir); + dir.buffer[dir.length] = '\0'; + Platform_Log1("DATA DIR: %s|", &dir); + + int res = chdir(dir.buffer) == -1 ? errno : 0; + if (!res) return 0; + + // show the path to the user + // TODO there must be a better way + Window_ShowDialog("Failed to set working directory to", dir.buffer); + return res; +} + + +/*########################################################################################################################* +*-----------------------------------------------------Java Interop--------------------------------------------------------* +*#########################################################################################################################*/ +jclass App_Class; +jobject App_Instance; +JavaVM* VM_Ptr; + +/* JNI helpers */ +cc_string JavaGetString(JNIEnv* env, jstring str, char* buffer) { + const char* src; int len; + cc_string dst; + src = (*env)->GetStringUTFChars(env, str, NULL); + len = (*env)->GetStringUTFLength(env, str); + + dst.buffer = buffer; + dst.length = 0; + dst.capacity = NATIVE_STR_LEN; + String_AppendUtf8(&dst, src, len); + + (*env)->ReleaseStringUTFChars(env, str, src); + return dst; +} + +jobject JavaMakeString(JNIEnv* env, const cc_string* str) { + cc_uint8 tmp[2048 + 4]; + cc_uint8* cur; + int i, len = 0; + + for (i = 0; i < str->length && len < 2048; i++) { + cur = tmp + len; + len += Convert_CP437ToUtf8(str->buffer[i], cur); + } + tmp[len] = '\0'; + return (*env)->NewStringUTF(env, (const char*)tmp); +} + +jbyteArray JavaMakeBytes(JNIEnv* env, const void* src, cc_uint32 len) { + if (!len) return NULL; + jbyteArray arr = (*env)->NewByteArray(env, len); + (*env)->SetByteArrayRegion(env, arr, 0, len, src); + return arr; +} + +void JavaCallVoid(JNIEnv* env, const char* name, const char* sig, jvalue* args) { + jmethodID method = (*env)->GetMethodID(env, App_Class, name, sig); + (*env)->CallVoidMethodA(env, App_Instance, method, args); +} + +jlong JavaCallLong(JNIEnv* env, const char* name, const char* sig, jvalue* args) { + jmethodID method = (*env)->GetMethodID(env, App_Class, name, sig); + return (*env)->CallLongMethodA(env, App_Instance, method, args); +} + +jobject JavaCallObject(JNIEnv* env, const char* name, const char* sig, jvalue* args) { + jmethodID method = (*env)->GetMethodID(env, App_Class, name, sig); + return (*env)->CallObjectMethodA(env, App_Instance, method, args); +} + +void JavaCall_String_Void(const char* name, const cc_string* value) { + JNIEnv* env; + jvalue args[1]; + JavaGetCurrentEnv(env); + + args[0].l = JavaMakeString(env, value); + JavaCallVoid(env, name, "(Ljava/lang/String;)V", args); + (*env)->DeleteLocalRef(env, args[0].l); +} + +static void ReturnString(JNIEnv* env, jobject obj, cc_string* dst) { + const jchar* src; + jsize len; + if (!obj) return; + + src = (*env)->GetStringChars(env, obj, NULL); + len = (*env)->GetStringLength(env, obj); + String_AppendUtf16(dst, src, len * 2); + (*env)->ReleaseStringChars(env, obj, src); + (*env)->DeleteLocalRef(env, obj); +} + +void JavaCall_Void_String(const char* name, cc_string* dst) { + JNIEnv* env; + jobject obj; + JavaGetCurrentEnv(env); + + obj = JavaCallObject(env, name, "()Ljava/lang/String;", NULL); + ReturnString(env, obj, dst); +} + +void JavaCall_String_String(const char* name, const cc_string* arg, cc_string* dst) { + JNIEnv* env; + jobject obj; + jvalue args[1]; + JavaGetCurrentEnv(env); + + args[0].l = JavaMakeString(env, arg); + obj = JavaCallObject(env, name, "(Ljava/lang/String;)Ljava/lang/String;", args); + ReturnString(env, obj, dst); + (*env)->DeleteLocalRef(env, args[0].l); +} + + +/*########################################################################################################################* +*----------------------------------------------------Initialisation-------------------------------------------------------* +*#########################################################################################################################*/ +extern void android_main(void); +static void JNICALL java_updateInstance(JNIEnv* env, jobject instance) { + Platform_LogConst("App instance updated!"); + App_Instance = (*env)->NewGlobalRef(env, instance); + /* TODO: Do we actually need to remove that global ref later? */ +} + +/* Called eventually by the activity java class to actually start the game */ +static void JNICALL java_runGameAsync(JNIEnv* env, jobject instance) { + void* thread; + java_updateInstance(env, instance); + + Platform_LogConst("Running game async!"); + /* The game must be run on a separate thread, as blocking the */ + /* main UI thread will cause a 'App not responding..' messagebox */ + Thread_Run(&thread, android_main, 1024 * 1024, "Game"); // TODO check stack size needed + Thread_Detach(thread); +} +static const JNINativeMethod methods[] = { + { "updateInstance", "()V", java_updateInstance }, + { "runGameAsync", "()V", java_runGameAsync } +}; + +/* This method is automatically called by the Java VM when the */ +/* activity java class calls 'System.loadLibrary("classicube");' */ +CC_API jint JNI_OnLoad(JavaVM* vm, void* reserved) { + jclass klass; + JNIEnv* env; + VM_Ptr = vm; + JavaGetCurrentEnv(env); + + klass = (*env)->FindClass(env, "com/classicube/MainActivity"); + App_Class = (*env)->NewGlobalRef(env, klass); + JavaRegisterNatives(env, methods); + return JNI_VERSION_1_4; +} +#endif |