From 2d86b8734b9eb753ab6ff45fbea0ac3689dc49bf Mon Sep 17 00:00:00 2001 From: Karim Akra Date: Wed, 14 Jan 2026 19:51:29 +0200 Subject: [PATCH 01/23] WIP Android AAsets_Manager IO --- source/engine/mobile/backend/Assets.hx | 9 ++ .../engine/mobile/backend/android/Assets.hx | 143 ++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 source/engine/mobile/backend/Assets.hx create mode 100644 source/engine/mobile/backend/android/Assets.hx diff --git a/source/engine/mobile/backend/Assets.hx b/source/engine/mobile/backend/Assets.hx new file mode 100644 index 00000000..e7d6a316 --- /dev/null +++ b/source/engine/mobile/backend/Assets.hx @@ -0,0 +1,9 @@ +package mobile.backend; + +#if android +typedef Assets = mobile.backend.android.Assets; +// #elseif ios +// typedef Assets = mobile.backend.ios.Assets; +#else +typedef Assets = Dynamic; +#end \ No newline at end of file diff --git a/source/engine/mobile/backend/android/Assets.hx b/source/engine/mobile/backend/android/Assets.hx new file mode 100644 index 00000000..39d7eefb --- /dev/null +++ b/source/engine/mobile/backend/android/Assets.hx @@ -0,0 +1,143 @@ +package mobile.backend.android; + +// Code is mostly taken from SDL. +// This class implements IO methods for the native android NDK AAsets_Manager to read bundled app assets. + +#if android +@:cppNamespaceCode(' +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct LocalReferenceHolder +{ + JNIEnv *m_env; + const char *m_func; +}; + +// static int AtomicIncRef(a) +// { +// return __sync_fetch_and_add (a, 1) +// } + +static struct LocalReferenceHolder LocalReferenceHolder_Setup(const char *func) +{ + struct LocalReferenceHolder refholder; + refholder.m_env = NULL; + refholder.m_func = func; + __android_log_print (ANDROID_LOG_DEBUG, "Shadow Engine", "Entering function %s", func); + return refholder; +} + +static bool LocalReferenceHolder_Init(struct LocalReferenceHolder *refholder, JNIEnv *env) +{ + const int capacity = 16; + if ((*env).PushLocalFrame(capacity) < 0) { + __android_log_print (ANDROID_LOG_ERROR, "Shadow Engine", "Failed to allocate enough JVM local references"); + return false; + } + // AtomicIncRef(&s_active); + refholder->m_env = env; + return true; +} + +static void LocalReferenceHolder_Cleanup(struct LocalReferenceHolder *refholder) +{ + __android_log_print (ANDROID_LOG_DEBUG, "Shadow Engine", "Leaving function %s", refholder->m_func); + if (refholder->m_env) { + JNIEnv *env = refholder->m_env; + (*env).PopLocalFrame(NULL); + // AtomicIncRef(&s_active); + } +} +static jmethodID midGetContext; +static jclass mActivityClass; +static AAssetManager *asset_manager = NULL; +static jobject javaAssetManagerRef = 0; +') +class Assets +{ + @:functionCode(' + JNIEnv* env = (JNIEnv*)(uintptr_t)a; + // JNIEnv *env = (JNIEnv *)JNI::GetEnv(); + + jclass cls = env->FindClass("org/libsdl/app/SDLActivity"); + mActivityClass = (jclass)((*env).NewGlobalRef(cls)); + + struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__); + jmethodID mid; + jobject context; + jobject javaAssetManager; + + if (!LocalReferenceHolder_Init(&refs, env)) { + LocalReferenceHolder_Cleanup(&refs); + return; + } + + /* context = SDLActivity.getContext(); */ + midGetContext = (*env).GetStaticMethodID(mActivityClass, "getContext","()Landroid/content/Context;"); + context = (*env).CallStaticObjectMethod(mActivityClass, midGetContext); + + /* javaAssetManager = context.getAssets(); */ + mid = (*env).GetMethodID((*env).GetObjectClass(context), + "getAssets", "()Landroid/content/res/AssetManager;"); + javaAssetManager = (*env).CallObjectMethod(context, mid); + + /** + * Given a Dalvik AssetManager object, obtain the corresponding native AAssetManager + * object. Note that the caller is responsible for obtaining and holding a VM reference + * to the jobject to prevent its being garbage collected while the native object is + * in use. + */ + javaAssetManagerRef = (*env).NewGlobalRef(javaAssetManager); + asset_manager = AAssetManager_fromJava(env, javaAssetManagerRef); + + if (asset_manager == NULL) { + (*env).DeleteGlobalRef(javaAssetManagerRef); + __android_log_print (ANDROID_LOG_DEBUG, "Shadow Engine", "Failed to create Android Assets Manager"); + } + + LocalReferenceHolder_Cleanup(&refs); + ') + public static function init(a:Dynamic):Void + { + return; + } + + @:functionCode(' + JNIEnv* env = (JNIEnv*)(uintptr_t)a; + // JNIEnv *env = (JNIEnv *)JNI::GetEnv(); + + if (asset_manager) { + (*env).DeleteGlobalRef(javaAssetManagerRef); + asset_manager = NULL; + } + ') + public static function destroy(a:Dynamic):Void + { + return; + } + + @:functionCode(' + AAsset* asset = AAssetManager_open(asset_manager, file, AASSET_MODE_UNKNOWN); + + bool ret = asset != NULL; + + if (ret) + AAsset_close(asset); + + return ret; + ') + public static function exists(file:cpp.ConstCharStar):Bool + { + return false; + } + +} +#end \ No newline at end of file From 37b9121dd649eab75efc2f3ce3fa75faa5b78363 Mon Sep 17 00:00:00 2001 From: Karim Akra Date: Wed, 14 Jan 2026 20:17:58 +0200 Subject: [PATCH 02/23] remove useless lines --- source/engine/mobile/backend/android/Assets.hx | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/source/engine/mobile/backend/android/Assets.hx b/source/engine/mobile/backend/android/Assets.hx index 39d7eefb..569e0f2a 100644 --- a/source/engine/mobile/backend/android/Assets.hx +++ b/source/engine/mobile/backend/android/Assets.hx @@ -1,7 +1,7 @@ package mobile.backend.android; // Code is mostly taken from SDL. -// This class implements IO methods for the native android NDK AAsets_Manager to read bundled app assets. +// This class implements IO methods for the native android NDK AAsset_Manager to read bundled app assets. #if android @:cppNamespaceCode(' @@ -21,11 +21,6 @@ struct LocalReferenceHolder const char *m_func; }; -// static int AtomicIncRef(a) -// { -// return __sync_fetch_and_add (a, 1) -// } - static struct LocalReferenceHolder LocalReferenceHolder_Setup(const char *func) { struct LocalReferenceHolder refholder; @@ -42,7 +37,6 @@ static bool LocalReferenceHolder_Init(struct LocalReferenceHolder *refholder, JN __android_log_print (ANDROID_LOG_ERROR, "Shadow Engine", "Failed to allocate enough JVM local references"); return false; } - // AtomicIncRef(&s_active); refholder->m_env = env; return true; } @@ -53,9 +47,9 @@ static void LocalReferenceHolder_Cleanup(struct LocalReferenceHolder *refholder) if (refholder->m_env) { JNIEnv *env = refholder->m_env; (*env).PopLocalFrame(NULL); - // AtomicIncRef(&s_active); } } + static jmethodID midGetContext; static jclass mActivityClass; static AAssetManager *asset_manager = NULL; @@ -65,7 +59,6 @@ class Assets { @:functionCode(' JNIEnv* env = (JNIEnv*)(uintptr_t)a; - // JNIEnv *env = (JNIEnv *)JNI::GetEnv(); jclass cls = env->FindClass("org/libsdl/app/SDLActivity"); mActivityClass = (jclass)((*env).NewGlobalRef(cls)); @@ -112,7 +105,6 @@ class Assets @:functionCode(' JNIEnv* env = (JNIEnv*)(uintptr_t)a; - // JNIEnv *env = (JNIEnv *)JNI::GetEnv(); if (asset_manager) { (*env).DeleteGlobalRef(javaAssetManagerRef); From 23067bf1ce7611aa36f7f46cb955394ac7ecf668 Mon Sep 17 00:00:00 2001 From: Homura Date: Fri, 16 Jan 2026 00:38:54 +0300 Subject: [PATCH 03/23] rewrite some comments --- source/engine/mobile/backend/android/Assets.hx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/source/engine/mobile/backend/android/Assets.hx b/source/engine/mobile/backend/android/Assets.hx index 569e0f2a..26939210 100644 --- a/source/engine/mobile/backend/android/Assets.hx +++ b/source/engine/mobile/backend/android/Assets.hx @@ -1,7 +1,9 @@ package mobile.backend.android; -// Code is mostly taken from SDL. -// This class implements IO methods for the native android NDK AAsset_Manager to read bundled app assets. +/** + * The code for this class is mostly taken from SDL2. + * This class implements IO methods for the native Android NDK's AAAssetManager to read bundled app assets. + */ #if android @:cppNamespaceCode(' @@ -73,11 +75,11 @@ class Assets return; } - /* context = SDLActivity.getContext(); */ + // context = SDLActivity.getContext(); midGetContext = (*env).GetStaticMethodID(mActivityClass, "getContext","()Landroid/content/Context;"); context = (*env).CallStaticObjectMethod(mActivityClass, midGetContext); - /* javaAssetManager = context.getAssets(); */ + // javaAssetManager = context.getAssets(); mid = (*env).GetMethodID((*env).GetObjectClass(context), "getAssets", "()Landroid/content/res/AssetManager;"); javaAssetManager = (*env).CallObjectMethod(context, mid); @@ -132,4 +134,4 @@ class Assets } } -#end \ No newline at end of file +#end From e0662f862bc74a30f7d9100baf07d53afca58446 Mon Sep 17 00:00:00 2001 From: Homura Date: Fri, 16 Jan 2026 00:40:18 +0300 Subject: [PATCH 04/23] oops --- source/engine/mobile/backend/android/Assets.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/engine/mobile/backend/android/Assets.hx b/source/engine/mobile/backend/android/Assets.hx index 26939210..39015acc 100644 --- a/source/engine/mobile/backend/android/Assets.hx +++ b/source/engine/mobile/backend/android/Assets.hx @@ -2,7 +2,7 @@ package mobile.backend.android; /** * The code for this class is mostly taken from SDL2. - * This class implements IO methods for the native Android NDK's AAAssetManager to read bundled app assets. + * This class implements IO methods from the Android NDK's AAssetManager to read bundled app assets. */ #if android From 674766578a6156003ade96317387ac7ce3fc2290 Mon Sep 17 00:00:00 2001 From: Karim Akra Date: Fri, 16 Jan 2026 14:50:09 +0200 Subject: [PATCH 05/23] move all c++ functions to cppNamespaceCode --- .../engine/mobile/backend/android/Assets.hx | 157 ++++++++++-------- 1 file changed, 90 insertions(+), 67 deletions(-) diff --git a/source/engine/mobile/backend/android/Assets.hx b/source/engine/mobile/backend/android/Assets.hx index 39015acc..2e57e9de 100644 --- a/source/engine/mobile/backend/android/Assets.hx +++ b/source/engine/mobile/backend/android/Assets.hx @@ -17,6 +17,11 @@ package mobile.backend.android; #include #include +static jmethodID midGetContext; +static jclass mActivityClass; +static AAssetManager *asset_manager = NULL; +static jobject javaAssetManagerRef = 0; + struct LocalReferenceHolder { JNIEnv *m_env; @@ -52,86 +57,104 @@ static void LocalReferenceHolder_Cleanup(struct LocalReferenceHolder *refholder) } } -static jmethodID midGetContext; -static jclass mActivityClass; -static AAssetManager *asset_manager = NULL; -static jobject javaAssetManagerRef = 0; +void Assets_obj::native_init(::Dynamic jni_env) +{ + JNIEnv* env = (JNIEnv*)(uintptr_t)jni_env; + jclass cls = env->FindClass("org/libsdl/app/SDLActivity"); + mActivityClass = (jclass)((*env).NewGlobalRef(cls)); + + struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__); + jmethodID mid; + jobject context; + jobject javaAssetManager; + + if (!LocalReferenceHolder_Init(&refs, env)) { + LocalReferenceHolder_Cleanup(&refs); + return; + } + + // context = SDLActivity.getContext(); + midGetContext = (*env).GetStaticMethodID(mActivityClass, "getContext","()Landroid/content/Context;"); + context = (*env).CallStaticObjectMethod(mActivityClass, midGetContext); + + // javaAssetManager = context.getAssets(); + mid = (*env).GetMethodID((*env).GetObjectClass(context), + "getAssets", "()Landroid/content/res/AssetManager;"); + javaAssetManager = (*env).CallObjectMethod(context, mid); + + /** + * Given a Dalvik AssetManager object, obtain the corresponding native AAssetManager + * object. Note that the caller is responsible for obtaining and holding a VM reference + * to the jobject to prevent its being garbage collected while the native object is + * in use. + */ + javaAssetManagerRef = (*env).NewGlobalRef(javaAssetManager); + asset_manager = AAssetManager_fromJava(env, javaAssetManagerRef); + + if (asset_manager == NULL) { + (*env).DeleteGlobalRef(javaAssetManagerRef); + __android_log_print (ANDROID_LOG_DEBUG, "Shadow Engine", "Failed to create Android Assets Manager"); + } + + LocalReferenceHolder_Cleanup(&refs); +} + +void Assets_obj::native_destroy(::Dynamic jni_env) +{ + JNIEnv* env = (JNIEnv*)(uintptr_t)jni_env; + + if (asset_manager) { + (*env).DeleteGlobalRef(javaAssetManagerRef); + asset_manager = NULL; + } +} + +bool Assets_obj::native_exists(const char* file) +{ + AAsset* asset = AAssetManager_open(asset_manager, file, AASSET_MODE_UNKNOWN); + bool ret = asset != NULL; + + if (ret) + AAsset_close(asset); + + return ret; +} +') +@:headerClassCode(' +static bool native_exists(const char* file); +static void native_init(::Dynamic jni_env); +static void native_destroy(::Dynamic jni_env); ') class Assets { - @:functionCode(' - JNIEnv* env = (JNIEnv*)(uintptr_t)a; - - jclass cls = env->FindClass("org/libsdl/app/SDLActivity"); - mActivityClass = (jclass)((*env).NewGlobalRef(cls)); - - struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__); - jmethodID mid; - jobject context; - jobject javaAssetManager; - - if (!LocalReferenceHolder_Init(&refs, env)) { - LocalReferenceHolder_Cleanup(&refs); - return; - } - - // context = SDLActivity.getContext(); - midGetContext = (*env).GetStaticMethodID(mActivityClass, "getContext","()Landroid/content/Context;"); - context = (*env).CallStaticObjectMethod(mActivityClass, midGetContext); - - // javaAssetManager = context.getAssets(); - mid = (*env).GetMethodID((*env).GetObjectClass(context), - "getAssets", "()Landroid/content/res/AssetManager;"); - javaAssetManager = (*env).CallObjectMethod(context, mid); - - /** - * Given a Dalvik AssetManager object, obtain the corresponding native AAssetManager - * object. Note that the caller is responsible for obtaining and holding a VM reference - * to the jobject to prevent its being garbage collected while the native object is - * in use. - */ - javaAssetManagerRef = (*env).NewGlobalRef(javaAssetManager); - asset_manager = AAssetManager_fromJava(env, javaAssetManagerRef); - - if (asset_manager == NULL) { - (*env).DeleteGlobalRef(javaAssetManagerRef); - __android_log_print (ANDROID_LOG_DEBUG, "Shadow Engine", "Failed to create Android Assets Manager"); - } - - LocalReferenceHolder_Cleanup(&refs); - ') - public static function init(a:Dynamic):Void + public static function init():Void { - return; + _init(lime.system.JNI.getEnv()); } - @:functionCode(' - JNIEnv* env = (JNIEnv*)(uintptr_t)a; - - if (asset_manager) { - (*env).DeleteGlobalRef(javaAssetManagerRef); - asset_manager = NULL; - } - ') - public static function destroy(a:Dynamic):Void + public static function destroy():Void { - return; + _destroy(lime.system.JNI.getEnv()); } - @:functionCode(' - AAsset* asset = AAssetManager_open(asset_manager, file, AASSET_MODE_UNKNOWN); - - bool ret = asset != NULL; - - if (ret) - AAsset_close(asset); - - return ret; - ') + @:native('mobile::backend::android::Assets_obj::native_exists') public static function exists(file:cpp.ConstCharStar):Bool { return false; } + @:noCompletion + @:native('mobile::backend::android::Assets_obj::native_init') + private static function _init(jni_env:Dynamic):Void + { + return; + } + + @:noCompletion + @:native('mobile::backend::android::Assets_obj::native_destroy') + private static function _destroy(jni_env:Dynamic):Void + { + return; + } } #end From 4a59019f8e6407b41af9f264e929912123bb6f34 Mon Sep 17 00:00:00 2001 From: Karim Akra Date: Fri, 16 Jan 2026 14:52:51 +0200 Subject: [PATCH 06/23] remove useless includes --- source/engine/mobile/backend/android/Assets.hx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/source/engine/mobile/backend/android/Assets.hx b/source/engine/mobile/backend/android/Assets.hx index 2e57e9de..0cc457d0 100644 --- a/source/engine/mobile/backend/android/Assets.hx +++ b/source/engine/mobile/backend/android/Assets.hx @@ -9,13 +9,7 @@ package mobile.backend.android; @:cppNamespaceCode(' #include #include -#include #include -#include -#include -#include -#include -#include static jmethodID midGetContext; static jclass mActivityClass; From 5600c9d89981a1e48490c19132cecc3e79602d8a Mon Sep 17 00:00:00 2001 From: Karim Akra Date: Fri, 16 Jan 2026 15:46:42 +0200 Subject: [PATCH 07/23] Added getBytes and getContent (fuck you GC) --- .../engine/mobile/backend/android/Assets.hx | 101 +++++++++++++++++- 1 file changed, 97 insertions(+), 4 deletions(-) diff --git a/source/engine/mobile/backend/android/Assets.hx b/source/engine/mobile/backend/android/Assets.hx index 0cc457d0..72f3feb1 100644 --- a/source/engine/mobile/backend/android/Assets.hx +++ b/source/engine/mobile/backend/android/Assets.hx @@ -103,9 +103,9 @@ void Assets_obj::native_destroy(::Dynamic jni_env) } } -bool Assets_obj::native_exists(const char* file) +bool Assets_obj::native_exists(::String file) { - AAsset* asset = AAssetManager_open(asset_manager, file, AASSET_MODE_UNKNOWN); + AAsset* asset = AAssetManager_open(asset_manager, file.__s, AASSET_MODE_UNKNOWN); bool ret = asset != NULL; if (ret) @@ -113,11 +113,70 @@ bool Assets_obj::native_exists(const char* file) return ret; } + +::String Assets_obj::native_getContent(::String file) { + std::vector buffer; + + hx::EnterGCFreeZone(); + AAsset* asset = AAssetManager_open(asset_manager, file.__s, AASSET_MODE_BUFFER); + + if (!asset) { + hx::ExitGCFreeZone(); + return ::String(null()); + } + + int len = AAsset_getLength(asset); + if (len <= 0) { + AAsset_close(asset); + hx::ExitGCFreeZone(); + return ::String::emptyString; + } + + const char* src = (const char*)AAsset_getBuffer(asset); + + buffer.resize(len); + memcpy(&buffer[0], src, len); + + AAsset_close(asset); + hx::ExitGCFreeZone(); + + return ::String::create(&buffer[0], buffer.size()); +} + +Array Assets_obj::native_getBytes(::String file) { + hx::EnterGCFreeZone(); + AAsset* asset = AAssetManager_open(asset_manager, file.__s, AASSET_MODE_BUFFER); + + if (!asset) { + hx::ExitGCFreeZone(); + return null(); + } + + int len = AAsset_getLength(asset); + const unsigned char* src = (const unsigned char*)AAsset_getBuffer(asset); + hx::ExitGCFreeZone(); + + Array buffer = Array_obj::__new(len, len); + if (len > 0) { + hx::EnterGCFreeZone(); + memcpy(buffer->getBase(), src, len); + AAsset_close(asset); + hx::ExitGCFreeZone(); + } else { + hx::EnterGCFreeZone(); + AAsset_close(asset); + hx::ExitGCFreeZone(); + } + + return buffer; +} ') @:headerClassCode(' -static bool native_exists(const char* file); static void native_init(::Dynamic jni_env); static void native_destroy(::Dynamic jni_env); +static bool native_exists(::String file); +static ::String native_getContent(::String file); +static Array native_getBytes(::String file); ') class Assets { @@ -131,8 +190,28 @@ class Assets _destroy(lime.system.JNI.getEnv()); } + public static function getContent(file:String):String + { + var content:String = _getContent(file); + + if (content == null) + throw 'file_contents, $file'; + + return content; + } + + public static function getBytes(file:String):haxe.io.Bytes + { + var data:Array = _getBytes(file); + + if (data == null || data.length <= 0) + throw 'file_contents, $file'; + + return haxe.io.Bytes.ofData(data); + } + @:native('mobile::backend::android::Assets_obj::native_exists') - public static function exists(file:cpp.ConstCharStar):Bool + public static function exists(file:String):Bool { return false; } @@ -150,5 +229,19 @@ class Assets { return; } + + @:noCompletion + @:native('mobile::backend::android::Assets_obj::native_getContent') + public static function _getContent(file:String):String + { + return null; + } + + @:noCompletion + @:native('mobile::backend::android::Assets_obj::native_getBytes') + private static function _getBytes(file:String):Array + { + return null; + } } #end From dc23e3ab5e0f36ffdbc5126a2fa0b4f3cd69601f Mon Sep 17 00:00:00 2001 From: Homura Date: Fri, 16 Jan 2026 19:27:48 +0300 Subject: [PATCH 08/23] `USE_OPENFL_FILESYSTEM` and move the Mobile IO class into `mobile.backend.io`` --- project.hxp | 2 + source/engine/backend/io/File.hx | 6 + source/engine/backend/io/FileSystem.hx | 75 ++++-- source/engine/mobile/backend/Assets.hx | 9 - .../engine/mobile/backend/android/Assets.hx | 247 ----------------- source/engine/mobile/backend/io/Assets.hx | 9 + .../mobile/backend/io/android/Assets.hx | 251 ++++++++++++++++++ 7 files changed, 315 insertions(+), 284 deletions(-) delete mode 100644 source/engine/mobile/backend/Assets.hx delete mode 100644 source/engine/mobile/backend/android/Assets.hx create mode 100644 source/engine/mobile/backend/io/Assets.hx create mode 100644 source/engine/mobile/backend/io/android/Assets.hx diff --git a/project.hxp b/project.hxp index fd6c3a1c..958260b8 100644 --- a/project.hxp +++ b/project.hxp @@ -32,6 +32,7 @@ class Project extends HXProject static final DISCORD_ALLOWED:CompileFlag = CompileFlag.get("DISCORD_ALLOWED"); static final MODCHARTS_ALLOWED:CompileFlag = CompileFlag.get("MODCHARTS_ALLOWED"); static final DCEBUILD:CompileFlag = CompileFlag.get("DCEBUILD"); + static final USE_OPENFL_FILESYSTEM:CompileFlag = CompileFlag.get("USE_OPENFL_FILESYSTEM"); static final ENABLE_ASCII_ART:Bool = true; @@ -213,6 +214,7 @@ class Project extends HXProject DISCORD_ALLOWED.integrate((isDesktop() && !isHashLink())); MODCHARTS_ALLOWED.integrate(/*DCEBUILD.isDisabled()*/false); DCEBUILD.integrate(false); + USE_OPENFL_FILESYSTEM.integrate(MODS_ALLOWED.isDisabled() || isMobile()); setHaxedef("FLX_NO_FOCUS_LOST_SCREEN"); if (!isDebug()) diff --git a/source/engine/backend/io/File.hx b/source/engine/backend/io/File.hx index c82fdd17..7a8f209c 100644 --- a/source/engine/backend/io/File.hx +++ b/source/engine/backend/io/File.hx @@ -24,6 +24,7 @@ class File return path; } + #if FILESYSTEM_OPENFL static function openflcwd(path:String):String { @:privateAccess @@ -33,6 +34,7 @@ class File return path; } + #end public static function getContent(path:String):Null { @@ -50,8 +52,10 @@ class File #end #end + #if FILESYSTEM_OPENFL if (Assets.exists(openflcwd(path))) return Assets.getText(openflcwd(path)); + #end return null; } @@ -72,6 +76,7 @@ class File #end #end + #if FILESYSTEM_OPENFL if (Assets.exists(openflcwd(path))) switch (haxe.io.Path.extension(path).toLowerCase()) { @@ -80,6 +85,7 @@ class File default: return Assets.getBytes(openflcwd(path)); } + #end return null; } diff --git a/source/engine/backend/io/FileSystem.hx b/source/engine/backend/io/FileSystem.hx index 17f90833..3fbd288f 100644 --- a/source/engine/backend/io/FileSystem.hx +++ b/source/engine/backend/io/FileSystem.hx @@ -23,6 +23,7 @@ class FileSystem return path; } + #if FILESYSTEM_OPENFL static function openflcwd(path:String):String { @:privateAccess @@ -32,6 +33,7 @@ class FileSystem return path; } + #end public static function exists(path:String):Bool { @@ -49,10 +51,12 @@ class FileSystem #end #end - if (Assets.exists(openflcwd(path))) + #if FILESYSTEM_OPENFL + if (Assets.exists(openflcwd(path)) || Assets.list().filter(asset -> asset.startsWith(path) && asset != path).length > 0) return true; + #end - return Assets.list().filter(asset -> asset.startsWith(path) && asset != path).length > 0; + return false; } public static function rename(path:String, newPath:String):Void @@ -139,7 +143,12 @@ class FileSystem #end #end - return Assets.list().filter(asset -> asset.startsWith(path) && asset != path).length > 0; + #if FILESYSTEM_OPENFL + if (Assets.list().filter(asset -> asset.startsWith(path) && asset != path).length > 0) + return true; + #end + + return false; } public static function createDirectory(path:String):Void @@ -186,44 +195,54 @@ class FileSystem public static function readDirectory(path:String):Array { + var result:Array = null; + #if MODS_ALLOWED #if linux - var actualPath:String = cwd(path); - actualPath = getCaseInsensitivePath(path); - if (actualPath == null) - actualPath = path; + var actualPath = cwd(path); + actualPath = getCaseInsensitivePath(path) ?? path; if (SysFileSystem.exists(actualPath) && SysFileSystem.isDirectory(actualPath)) - return SysFileSystem.readDirectory(actualPath); + result = SysFileSystem.readDirectory(actualPath); #else if (SysFileSystem.exists(cwd(path)) && SysFileSystem.isDirectory(cwd(path))) - return SysFileSystem.readDirectory(cwd(path) ); + result = SysFileSystem.readDirectory(cwd(path)); #end #end - var filteredList:Array = Assets.list().filter(f -> f.startsWith(path)); - var results:Array = []; - for (i in filteredList.copy()) + #if FILESYSTEM_OPENFL + if (result == null) { - var slashsCount:Int = path.split('/').length; - if (path.endsWith('/')) - slashsCount -= 1; + var filteredList = Assets.list().filter(f -> f.startsWith(path)); + var results:Array = []; - if (i.split('/').length - 1 != slashsCount) - filteredList.remove(i); - } - for (item in filteredList) - { - @:privateAccess - for (library in lime.utils.Assets.libraries.keys()) + for (i in filteredList.copy()) + { + var slashsCount = path.split('/').length; + if (path.endsWith('/')) + slashsCount--; + + if (i.split('/').length - 1 != slashsCount) + filteredList.remove(i); + } + + for (item in filteredList) { - var libPath:String = '$library:$item'; - if (library != 'default' && Assets.exists(libPath) && !results.contains(libPath)) - results.push(libPath); - else if (Assets.exists(item) && !results.contains(item)) - results.push(item); + @:privateAccess + for (library in lime.utils.Assets.libraries.keys()) + { + var libPath = '$library:$item'; + if (library != 'default' && Assets.exists(libPath) && !results.contains(libPath)) + results.push(libPath); + else if (Assets.exists(item) && !results.contains(item)) + results.push(item); + } } + + result = results.map(f -> f.substr(f.lastIndexOf("/") + 1)); } - return results.map(f -> f.substr(f.lastIndexOf("/") + 1)); + #end + + return result ?? []; } #if (linux && MODS_ALLOWED) diff --git a/source/engine/mobile/backend/Assets.hx b/source/engine/mobile/backend/Assets.hx deleted file mode 100644 index e7d6a316..00000000 --- a/source/engine/mobile/backend/Assets.hx +++ /dev/null @@ -1,9 +0,0 @@ -package mobile.backend; - -#if android -typedef Assets = mobile.backend.android.Assets; -// #elseif ios -// typedef Assets = mobile.backend.ios.Assets; -#else -typedef Assets = Dynamic; -#end \ No newline at end of file diff --git a/source/engine/mobile/backend/android/Assets.hx b/source/engine/mobile/backend/android/Assets.hx deleted file mode 100644 index 72f3feb1..00000000 --- a/source/engine/mobile/backend/android/Assets.hx +++ /dev/null @@ -1,247 +0,0 @@ -package mobile.backend.android; - -/** - * The code for this class is mostly taken from SDL2. - * This class implements IO methods from the Android NDK's AAssetManager to read bundled app assets. - */ - -#if android -@:cppNamespaceCode(' -#include -#include -#include - -static jmethodID midGetContext; -static jclass mActivityClass; -static AAssetManager *asset_manager = NULL; -static jobject javaAssetManagerRef = 0; - -struct LocalReferenceHolder -{ - JNIEnv *m_env; - const char *m_func; -}; - -static struct LocalReferenceHolder LocalReferenceHolder_Setup(const char *func) -{ - struct LocalReferenceHolder refholder; - refholder.m_env = NULL; - refholder.m_func = func; - __android_log_print (ANDROID_LOG_DEBUG, "Shadow Engine", "Entering function %s", func); - return refholder; -} - -static bool LocalReferenceHolder_Init(struct LocalReferenceHolder *refholder, JNIEnv *env) -{ - const int capacity = 16; - if ((*env).PushLocalFrame(capacity) < 0) { - __android_log_print (ANDROID_LOG_ERROR, "Shadow Engine", "Failed to allocate enough JVM local references"); - return false; - } - refholder->m_env = env; - return true; -} - -static void LocalReferenceHolder_Cleanup(struct LocalReferenceHolder *refholder) -{ - __android_log_print (ANDROID_LOG_DEBUG, "Shadow Engine", "Leaving function %s", refholder->m_func); - if (refholder->m_env) { - JNIEnv *env = refholder->m_env; - (*env).PopLocalFrame(NULL); - } -} - -void Assets_obj::native_init(::Dynamic jni_env) -{ - JNIEnv* env = (JNIEnv*)(uintptr_t)jni_env; - jclass cls = env->FindClass("org/libsdl/app/SDLActivity"); - mActivityClass = (jclass)((*env).NewGlobalRef(cls)); - - struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__); - jmethodID mid; - jobject context; - jobject javaAssetManager; - - if (!LocalReferenceHolder_Init(&refs, env)) { - LocalReferenceHolder_Cleanup(&refs); - return; - } - - // context = SDLActivity.getContext(); - midGetContext = (*env).GetStaticMethodID(mActivityClass, "getContext","()Landroid/content/Context;"); - context = (*env).CallStaticObjectMethod(mActivityClass, midGetContext); - - // javaAssetManager = context.getAssets(); - mid = (*env).GetMethodID((*env).GetObjectClass(context), - "getAssets", "()Landroid/content/res/AssetManager;"); - javaAssetManager = (*env).CallObjectMethod(context, mid); - - /** - * Given a Dalvik AssetManager object, obtain the corresponding native AAssetManager - * object. Note that the caller is responsible for obtaining and holding a VM reference - * to the jobject to prevent its being garbage collected while the native object is - * in use. - */ - javaAssetManagerRef = (*env).NewGlobalRef(javaAssetManager); - asset_manager = AAssetManager_fromJava(env, javaAssetManagerRef); - - if (asset_manager == NULL) { - (*env).DeleteGlobalRef(javaAssetManagerRef); - __android_log_print (ANDROID_LOG_DEBUG, "Shadow Engine", "Failed to create Android Assets Manager"); - } - - LocalReferenceHolder_Cleanup(&refs); -} - -void Assets_obj::native_destroy(::Dynamic jni_env) -{ - JNIEnv* env = (JNIEnv*)(uintptr_t)jni_env; - - if (asset_manager) { - (*env).DeleteGlobalRef(javaAssetManagerRef); - asset_manager = NULL; - } -} - -bool Assets_obj::native_exists(::String file) -{ - AAsset* asset = AAssetManager_open(asset_manager, file.__s, AASSET_MODE_UNKNOWN); - bool ret = asset != NULL; - - if (ret) - AAsset_close(asset); - - return ret; -} - -::String Assets_obj::native_getContent(::String file) { - std::vector buffer; - - hx::EnterGCFreeZone(); - AAsset* asset = AAssetManager_open(asset_manager, file.__s, AASSET_MODE_BUFFER); - - if (!asset) { - hx::ExitGCFreeZone(); - return ::String(null()); - } - - int len = AAsset_getLength(asset); - if (len <= 0) { - AAsset_close(asset); - hx::ExitGCFreeZone(); - return ::String::emptyString; - } - - const char* src = (const char*)AAsset_getBuffer(asset); - - buffer.resize(len); - memcpy(&buffer[0], src, len); - - AAsset_close(asset); - hx::ExitGCFreeZone(); - - return ::String::create(&buffer[0], buffer.size()); -} - -Array Assets_obj::native_getBytes(::String file) { - hx::EnterGCFreeZone(); - AAsset* asset = AAssetManager_open(asset_manager, file.__s, AASSET_MODE_BUFFER); - - if (!asset) { - hx::ExitGCFreeZone(); - return null(); - } - - int len = AAsset_getLength(asset); - const unsigned char* src = (const unsigned char*)AAsset_getBuffer(asset); - hx::ExitGCFreeZone(); - - Array buffer = Array_obj::__new(len, len); - if (len > 0) { - hx::EnterGCFreeZone(); - memcpy(buffer->getBase(), src, len); - AAsset_close(asset); - hx::ExitGCFreeZone(); - } else { - hx::EnterGCFreeZone(); - AAsset_close(asset); - hx::ExitGCFreeZone(); - } - - return buffer; -} -') -@:headerClassCode(' -static void native_init(::Dynamic jni_env); -static void native_destroy(::Dynamic jni_env); -static bool native_exists(::String file); -static ::String native_getContent(::String file); -static Array native_getBytes(::String file); -') -class Assets -{ - public static function init():Void - { - _init(lime.system.JNI.getEnv()); - } - - public static function destroy():Void - { - _destroy(lime.system.JNI.getEnv()); - } - - public static function getContent(file:String):String - { - var content:String = _getContent(file); - - if (content == null) - throw 'file_contents, $file'; - - return content; - } - - public static function getBytes(file:String):haxe.io.Bytes - { - var data:Array = _getBytes(file); - - if (data == null || data.length <= 0) - throw 'file_contents, $file'; - - return haxe.io.Bytes.ofData(data); - } - - @:native('mobile::backend::android::Assets_obj::native_exists') - public static function exists(file:String):Bool - { - return false; - } - - @:noCompletion - @:native('mobile::backend::android::Assets_obj::native_init') - private static function _init(jni_env:Dynamic):Void - { - return; - } - - @:noCompletion - @:native('mobile::backend::android::Assets_obj::native_destroy') - private static function _destroy(jni_env:Dynamic):Void - { - return; - } - - @:noCompletion - @:native('mobile::backend::android::Assets_obj::native_getContent') - public static function _getContent(file:String):String - { - return null; - } - - @:noCompletion - @:native('mobile::backend::android::Assets_obj::native_getBytes') - private static function _getBytes(file:String):Array - { - return null; - } -} -#end diff --git a/source/engine/mobile/backend/io/Assets.hx b/source/engine/mobile/backend/io/Assets.hx new file mode 100644 index 00000000..8a0efba5 --- /dev/null +++ b/source/engine/mobile/backend/io/Assets.hx @@ -0,0 +1,9 @@ +package mobile.backend.io; + +#if android +typedef Assets = mobile.backend.io.android.Assets; +// #elseif ios +// typedef Assets = mobile.backend.io.ios.Assets; +#else +typedef Assets = Dynamic; +#end \ No newline at end of file diff --git a/source/engine/mobile/backend/io/android/Assets.hx b/source/engine/mobile/backend/io/android/Assets.hx new file mode 100644 index 00000000..85c3cd35 --- /dev/null +++ b/source/engine/mobile/backend/io/android/Assets.hx @@ -0,0 +1,251 @@ +package mobile.backend.io.android; + +/** + * The code for this class is mostly taken from SDL2. + * This class implements IO methods from the Android NDK's AAssetManager to read bundled app assets. + */ + +#if android +import haxe.io.Bytes; +import lime.system.JNI; + +@:cppNamespaceCode(' + #include + #include + #include + + static jmethodID midGetContext; + static jclass mActivityClass; + static AAssetManager *asset_manager = NULL; + static jobject javaAssetManagerRef = 0; + + struct LocalReferenceHolder + { + JNIEnv *m_env; + const char *m_func; + }; + + static struct LocalReferenceHolder LocalReferenceHolder_Setup(const char *func) + { + struct LocalReferenceHolder refholder; + refholder.m_env = NULL; + refholder.m_func = func; + __android_log_print (ANDROID_LOG_DEBUG, "Shadow Engine", "Entering function %s", func); + return refholder; + } + + static bool LocalReferenceHolder_Init(struct LocalReferenceHolder *refholder, JNIEnv *env) + { + const int capacity = 16; + if ((*env).PushLocalFrame(capacity) < 0) + { + __android_log_print (ANDROID_LOG_ERROR, "Shadow Engine", "Failed to allocate enough JVM local references"); + return false; + } + refholder->m_env = env; + return true; + } + + static void LocalReferenceHolder_Cleanup(struct LocalReferenceHolder *refholder) + { + __android_log_print (ANDROID_LOG_DEBUG, "Shadow Engine", "Leaving function %s", refholder->m_func); + if (refholder->m_env) + { + JNIEnv *env = refholder->m_env; + (*env).PopLocalFrame(NULL); + } + } + + void Assets_obj::native_init(::Dynamic jni_env) + { + JNIEnv* env = (JNIEnv*)(uintptr_t)jni_env; + jclass cls = env->FindClass("org/libsdl/app/SDLActivity"); + mActivityClass = (jclass)((*env).NewGlobalRef(cls)); + + struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__); + jmethodID mid; + jobject context; + jobject javaAssetManager; + + if (!LocalReferenceHolder_Init(&refs, env)) + { + LocalReferenceHolder_Cleanup(&refs); + return; + } + + // context = SDLActivity.getContext(); + midGetContext = (*env).GetStaticMethodID(mActivityClass, "getContext","()Landroid/content/Context;"); + context = (*env).CallStaticObjectMethod(mActivityClass, midGetContext); + + // javaAssetManager = context.getAssets(); + mid = (*env).GetMethodID((*env).GetObjectClass(context), + "getAssets", "()Landroid/content/res/AssetManager;"); + javaAssetManager = (*env).CallObjectMethod(context, mid); + + /** + * Given a Dalvik AssetManager object, obtain the corresponding native AAssetManager + * object. Note that the caller is responsible for obtaining and holding a VM reference + * to the jobject to prevent its being garbage collected while the native object is + * in use. + */ + javaAssetManagerRef = (*env).NewGlobalRef(javaAssetManager); + asset_manager = AAssetManager_fromJava(env, javaAssetManagerRef); + + if (asset_manager == NULL) + { + (*env).DeleteGlobalRef(javaAssetManagerRef); + __android_log_print (ANDROID_LOG_DEBUG, "Shadow Engine", "Failed to create Android Assets Manager"); + } + + LocalReferenceHolder_Cleanup(&refs); + } + + void Assets_obj::native_destroy(::Dynamic jni_env) + { + JNIEnv* env = (JNIEnv*)(uintptr_t)jni_env; + + if (asset_manager) + { + (*env).DeleteGlobalRef(javaAssetManagerRef); + asset_manager = NULL; + } + } + + bool Assets_obj::native_exists(::String file) + { + AAsset* asset = AAssetManager_open(asset_manager, file.__s, AASSET_MODE_UNKNOWN); + bool ret = asset != NULL; + + if (ret) + AAsset_close(asset); + + return ret; + } + + ::String Assets_obj::native_getContent(::String file) { + std::vector buffer; + + hx::EnterGCFreeZone(); + AAsset* asset = AAssetManager_open(asset_manager, file.__s, AASSET_MODE_BUFFER); + + if (!asset) + { + hx::ExitGCFreeZone(); + return ::String(null()); + } + + int len = AAsset_getLength(asset); + if (len <= 0) + { + AAsset_close(asset); + hx::ExitGCFreeZone(); + return ::String::emptyString; + } + + const char* src = (const char*)AAsset_getBuffer(asset); + + buffer.resize(len); + memcpy(&buffer[0], src, len); + + AAsset_close(asset); + hx::ExitGCFreeZone(); + + return ::String::create(&buffer[0], buffer.size()); + } + + Array Assets_obj::native_getBytes(::String file) { + hx::EnterGCFreeZone(); + AAsset* asset = AAssetManager_open(asset_manager, file.__s, AASSET_MODE_BUFFER); + + if (!asset) + { + hx::ExitGCFreeZone(); + return null(); + } + + int len = AAsset_getLength(asset); + const unsigned char* src = (const unsigned char*)AAsset_getBuffer(asset); + hx::ExitGCFreeZone(); + + Array buffer = Array_obj::__new(len, len); + if (len > 0) + { + hx::EnterGCFreeZone(); + memcpy(buffer->getBase(), src, len); + AAsset_close(asset); + hx::ExitGCFreeZone(); + } + else + { + hx::EnterGCFreeZone(); + AAsset_close(asset); + hx::ExitGCFreeZone(); + } + + return buffer; + } +') +@:headerClassCode(' + static void native_init(::Dynamic jni_env); + static void native_destroy(::Dynamic jni_env); + static bool native_exists(::String file); + static ::String native_getContent(::String file); + static Array native_getBytes(::String file); +') +class Assets +{ + public static function init():Void + { + __init(JNI.getEnv()); + } + + public static function destroy():Void + { + __destroy(JNI.getEnv()); + } + + public static function getContent(file:String):String + { + final content:String = __getContent(file); + + if (content == null) + throw 'file_contents, $file'; + + return content; + } + + public static function getBytes(file:String):Bytes + { + final data:Array = __getBytes(file); + + if (data == null || data.length <= 0) + throw 'file_contents, $file'; + + return Bytes.ofData(data); + } + + @:native('mobile::backend::android::Assets_obj::native_exists') + public static function exists(file:String):Bool + return false; + + @:noCompletion + @:native('mobile::backend::android::Assets_obj::native_init') + private static function __init(jni_env:Dynamic):Void + return; + + @:noCompletion + @:native('mobile::backend::android::Assets_obj::native_destroy') + private static function __destroy(jni_env:Dynamic):Void + return; + + @:noCompletion + @:native('mobile::backend::android::Assets_obj::native_getContent') + public static function __getContent(file:String):String + return null; + + @:noCompletion + @:native('mobile::backend::android::Assets_obj::native_getBytes') + private static function __getBytes(file:String):Array + return null; +} +#end From d15b15f89edad4e5028e1787f975bf0a35417d2e Mon Sep 17 00:00:00 2001 From: Homura Date: Fri, 16 Jan 2026 19:33:37 +0300 Subject: [PATCH 09/23] dum --- project.hxp | 2 +- source/engine/backend/io/File.hx | 6 +++--- source/engine/backend/io/FileSystem.hx | 8 ++++---- source/engine/mobile/backend/io/android/Assets.hx | 10 +++++----- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/project.hxp b/project.hxp index 958260b8..c0a857e2 100644 --- a/project.hxp +++ b/project.hxp @@ -214,7 +214,7 @@ class Project extends HXProject DISCORD_ALLOWED.integrate((isDesktop() && !isHashLink())); MODCHARTS_ALLOWED.integrate(/*DCEBUILD.isDisabled()*/false); DCEBUILD.integrate(false); - USE_OPENFL_FILESYSTEM.integrate(MODS_ALLOWED.isDisabled() || isMobile()); + USE_OPENFL_FILESYSTEM.integrate(MODS_ALLOWED.isDisabled()/*|| isMobile()*/); setHaxedef("FLX_NO_FOCUS_LOST_SCREEN"); if (!isDebug()) diff --git a/source/engine/backend/io/File.hx b/source/engine/backend/io/File.hx index 7a8f209c..a87a35ba 100644 --- a/source/engine/backend/io/File.hx +++ b/source/engine/backend/io/File.hx @@ -24,7 +24,7 @@ class File return path; } - #if FILESYSTEM_OPENFL + #if USE_OPENFL_FILESYSTEM static function openflcwd(path:String):String { @:privateAccess @@ -52,7 +52,7 @@ class File #end #end - #if FILESYSTEM_OPENFL + #if USE_OPENFL_FILESYSTEM if (Assets.exists(openflcwd(path))) return Assets.getText(openflcwd(path)); #end @@ -76,7 +76,7 @@ class File #end #end - #if FILESYSTEM_OPENFL + #if USE_OPENFL_FILESYSTEM if (Assets.exists(openflcwd(path))) switch (haxe.io.Path.extension(path).toLowerCase()) { diff --git a/source/engine/backend/io/FileSystem.hx b/source/engine/backend/io/FileSystem.hx index 3fbd288f..541133d2 100644 --- a/source/engine/backend/io/FileSystem.hx +++ b/source/engine/backend/io/FileSystem.hx @@ -23,7 +23,7 @@ class FileSystem return path; } - #if FILESYSTEM_OPENFL + #if USE_OPENFL_FILESYSTEM static function openflcwd(path:String):String { @:privateAccess @@ -51,7 +51,7 @@ class FileSystem #end #end - #if FILESYSTEM_OPENFL + #if USE_OPENFL_FILESYSTEM if (Assets.exists(openflcwd(path)) || Assets.list().filter(asset -> asset.startsWith(path) && asset != path).length > 0) return true; #end @@ -143,7 +143,7 @@ class FileSystem #end #end - #if FILESYSTEM_OPENFL + #if USE_OPENFL_FILESYSTEM if (Assets.list().filter(asset -> asset.startsWith(path) && asset != path).length > 0) return true; #end @@ -209,7 +209,7 @@ class FileSystem #end #end - #if FILESYSTEM_OPENFL + #if USE_OPENFL_FILESYSTEM if (result == null) { var filteredList = Assets.list().filter(f -> f.startsWith(path)); diff --git a/source/engine/mobile/backend/io/android/Assets.hx b/source/engine/mobile/backend/io/android/Assets.hx index 85c3cd35..00d5f00b 100644 --- a/source/engine/mobile/backend/io/android/Assets.hx +++ b/source/engine/mobile/backend/io/android/Assets.hx @@ -224,27 +224,27 @@ class Assets return Bytes.ofData(data); } - @:native('mobile::backend::android::Assets_obj::native_exists') + @:native('mobile::backend::io::android::::Assets_obj::native_exists') public static function exists(file:String):Bool return false; @:noCompletion - @:native('mobile::backend::android::Assets_obj::native_init') + @:native('mobile::backend::io::android::::Assets_obj::native_init') private static function __init(jni_env:Dynamic):Void return; @:noCompletion - @:native('mobile::backend::android::Assets_obj::native_destroy') + @:native('mobile::backend::io::android::::Assets_obj::native_destroy') private static function __destroy(jni_env:Dynamic):Void return; @:noCompletion - @:native('mobile::backend::android::Assets_obj::native_getContent') + @:native('mobile::backend::io::android::::Assets_obj::native_getContent') public static function __getContent(file:String):String return null; @:noCompletion - @:native('mobile::backend::android::Assets_obj::native_getBytes') + @:native('mobile::backend::io::android::::Assets_obj::native_getBytes') private static function __getBytes(file:String):Array return null; } From 0354eccbdcc952f1eb9fb04d5958dc683642883b Mon Sep 17 00:00:00 2001 From: Homura Date: Fri, 16 Jan 2026 19:34:09 +0300 Subject: [PATCH 10/23] love vscode --- source/engine/mobile/backend/io/android/Assets.hx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/engine/mobile/backend/io/android/Assets.hx b/source/engine/mobile/backend/io/android/Assets.hx index 00d5f00b..e4135520 100644 --- a/source/engine/mobile/backend/io/android/Assets.hx +++ b/source/engine/mobile/backend/io/android/Assets.hx @@ -224,27 +224,27 @@ class Assets return Bytes.ofData(data); } - @:native('mobile::backend::io::android::::Assets_obj::native_exists') + @:native('mobile::backend::io::android::Assets_obj::native_exists') public static function exists(file:String):Bool return false; @:noCompletion - @:native('mobile::backend::io::android::::Assets_obj::native_init') + @:native('mobile::backend::io::android::Assets_obj::native_init') private static function __init(jni_env:Dynamic):Void return; @:noCompletion - @:native('mobile::backend::io::android::::Assets_obj::native_destroy') + @:native('mobile::backend::io::android::Assets_obj::native_destroy') private static function __destroy(jni_env:Dynamic):Void return; @:noCompletion - @:native('mobile::backend::io::android::::Assets_obj::native_getContent') + @:native('mobile::backend::io::android::Assets_obj::native_getContent') public static function __getContent(file:String):String return null; @:noCompletion - @:native('mobile::backend::io::android::::Assets_obj::native_getBytes') + @:native('mobile::backend::io::android::Assets_obj::native_getBytes') private static function __getBytes(file:String):Array return null; } From 328b8d3ce7ba800c162179034e7fb919f6006328 Mon Sep 17 00:00:00 2001 From: Homura Date: Sun, 18 Jan 2026 10:39:23 +0300 Subject: [PATCH 11/23] add final dir --- .github/workflows/release.yml | 18 +++++++++--------- project.hxp | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1d2d4bb5..a075feb9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,55 +19,55 @@ jobs: buildArgs: "windows -final -32 -D HXCPP_M32 -D officialBuild" assetType: S3TC artifactName: windowsBuild-i686 - artifactPath: export\release\windows\bin\* + artifactPath: export\final\windows\bin\* - name: Windows x86_64 os: windows-2025 buildArgs: "windows -final -64 -D HXCPP_M64 -D officialBuild" assetType: S3TC artifactName: windowsBuild-x86_64 - artifactPath: export\release\windows\bin\* + artifactPath: export\final\windows\bin\* - name: Windows ARM64 os: windows-2025 buildArgs: "windows -final -arm64 -D HXCPP_ARM64 -D officialBuild" assetType: S3TC artifactName: windowsBuild-arm64 - artifactPath: export\release\windows\bin\* + artifactPath: export\final\windows\bin\* - name: Linux i686 os: ubuntu-24.04 buildArgs: "linux -final -32 -D HXCPP_M32 -D officialBuild" assetType: S3TC artifactName: linuxBuild-i686 - artifactPath: export/release/linux/bin/* + artifactPath: export/final/linux/bin/* - name: Linux x86_64 os: ubuntu-24.04 buildArgs: "linux -final -64 -D HXCPP_M64 -D officialBuild" assetType: S3TC artifactName: linuxBuild-x86_64 - artifactPath: export/release/linux/bin/* + artifactPath: export/final/linux/bin/* - name: Linux ARMV7 os: ubuntu-24.04-arm buildArgs: "linux -final -armv7 -D HXCPP_ARMV7 -D officialBuild" assetType: ASTC artifactName: linuxBuild-armv7 - artifactPath: export/release/linux/bin/* + artifactPath: export/final/linux/bin/* - name: Linux ARM64 os: ubuntu-24.04-arm buildArgs: "linux -final -arm64 -D HXCPP_ARM64 -D officialBuild" assetType: ASTC artifactName: linuxBuild-arm64 - artifactPath: export/release/linux/bin/* + artifactPath: export/final/linux/bin/* - name: Android os: macos-26 buildArgs: "android -final -D officialBuild" assetType: ASTC artifactName: androidBuild - artifactPath: "export/release/android/bin/app/build/outputs/apk/release/*.apk" + artifactPath: "export/final/android/bin/app/build/outputs/apk/release/*.apk" - name: iOS os: macos-26 buildArgs: "ios -final -nosign -D officialBuild" assetType: ASTC artifactName: iOSBuild - artifactPath: "export/release/ios/build/Release-iphoneos/*.ipa" + artifactPath: "export/final/ios/build/Release-iphoneos/*.ipa" uses: ./.github/workflows/build.yml secrets: SE_KEYSTORE_FILE: ${{ secrets.SE_KEYSTORE_FILE }} diff --git a/project.hxp b/project.hxp index 56212982..c0be8eb8 100644 --- a/project.hxp +++ b/project.hxp @@ -172,7 +172,7 @@ class Project extends HXProject app.file = EXECUTABLE; app.preloader = PRELOADER; - var buildDir = 'export/${isDebug() ? 'debug' : 'release'}/'; + var buildDir = 'export/${isDebug() ? 'debug' : isFinal() ? 'final' : 'release'}/'; app.path = buildDir; sources = SOURCE_FOLDERS; From 58c5cd0502d27c2cb31b242f9d35a48fbd5e94e8 Mon Sep 17 00:00:00 2001 From: Homura Date: Sun, 18 Jan 2026 11:00:40 +0300 Subject: [PATCH 12/23] some implements to Shadow FS --- source/engine/backend/io/File.hx | 38 ++++++++++++++++------ source/engine/backend/io/FileSystem.hx | 45 +++++++++++++++++++------- 2 files changed, 61 insertions(+), 22 deletions(-) diff --git a/source/engine/backend/io/File.hx b/source/engine/backend/io/File.hx index a87a35ba..17317e97 100644 --- a/source/engine/backend/io/File.hx +++ b/source/engine/backend/io/File.hx @@ -1,7 +1,13 @@ package backend.io; -import openfl.Assets; -#if sys +#if USE_OPENFL_FILESYSTEM +import lime.utils.Assets as LimeAssets; +import openfl.Assets as OpenFLAssets; +#end +#if mobile +import mobile.backend.io.Assets as MobileAssets; +#end +#if (sys && MODS_ALLOWED) import sys.FileSystem as SysFileSystem; import sys.FileStat; import sys.io.File as SysFile; @@ -28,8 +34,8 @@ class File static function openflcwd(path:String):String { @:privateAccess - for (library in lime.utils.Assets.libraries.keys()) - if (Assets.exists('$library:$path') && !path.startsWith('$library:')) + for (library in LimeAssets.libraries.keys()) + if (OpenFLAssets.exists('$library:$path') && !path.startsWith('$library:')) return '$library:$path'; return path; @@ -52,9 +58,14 @@ class File #end #end + #if mobile + if (MobileAssets.exists(path)) + return MobileAssets.getContent(path); + #end + #if USE_OPENFL_FILESYSTEM - if (Assets.exists(openflcwd(path))) - return Assets.getText(openflcwd(path)); + if (OpenFLAssets.exists(openflcwd(path))) + return OpenFLAssets.getText(openflcwd(path)); #end return null; @@ -76,14 +87,19 @@ class File #end #end + #if mobile + if (MobileAssets.exists(path)) + return MobileAssets.getBytes(path); + #end + #if USE_OPENFL_FILESYSTEM - if (Assets.exists(openflcwd(path))) + if (OpenFLAssets.exists(openflcwd(path))) switch (haxe.io.Path.extension(path).toLowerCase()) { case 'otf' | 'ttf': return openfl.utils.ByteArray.fromFile(openflcwd(path)); default: - return Assets.getBytes(openflcwd(path)); + return OpenFLAssets.getBytes(openflcwd(path)); } #end @@ -116,9 +132,11 @@ class File #else return SysFile.read(cwd(path), binary); #end - #else - return null; #end + #if mobile + // SHADOW TODO + #end + return null; } public static function write(path:String, binary:Bool = true):Null diff --git a/source/engine/backend/io/FileSystem.hx b/source/engine/backend/io/FileSystem.hx index 541133d2..84a78bf2 100644 --- a/source/engine/backend/io/FileSystem.hx +++ b/source/engine/backend/io/FileSystem.hx @@ -1,7 +1,13 @@ package backend.io; -import openfl.Assets; -#if sys +#if USE_OPENFL_FILESYSTEM +import lime.utils.Assets as LimeAssets; +import openfl.Assets as OpenFLAssets; +#end +#if mobile +import mobile.backend.io.Assets as MobileAssets; +#end +#if (sys && MODS_ALLOWED) import sys.FileSystem as SysFileSystem; import sys.FileStat; #end @@ -27,8 +33,8 @@ class FileSystem static function openflcwd(path:String):String { @:privateAccess - for (library in lime.utils.Assets.libraries.keys()) - if (Assets.exists('$library:$path') && !path.startsWith('$library:')) + for (library in LimeAssets.libraries.keys()) + if (OpenFLAssets.exists('$library:$path') && !path.startsWith('$library:')) return '$library:$path'; return path; @@ -51,8 +57,13 @@ class FileSystem #end #end + #if mobile + if (MobileAssets.exists(path)) + return true; + #end + #if USE_OPENFL_FILESYSTEM - if (Assets.exists(openflcwd(path)) || Assets.list().filter(asset -> asset.startsWith(path) && asset != path).length > 0) + if (OpenFLAssets.exists(openflcwd(path)) || OpenFLAssets.list().filter(asset -> asset.startsWith(path) && asset != path).length > 0) return true; #end @@ -88,9 +99,11 @@ class FileSystem #else return SysFileSystem.stat(cwd(path)); #end - #else - return null; #end + #if mobile + // SHADOW TODO + #end + return null; } public static function fullPath(path:String):String @@ -143,8 +156,12 @@ class FileSystem #end #end + #if mobile + // SHADOW TODO + #end + #if USE_OPENFL_FILESYSTEM - if (Assets.list().filter(asset -> asset.startsWith(path) && asset != path).length > 0) + if (OpenFLAssets.list().filter(asset -> asset.startsWith(path) && asset != path).length > 0) return true; #end @@ -209,10 +226,14 @@ class FileSystem #end #end + #if mobile + // SHADOW TODO + #end + #if USE_OPENFL_FILESYSTEM if (result == null) { - var filteredList = Assets.list().filter(f -> f.startsWith(path)); + var filteredList = OpenFLAssets.list().filter(f -> f.startsWith(path)); var results:Array = []; for (i in filteredList.copy()) @@ -228,12 +249,12 @@ class FileSystem for (item in filteredList) { @:privateAccess - for (library in lime.utils.Assets.libraries.keys()) + for (library in LimeAssets.libraries.keys()) { var libPath = '$library:$item'; - if (library != 'default' && Assets.exists(libPath) && !results.contains(libPath)) + if (library != 'default' && OpenFLAssets.exists(libPath) && !results.contains(libPath)) results.push(libPath); - else if (Assets.exists(item) && !results.contains(item)) + else if (OpenFLAssets.exists(item) && !results.contains(item)) results.push(item); } } From c8ad1f07ded6df2f078e10297b5d068b294dd09e Mon Sep 17 00:00:00 2001 From: Homura Date: Sun, 18 Jan 2026 11:03:36 +0300 Subject: [PATCH 13/23] b --- source/engine/backend/io/FileSystem.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/engine/backend/io/FileSystem.hx b/source/engine/backend/io/FileSystem.hx index 84a78bf2..134fa682 100644 --- a/source/engine/backend/io/FileSystem.hx +++ b/source/engine/backend/io/FileSystem.hx @@ -216,7 +216,7 @@ class FileSystem #if MODS_ALLOWED #if linux - var actualPath = cwd(path); + var actualPath:String = cwd(path); actualPath = getCaseInsensitivePath(path) ?? path; if (SysFileSystem.exists(actualPath) && SysFileSystem.isDirectory(actualPath)) result = SysFileSystem.readDirectory(actualPath); From a06c6c1a201b2f8a496335d9852c584dd37aaf8f Mon Sep 17 00:00:00 2001 From: Homura Date: Sun, 18 Jan 2026 11:06:28 +0300 Subject: [PATCH 14/23] we don't need a Dynamic as last resort. --- source/engine/mobile/backend/io/Assets.hx | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/engine/mobile/backend/io/Assets.hx b/source/engine/mobile/backend/io/Assets.hx index 8a0efba5..89cd20f6 100644 --- a/source/engine/mobile/backend/io/Assets.hx +++ b/source/engine/mobile/backend/io/Assets.hx @@ -4,6 +4,4 @@ package mobile.backend.io; typedef Assets = mobile.backend.io.android.Assets; // #elseif ios // typedef Assets = mobile.backend.io.ios.Assets; -#else -typedef Assets = Dynamic; #end \ No newline at end of file From 74416b86e66fc799d594c04280da1fe0c4c191f5 Mon Sep 17 00:00:00 2001 From: Homura Date: Mon, 19 Jan 2026 22:06:12 +0300 Subject: [PATCH 15/23] directory stuff and optimize getBytes --- project.hxp | 2 +- source/engine/backend/Main.hx | 1 + source/engine/backend/io/File.hx | 20 +- source/engine/backend/io/FileSystem.hx | 37 +- .../mobile/backend/io/android/Assets.hx | 397 ++++++++++++------ 5 files changed, 295 insertions(+), 162 deletions(-) diff --git a/project.hxp b/project.hxp index c0be8eb8..514df3c3 100644 --- a/project.hxp +++ b/project.hxp @@ -214,7 +214,7 @@ class Project extends HXProject DISCORD_ALLOWED.integrate((isDesktop() && !isHashLink())); MODCHARTS_ALLOWED.integrate(/*DCEBUILD.isDisabled()*/false); DCEBUILD.integrate(false); - USE_OPENFL_FILESYSTEM.integrate(MODS_ALLOWED.isDisabled()/*|| isMobile()*/); + USE_OPENFL_FILESYSTEM.integrate(MODS_ALLOWED.isDisabled() && !isMobile()); setHaxedef("FLX_NO_FOCUS_LOST_SCREEN"); if (!isDebug()) diff --git a/source/engine/backend/Main.hx b/source/engine/backend/Main.hx index f531b4b0..32749e85 100644 --- a/source/engine/backend/Main.hx +++ b/source/engine/backend/Main.hx @@ -69,6 +69,7 @@ class Main extends Sprite #if android StorageUtil.requestPermissions(); #end + mobile.backend.io.Assets.init(); #end super(); diff --git a/source/engine/backend/io/File.hx b/source/engine/backend/io/File.hx index 17317e97..532d627d 100644 --- a/source/engine/backend/io/File.hx +++ b/source/engine/backend/io/File.hx @@ -58,16 +58,16 @@ class File #end #end - #if mobile - if (MobileAssets.exists(path)) - return MobileAssets.getContent(path); - #end - #if USE_OPENFL_FILESYSTEM if (OpenFLAssets.exists(openflcwd(path))) return OpenFLAssets.getText(openflcwd(path)); #end + #if mobile + if (MobileAssets.exists(path)) + return MobileAssets.getContent(path); + #end + return null; } @@ -87,11 +87,6 @@ class File #end #end - #if mobile - if (MobileAssets.exists(path)) - return MobileAssets.getBytes(path); - #end - #if USE_OPENFL_FILESYSTEM if (OpenFLAssets.exists(openflcwd(path))) switch (haxe.io.Path.extension(path).toLowerCase()) @@ -103,6 +98,11 @@ class File } #end + #if mobile + if (MobileAssets.exists(path)) + return MobileAssets.getBytes(path); + #end + return null; } diff --git a/source/engine/backend/io/FileSystem.hx b/source/engine/backend/io/FileSystem.hx index 134fa682..7f36828d 100644 --- a/source/engine/backend/io/FileSystem.hx +++ b/source/engine/backend/io/FileSystem.hx @@ -57,13 +57,13 @@ class FileSystem #end #end - #if mobile - if (MobileAssets.exists(path)) + #if USE_OPENFL_FILESYSTEM + if (OpenFLAssets.exists(openflcwd(path)) || OpenFLAssets.list().filter(asset -> asset.startsWith(path) && asset != path).length > 0) return true; #end - #if USE_OPENFL_FILESYSTEM - if (OpenFLAssets.exists(openflcwd(path)) || OpenFLAssets.list().filter(asset -> asset.startsWith(path) && asset != path).length > 0) + #if mobile + if (MobileAssets.exists(path)) return true; #end @@ -95,13 +95,16 @@ class FileSystem actualPath = getCaseInsensitivePath(path); if (actualPath == null) actualPath = path; - return SysFileSystem.stat(actualPath); + if (SysFileSystem.exists(actualPath)) + return SysFileSystem.stat(actualPath); #else - return SysFileSystem.stat(cwd(path)); + if (SysFileSystem.exists(cwd(path))) + return SysFileSystem.stat(cwd(path)); #end #end #if mobile - // SHADOW TODO + if (MobileAssets.exists(path)) + return MobileAssets.stat(path); #end return null; } @@ -156,15 +159,16 @@ class FileSystem #end #end - #if mobile - // SHADOW TODO - #end - #if USE_OPENFL_FILESYSTEM if (OpenFLAssets.list().filter(asset -> asset.startsWith(path) && asset != path).length > 0) return true; #end + #if mobile + if (MobileAssets.isDirectory(path)) + return true; + #end + return false; } @@ -226,14 +230,10 @@ class FileSystem #end #end - #if mobile - // SHADOW TODO - #end - #if USE_OPENFL_FILESYSTEM if (result == null) { - var filteredList = OpenFLAssets.list().filter(f -> f.startsWith(path)); + var filteredList:Array = OpenFLAssets.list().filter(f -> f.startsWith(path)); var results:Array = []; for (i in filteredList.copy()) @@ -263,6 +263,11 @@ class FileSystem } #end + #if mobile + if (MobileAssets.exists(path) && MobileAssets.isDirectory(path)) + result = MobileAssets.readDirectory(path); + #end + return result ?? []; } diff --git a/source/engine/mobile/backend/io/android/Assets.hx b/source/engine/mobile/backend/io/android/Assets.hx index e4135520..e196aa31 100644 --- a/source/engine/mobile/backend/io/android/Assets.hx +++ b/source/engine/mobile/backend/io/android/Assets.hx @@ -4,193 +4,284 @@ package mobile.backend.io.android; * The code for this class is mostly taken from SDL2. * This class implements IO methods from the Android NDK's AAssetManager to read bundled app assets. */ - #if android import haxe.io.Bytes; import lime.system.JNI; +import sys.FileStat; +@:cppFileCode(' +#ifndef INCLUDED_Date +#include +#endif +') @:cppNamespaceCode(' - #include - #include - #include +#include +#include +#include - static jmethodID midGetContext; - static jclass mActivityClass; - static AAssetManager *asset_manager = NULL; - static jobject javaAssetManagerRef = 0; +static jmethodID midGetContext; +static jclass mActivityClass; +static AAssetManager *asset_manager = NULL; +static jobject javaAssetManagerRef = 0; - struct LocalReferenceHolder - { - JNIEnv *m_env; - const char *m_func; - }; +struct LocalReferenceHolder +{ + JNIEnv *m_env; + const char *m_func; +}; - static struct LocalReferenceHolder LocalReferenceHolder_Setup(const char *func) +static struct LocalReferenceHolder LocalReferenceHolder_Setup(const char *func) +{ + struct LocalReferenceHolder refholder; + refholder.m_env = NULL; + refholder.m_func = func; + __android_log_print (ANDROID_LOG_DEBUG, "Shadow Engine", "Entering function %s", func); + return refholder; +} + +static bool LocalReferenceHolder_Init(struct LocalReferenceHolder *refholder, JNIEnv *env) +{ + const int capacity = 16; + if ((*env).PushLocalFrame(capacity) < 0) { - struct LocalReferenceHolder refholder; - refholder.m_env = NULL; - refholder.m_func = func; - __android_log_print (ANDROID_LOG_DEBUG, "Shadow Engine", "Entering function %s", func); - return refholder; + __android_log_print (ANDROID_LOG_ERROR, "Shadow Engine", "Failed to allocate enough JVM local references"); + return false; } + refholder->m_env = env; + return true; +} - static bool LocalReferenceHolder_Init(struct LocalReferenceHolder *refholder, JNIEnv *env) +static void LocalReferenceHolder_Cleanup(struct LocalReferenceHolder *refholder) +{ + __android_log_print (ANDROID_LOG_DEBUG, "Shadow Engine", "Leaving function %s", refholder->m_func); + if (refholder->m_env) { - const int capacity = 16; - if ((*env).PushLocalFrame(capacity) < 0) - { - __android_log_print (ANDROID_LOG_ERROR, "Shadow Engine", "Failed to allocate enough JVM local references"); - return false; - } - refholder->m_env = env; - return true; + JNIEnv *env = refholder->m_env; + (*env).PopLocalFrame(NULL); } +} - static void LocalReferenceHolder_Cleanup(struct LocalReferenceHolder *refholder) +void Assets_obj::native_init(::Dynamic jni_env) +{ + JNIEnv* env = (JNIEnv*)(uintptr_t)jni_env; + jclass cls = env->FindClass("org/libsdl/app/SDLActivity"); + mActivityClass = (jclass)((*env).NewGlobalRef(cls)); + + struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__); + jmethodID mid; + jobject context; + jobject javaAssetManager; + + if (!LocalReferenceHolder_Init(&refs, env)) { - __android_log_print (ANDROID_LOG_DEBUG, "Shadow Engine", "Leaving function %s", refholder->m_func); - if (refholder->m_env) - { - JNIEnv *env = refholder->m_env; - (*env).PopLocalFrame(NULL); - } + LocalReferenceHolder_Cleanup(&refs); + return; } - void Assets_obj::native_init(::Dynamic jni_env) + // context = SDLActivity.getContext(); + midGetContext = (*env).GetStaticMethodID(mActivityClass, "getContext","()Landroid/content/Context;"); + context = (*env).CallStaticObjectMethod(mActivityClass, midGetContext); + + // javaAssetManager = context.getAssets(); + mid = (*env).GetMethodID((*env).GetObjectClass(context), "getAssets", "()Landroid/content/res/AssetManager;"); + javaAssetManager = (*env).CallObjectMethod(context, mid); + + /** + * Given a Dalvik AssetManager object, obtain the corresponding native AAssetManager + * object. Note that the caller is responsible for obtaining and holding a VM reference + * to the jobject to prevent its being garbage collected while the native object is + * in use. + */ + javaAssetManagerRef = (*env).NewGlobalRef(javaAssetManager); + asset_manager = AAssetManager_fromJava(env, javaAssetManagerRef); + + if (asset_manager == NULL) { - JNIEnv* env = (JNIEnv*)(uintptr_t)jni_env; - jclass cls = env->FindClass("org/libsdl/app/SDLActivity"); - mActivityClass = (jclass)((*env).NewGlobalRef(cls)); + (*env).DeleteGlobalRef(javaAssetManagerRef); + __android_log_print (ANDROID_LOG_DEBUG, "Shadow Engine", "Failed to create Android Assets Manager"); + } - struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__); - jmethodID mid; - jobject context; - jobject javaAssetManager; + LocalReferenceHolder_Cleanup(&refs); +} - if (!LocalReferenceHolder_Init(&refs, env)) - { - LocalReferenceHolder_Cleanup(&refs); - return; - } +void Assets_obj::native_destroy(::Dynamic jni_env) +{ + JNIEnv* env = (JNIEnv*)(uintptr_t)jni_env; - // context = SDLActivity.getContext(); - midGetContext = (*env).GetStaticMethodID(mActivityClass, "getContext","()Landroid/content/Context;"); - context = (*env).CallStaticObjectMethod(mActivityClass, midGetContext); - - // javaAssetManager = context.getAssets(); - mid = (*env).GetMethodID((*env).GetObjectClass(context), - "getAssets", "()Landroid/content/res/AssetManager;"); - javaAssetManager = (*env).CallObjectMethod(context, mid); - - /** - * Given a Dalvik AssetManager object, obtain the corresponding native AAssetManager - * object. Note that the caller is responsible for obtaining and holding a VM reference - * to the jobject to prevent its being garbage collected while the native object is - * in use. - */ - javaAssetManagerRef = (*env).NewGlobalRef(javaAssetManager); - asset_manager = AAssetManager_fromJava(env, javaAssetManagerRef); - - if (asset_manager == NULL) - { - (*env).DeleteGlobalRef(javaAssetManagerRef); - __android_log_print (ANDROID_LOG_DEBUG, "Shadow Engine", "Failed to create Android Assets Manager"); - } - - LocalReferenceHolder_Cleanup(&refs); + if (asset_manager) + { + (*env).DeleteGlobalRef(javaAssetManagerRef); + asset_manager = NULL; } +} - void Assets_obj::native_destroy(::Dynamic jni_env) +bool Assets_obj::native_exists(::String path) +{ + hx::EnterGCFreeZone(); + AAsset* file = AAssetManager_open(asset_manager, path.__s, AASSET_MODE_UNKNOWN); + if (file != NULL) { - JNIEnv* env = (JNIEnv*)(uintptr_t)jni_env; + AAsset_close(file); + hx::ExitGCFreeZone(); + return true; + } - if (asset_manager) - { - (*env).DeleteGlobalRef(javaAssetManagerRef); - asset_manager = NULL; - } + hx::EnterGCFreeZone(); + AAssetDir* dir = AAssetManager_openDir(asset_manager, path.__s); + if (AAssetDir_getNextFileName(dir) != NULL) + { + AAssetDir_close(dir); + hx::ExitGCFreeZone(); + return true; + } + + return false; +} + +::String Assets_obj::native_getContent(::String file) { + std::vector buffer; + + hx::EnterGCFreeZone(); + AAsset* asset = AAssetManager_open(asset_manager, file.__s, AASSET_MODE_BUFFER); + + if (!asset) + { + hx::ExitGCFreeZone(); + return ::String(null()); } - bool Assets_obj::native_exists(::String file) + int len = AAsset_getLength(asset); + if (len <= 0) { - AAsset* asset = AAssetManager_open(asset_manager, file.__s, AASSET_MODE_UNKNOWN); - bool ret = asset != NULL; + AAsset_close(asset); + hx::ExitGCFreeZone(); + return ::String::emptyString; + } - if (ret) - AAsset_close(asset); + const char* src = (const char*)AAsset_getBuffer(asset); + + buffer.resize(len); + memcpy(&buffer[0], src, len); + + AAsset_close(asset); + hx::ExitGCFreeZone(); + + return ::String::create(&buffer[0], buffer.size()); +} - return ret; +Array Assets_obj::native_getBytes(::String file) { + hx::EnterGCFreeZone(); + AAsset* asset = AAssetManager_open(asset_manager, file.__s, AASSET_MODE_STREAMING); + + if (!asset) + { + hx::ExitGCFreeZone(); + return null(); } - ::String Assets_obj::native_getContent(::String file) { - std::vector buffer; - - hx::EnterGCFreeZone(); - AAsset* asset = AAssetManager_open(asset_manager, file.__s, AASSET_MODE_BUFFER); - - if (!asset) - { - hx::ExitGCFreeZone(); - return ::String(null()); - } + int len = AAsset_getLength(asset); + Array buffer = Array_obj::__new(len, len); - int len = AAsset_getLength(asset); - if (len <= 0) + if (len > 0) + { + const int chunkSize = 8192; + int bytesRead = 0; + while (bytesRead < len) { - AAsset_close(asset); - hx::ExitGCFreeZone(); - return ::String::emptyString; + int toRead = (len - bytesRead > chunkSize) ? chunkSize : (len - bytesRead); + int result = AAsset_read(asset, buffer->getBase() + bytesRead, toRead); + if (result <= 0) + break; + bytesRead += result; } + } + + AAsset_close(asset); + hx::ExitGCFreeZone(); + return buffer; +} - const char* src = (const char*)AAsset_getBuffer(asset); - - buffer.resize(len); - memcpy(&buffer[0], src, len); +bool Assets_obj::native_isDirectory(::String path) +{ + hx::EnterGCFreeZone(); + AAssetDir* dir = AAssetManager_openDir(asset_manager, path.__s); - AAsset_close(asset); + if (AAssetDir_getNextFileName(dir) != NULL) + { + AAssetDir_close(dir); hx::ExitGCFreeZone(); - - return ::String::create(&buffer[0], buffer.size()); + return true; } - Array Assets_obj::native_getBytes(::String file) { - hx::EnterGCFreeZone(); - AAsset* asset = AAssetManager_open(asset_manager, file.__s, AASSET_MODE_BUFFER); - - if (!asset) - { - hx::ExitGCFreeZone(); - return null(); - } + return false; +} + +Array<::String> Assets_obj::native_readDirectory(::String path) +{ + Array<::String> result = Array_obj<::String>::__new(0, 0); + hx::EnterGCFreeZone(); + AAssetDir* dir = AAssetManager_openDir(asset_manager, path.__s); + const char* filename; - int len = AAsset_getLength(asset); - const unsigned char* src = (const unsigned char*)AAsset_getBuffer(asset); + if (!dir) + { hx::ExitGCFreeZone(); + return result; + } + + while ((filename = AAssetDir_getNextFileName(dir)) != NULL) + { + result->push(::String(filename)); + } - Array buffer = Array_obj::__new(len, len); - if (len > 0) - { - hx::EnterGCFreeZone(); - memcpy(buffer->getBase(), src, len); - AAsset_close(asset); - hx::ExitGCFreeZone(); - } - else + AAssetDir_close(dir); + hx::ExitGCFreeZone(); + return result; +} + +::Dynamic Assets_obj::native_stat(::String path) +{ + hx::Anon anon = hx::Anon_obj::Create(); + bool isDir = native_isDirectory(path); + int fileSize = 0; + int mode = isDir ? 0x4000 : 0x8000; + + if (!isDir) + { + hx::EnterGCFreeZone(); + AAsset* asset = AAssetManager_open(asset_manager, path.__s, AASSET_MODE_UNKNOWN); + if (asset) { - hx::EnterGCFreeZone(); + fileSize = AAsset_getLength(asset); AAsset_close(asset); - hx::ExitGCFreeZone(); } - - return buffer; + hx::ExitGCFreeZone(); } + + anon->Add(HX_CSTRING("gid"), 0); + anon->Add(HX_CSTRING("uid"), 0); + anon->Add(HX_CSTRING("atime"), ::Date_obj::fromTime(0.0)); + anon->Add(HX_CSTRING("mtime"), ::Date_obj::fromTime(0.0)); + anon->Add(HX_CSTRING("ctime"), ::Date_obj::fromTime(0.0)); + anon->Add(HX_CSTRING("size"), fileSize); + anon->Add(HX_CSTRING("dev"), 0); + anon->Add(HX_CSTRING("ino"), 0); + anon->Add(HX_CSTRING("nlink"), 0); + anon->Add(HX_CSTRING("rdev"), 0); + anon->Add(HX_CSTRING("mode"), mode); + + return anon; +} ') @:headerClassCode(' static void native_init(::Dynamic jni_env); static void native_destroy(::Dynamic jni_env); - static bool native_exists(::String file); + static bool native_exists(::String path); static ::String native_getContent(::String file); static Array native_getBytes(::String file); + static bool native_isDirectory(::String path); + static Array<::String> native_readDirectory(::String path); + static ::Dynamic native_stat(::String path); ') class Assets { @@ -224,8 +315,29 @@ class Assets return Bytes.ofData(data); } + public static function isDirectory(path:String):Bool + { + return __isDirectory(path); + } + + public static function readDirectory(path:String):Array + { + return __readDirectory(path); + } + + public static function stat(path:String):FileStat + { + return __stat(path); + } + + public static function exists(path:String):Bool + { + return __exists(path); + } + + @:noCompletion @:native('mobile::backend::io::android::Assets_obj::native_exists') - public static function exists(file:String):Bool + public static function __exists(path:String):Bool return false; @:noCompletion @@ -247,5 +359,20 @@ class Assets @:native('mobile::backend::io::android::Assets_obj::native_getBytes') private static function __getBytes(file:String):Array return null; + + @:noCompletion + @:native('mobile::backend::io::android::Assets_obj::native_isDirectory') + private static function __isDirectory(path:String):Bool + return false; + + @:noCompletion + @:native('mobile::backend::io::android::Assets_obj::native_readDirectory') + private static function __readDirectory(path:String):Array + return null; + + @:noCompletion + @:native('mobile::backend::io::android::Assets_obj::native_stat') + private static function __stat(path:String):Dynamic + return null; } #end From bef9b6f27120fe6aa629d10cd97939c34c1398ba Mon Sep 17 00:00:00 2001 From: Homura Date: Mon, 19 Jan 2026 22:53:31 +0300 Subject: [PATCH 16/23] doing old shi --- source/engine/backend/io/FileSystem.hx | 76 +++++++++++++------------- 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/source/engine/backend/io/FileSystem.hx b/source/engine/backend/io/FileSystem.hx index 7f36828d..3d34f1dc 100644 --- a/source/engine/backend/io/FileSystem.hx +++ b/source/engine/backend/io/FileSystem.hx @@ -216,61 +216,63 @@ class FileSystem public static function readDirectory(path:String):Array { - var result:Array = null; - #if MODS_ALLOWED #if linux var actualPath:String = cwd(path); - actualPath = getCaseInsensitivePath(path) ?? path; + actualPath = getCaseInsensitivePath(path); + if (actualPath == null) + actualPath = path; if (SysFileSystem.exists(actualPath) && SysFileSystem.isDirectory(actualPath)) - result = SysFileSystem.readDirectory(actualPath); + return SysFileSystem.readDirectory(actualPath); #else if (SysFileSystem.exists(cwd(path)) && SysFileSystem.isDirectory(cwd(path))) - result = SysFileSystem.readDirectory(cwd(path)); + return SysFileSystem.readDirectory(cwd(path)); #end #end #if USE_OPENFL_FILESYSTEM - if (result == null) - { - var filteredList:Array = OpenFLAssets.list().filter(f -> f.startsWith(path)); - var results:Array = []; - - for (i in filteredList.copy()) - { - var slashsCount = path.split('/').length; - if (path.endsWith('/')) - slashsCount--; - - if (i.split('/').length - 1 != slashsCount) - filteredList.remove(i); - } - - for (item in filteredList) - { - @:privateAccess - for (library in LimeAssets.libraries.keys()) - { - var libPath = '$library:$item'; - if (library != 'default' && OpenFLAssets.exists(libPath) && !results.contains(libPath)) - results.push(libPath); - else if (OpenFLAssets.exists(item) && !results.contains(item)) - results.push(item); - } - } - - result = results.map(f -> f.substr(f.lastIndexOf("/") + 1)); - } + if (OpenFLAssets.list().filter(asset -> asset.startsWith(path) && asset != path).length > 0) + return openflReadDirectory(path); #end #if mobile if (MobileAssets.exists(path) && MobileAssets.isDirectory(path)) - result = MobileAssets.readDirectory(path); + return MobileAssets.readDirectory(path); #end - return result ?? []; + return null; } + #if USE_OPENFL_FILESYSTEM + static function openflReadDirectory(path:String):Array + { + var filteredList:Array = OpenFLAssets.list().filter(f -> f.startsWith(path)); + var results:Array = []; + for (i in filteredList.copy()) + { + var slashsCount:Int = path.split('/').length; + if (path.endsWith('/')) + slashsCount -= 1; + + if (i.split('/').length - 1 != slashsCount) + filteredList.remove(i); + } + for (item in filteredList) + { + @:privateAccess + for (library in LimeAssets.libraries.keys()) + { + var libPath:String = '$library:$item'; + if (library != 'default' && Assets.exists(libPath) && !results.contains(libPath)) + results.push(libPath); + else if (OpenFLAssets.exists(item) && !results.contains(item)) + results.push(item); + } + } + return results.map(f -> f.substr(f.lastIndexOf("/") + 1)); + } + #end + #if (linux && MODS_ALLOWED) static function getCaseInsensitivePath(path:String):String { From fc09d48fa17308c2aabf2d4c1a056a996fef0e60 Mon Sep 17 00:00:00 2001 From: Homura Date: Mon, 19 Jan 2026 22:54:40 +0300 Subject: [PATCH 17/23] alternative name for MobileData --- source/engine/mobile/backend/MobileData.hx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/engine/mobile/backend/MobileData.hx b/source/engine/mobile/backend/MobileData.hx index 608519a1..e50e76cd 100644 --- a/source/engine/mobile/backend/MobileData.hx +++ b/source/engine/mobile/backend/MobileData.hx @@ -24,13 +24,13 @@ class MobileData save = new FlxSave(); save.bind('MobileControls', CoolUtil.getSavePath()); - readDirectory(Paths.getSharedPath('mobile/DPadModes'), dpadModes); - readDirectory(Paths.getSharedPath('mobile/ActionModes'), actionModes); + readFilesFromDirectory(Paths.getSharedPath('mobile/DPadModes'), dpadModes); + readFilesFromDirectory(Paths.getSharedPath('mobile/ActionModes'), actionModes); #if MODS_ALLOWED for (folder in Mods.directoriesWithFile(Paths.getSharedPath(), 'mobile/')) { - readDirectory(Path.join([folder, 'DPadModes']), dpadModes); - readDirectory(Path.join([folder, 'ActionModes']), actionModes); + readFilesFromDirectory(Path.join([folder, 'DPadModes']), dpadModes); + readFilesFromDirectory(Path.join([folder, 'ActionModes']), actionModes); } #end @@ -96,7 +96,7 @@ class MobileData return buttonsInstance; } - public static function readDirectory(folder:String, map:Dynamic) + public static function readFilesFromDirectory(folder:String, map:Dynamic) { folder = folder.contains(':') ? folder.split(':')[1] : folder; From d27272fcf8b1ed72d26edc515ff015fa88f563b2 Mon Sep 17 00:00:00 2001 From: Homura Date: Tue, 20 Jan 2026 23:15:55 +0300 Subject: [PATCH 18/23] downgrade some runner versions to future proof --- .github/workflows/main.yml | 10 +++++----- .github/workflows/release.yml | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5ba33f0d..ee695cec 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -27,25 +27,25 @@ jobs: artifactName: windowsBuild-arm64 artifactPath: export\release\windows\bin\* - name: Linux i686 - os: ubuntu-24.04 + os: ubuntu-22.04 buildArgs: "linux -32 -D HXCPP_M32" assetType: S3TC artifactName: linuxBuild-i686 artifactPath: export/release/linux/bin/* - name: Linux x86_64 - os: ubuntu-24.04 + os: ubuntu-22.04 buildArgs: "linux -64 -D HXCPP_M64" assetType: S3TC artifactName: linuxBuild-x86_64 artifactPath: export/release/linux/bin/* - name: Linux ARMV7 - os: ubuntu-24.04-arm + os: ubuntu-22.04-arm buildArgs: "linux -armv7 -D HXCPP_ARMV7" assetType: ASTC artifactName: linuxBuild-armv7 artifactPath: export/release/linux/bin/* - name: Linux ARM64 - os: ubuntu-24.04-arm + os: ubuntu-22.04-arm buildArgs: "linux -arm64 -D HXCPP_ARM64" assetType: ASTC artifactName: linuxBuild-arm64 @@ -57,7 +57,7 @@ jobs: artifactName: androidBuild artifactPath: "export/release/android/bin/app/build/outputs/apk/release/*.apk" - name: iOS - os: macos-26 + os: macos-15 buildArgs: "ios -nosign" assetType: ASTC artifactName: iOSBuild diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a075feb9..19b4516a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,25 +33,25 @@ jobs: artifactName: windowsBuild-arm64 artifactPath: export\final\windows\bin\* - name: Linux i686 - os: ubuntu-24.04 + os: ubuntu-22.04 buildArgs: "linux -final -32 -D HXCPP_M32 -D officialBuild" assetType: S3TC artifactName: linuxBuild-i686 artifactPath: export/final/linux/bin/* - name: Linux x86_64 - os: ubuntu-24.04 + os: ubuntu-22.04 buildArgs: "linux -final -64 -D HXCPP_M64 -D officialBuild" assetType: S3TC artifactName: linuxBuild-x86_64 artifactPath: export/final/linux/bin/* - name: Linux ARMV7 - os: ubuntu-24.04-arm + os: ubuntu-22.04-arm buildArgs: "linux -final -armv7 -D HXCPP_ARMV7 -D officialBuild" assetType: ASTC artifactName: linuxBuild-armv7 artifactPath: export/final/linux/bin/* - name: Linux ARM64 - os: ubuntu-24.04-arm + os: ubuntu-22.04-arm buildArgs: "linux -final -arm64 -D HXCPP_ARM64 -D officialBuild" assetType: ASTC artifactName: linuxBuild-arm64 @@ -63,7 +63,7 @@ jobs: artifactName: androidBuild artifactPath: "export/final/android/bin/app/build/outputs/apk/release/*.apk" - name: iOS - os: macos-26 + os: macos-15 buildArgs: "ios -final -nosign -D officialBuild" assetType: ASTC artifactName: iOSBuild From fef4e5241a286a4d499c283198bf5721d4a5e7a4 Mon Sep 17 00:00:00 2001 From: Homura Date: Tue, 20 Jan 2026 23:17:22 +0300 Subject: [PATCH 19/23] right --- .github/workflows/main.yml | 4 ++-- .github/workflows/release.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ee695cec..f1c45f59 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -79,7 +79,7 @@ jobs: uses: ./.github/workflows/build.yml with: name: macOS x86_64 - os: macos-26 + os: macos-15 buildArgs: "mac -64 -D HXCPP_M64" assetType: S3TC artifactName: macOSBuild-x86_64 @@ -90,7 +90,7 @@ jobs: uses: ./.github/workflows/build.yml with: name: macOS ARM64 - os: macos-26 + os: macos-15 buildArgs: "mac -arm64 -D HXCPP_ARM64" assetType: S3TC artifactName: macOSBuild-arm64 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 19b4516a..d5663659 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -85,7 +85,7 @@ jobs: uses: ./.github/workflows/build.yml with: name: macOS x86_64 - os: macos-26 + os: macos-15 buildArgs: "mac -64 -D HXCPP_M64" assetType: S3TC artifactName: macOSBuild-x86_64 @@ -96,7 +96,7 @@ jobs: uses: ./.github/workflows/build.yml with: name: macOS ARM64 - os: macos-26 + os: macos-15 buildArgs: "mac -arm64 -D HXCPP_ARM64" assetType: S3TC artifactName: macOSBuild-arm64 From 92f9ffc3f6e99c18173db7e98b53d4cc9286b69e Mon Sep 17 00:00:00 2001 From: Karim Akra Date: Fri, 30 Jan 2026 19:27:53 +0200 Subject: [PATCH 20/23] use file descriptor for bytes --- source/engine/backend/Paths.hx | 5 +- .../mobile/backend/io/android/Assets.hx | 64 +++++++++++++------ 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/source/engine/backend/Paths.hx b/source/engine/backend/Paths.hx index 146e5d75..9aed27a3 100644 --- a/source/engine/backend/Paths.hx +++ b/source/engine/backend/Paths.hx @@ -1,5 +1,6 @@ package backend; +import lime.media.AudioBuffer; import flixel.graphics.frames.FlxFrame.FlxFrameAngle; import flixel.graphics.frames.FlxAtlasFrames; import flixel.graphics.FlxGraphic; @@ -283,7 +284,7 @@ class Paths if (bitmap == null) { if (FileSystem.exists(file)) - bitmap = BitmapData.fromFile(file); + bitmap = BitmapData.fromBytes(File.getBytes(file)); else { if (Assets.exists(file, getImageAssetType(GPU_IMAGE_EXT))) @@ -478,7 +479,7 @@ class Paths { if (!currentTrackedSounds.exists(file)) { - currentTrackedSounds.set(file, Sound.fromFile(file)); + currentTrackedSounds.set(file, Sound.fromAudioBuffer(AudioBuffer.fromBytes(File.getBytes(file)))); // trace('precached mod sound: $file'); } localTrackedAssets.push(file); diff --git a/source/engine/mobile/backend/io/android/Assets.hx b/source/engine/mobile/backend/io/android/Assets.hx index e196aa31..e71501c9 100644 --- a/source/engine/mobile/backend/io/android/Assets.hx +++ b/source/engine/mobile/backend/io/android/Assets.hx @@ -18,6 +18,7 @@ import sys.FileStat; #include #include #include +#include static jmethodID midGetContext; static jclass mActivityClass; @@ -126,7 +127,6 @@ bool Assets_obj::native_exists(::String path) return true; } - hx::EnterGCFreeZone(); AAssetDir* dir = AAssetManager_openDir(asset_manager, path.__s); if (AAssetDir_getNextFileName(dir) != NULL) { @@ -135,6 +135,12 @@ bool Assets_obj::native_exists(::String path) return true; } + if (file) + AAsset_close(file); + + if (dir) + AAssetDir_close(dir); + return false; } @@ -179,23 +185,41 @@ Array Assets_obj::native_getBytes(::String file) { return null(); } - int len = AAsset_getLength(asset); - Array buffer = Array_obj::__new(len, len); + int fd; + off_t outStart; + off_t outLength; + fd = AAsset_openFileDescriptor (asset, &outStart, &outLength); - if (len > 0) - { - const int chunkSize = 8192; - int bytesRead = 0; - while (bytesRead < len) - { - int toRead = (len - bytesRead > chunkSize) ? chunkSize : (len - bytesRead); - int result = AAsset_read(asset, buffer->getBase() + bytesRead, toRead); - if (result <= 0) - break; - bytesRead += result; - } - } - + if (fd < 0) { + AAsset_close(asset); + hx::ExitGCFreeZone(); + return null(); + } + + Array buffer = Array_obj::__new(outLength, outLength); + + if (lseek(fd, outStart, SEEK_SET) == -1) { + close(fd); + AAsset_close(asset); + hx::ExitGCFreeZone(); + return null(); + } + + int totalRead = 0; + while (totalRead < outLength) { + int bytesRead = read(fd, buffer->getBase() + totalRead, outLength - totalRead); + + if (bytesRead <= 0) { + close(fd); + AAsset_close(asset); + hx::ExitGCFreeZone(); + return null(); + } + + totalRead += bytesRead; + } + + close(fd); AAsset_close(asset); hx::ExitGCFreeZone(); return buffer; @@ -206,13 +230,17 @@ bool Assets_obj::native_isDirectory(::String path) hx::EnterGCFreeZone(); AAssetDir* dir = AAssetManager_openDir(asset_manager, path.__s); - if (AAssetDir_getNextFileName(dir) != NULL) + if (dir && AAssetDir_getNextFileName(dir) != NULL) { AAssetDir_close(dir); hx::ExitGCFreeZone(); return true; } + if (dir) + AAssetDir_close(dir); + + hx::ExitGCFreeZone(); return false; } From 8cdf636b6c92de0dea96839dddc92eabd0d053c2 Mon Sep 17 00:00:00 2001 From: Karim Akra Date: Fri, 30 Jan 2026 21:04:42 +0200 Subject: [PATCH 21/23] fix cresh & use file system for audio and bitmaps --- source/engine/backend/Paths.hx | 25 +++++++++++++------ .../mobile/backend/io/android/Assets.hx | 2 +- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/source/engine/backend/Paths.hx b/source/engine/backend/Paths.hx index 9aed27a3..4b819b1e 100644 --- a/source/engine/backend/Paths.hx +++ b/source/engine/backend/Paths.hx @@ -1,5 +1,6 @@ package backend; +import haxe.io.Path; import lime.media.AudioBuffer; import flixel.graphics.frames.FlxFrame.FlxFrameAngle; import flixel.graphics.frames.FlxAtlasFrames; @@ -253,10 +254,10 @@ class Paths localTrackedAssets.push(file); return currentTrackedAssets.get(file); } - else if (Assets.exists(file, getImageAssetType(GPU_IMAGE_EXT))) - bitmap = Assets.getBitmapData(file); + else if (FileSystem.exists(file)) + bitmap = getBitmapData(file); - if (Assets.exists(getPath('images/$key.$IMAGE_EXT', getImageAssetType(IMAGE_EXT), library), getImageAssetType(IMAGE_EXT))) + if (FileSystem.exists(getPath('images/$key.$IMAGE_EXT', getImageAssetType(IMAGE_EXT), library))) { file = getPath('images/$key.$IMAGE_EXT', getImageAssetType(IMAGE_EXT), library); if (currentTrackedAssets.exists(file)) @@ -264,7 +265,7 @@ class Paths localTrackedAssets.push(file); return currentTrackedAssets.get(file); } - bitmap = Assets.getBitmapData(file); + bitmap = getBitmapData(file); } } @@ -279,12 +280,22 @@ class Paths return null; } + static public function getBitmapData(file:String):BitmapData + { + var bytes = File.getBytes(file); + return switch (Path.extension(file)) { + case 'astc': BitmapData.fromTexture(FlxG.stage.context3D.createASTCTexture(bytes)); + case 'dds': BitmapData.fromTexture(FlxG.stage.context3D.createS3TCTexture(bytes)); + default: BitmapData.fromBytes(bytes); + } + } + static public function cacheBitmap(file:String, ?bitmap:BitmapData = null) { if (bitmap == null) { if (FileSystem.exists(file)) - bitmap = BitmapData.fromBytes(File.getBytes(file)); + bitmap = getBitmapData(file); else { if (Assets.exists(file, getImageAssetType(GPU_IMAGE_EXT))) @@ -497,8 +508,8 @@ class Paths { var retKey:String = (path != null) ? '$path/$key' : key; retKey = getPath('$retKey.ogg', SOUND, library); - if (Assets.exists(retKey, SOUND)) - currentTrackedSounds.set(gottenPath, Assets.getSound(retKey)); + if (FileSystem.exists(retKey)) + currentTrackedSounds.set(gottenPath, Sound.fromAudioBuffer(AudioBuffer.fromBytes(File.getBytes(retKey)))); } localTrackedAssets.push(gottenPath); return currentTrackedSounds.get(gottenPath); diff --git a/source/engine/mobile/backend/io/android/Assets.hx b/source/engine/mobile/backend/io/android/Assets.hx index e71501c9..cbcde166 100644 --- a/source/engine/mobile/backend/io/android/Assets.hx +++ b/source/engine/mobile/backend/io/android/Assets.hx @@ -128,7 +128,7 @@ bool Assets_obj::native_exists(::String path) } AAssetDir* dir = AAssetManager_openDir(asset_manager, path.__s); - if (AAssetDir_getNextFileName(dir) != NULL) + if (dir && AAssetDir_getNextFileName(dir) != NULL) { AAssetDir_close(dir); hx::ExitGCFreeZone(); From 52fb395612b5132c56e918dc1fb8cfdf36dfbf5e Mon Sep 17 00:00:00 2001 From: Karim Akra Date: Fri, 30 Jan 2026 21:18:55 +0200 Subject: [PATCH 22/23] add more missing closes and gc stuff --- source/engine/mobile/backend/io/android/Assets.hx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/engine/mobile/backend/io/android/Assets.hx b/source/engine/mobile/backend/io/android/Assets.hx index cbcde166..c8383f71 100644 --- a/source/engine/mobile/backend/io/android/Assets.hx +++ b/source/engine/mobile/backend/io/android/Assets.hx @@ -127,6 +127,9 @@ bool Assets_obj::native_exists(::String path) return true; } + if (file) + AAsset_close(file); + AAssetDir* dir = AAssetManager_openDir(asset_manager, path.__s); if (dir && AAssetDir_getNextFileName(dir) != NULL) { @@ -135,12 +138,10 @@ bool Assets_obj::native_exists(::String path) return true; } - if (file) - AAsset_close(file); - if (dir) AAssetDir_close(dir); + hx::ExitGCFreeZone(); return false; } From 42198a3846e4e65b3fb7b98be17752caaf181383 Mon Sep 17 00:00:00 2001 From: Homura Date: Tue, 3 Feb 2026 17:26:32 +0300 Subject: [PATCH 23/23] revert final dir as it's useless --- .github/workflows/release.yml | 18 +++++++++--------- project.hxp | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 67ffdeb5..1bdb68f6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,55 +19,55 @@ jobs: buildArgs: "windows -final -32 -D HXCPP_M32 -D officialBuild" assetType: S3TC artifactName: windowsBuild-i686 - artifactPath: export\final\windows\bin\* + artifactPath: export\release\windows\bin\* - name: Windows x86_64 os: windows-2025 buildArgs: "windows -final -64 -D HXCPP_M64 -D officialBuild" assetType: S3TC artifactName: windowsBuild-x86_64 - artifactPath: export\final\windows\bin\* + artifactPath: export\release\windows\bin\* - name: Windows ARM64 os: windows-2025 buildArgs: "windows -final -arm64 -D HXCPP_ARM64 -D officialBuild" assetType: S3TC artifactName: windowsBuild-arm64 - artifactPath: export\final\windows\bin\* + artifactPath: export\release\windows\bin\* - name: Linux i686 os: ubuntu-22.04 buildArgs: "linux -final -32 -D HXCPP_M32 -D officialBuild" assetType: S3TC artifactName: linuxBuild-i686 - artifactPath: export/final/linux/bin/* + artifactPath: export/release/linux/bin/* - name: Linux x86_64 os: ubuntu-22.04 buildArgs: "linux -final -64 -D HXCPP_M64 -D officialBuild" assetType: S3TC artifactName: linuxBuild-x86_64 - artifactPath: export/final/linux/bin/* + artifactPath: export/release/linux/bin/* - name: Linux ARMV7 os: ubuntu-22.04-arm buildArgs: "linux -final -armv7 -D HXCPP_ARMV7 -D officialBuild" assetType: ASTC artifactName: linuxBuild-armv7 - artifactPath: export/final/linux/bin/* + artifactPath: export/release/linux/bin/* - name: Linux ARM64 os: ubuntu-22.04-arm buildArgs: "linux -final -arm64 -D HXCPP_ARM64 -D officialBuild" assetType: ASTC artifactName: linuxBuild-arm64 - artifactPath: export/final/linux/bin/* + artifactPath: export/release/linux/bin/* - name: Android os: macos-26 buildArgs: "android -final -D officialBuild" assetType: ASTC artifactName: androidBuild - artifactPath: "export/final/android/bin/app/build/outputs/apk/release/*.apk" + artifactPath: "export/release/android/bin/app/build/outputs/apk/release/*.apk" - name: iOS os: macos-15 buildArgs: "ios -final -nosign -D officialBuild" assetType: ASTC artifactName: iOSBuild - artifactPath: "export/final/ios/build/Release-iphoneos/*.ipa" + artifactPath: "export/release/ios/build/Release-iphoneos/*.ipa" uses: ./.github/workflows/build.yml secrets: SE_KEYSTORE_FILE: ${{ secrets.SE_KEYSTORE_FILE }} diff --git a/project.hxp b/project.hxp index 77aa1d9b..4a979af3 100644 --- a/project.hxp +++ b/project.hxp @@ -172,7 +172,7 @@ class Project extends HXProject app.file = EXECUTABLE; app.preloader = PRELOADER; - var buildDir = 'export/${isDebug() ? 'debug' : isFinal() ? 'final' : 'release'}/'; + var buildDir = 'export/${isDebug() ? 'debug' : 'release'}/'; app.path = buildDir; for (shadowName in LIBRARY_SHADOWS_LIST)