From 2d86b8734b9eb753ab6ff45fbea0ac3689dc49bf Mon Sep 17 00:00:00 2001 From: Karim Akra Date: Wed, 14 Jan 2026 19:51:29 +0200 Subject: [PATCH 01/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] `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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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) From 3cf39c0043f906e05e3df63b085fe12584c8561b Mon Sep 17 00:00:00 2001 From: Homura Date: Mon, 16 Feb 2026 18:32:12 +0300 Subject: [PATCH 24/50] e --- source/engine/mobile/backend/io/android/Assets.hx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/engine/mobile/backend/io/android/Assets.hx b/source/engine/mobile/backend/io/android/Assets.hx index c8383f71..2f77832d 100644 --- a/source/engine/mobile/backend/io/android/Assets.hx +++ b/source/engine/mobile/backend/io/android/Assets.hx @@ -5,6 +5,7 @@ package mobile.backend.io.android; * This class implements IO methods from the Android NDK's AAssetManager to read bundled app assets. */ #if android +import cpp.UInt8; import haxe.io.Bytes; import lime.system.JNI; import sys.FileStat; @@ -336,7 +337,7 @@ class Assets public static function getBytes(file:String):Bytes { - final data:Array = __getBytes(file); + final data:Array = __getBytes(file); if (data == null || data.length <= 0) throw 'file_contents, $file'; @@ -386,7 +387,7 @@ class Assets @:noCompletion @:native('mobile::backend::io::android::Assets_obj::native_getBytes') - private static function __getBytes(file:String):Array + private static function __getBytes(file:String):Array return null; @:noCompletion From 3a4e2792ffce58dba6a8a870cd308d4a35efe237 Mon Sep 17 00:00:00 2001 From: Homura Date: Mon, 16 Feb 2026 18:35:03 +0300 Subject: [PATCH 25/50] why this still here --- source/engine/backend/Paths.hx | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/engine/backend/Paths.hx b/source/engine/backend/Paths.hx index e1926b68..3500958b 100644 --- a/source/engine/backend/Paths.hx +++ b/source/engine/backend/Paths.hx @@ -1,7 +1,5 @@ package backend; -import haxe.io.Path; -import lime.media.AudioBuffer; import flixel.graphics.frames.FlxFrame.FlxFrameAngle; import flixel.graphics.frames.FlxAtlasFrames; import flixel.graphics.FlxGraphic; From d747e229365ae31118c261d7f207c80a9a429c2c Mon Sep 17 00:00:00 2001 From: Homura Date: Thu, 26 Feb 2026 00:31:58 +0300 Subject: [PATCH 26/50] literally gonna kill me --- project.hxp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project.hxp b/project.hxp index 1db4c2d8..fa0f0f68 100644 --- a/project.hxp +++ b/project.hxp @@ -34,7 +34,7 @@ class Project extends HXProject static final FEATURE_DISCORD_RPC:CompileFlag = CompileFlag.get("FEATURE_DISCORD_RPC"); static final FEATURE_MOBILE_CONTROLS:CompileFlag = CompileFlag.get("FEATURE_MOBILE_CONTROLS"); static final FEATURE_DCE:CompileFlag = CompileFlag.get("FEATURE_DCE"); - static final USE_OPENFL_FILESYSTEM:CompileFlag = CompileFlag.get("USE_OPENFL_FILESYSTEM"); + static final USE_OPENFL_FILESYSTEM:CompileFlag = CompileFlag.get("USE_OPENFL_FILESYSTEM"); static final ENABLE_ASCII_ART:Bool = true; @@ -216,7 +216,7 @@ class Project extends HXProject FEATURE_DISCORD_RPC.integrate((isDesktop() && !isHashLink())); FEATURE_MOBILE_CONTROLS.integrate(isMobile()); FEATURE_DCE.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()) From 325456c7829608f812a3638987fb631560815351 Mon Sep 17 00:00:00 2001 From: Homura Date: Thu, 26 Feb 2026 00:45:06 +0300 Subject: [PATCH 27/50] e --- source/engine/backend/io/File.hx | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/source/engine/backend/io/File.hx b/source/engine/backend/io/File.hx index 2429ea24..ed621716 100644 --- a/source/engine/backend/io/File.hx +++ b/source/engine/backend/io/File.hx @@ -3,6 +3,7 @@ package backend.io; #if USE_OPENFL_FILESYSTEM import lime.utils.Assets as LimeAssets; import openfl.Assets as OpenFLAssets; +import openfl.utils.ByteArray as OpenFLByteArray; #end #if mobile import mobile.backend.io.Assets as MobileAssets; @@ -60,7 +61,7 @@ class File #if USE_OPENFL_FILESYSTEM if (OpenFLAssets.exists(openflcwd(path))) - return OpenFLAssets.getText(openflcwd(path)); + return OpenFLByteArray.fromFile(openflcwd(path)).toString(); #end #if mobile @@ -89,13 +90,7 @@ class File #if USE_OPENFL_FILESYSTEM if (OpenFLAssets.exists(openflcwd(path))) - switch (haxe.io.Path.extension(path).toLowerCase()) - { - case 'otf' | 'ttf': - return openfl.utils.ByteArray.fromFile(openflcwd(path)); - default: - return OpenFLAssets.getBytes(openflcwd(path)); - } + return OpenFLByteArray.fromFile(openflcwd(path)); #end #if mobile From 760c9ba620f1481f9b9911e5771599bd780922a7 Mon Sep 17 00:00:00 2001 From: Homura Date: Sat, 21 Mar 2026 11:18:01 +0300 Subject: [PATCH 28/50] smth fun --- project.hxp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.hxp b/project.hxp index 6a7037cb..ade4d886 100644 --- a/project.hxp +++ b/project.hxp @@ -220,7 +220,7 @@ class Project extends HXProject FEATURE_MOBILE_CONTROLS.integrate(isMobile()); FEATURE_DCE.integrate(false); FEATURE_FUNKIN_CONTENT.integrate(true); - USE_OPENFL_FILESYSTEM.integrate(MODS_ALLOWED.isDisabled() && !isMobile()); + USE_OPENFL_FILESYSTEM.integrate(FEATURE_MODS.isDisabled() && !isMobile()); if (FEATURE_FUNKIN_CONTENT.isEnabled()) FEATURE_HSCRIPT.integrate(true); From f410034068576b5e60a1a4cf4d13319e3e2c3547 Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 11:25:12 +0300 Subject: [PATCH 29/50] thing --- .../mobile/backend/io/android/Assets.hx | 244 +++++++++++------- 1 file changed, 155 insertions(+), 89 deletions(-) diff --git a/source/engine/mobile/backend/io/android/Assets.hx b/source/engine/mobile/backend/io/android/Assets.hx index 2f77832d..96ced060 100644 --- a/source/engine/mobile/backend/io/android/Assets.hx +++ b/source/engine/mobile/backend/io/android/Assets.hx @@ -7,6 +7,7 @@ package mobile.backend.io.android; #if android import cpp.UInt8; import haxe.io.Bytes; +import haxe.io.BytesInput; import lime.system.JNI; import sys.FileStat; @@ -14,6 +15,8 @@ import sys.FileStat; #ifndef INCLUDED_Date #include #endif +#include +#include ') @:cppNamespaceCode(' #include @@ -37,7 +40,7 @@ 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); + __android_log_print(ANDROID_LOG_DEBUG, "Shadow Engine", "Entering function %s", func); return refholder; } @@ -46,7 +49,7 @@ static bool LocalReferenceHolder_Init(struct LocalReferenceHolder *refholder, JN const int capacity = 16; if ((*env).PushLocalFrame(capacity) < 0) { - __android_log_print (ANDROID_LOG_ERROR, "Shadow Engine", "Failed to allocate enough JVM local references"); + __android_log_print(ANDROID_LOG_ERROR, "Shadow Engine", "Failed to allocate enough JVM local references"); return false; } refholder->m_env = env; @@ -55,7 +58,7 @@ static bool LocalReferenceHolder_Init(struct LocalReferenceHolder *refholder, JN static void LocalReferenceHolder_Cleanup(struct LocalReferenceHolder *refholder) { - __android_log_print (ANDROID_LOG_DEBUG, "Shadow Engine", "Leaving function %s", refholder->m_func); + __android_log_print(ANDROID_LOG_DEBUG, "Shadow Engine", "Leaving function %s", refholder->m_func); if (refholder->m_env) { JNIEnv *env = refholder->m_env; @@ -68,7 +71,7 @@ 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; @@ -81,7 +84,7 @@ void Assets_obj::native_init(::Dynamic jni_env) } // context = SDLActivity.getContext(); - midGetContext = (*env).GetStaticMethodID(mActivityClass, "getContext","()Landroid/content/Context;"); + midGetContext = (*env).GetStaticMethodID(mActivityClass, "getContext", "()Landroid/content/Context;"); context = (*env).CallStaticObjectMethod(mActivityClass, midGetContext); // javaAssetManager = context.getAssets(); @@ -90,7 +93,7 @@ void Assets_obj::native_init(::Dynamic jni_env) /** * Given a Dalvik AssetManager object, obtain the corresponding native AAssetManager - * object. Note that the caller is responsible for obtaining and holding a VM reference + * 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. */ @@ -100,9 +103,9 @@ void Assets_obj::native_init(::Dynamic jni_env) if (asset_manager == NULL) { (*env).DeleteGlobalRef(javaAssetManagerRef); - __android_log_print (ANDROID_LOG_DEBUG, "Shadow Engine", "Failed to create Android Assets Manager"); + __android_log_print(ANDROID_LOG_ERROR, "Shadow Engine", "Failed to create Android Assets Manager"); } - + LocalReferenceHolder_Cleanup(&refs); } @@ -119,46 +122,49 @@ void Assets_obj::native_destroy(::Dynamic jni_env) bool Assets_obj::native_exists(::String path) { + if (!asset_manager) + return false; + hx::EnterGCFreeZone(); + AAsset* file = AAssetManager_open(asset_manager, path.__s, AASSET_MODE_UNKNOWN); if (file != NULL) { - AAsset_close(file); + AAsset_close(file); hx::ExitGCFreeZone(); - return true; - } - - if (file) - AAsset_close(file); + return true; + } AAssetDir* dir = AAssetManager_openDir(asset_manager, path.__s); if (dir && AAssetDir_getNextFileName(dir) != NULL) { - AAssetDir_close(dir); + AAssetDir_close(dir); hx::ExitGCFreeZone(); - return true; - } + return true; + } if (dir) - AAssetDir_close(dir); + AAssetDir_close(dir); hx::ExitGCFreeZone(); return false; } -::String Assets_obj::native_getContent(::String file) { - std::vector buffer; - +::String Assets_obj::native_getContent(::String file) +{ + if (!asset_manager) + return ::String(null()); + 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); + off64_t len = AAsset_getLength64(asset); if (len <= 0) { AAsset_close(asset); @@ -166,62 +172,111 @@ bool Assets_obj::native_exists(::String path) return ::String::emptyString; } + std::vector buffer((size_t)len); + const char* src = (const char*)AAsset_getBuffer(asset); - - buffer.resize(len); - memcpy(&buffer[0], src, len); + if (src != NULL) + { + memcpy(&buffer[0], src, (size_t)len); + } + else + { + off64_t totalRead = 0; + while (totalRead < len) + { + int bytesRead = AAsset_read(asset, &buffer[totalRead], (size_t)(len - totalRead)); + if (bytesRead <= 0) + { + AAsset_close(asset); + hx::ExitGCFreeZone(); + return ::String(null()); + } + totalRead += bytesRead; + } + } AAsset_close(asset); hx::ExitGCFreeZone(); - return ::String::create(&buffer[0], buffer.size()); + return ::String::create(&buffer[0], (int)buffer.size()); } -Array Assets_obj::native_getBytes(::String file) { +Array Assets_obj::native_getBytes(::String file) +{ + if (!asset_manager) + return null(); + hx::EnterGCFreeZone(); AAsset* asset = AAssetManager_open(asset_manager, file.__s, AASSET_MODE_STREAMING); - + if (!asset) { hx::ExitGCFreeZone(); - return null(); + return null(); } - int fd; - off_t outStart; - off_t outLength; - fd = AAsset_openFileDescriptor (asset, &outStart, &outLength); - - if (fd < 0) { + off64_t len = AAsset_getLength64(asset); + if (len == 0) + { AAsset_close(asset); hx::ExitGCFreeZone(); - return null(); - } - - Array buffer = Array_obj::__new(outLength, outLength); - - if (lseek(fd, outStart, SEEK_SET) == -1) { - close(fd); + return Array_obj::__new(0, 0); + } + if (len < 0) + { AAsset_close(asset); hx::ExitGCFreeZone(); - return null(); - } + return null(); + } - int totalRead = 0; - while (totalRead < outLength) { - int bytesRead = read(fd, buffer->getBase() + totalRead, outLength - totalRead); + Array buffer = Array_obj::__new((int)len, (int)len); + + int fd; + off_t outStart; + off_t outLength; + fd = AAsset_openFileDescriptor(asset, &outStart, &outLength); - if (bytesRead <= 0) { - close(fd); + if (fd >= 0) + { + if (lseek(fd, outStart, SEEK_SET) == -1) + { + close(fd); AAsset_close(asset); hx::ExitGCFreeZone(); - return null(); - } - - totalRead += bytesRead; - } + return null(); + } + + off64_t totalRead = 0; + while (totalRead < len) + { + int bytesRead = read(fd, buffer->getBase() + totalRead, (size_t)(len - totalRead)); + if (bytesRead <= 0) + { + close(fd); + AAsset_close(asset); + hx::ExitGCFreeZone(); + return null(); + } + totalRead += bytesRead; + } + close(fd); + } + else + { + off64_t totalRead = 0; + while (totalRead < len) + { + int bytesRead = AAsset_read(asset, buffer->getBase() + totalRead, (size_t)(len - totalRead)); + if (bytesRead <= 0) + { + AAsset_close(asset); + hx::ExitGCFreeZone(); + return null(); + } + totalRead += bytesRead; + } + } - close(fd); AAsset_close(asset); hx::ExitGCFreeZone(); return buffer; @@ -229,6 +284,9 @@ Array Assets_obj::native_getBytes(::String file) { bool Assets_obj::native_isDirectory(::String path) { + if (!asset_manager) + return false; + hx::EnterGCFreeZone(); AAssetDir* dir = AAssetManager_openDir(asset_manager, path.__s); @@ -248,24 +306,27 @@ bool Assets_obj::native_isDirectory(::String path) Array<::String> Assets_obj::native_readDirectory(::String path) { - Array<::String> result = Array_obj<::String>::__new(0, 0); + if (!asset_manager) + return Array_obj<::String>::__new(0, 0); + + std::vector names; + hx::EnterGCFreeZone(); AAssetDir* dir = AAssetManager_openDir(asset_manager, path.__s); - const char* filename; - if (!dir) - { - hx::ExitGCFreeZone(); - return result; - } - - while ((filename = AAssetDir_getNextFileName(dir)) != NULL) + if (dir) { - result->push(::String(filename)); + const char* filename; + while ((filename = AAssetDir_getNextFileName(dir)) != NULL) + names.push_back(filename); + AAssetDir_close(dir); } - - AAssetDir_close(dir); hx::ExitGCFreeZone(); + + Array<::String> result = Array_obj<::String>::__new(0, 0); + for (size_t i = 0; i < names.size(); i++) + result->push(::String(names[i].c_str())); + return result; } @@ -276,29 +337,29 @@ Array<::String> Assets_obj::native_readDirectory(::String path) int fileSize = 0; int mode = isDir ? 0x4000 : 0x8000; - if (!isDir) + if (!isDir && asset_manager) { hx::EnterGCFreeZone(); AAsset* asset = AAssetManager_open(asset_manager, path.__s, AASSET_MODE_UNKNOWN); if (asset) { - fileSize = AAsset_getLength(asset); + fileSize = (int)AAsset_getLength64(asset); AAsset_close(asset); } hx::ExitGCFreeZone(); } - anon->Add(HX_CSTRING("gid"), 0); - anon->Add(HX_CSTRING("uid"), 0); + 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("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); + anon->Add(HX_CSTRING("rdev"), 0); + anon->Add(HX_CSTRING("mode"), mode); return anon; } @@ -339,12 +400,22 @@ class Assets { final data:Array = __getBytes(file); - if (data == null || data.length <= 0) + if (data == null) throw 'file_contents, $file'; return Bytes.ofData(data); } + public static function read(file:String):BytesInput + { + return new BytesInput(getBytes(file)); + } + + public static function exists(path:String):Bool + { + return __exists(path); + } + public static function isDirectory(path:String):Bool { return __isDirectory(path); @@ -360,16 +431,6 @@ class Assets 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(path:String):Bool - return false; - @:noCompletion @:native('mobile::backend::io::android::Assets_obj::native_init') private static function __init(jni_env:Dynamic):Void @@ -380,9 +441,14 @@ class Assets private static function __destroy(jni_env:Dynamic):Void return; + @:noCompletion + @:native('mobile::backend::io::android::Assets_obj::native_exists') + private static function __exists(path:String):Bool + return false; + @:noCompletion @:native('mobile::backend::io::android::Assets_obj::native_getContent') - public static function __getContent(file:String):String + private static function __getContent(file:String):String return null; @:noCompletion From f8a134de2cdfc83381fcc1c32a25e10ff13bc488 Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 11:30:14 +0300 Subject: [PATCH 30/50] dum --- source/engine/backend/io/File.hx | 2 +- source/engine/backend/io/FileSystem.hx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/engine/backend/io/File.hx b/source/engine/backend/io/File.hx index 3eba9e91..ca059195 100644 --- a/source/engine/backend/io/File.hx +++ b/source/engine/backend/io/File.hx @@ -8,7 +8,7 @@ import openfl.utils.ByteArray as OpenFLByteArray; #if mobile import mobile.backend.io.Assets as MobileAssets; #end -#if (sys && MODS_ALLOWED) +#if (sys && FEATURE_MODS) import sys.FileSystem as SysFileSystem; import sys.FileStat; import sys.io.File as SysFile; diff --git a/source/engine/backend/io/FileSystem.hx b/source/engine/backend/io/FileSystem.hx index a3e8107f..2a470563 100644 --- a/source/engine/backend/io/FileSystem.hx +++ b/source/engine/backend/io/FileSystem.hx @@ -7,7 +7,7 @@ import openfl.Assets as OpenFLAssets; #if mobile import mobile.backend.io.Assets as MobileAssets; #end -#if (sys && MODS_ALLOWED) +#if (sys && FEATURE_MODS) import sys.FileSystem as SysFileSystem; import sys.FileStat; #end From 2c18626363a014dac3f745c27665771a63a460d9 Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 11:41:45 +0300 Subject: [PATCH 31/50] ayfon --- project.hxp | 5 +- source/engine/backend/io/File.hx | 2 +- source/engine/backend/io/FileSystem.hx | 2 +- source/engine/mobile/backend/io/Assets.hx | 4 +- .../mobile/backend/io/android/Assets.hx | 2 +- source/engine/mobile/backend/io/ios/Assets.hx | 323 ++++++++++++++++++ 6 files changed, 330 insertions(+), 8 deletions(-) create mode 100644 source/engine/mobile/backend/io/ios/Assets.hx diff --git a/project.hxp b/project.hxp index b992d67f..caf2fad4 100644 --- a/project.hxp +++ b/project.hxp @@ -240,13 +240,12 @@ class Project extends HXProject FEATURE_DCE.integrate(false); FEATURE_TRACY.integrate(false); FEATURE_FUNKIN_CONTENT.integrate(true); - USE_OPENFL_FILESYSTEM.integrate(FEATURE_MODS.isDisabled() && !isMobile()); - if (FEATURE_FUNKIN_CONTENT.isEnabled()) FEATURE_HSCRIPT.integrate(true); - FEATURE_EMBED_ASSETS.integrate(false); + USE_OPENFL_FILESYSTEM.integrate((FEATURE_MODS.isDisabled() || FEATURE_EMBED_ASSETS.isEnabled()) && !isMobile()); + setHaxedef("FLX_NO_FOCUS_LOST_SCREEN"); if (!isDebug()) setHaxedef("FLX_NO_DEBUG"); diff --git a/source/engine/backend/io/File.hx b/source/engine/backend/io/File.hx index ca059195..9041a7e0 100644 --- a/source/engine/backend/io/File.hx +++ b/source/engine/backend/io/File.hx @@ -131,7 +131,7 @@ class File #end #end #if mobile - // SHADOW TODO + return MobileAssets.read(path, binary); #end return null; } diff --git a/source/engine/backend/io/FileSystem.hx b/source/engine/backend/io/FileSystem.hx index 2a470563..e707ef38 100644 --- a/source/engine/backend/io/FileSystem.hx +++ b/source/engine/backend/io/FileSystem.hx @@ -273,7 +273,7 @@ class FileSystem } #end - #if ((linux || ios) && FEATURE_MODS) + #if (linux && FEATURE_MODS) static function getCaseInsensitivePath(path:String):String { if (SysFileSystem.exists(path)) diff --git a/source/engine/mobile/backend/io/Assets.hx b/source/engine/mobile/backend/io/Assets.hx index 89cd20f6..95e0cf66 100644 --- a/source/engine/mobile/backend/io/Assets.hx +++ b/source/engine/mobile/backend/io/Assets.hx @@ -2,6 +2,6 @@ package mobile.backend.io; #if android typedef Assets = mobile.backend.io.android.Assets; -// #elseif ios -// typedef Assets = mobile.backend.io.ios.Assets; +#elseif ios +typedef Assets = mobile.backend.io.ios.Assets; #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 index 96ced060..fa92aa91 100644 --- a/source/engine/mobile/backend/io/android/Assets.hx +++ b/source/engine/mobile/backend/io/android/Assets.hx @@ -406,7 +406,7 @@ class Assets return Bytes.ofData(data); } - public static function read(file:String):BytesInput + public static function read(file:String, ?binary:Bool):BytesInput { return new BytesInput(getBytes(file)); } diff --git a/source/engine/mobile/backend/io/ios/Assets.hx b/source/engine/mobile/backend/io/ios/Assets.hx new file mode 100644 index 00000000..2df623ca --- /dev/null +++ b/source/engine/mobile/backend/io/ios/Assets.hx @@ -0,0 +1,323 @@ +package mobile.backend.io.ios; + +#if ios +import cpp.UInt8; +import haxe.io.Bytes; +import haxe.io.BytesInput; +import sys.FileStat; + +@:cppFileCode(' +#ifndef INCLUDED_Date +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +') +@:cppNamespaceCode(' +static const std::string& getBundleResourcePath() +{ + static std::string cached; + static bool resolved = false; + if (resolved) + return cached; + + CFBundleRef bundle = CFBundleGetMainBundle(); + if (bundle) + { + CFURLRef url = CFBundleCopyResourcesDirectoryURL(bundle); + if (url) + { + char path[PATH_MAX]; + if (CFURLGetFileSystemRepresentation(url, true, (UInt8*)path, (CFIndex)sizeof(path))) + cached = path; + CFRelease(url); + } + } + resolved = true; + return cached; +} + +static std::string resolveAssetPath(const char* logicalPath) +{ + const std::string& base = getBundleResourcePath(); + if (base.empty()) + return std::string(); + // avoiding double-slash if logicalPath already starts + if (logicalPath[0] == '/') + return base + logicalPath; + return base + "/" + logicalPath; +} + +bool Assets_obj::native_exists(::String path) +{ + hx::EnterGCFreeZone(); + std::string fullPath = resolveAssetPath(path.__s); + bool exists = false; + if (!fullPath.empty()) + { + struct stat st; + exists = (stat(fullPath.c_str(), &st) == 0); + } + hx::ExitGCFreeZone(); + return exists; +} + +::String Assets_obj::native_getContent(::String file) +{ + hx::EnterGCFreeZone(); + std::string fullPath = resolveAssetPath(file.__s); + std::vector buffer; + bool failed = true; + + if (!fullPath.empty()) + { + int fd = open(fullPath.c_str(), O_RDONLY | O_CLOEXEC); + if (fd >= 0) + { + struct stat st; + if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) + { + off_t len = st.st_size; + if (len == 0) + { + failed = false; // valid empty file + } + else + { + buffer.resize((size_t)len); + ssize_t totalRead = 0; + while (totalRead < (ssize_t)len) + { + ssize_t n = read(fd, &buffer[totalRead], (size_t)(len - totalRead)); + if (n <= 0) { buffer.clear(); break; } + totalRead += n; + } + if (totalRead == (ssize_t)len) + failed = false; + } + } + close(fd); + } + } + + hx::ExitGCFreeZone(); + + if (failed) + return ::String(null()); + if (buffer.empty()) + return ::String::emptyString; + return ::String::create(&buffer[0], (int)buffer.size()); +} + +Array Assets_obj::native_getBytes(::String file) +{ + hx::EnterGCFreeZone(); + std::string fullPath = resolveAssetPath(file.__s); + off_t len = -1; + bool isFile = false; + + if (!fullPath.empty()) + { + struct stat st; + if (stat(fullPath.c_str(), &st) == 0 && S_ISREG(st.st_mode)) + { + len = st.st_size; + isFile = true; + } + } + hx::ExitGCFreeZone(); + + if (!isFile) + return null(); + + if (len == 0) + return Array_obj::__new(0, 0); + + Array result = Array_obj::__new((int)len, (int)len); + + hx::EnterGCFreeZone(); + int fd = open(fullPath.c_str(), O_RDONLY | O_CLOEXEC); + bool readOk = false; + + if (fd >= 0) + { + ssize_t totalRead = 0; + while (totalRead < (ssize_t)len) + { + ssize_t n = read(fd, result->getBase() + totalRead, (size_t)(len - totalRead)); + if (n <= 0) break; + totalRead += n; + } + readOk = (totalRead == (ssize_t)len); + close(fd); + } + hx::ExitGCFreeZone(); + + return readOk ? result : null(); +} + +bool Assets_obj::native_isDirectory(::String path) +{ + hx::EnterGCFreeZone(); + std::string fullPath = resolveAssetPath(path.__s); + bool isDir = false; + if (!fullPath.empty()) + { + struct stat st; + if (stat(fullPath.c_str(), &st) == 0) + isDir = S_ISDIR(st.st_mode); + } + hx::ExitGCFreeZone(); + return isDir; +} + +Array<::String> Assets_obj::native_readDirectory(::String path) +{ + hx::EnterGCFreeZone(); + std::string fullPath = resolveAssetPath(path.__s); + std::vector names; + + if (!fullPath.empty()) + { + DIR* dir = opendir(fullPath.c_str()); + if (dir) + { + struct dirent* entry; + while ((entry = readdir(dir)) != NULL) + { + const char* name = entry->d_name; + if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) + continue; + names.push_back(name); + } + closedir(dir); + } + } + hx::ExitGCFreeZone(); + + Array<::String> result = Array_obj<::String>::__new(0, 0); + for (size_t i = 0; i < names.size(); i++) + result->push(::String(names[i].c_str())); + return result; +} + +::Dynamic Assets_obj::native_stat(::String path) +{ + hx::EnterGCFreeZone(); + std::string fullPath = resolveAssetPath(path.__s); + bool found = false; + struct stat st; + memset(&st, 0, sizeof(st)); + if (!fullPath.empty()) + found = (stat(fullPath.c_str(), &st) == 0); + hx::ExitGCFreeZone(); + + hx::Anon anon = hx::Anon_obj::Create(); + int mode = !found ? 0 : (S_ISDIR(st.st_mode) ? 0x4000 : 0x8000); + + anon->Add(HX_CSTRING("gid"), found ? (int)st.st_gid : 0); + anon->Add(HX_CSTRING("uid"), found ? (int)st.st_uid : 0); + anon->Add(HX_CSTRING("atime"), ::Date_obj::fromTime(found ? (double)st.st_atime * 1000.0 : 0.0)); + anon->Add(HX_CSTRING("mtime"), ::Date_obj::fromTime(found ? (double)st.st_mtime * 1000.0 : 0.0)); + anon->Add(HX_CSTRING("ctime"), ::Date_obj::fromTime(found ? (double)st.st_ctime * 1000.0 : 0.0)); + anon->Add(HX_CSTRING("size"), found ? (int)st.st_size : 0); + anon->Add(HX_CSTRING("dev"), found ? (int)st.st_dev : 0); + anon->Add(HX_CSTRING("ino"), found ? (int)st.st_ino : 0); + anon->Add(HX_CSTRING("nlink"), found ? (int)st.st_nlink : 0); + anon->Add(HX_CSTRING("rdev"), found ? (int)st.st_rdev : 0); + anon->Add(HX_CSTRING("mode"), mode); + return anon; +} +') +@:headerClassCode(' + 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 +{ + 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) + throw 'file_contents, $file'; + + return Bytes.ofData(data); + } + + public static function read(file:String, ?binary:Bool):BytesInput + { + return new BytesInput(getBytes(file)); + } + + public static function exists(path:String):Bool + { + return __exists(path); + } + + 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); + } + + @:noCompletion + @:native('mobile::backend::io::ios::Assets_obj::native_exists') + private static function __exists(path:String):Bool + return false; + + @:noCompletion + @:native('mobile::backend::io::ios::Assets_obj::native_getContent') + private static function __getContent(file:String):String + return null; + + @:noCompletion + @:native('mobile::backend::io::ios::Assets_obj::native_getBytes') + private static function __getBytes(file:String):Array + return null; + + @:noCompletion + @:native('mobile::backend::io::ios::Assets_obj::native_isDirectory') + private static function __isDirectory(path:String):Bool + return false; + + @:noCompletion + @:native('mobile::backend::io::ios::Assets_obj::native_readDirectory') + private static function __readDirectory(path:String):Array + return null; + + @:noCompletion + @:native('mobile::backend::io::ios::Assets_obj::native_stat') + private static function __stat(path:String):Dynamic + return null; +} +#end From d15cf680bb6a7a2f0ccb08720168651a8d90531e Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 11:51:57 +0300 Subject: [PATCH 32/50] gonna null for now --- source/engine/backend/io/File.hx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/source/engine/backend/io/File.hx b/source/engine/backend/io/File.hx index 9041a7e0..c0abbcb1 100644 --- a/source/engine/backend/io/File.hx +++ b/source/engine/backend/io/File.hx @@ -129,11 +129,14 @@ class File #else return SysFile.read(cwd(path), binary); #end - #end + #else #if mobile - return MobileAssets.read(path, binary); - #end + // return MobileAssets.read(path, binary); return null; + #else + return null; + #end + #end } public static function write(path:String, binary:Bool = true):Null<#if sys FileOutput #else Dynamic #end> From 71454d6bef01c63505f5f35b48ed78cf267a36bc Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 12:04:49 +0300 Subject: [PATCH 33/50] plain number --- source/engine/mobile/backend/io/ios/Assets.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/engine/mobile/backend/io/ios/Assets.hx b/source/engine/mobile/backend/io/ios/Assets.hx index 2df623ca..f0618f66 100644 --- a/source/engine/mobile/backend/io/ios/Assets.hx +++ b/source/engine/mobile/backend/io/ios/Assets.hx @@ -192,7 +192,7 @@ Array<::String> Assets_obj::native_readDirectory(::String path) while ((entry = readdir(dir)) != NULL) { const char* name = entry->d_name; - if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) + if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) continue; names.push_back(name); } From 1f1134012f82f5f057f30925761e0c9e3d5a9811 Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 12:17:13 +0300 Subject: [PATCH 34/50] I'm gonna try my luck --- source/engine/mobile/backend/io/ios/Assets.hx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/engine/mobile/backend/io/ios/Assets.hx b/source/engine/mobile/backend/io/ios/Assets.hx index f0618f66..05b28adc 100644 --- a/source/engine/mobile/backend/io/ios/Assets.hx +++ b/source/engine/mobile/backend/io/ios/Assets.hx @@ -19,7 +19,7 @@ import sys.FileStat; #include #include ') -@:cppNamespaceCode(' +@:cppNamespaceCode(''' static const std::string& getBundleResourcePath() { static std::string cached; @@ -192,7 +192,7 @@ Array<::String> Assets_obj::native_readDirectory(::String path) while ((entry = readdir(dir)) != NULL) { const char* name = entry->d_name; - if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) + if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) continue; names.push_back(name); } @@ -234,7 +234,7 @@ Array<::String> Assets_obj::native_readDirectory(::String path) anon->Add(HX_CSTRING("mode"), mode); return anon; } -') +''') @:headerClassCode(' static bool native_exists(::String path); static ::String native_getContent(::String file); From 90ea3aa969d911f1f97dc7a432231bc39026f2f5 Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 12:28:12 +0300 Subject: [PATCH 35/50] bro wat --- source/engine/mobile/backend/io/ios/Assets.hx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/engine/mobile/backend/io/ios/Assets.hx b/source/engine/mobile/backend/io/ios/Assets.hx index 05b28adc..8b9b94ed 100644 --- a/source/engine/mobile/backend/io/ios/Assets.hx +++ b/source/engine/mobile/backend/io/ios/Assets.hx @@ -19,7 +19,7 @@ import sys.FileStat; #include #include ') -@:cppNamespaceCode(''' +@:cppNamespaceCode(' static const std::string& getBundleResourcePath() { static std::string cached; @@ -49,7 +49,7 @@ static std::string resolveAssetPath(const char* logicalPath) if (base.empty()) return std::string(); // avoiding double-slash if logicalPath already starts - if (logicalPath[0] == '/') + if (logicalPath[0] == \'/\') return base + logicalPath; return base + "/" + logicalPath; } @@ -192,7 +192,7 @@ Array<::String> Assets_obj::native_readDirectory(::String path) while ((entry = readdir(dir)) != NULL) { const char* name = entry->d_name; - if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) + if (name[0] == \'.\' && (name[1] == \'\\0\' || (name[1] == \'.\' && name[2] == \'\\0\'))) continue; names.push_back(name); } @@ -234,7 +234,7 @@ Array<::String> Assets_obj::native_readDirectory(::String path) anon->Add(HX_CSTRING("mode"), mode); return anon; } -''') +') @:headerClassCode(' static bool native_exists(::String path); static ::String native_getContent(::String file); From a2e58e14571a365ceced1abecdbbb495ab395244 Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 15:28:20 +0300 Subject: [PATCH 36/50] no-op funcs --- source/engine/mobile/backend/io/ios/Assets.hx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/engine/mobile/backend/io/ios/Assets.hx b/source/engine/mobile/backend/io/ios/Assets.hx index 8b9b94ed..d1a60607 100644 --- a/source/engine/mobile/backend/io/ios/Assets.hx +++ b/source/engine/mobile/backend/io/ios/Assets.hx @@ -245,6 +245,9 @@ Array<::String> Assets_obj::native_readDirectory(::String path) ') class Assets { + public static function init():Void {} + public static function destroy():Void {} + public static function getContent(file:String):String { final content:String = __getContent(file); From 6835b8a81dbb42c9d6f6e83d54d7fc9bf534a756 Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 15:39:50 +0300 Subject: [PATCH 37/50] ugh --- source/engine/mobile/backend/io/android/Assets.hx | 4 ++-- source/engine/mobile/backend/io/ios/Assets.hx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/engine/mobile/backend/io/android/Assets.hx b/source/engine/mobile/backend/io/android/Assets.hx index fa92aa91..36311e2e 100644 --- a/source/engine/mobile/backend/io/android/Assets.hx +++ b/source/engine/mobile/backend/io/android/Assets.hx @@ -406,10 +406,10 @@ class Assets return Bytes.ofData(data); } - public static function read(file:String, ?binary:Bool):BytesInput + /*public static function read(file:String, ?binary:Bool):BytesInput { return new BytesInput(getBytes(file)); - } + }*/ public static function exists(path:String):Bool { diff --git a/source/engine/mobile/backend/io/ios/Assets.hx b/source/engine/mobile/backend/io/ios/Assets.hx index d1a60607..0e76abf8 100644 --- a/source/engine/mobile/backend/io/ios/Assets.hx +++ b/source/engine/mobile/backend/io/ios/Assets.hx @@ -268,10 +268,10 @@ class Assets return Bytes.ofData(data); } - public static function read(file:String, ?binary:Bool):BytesInput + /*public static function read(file:String, ?binary:Bool):BytesInput { return new BytesInput(getBytes(file)); - } + }*/ public static function exists(path:String):Bool { From 6493aad32306818479203eadd00ed17c2d1d141e Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 16:15:55 +0300 Subject: [PATCH 38/50] idfk --- source/engine/mobile/backend/io/ios/Assets.hx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/engine/mobile/backend/io/ios/Assets.hx b/source/engine/mobile/backend/io/ios/Assets.hx index 0e76abf8..00ebe4ec 100644 --- a/source/engine/mobile/backend/io/ios/Assets.hx +++ b/source/engine/mobile/backend/io/ios/Assets.hx @@ -62,7 +62,7 @@ bool Assets_obj::native_exists(::String path) if (!fullPath.empty()) { struct stat st; - exists = (stat(fullPath.c_str(), &st) == 0); + exists = (::stat(fullPath.c_str(), &st) == 0); } hx::ExitGCFreeZone(); return exists; @@ -125,7 +125,7 @@ Array Assets_obj::native_getBytes(::String file) if (!fullPath.empty()) { struct stat st; - if (stat(fullPath.c_str(), &st) == 0 && S_ISREG(st.st_mode)) + if (::stat(fullPath.c_str(), &st) == 0 && S_ISREG(st.st_mode)) { len = st.st_size; isFile = true; @@ -170,7 +170,7 @@ bool Assets_obj::native_isDirectory(::String path) if (!fullPath.empty()) { struct stat st; - if (stat(fullPath.c_str(), &st) == 0) + if (::stat(fullPath.c_str(), &st) == 0) isDir = S_ISDIR(st.st_mode); } hx::ExitGCFreeZone(); @@ -215,7 +215,7 @@ Array<::String> Assets_obj::native_readDirectory(::String path) struct stat st; memset(&st, 0, sizeof(st)); if (!fullPath.empty()) - found = (stat(fullPath.c_str(), &st) == 0); + found = (::stat(fullPath.c_str(), &st) == 0); hx::ExitGCFreeZone(); hx::Anon anon = hx::Anon_obj::Create(); From ffc929c02ce7289c80c2eba4f84b92d4005f7a9e Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 17:26:15 +0300 Subject: [PATCH 39/50] little more OpenFL fixes --- source/engine/backend/io/File.hx | 10 ++++++++-- source/engine/backend/io/FileSystem.hx | 6 ++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/source/engine/backend/io/File.hx b/source/engine/backend/io/File.hx index c0abbcb1..0d3f0fb9 100644 --- a/source/engine/backend/io/File.hx +++ b/source/engine/backend/io/File.hx @@ -63,7 +63,7 @@ class File #if USE_OPENFL_FILESYSTEM if (OpenFLAssets.exists(openflcwd(path))) - return OpenFLByteArray.fromFile(openflcwd(path)).toString(); + return OpenFLAssets.getText(openflcwd(path)); #end #if mobile @@ -92,7 +92,13 @@ class File #if USE_OPENFL_FILESYSTEM if (OpenFLAssets.exists(openflcwd(path))) - return OpenFLByteArray.fromFile(openflcwd(path)); + switch (haxe.io.Path.extension(path).toLowerCase()) + { + case 'otf' | 'ttf': + return OpenFLByteArray.fromFile(openflcwd(path)); + default: + return OpenFLAssets.getBytes(openflcwd(path)); + } #end #if mobile diff --git a/source/engine/backend/io/FileSystem.hx b/source/engine/backend/io/FileSystem.hx index e707ef38..ddf20dbb 100644 --- a/source/engine/backend/io/FileSystem.hx +++ b/source/engine/backend/io/FileSystem.hx @@ -101,12 +101,14 @@ class FileSystem if (SysFileSystem.exists(cwd(path))) return SysFileSystem.stat(cwd(path)); #end - #end + #else #if mobile if (MobileAssets.exists(path)) return MobileAssets.stat(path); - #end + #else return null; + #end + #end } public static function fullPath(path:String):String From b6d7ad4d7ea700dd28d263d7c180d690ab50fc73 Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 17:30:08 +0300 Subject: [PATCH 40/50] puh --- project.hxp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/project.hxp b/project.hxp index caf2fad4..44460bd0 100644 --- a/project.hxp +++ b/project.hxp @@ -240,9 +240,10 @@ class Project extends HXProject FEATURE_DCE.integrate(false); FEATURE_TRACY.integrate(false); FEATURE_FUNKIN_CONTENT.integrate(true); + FEATURE_EMBED_ASSETS.integrate(false); + if (FEATURE_FUNKIN_CONTENT.isEnabled()) FEATURE_HSCRIPT.integrate(true); - FEATURE_EMBED_ASSETS.integrate(false); USE_OPENFL_FILESYSTEM.integrate((FEATURE_MODS.isDisabled() || FEATURE_EMBED_ASSETS.isEnabled()) && !isMobile()); From b378ae7e8999235845776a9165554d28410a868b Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 17:51:33 +0300 Subject: [PATCH 41/50] idfk?? --- source/engine/backend/io/FileSystem.hx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/source/engine/backend/io/FileSystem.hx b/source/engine/backend/io/FileSystem.hx index ddf20dbb..601f03d6 100644 --- a/source/engine/backend/io/FileSystem.hx +++ b/source/engine/backend/io/FileSystem.hx @@ -89,6 +89,10 @@ class FileSystem public static function stat(path:String):Null<#if sys FileStat #else Dynamic #end> { + #if mobile + if (MobileAssets.exists(path)) + return MobileAssets.stat(path); + #end #if FEATURE_MODS #if linux var actualPath:String = cwd(path); @@ -102,13 +106,8 @@ class FileSystem return SysFileSystem.stat(cwd(path)); #end #else - #if mobile - if (MobileAssets.exists(path)) - return MobileAssets.stat(path); - #else return null; #end - #end } public static function fullPath(path:String):String From c1314bb405a9821f988aa1b09d8f194fb28f51d8 Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 17:52:12 +0300 Subject: [PATCH 42/50] just fuck off --- source/engine/backend/io/FileSystem.hx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/engine/backend/io/FileSystem.hx b/source/engine/backend/io/FileSystem.hx index 601f03d6..03340ab7 100644 --- a/source/engine/backend/io/FileSystem.hx +++ b/source/engine/backend/io/FileSystem.hx @@ -89,10 +89,6 @@ class FileSystem public static function stat(path:String):Null<#if sys FileStat #else Dynamic #end> { - #if mobile - if (MobileAssets.exists(path)) - return MobileAssets.stat(path); - #end #if FEATURE_MODS #if linux var actualPath:String = cwd(path); @@ -106,6 +102,10 @@ class FileSystem return SysFileSystem.stat(cwd(path)); #end #else + #if mobile + if (MobileAssets.exists(path)) + return MobileAssets.stat(path); + #end return null; #end } From fa5cda019c2e450d61abe2a6822e81a0b0be8ad4 Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 17:52:43 +0300 Subject: [PATCH 43/50] d --- source/engine/backend/io/File.hx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/source/engine/backend/io/File.hx b/source/engine/backend/io/File.hx index 0d3f0fb9..182a6a09 100644 --- a/source/engine/backend/io/File.hx +++ b/source/engine/backend/io/File.hx @@ -138,10 +138,8 @@ class File #else #if mobile // return MobileAssets.read(path, binary); - return null; - #else - return null; #end + return null; #end } From 104f02142a3420c9d62f7a154aa9b972642a5f09 Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 18:53:53 +0300 Subject: [PATCH 44/50] I do not fucking understand Haxe --- source/engine/backend/io/FileSystem.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/source/engine/backend/io/FileSystem.hx b/source/engine/backend/io/FileSystem.hx index 03340ab7..fdf1fa09 100644 --- a/source/engine/backend/io/FileSystem.hx +++ b/source/engine/backend/io/FileSystem.hx @@ -101,6 +101,7 @@ class FileSystem if (SysFileSystem.exists(cwd(path))) return SysFileSystem.stat(cwd(path)); #end + return null; #else #if mobile if (MobileAssets.exists(path)) From 8a938bfa8cf32c9911cab8035a90ef2ab9fcc31c Mon Sep 17 00:00:00 2001 From: Simon Ars <127692841+SimonArs@users.noreply.github.com> Date: Wed, 24 Jun 2026 17:01:49 +0200 Subject: [PATCH 45/50] Diff enum abstract to enum and other changes --- source/engine/backend/Difficulty.hx | 45 +++++++++++--- source/engine/backend/WeekData.hx | 4 +- source/engine/objects/VideoSprite.hx | 62 +++++++++++-------- source/engine/psychlua/FunkinLua.hx | 4 +- source/engine/states/FreeplayState.hx | 2 +- source/engine/states/PlayState.hx | 2 +- source/engine/states/StoryMenuState.hx | 2 +- .../engine/states/editors/WeekEditorState.hx | 2 +- source/engine/substates/PauseSubState.hx | 4 +- 9 files changed, 82 insertions(+), 45 deletions(-) diff --git a/source/engine/backend/Difficulty.hx b/source/engine/backend/Difficulty.hx index 56c5b70a..b71ac2b1 100644 --- a/source/engine/backend/Difficulty.hx +++ b/source/engine/backend/Difficulty.hx @@ -24,7 +24,7 @@ class Difficulty final diff:Diff = getByIndex(index); - final fileSuffix:String = diff != NORMAL ? '-$diff' : ''; + final fileSuffix:String = diff != NORMAL ? '-${diffToString(diff)}' : ''; return Paths.formatToSongPath(fileSuffix); } @@ -32,12 +32,12 @@ class Difficulty { week ??= WeekData.getCurrentWeek(); - final diffStr:Array = week.difficulties; + final diffStr:Array = week.difficulties; if (diffStr != null && diffStr.length > 0) { list = []; for (diff in diffStr) - list.push((diff:String).toLowerCase()); + list.push(stringToDiff(diff)); } else resetList(); @@ -60,13 +60,38 @@ class Difficulty return includeDash ? '' : null; } + + inline public static function diffToString(diff:Diff):String + { + switch (diff) + { + case EASY: return "easy"; + case NORMAL: return "normal"; + case HARD: return "hard"; + case ERECT: return "erect"; + case NIGHTMARE: return "nightmare"; + } + } + + inline public static function stringToDiff(str:String):Diff + { + switch (str.toLowerCase()) + { + case "easy": return EASY; + case "normal": return NORMAL; + case "hard": return HARD; + case "erect": return ERECT; + case "nightmare": return NIGHTMARE; + default: return NORMAL; + } + } } -enum abstract Diff(String) from String to String +enum Diff { - final EASY:Diff = "easy"; - final NORMAL:Diff = "normal"; - final HARD:Diff = "hard"; - final ERECT:Diff = "erect"; - final NIGHTMARE:Diff = "nightmare"; -} + EASY; + NORMAL; + HARD; + ERECT; + NIGHTMARE; +} \ No newline at end of file diff --git a/source/engine/backend/WeekData.hx b/source/engine/backend/WeekData.hx index 13d12059..a3843448 100644 --- a/source/engine/backend/WeekData.hx +++ b/source/engine/backend/WeekData.hx @@ -14,7 +14,7 @@ typedef WeekFile = var hiddenUntilUnlocked:Bool; var hideStoryMode:Bool; var hideFreeplay:Bool; - var difficulties:Array; + var difficulties:Array; } class WeekData @@ -36,7 +36,7 @@ class WeekData public var hiddenUntilUnlocked:Bool; public var hideStoryMode:Bool; public var hideFreeplay:Bool; - public var difficulties:Array; + public var difficulties:Array; public var fileName:String; diff --git a/source/engine/objects/VideoSprite.hx b/source/engine/objects/VideoSprite.hx index 28c9c78c..4c0fd828 100644 --- a/source/engine/objects/VideoSprite.hx +++ b/source/engine/objects/VideoSprite.hx @@ -16,11 +16,13 @@ class VideoSprite extends FlxSpriteGroup public var cover:FlxSprite; public var canSkip(default, set):Bool = false; public var waiting:Bool = false; + final _timeToSkip:Float = 1; var videoName:String; var alreadyDestroyed:Bool = false; - public function new(videoName:String, isWaiting:Bool, canSkip:Bool = false, shouldLoop:Bool = false):Void { + public function new(videoName:String, isWaiting:Bool, canSkip:Bool = false, shouldLoop:Bool = false):Void + { super(); this.videoName = videoName; @@ -28,7 +30,8 @@ class VideoSprite extends FlxSpriteGroup cameras = [FlxG.cameras.list[FlxG.cameras.list.length - 1]]; waiting = isWaiting; - if (!waiting) { + if (!waiting) + { add(cover = new FlxSprite().makeGraphic(1, 1, FlxColor.BLACK)); cover.scale.set(FlxG.width + 100, FlxG.height + 100); cover.screenCenter(); @@ -46,7 +49,8 @@ class VideoSprite extends FlxSpriteGroup if (!shouldLoop) videoSprite.bitmap.onEndReached.add(finishVideo); - videoSprite.bitmap.onFormatSetup.add(() -> { + videoSprite.bitmap.onFormatSetup.add(() -> + { /* #if FEATURE_VIDEOS var wd:Int = videoSprite.bitmap.formatWidth; @@ -64,11 +68,14 @@ class VideoSprite extends FlxSpriteGroup videoSprite.load(videoName, shouldLoop ? ['input-repeat=65545'] : null); } - override function destroy():Void { - if (alreadyDestroyed) return; + override function destroy():Void + { + if (alreadyDestroyed) + return; - //trace('Video destroyed'); - if (cover != null) { + // trace('Video destroyed'); + if (cover != null) + { remove(cover); cover.destroy(); } @@ -76,7 +83,8 @@ class VideoSprite extends FlxSpriteGroup finishCallback = null; onSkip = null; - if (FlxG.state != null) { + if (FlxG.state != null) + { if (FlxG.state.members.contains(this)) FlxG.state.remove(this); @@ -88,7 +96,8 @@ class VideoSprite extends FlxSpriteGroup alreadyDestroyed = true; } - function finishVideo():Void { + function finishVideo():Void + { if (alreadyDestroyed) return; if (finishCallback != null) @@ -97,35 +106,44 @@ class VideoSprite extends FlxSpriteGroup destroy(); } - override function update(elapsed:Float):Void { - if (canSkip) { + override function update(elapsed:Float):Void + { + if (canSkip) + { if (Controls.instance.pressed('accept') || mobile.backend.TouchUtil.pressed) holdingTime = Math.max(0, Math.min(_timeToSkip, holdingTime + elapsed)); else if (holdingTime > 0) holdingTime = Math.max(0, FlxMath.lerp(holdingTime, -0.1, FlxMath.bound(elapsed * 3, 0, 1))); - updateSkipAlpha(); + if (skipSprite != null) + skipSprite.alpha = skipSprite.amount = FlxMath.bound(holdingTime / _timeToSkip * 1.025, 0, 1); - if (holdingTime >= _timeToSkip) { + if (holdingTime >= _timeToSkip) + { if (onSkip != null) onSkip(); finishCallback = null; videoSprite.bitmap.onEndReached.dispatch(); - //trace('Skipped video'); + // trace('Skipped video'); return; } } super.update(elapsed); } - function set_canSkip(val:Bool):Bool { - if (val) { - if (skipSprite == null) { + function set_canSkip(val:Bool):Bool + { + if (val) + { + if (skipSprite == null) + { add(skipSprite = new FlxRadialGauge(0, 0, backend.Paths.image('pie'))); skipSprite.setPosition(FlxG.width - (skipSprite.width + 80), FlxG.height - (skipSprite.height + 72)); - skipSprite.amount = 0; + skipSprite.alpha = skipSprite.amount = 0; + skipSprite.blend = INVERT; } } - else if (skipSprite != null) { + else if (skipSprite != null) + { remove(skipSprite); skipSprite = flixel.util.FlxDestroyUtil.destroy(skipSprite); } @@ -133,12 +151,6 @@ class VideoSprite extends FlxSpriteGroup return canSkip = val; } - function updateSkipAlpha():Void { - if (skipSprite == null) return; - skipSprite.amount = FlxMath.bound(holdingTime / _timeToSkip * 1.025, 0, 1); - skipSprite.alpha = FlxMath.remapToRange(skipSprite.amount, 0.025, 1, 0, 1); - } - public function play():Void videoSprite?.play(); diff --git a/source/engine/psychlua/FunkinLua.hx b/source/engine/psychlua/FunkinLua.hx index 73fcb920..a9abad50 100644 --- a/source/engine/psychlua/FunkinLua.hx +++ b/source/engine/psychlua/FunkinLua.hx @@ -109,8 +109,8 @@ class FunkinLua set('songLength', FlxG.sound.music.length); set('startedCountdown', false); - set('difficultyName', Difficulty.getByIndex()); - set('difficultyPath', Paths.formatToSongPath(Difficulty.getByIndex())); + set('difficultyName', Difficulty.diffToString(Difficulty.getByIndex())); + set('difficultyPath', Paths.formatToSongPath(Difficulty.diffToString(Difficulty.getByIndex()))); set('isErect', game.isErect); set('weekRaw', PlayState.storyWeek); set('week', WeekData.weeksList[PlayState.storyWeek]); diff --git a/source/engine/states/FreeplayState.hx b/source/engine/states/FreeplayState.hx index c72236d4..ca8f7eca 100644 --- a/source/engine/states/FreeplayState.hx +++ b/source/engine/states/FreeplayState.hx @@ -425,7 +425,7 @@ class FreeplayState extends MusicBeatState intendedScore = Highscore.getScore(songs[curSelected].songName, curDifficulty); intendedRating = Highscore.getRating(songs[curSelected].songName, curDifficulty); - final diffStr:String = Difficulty.getByIndex(curDifficulty); + final diffStr:String = Difficulty.diffToString(Difficulty.getByIndex(curDifficulty)); diffText.text = Difficulty.list.length > 1 ? '< ${diffStr.toUpperCase()} >' : diffStr.toUpperCase(); positionHighscore(); diff --git a/source/engine/states/PlayState.hx b/source/engine/states/PlayState.hx index 85d34bc6..d1bce80e 100644 --- a/source/engine/states/PlayState.hx +++ b/source/engine/states/PlayState.hx @@ -323,7 +323,7 @@ class PlayState extends MusicBeatState noteSkin = Note.defaultNoteSkin; #if FEATURE_DISCORD_RPC - storyDifficultyText = Difficulty.getByIndex(); + storyDifficultyText = Difficulty.diffToString(Difficulty.getByIndex()); if (isStoryMode) detailsText = "Story Mode: " + WeekData.getCurrentWeek().weekName; diff --git a/source/engine/states/StoryMenuState.hx b/source/engine/states/StoryMenuState.hx index 73dfcf5b..490fdc60 100644 --- a/source/engine/states/StoryMenuState.hx +++ b/source/engine/states/StoryMenuState.hx @@ -357,7 +357,7 @@ class StoryMenuState extends MusicBeatState callOnScripts('onChangeDifficulty'); WeekData.setDirectoryFromWeek(loadedWeeks[curWeek]); - var diff:String = Difficulty.list[curDifficulty]; + var diff:String = Difficulty.diffToString(Difficulty.list[curDifficulty]); var diffPath:String = 'menudifficulties/' + Paths.formatToSongPath(diff); var spriteSheetExists:Bool = Paths.fileExists('images/menudifficulties/$diff.xml', TEXT); diff --git a/source/engine/states/editors/WeekEditorState.hx b/source/engine/states/editors/WeekEditorState.hx index 1b97047d..9dafce37 100644 --- a/source/engine/states/editors/WeekEditorState.hx +++ b/source/engine/states/editors/WeekEditorState.hx @@ -335,7 +335,7 @@ class WeekEditorState extends MusicBeatState hideCheckbox.checked = weekFile.hideStoryMode; weekBeforeInputText.text = weekFile.weekBefore; - final diffs:Array = weekFile.difficulties; + final diffs:Array = weekFile.difficulties; if (diffs != null) { final diffStr:Array = [for (diff in diffs) diff]; diff --git a/source/engine/substates/PauseSubState.hx b/source/engine/substates/PauseSubState.hx index 36e7d8fc..26cb2c86 100644 --- a/source/engine/substates/PauseSubState.hx +++ b/source/engine/substates/PauseSubState.hx @@ -58,7 +58,7 @@ class PauseSubState extends MusicBeatSubstate menuItems = menuItemsOG; for (diff in Difficulty.list) - difficultyChoices.push(diff); + difficultyChoices.push(Difficulty.diffToString(diff)); difficultyChoices.push('BACK'); @@ -91,7 +91,7 @@ class PauseSubState extends MusicBeatSubstate levelInfo.updateHitbox(); add(levelInfo); - final diffka:String = Difficulty.getByIndex(); + final diffka:String = Difficulty.diffToString(Difficulty.getByIndex()); var levelDifficulty:FlxText = new FlxText(20, 15 + 32, 0, diffka.charAt(0).toUpperCase() + diffka.substr(1), 32); //cuz.. levelDifficulty.scrollFactor.set(); levelDifficulty.setFormat(Paths.font('vcr.ttf'), 32); From 9f56dfd5ae6d16cc0234e0481f45209984abf47c Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 18:56:01 +0300 Subject: [PATCH 46/50] remove PixelSplashShader --- source/engine/objects/NoteSplash.hx | 6 +- source/engine/objects/SustainSplash.hx | 7 +- source/engine/shaders/PixelSplashShader.hx | 85 ---------------------- source/engine/shaders/RGBPalette.hx | 15 +++- 4 files changed, 19 insertions(+), 94 deletions(-) delete mode 100644 source/engine/shaders/PixelSplashShader.hx diff --git a/source/engine/objects/NoteSplash.hx b/source/engine/objects/NoteSplash.hx index 5f1434d9..054d335d 100644 --- a/source/engine/objects/NoteSplash.hx +++ b/source/engine/objects/NoteSplash.hx @@ -2,7 +2,7 @@ package objects; import shaders.ColorSwap; import shaders.RGBPalette; -import shaders.PixelSplashShader.PixelSplashShaderRef; + import flixel.graphics.frames.FlxFrame; using backend.CoolUtil; @@ -18,7 +18,7 @@ typedef NoteSplashConfig = class NoteSplash extends FlxSprite { public var colorSwap:ColorSwap = null; - public var rgbShader:PixelSplashShaderRef; + public var rgbShader:RGBPalette; private var idleAnim:String; private var _textureLoaded:String = null; @@ -48,7 +48,7 @@ class NoteSplash extends FlxSprite } else { - rgbShader = new PixelSplashShaderRef(); + rgbShader = new RGBPalette(); shader = rgbShader.shader; } diff --git a/source/engine/objects/SustainSplash.hx b/source/engine/objects/SustainSplash.hx index 895929d6..6926faab 100644 --- a/source/engine/objects/SustainSplash.hx +++ b/source/engine/objects/SustainSplash.hx @@ -4,7 +4,6 @@ package objects; import shaders.ColorSwap; import shaders.RGBPalette; -import shaders.PixelSplashShader.PixelSplashShaderRef; using backend.CoolUtil; @@ -29,11 +28,11 @@ class SustainSplash extends FlxSprite public var targetStrumTime(default, null):Float; public var mustPress(default, null):Bool = true; public var colorSwap:ColorSwap; - public var rgbShaders(default, null):Array> = [[], []]; + public var rgbShaders(default, null):Array> = [[], []]; private var curTexture:String = null; private var reachedEnd:Bool = false; - private var rgbShader:PixelSplashShaderRef; + private var rgbShader:RGBPalette; public static function init(group:FlxTypedGroup, startCrochet:Float, frameRate:Int):Void { @@ -199,7 +198,7 @@ class SustainSplash extends FlxSprite { if (rgbShaders[shaderID][noteData] == null) { - rgbShader = new PixelSplashShaderRef(); + rgbShader = new RGBPalette(); rgbShaders[shaderID][noteData] = rgbShader; } diff --git a/source/engine/shaders/PixelSplashShader.hx b/source/engine/shaders/PixelSplashShader.hx deleted file mode 100644 index 894025b7..00000000 --- a/source/engine/shaders/PixelSplashShader.hx +++ /dev/null @@ -1,85 +0,0 @@ -package shaders; - -class PixelSplashShaderRef -{ - public var shader:PixelSplashShader = new PixelSplashShader(); - - public function copyValues(tempShader:RGBPalette) - { - var enabled:Bool = false; - if (tempShader != null) - enabled = true; - - if (enabled) - { - for (i in 0...3) - { - shader.r.value[i] = tempShader.shader.r.value[i]; - shader.g.value[i] = tempShader.shader.g.value[i]; - shader.b.value[i] = tempShader.shader.b.value[i]; - } - shader.mult.value[0] = tempShader.shader.mult.value[0]; - } - else - shader.mult.value[0] = 0.0; - } - - public function new() - { - shader.r.value = [0, 0, 0]; - shader.g.value = [0, 0, 0]; - shader.b.value = [0, 0, 0]; - shader.mult.value = [1]; - - var pixel:Float = 1; - /*if (PlayState.isPixelStage) - pixel = PlayState.daPixelZoom;*/ - shader.uBlocksize.value = [pixel, pixel]; - // trace('Created shader ' + Conductor.songPosition); - } -} - -class PixelSplashShader extends FlxShader -{ - @:glFragmentHeader(' - #pragma header - - uniform vec3 r; - uniform vec3 g; - uniform vec3 b; - uniform float mult; - uniform vec2 uBlocksize; - - vec4 flixel_texture2DCustom(sampler2D bitmap, vec2 coord) { - vec2 blocks = openfl_TextureSize / uBlocksize; - vec4 color = flixel_texture2D(bitmap, floor(coord * blocks) / blocks); - if (!hasTransform) { - return color; - } - - if(color.a == 0.0 || mult == 0.0) { - return color * openfl_Alphav; - } - - vec4 newColor = color; - newColor.rgb = min(color.r * r + color.g * g + color.b * b, vec3(1.0)); - newColor.a = color.a; - - color = mix(color, newColor, mult); - - if(color.a > 0.0) { - return vec4(color.rgb, color.a); - } - return vec4(0.0, 0.0, 0.0, 0.0); - }') - @:glFragmentSource(' - #pragma header - - void main() { - gl_FragColor = flixel_texture2DCustom(bitmap, openfl_TextureCoordv); - }') - public function new() - { - super(); - } -} diff --git a/source/engine/shaders/RGBPalette.hx b/source/engine/shaders/RGBPalette.hx index 178384ce..6273fc7a 100644 --- a/source/engine/shaders/RGBPalette.hx +++ b/source/engine/shaders/RGBPalette.hx @@ -45,6 +45,19 @@ class RGBPalette b = 0xFF0000FF; mult = 1.0; } + + public function copyValues(from:RGBPalette):Void + { + if (from != null) + { + r = from.r; + g = from.g; + b = from.b; + mult = from.mult; + } + else + mult = 0; + } } // automatic handler for easy usability @@ -135,8 +148,6 @@ class RGBShaderReference class RGBPaletteShader extends FlxShader { @:glFragmentHeader(' - #pragma header - uniform vec3 r; uniform vec3 g; uniform vec3 b; From bbdf8b29d159dce1c6c39fc17fb56fd7a4eed416 Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 19:24:45 +0300 Subject: [PATCH 47/50] fix loading sum assets --- source/engine/states/LoadingState.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/engine/states/LoadingState.hx b/source/engine/states/LoadingState.hx index c5c5fe79..c9d3f8f7 100644 --- a/source/engine/states/LoadingState.hx +++ b/source/engine/states/LoadingState.hx @@ -272,7 +272,7 @@ class LoadingState extends MusicBeatState public static function clearInvalids() { - clearInvalidFrom(imagesToPrepare, 'images', ['.png'], IMAGE); // leaving this as is + clearInvalidFrom(imagesToPrepare, 'images', ['png'], IMAGE); // leaving this as is // clearInvalidFrom(imagesToPrepare, 'images', ['.${Paths.IMAGE_EXT}'], Paths.IMAGE_ASSETTYPE); clearInvalidFrom(soundsToPrepare, 'sounds', Paths.SOUND_EXTS, SOUND); clearInvalidFrom(musicToPrepare, 'music', Paths.SOUND_EXTS, SOUND); @@ -310,7 +310,7 @@ class LoadingState extends MusicBeatState var valid:Bool = false; for (ext in exts) { - var myKey = '$prefix/$member$ext'; + var myKey = '$prefix/$member.$ext'; if (Paths.fileExists(myKey, type, false, library)) { valid = true; From 226a54028ea6cd0b67562612eab346705bc11075 Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 19:24:51 +0300 Subject: [PATCH 48/50] update assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index edbd84c5..188a48a7 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit edbd84c581c8d160ce67b191abc026aa2fa5bab7 +Subproject commit 188a48a7cb16a5b64c0fe08b4f8081679c1dfb19 From a7d2154358f8b8ceb22d77d0b96559d1176380e6 Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 19:56:53 +0300 Subject: [PATCH 49/50] god --- source/engine/backend/io/File.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/engine/backend/io/File.hx b/source/engine/backend/io/File.hx index 182a6a09..d9cdf7f1 100644 --- a/source/engine/backend/io/File.hx +++ b/source/engine/backend/io/File.hx @@ -209,7 +209,7 @@ class File #end } - #if ((linux || ios) && FEATURE_MODS) + #if (linux && FEATURE_MODS) static function getCaseInsensitivePath(path:String):String { if (SysFileSystem.exists(path)) From af26fec8834ce0a1b85856f22ce0e9c6339b0b28 Mon Sep 17 00:00:00 2001 From: Homura Date: Wed, 24 Jun 2026 20:02:21 +0300 Subject: [PATCH 50/50] eto --- source/engine/backend/io/FileSystem.hx | 6 +++--- source/engine/mobile/backend/io/ios/Assets.hx | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/source/engine/backend/io/FileSystem.hx b/source/engine/backend/io/FileSystem.hx index fdf1fa09..4b8efe79 100644 --- a/source/engine/backend/io/FileSystem.hx +++ b/source/engine/backend/io/FileSystem.hx @@ -58,7 +58,7 @@ class FileSystem #end #if USE_OPENFL_FILESYSTEM - if (OpenFLAssets.exists(openflcwd(path)) || OpenFLAssets.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 @@ -233,7 +233,7 @@ class FileSystem #end #if USE_OPENFL_FILESYSTEM - if (OpenFLAssets.list().filter(asset -> asset.startsWith(path) && asset != path).length > 0) + if (OpenFLAssets.list().filter(asset -> asset.startsWith(path + "/") && asset != path).length > 0) return openflReadDirectory(path); #end @@ -248,7 +248,7 @@ class FileSystem #if USE_OPENFL_FILESYSTEM static function openflReadDirectory(path:String):Array { - var filteredList:Array = 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()) { diff --git a/source/engine/mobile/backend/io/ios/Assets.hx b/source/engine/mobile/backend/io/ios/Assets.hx index 00ebe4ec..bf421f85 100644 --- a/source/engine/mobile/backend/io/ios/Assets.hx +++ b/source/engine/mobile/backend/io/ios/Assets.hx @@ -1,5 +1,9 @@ package mobile.backend.io.ios; +/** + * The code for this class is mostly taken from SDL2. + * This class implements IO methods from the CoreFoundation's CFBundle to read bundled app assets. + */ #if ios import cpp.UInt8; import haxe.io.Bytes;