From de368ade4a0ca9240ec560b8185feb4b1e0149a2 Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Tue, 21 Sep 2021 22:52:50 +0800 Subject: [PATCH 01/22] Break OggDemuxer::readPage loop on EOF. --- src/modules/video/theora/OggDemuxer.cpp | 19 ++++++++++++++----- src/modules/video/theora/OggDemuxer.h | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/modules/video/theora/OggDemuxer.cpp b/src/modules/video/theora/OggDemuxer.cpp index f5a14d936..acc6f9849 100644 --- a/src/modules/video/theora/OggDemuxer.cpp +++ b/src/modules/video/theora/OggDemuxer.cpp @@ -43,7 +43,7 @@ OggDemuxer::~OggDemuxer() ogg_sync_clear(&sync); } -void OggDemuxer::readPage() +void OggDemuxer::readPage(bool throweof) { char *syncBuffer = nullptr; while (ogg_sync_pageout(&sync, &page) != 1) @@ -53,6 +53,9 @@ void OggDemuxer::readPage() syncBuffer = ogg_sync_buffer(&sync, 8192); size_t read = file->read(syncBuffer, 8192); + if (read == 0 && throweof) + throw love::Exception("Invalid stream"); + ogg_sync_wrote(&sync, read); } } @@ -118,22 +121,23 @@ OggDemuxer::StreamType OggDemuxer::findStream() if (streamInited) { eos = false; + streamInited = false; file->seek(0); ogg_stream_clear(&stream); ogg_sync_reset(&sync); } - streamInited = true; while (true) { // If this page isn't at the start of a stream, we've seen all streams - readPage(); + readPage(true); if (!ogg_page_bos(&page)) break; videoSerial = ogg_page_serialno(&page); ogg_stream_init(&stream, videoSerial); ogg_stream_pagein(&stream, &page); + streamInited = true; StreamType type = determineType(); switch(type) @@ -145,10 +149,15 @@ OggDemuxer::StreamType OggDemuxer::findStream() } ogg_stream_clear(&stream); + streamInited = false; + } + + if (streamInited) + { + streamInited = false; + ogg_stream_clear(&stream); } - streamInited = false; - ogg_stream_clear(&stream); ogg_sync_reset(&sync); return TYPE_UNKNOWN; diff --git a/src/modules/video/theora/OggDemuxer.h b/src/modules/video/theora/OggDemuxer.h index a6b2de900..f55a352d2 100644 --- a/src/modules/video/theora/OggDemuxer.h +++ b/src/modules/video/theora/OggDemuxer.h @@ -67,7 +67,7 @@ private: int videoSerial; bool eos; - void readPage(); + void readPage(bool throweof = false); StreamType determineType(); }; // OggDemuxer From a57d207a57ac199b9a1c061081b97607131b86c8 Mon Sep 17 00:00:00 2001 From: Semyon Yentsov Date: Mon, 1 Nov 2021 01:37:18 +0300 Subject: [PATCH 02/22] Fix bug #1707 --- src/modules/graphics/Font.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/modules/graphics/Font.cpp b/src/modules/graphics/Font.cpp index 967fe78f2..5d3304904 100644 --- a/src/modules/graphics/Font.cpp +++ b/src/modules/graphics/Font.cpp @@ -896,14 +896,11 @@ void Font::getWrap(const ColoredCodepoints &codepoints, float wraplimit, std::ve } // Push the last line. - if (!wline.cps.empty()) - { - lines.push_back(wline); + lines.push_back(wline); - // Ignore the width of any trailing spaces, for individual lines. - if (linewidths) - linewidths->push_back(width - widthoftrailingspace); - } + // Ignore the width of any trailing spaces, for individual lines. + if (linewidths) + linewidths->push_back(width - widthoftrailingspace); } void Font::getWrap(const std::vector &text, float wraplimit, std::vector &lines, std::vector *linewidths) From b79b99bbaa60fb283d160782e5b31f953b43760c Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Tue, 2 Nov 2021 17:54:13 +0800 Subject: [PATCH 03/22] Use specialized logic when loading C modules in Android. --- src/common/android.cpp | 42 ++++++++++++++++++++++ src/common/android.h | 2 ++ src/modules/filesystem/wrap_Filesystem.cpp | 25 +++++++++++++ 3 files changed, 69 insertions(+) diff --git a/src/common/android.cpp b/src/common/android.cpp index 075b6b7d9..e926737a5 100644 --- a/src/common/android.cpp +++ b/src/common/android.cpp @@ -724,6 +724,48 @@ bool checkFusedGame(void **physfsIO_Out) return false; } +const char *getCRequirePath() +{ + static bool initialized = false; + static const char *path = nullptr; + + if (!initialized) + { + JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); + jobject activity = (jobject) SDL_AndroidGetActivity(); + + jclass clazz(env->GetObjectClass(activity)); + jmethodID method_id = env->GetMethodID(clazz, "getCRequirePath", "()Ljava/lang/String;"); + + path = ""; + initialized = true; + + if (method_id) + { + jstring cpath = (jstring) env->CallObjectMethod(activity, method_id); + const char *utf = env->GetStringUTFChars(cpath, nullptr); + if (utf) + { + path = SDL_strdup(utf); + env->ReleaseStringUTFChars(cpath, utf); + } + + env->DeleteLocalRef(cpath); + } + else + { + // NoSuchMethodException is thrown in case methodID is null + env->ExceptionClear(); + return ""; + } + + env->DeleteLocalRef(activity); + env->DeleteLocalRef(clazz); + } + + return path; +} + } // android } // love diff --git a/src/common/android.h b/src/common/android.h index 68b2259bf..3c0c5a35f 100644 --- a/src/common/android.h +++ b/src/common/android.h @@ -101,6 +101,8 @@ void deinitializeVirtualArchive(); */ bool checkFusedGame(void **physfsIO_Out); +const char *getCRequirePath(); + } // android } // love diff --git a/src/modules/filesystem/wrap_Filesystem.cpp b/src/modules/filesystem/wrap_Filesystem.cpp index 62f356f0f..41db59725 100644 --- a/src/modules/filesystem/wrap_Filesystem.cpp +++ b/src/modules/filesystem/wrap_Filesystem.cpp @@ -29,6 +29,10 @@ #include "physfs/Filesystem.h" +#ifdef LOVE_ANDROID +#include "common/android.h" +#endif + // SDL #include @@ -782,6 +786,23 @@ int extloader(lua_State *L) void *handle = nullptr; auto *inst = instance(); +#ifdef LOVE_ANDROID + // Specifically Android, look the library path based on getCRequirePath first + std::string androidPath(love::android::getCRequirePath()); + + if (!androidPath.empty()) + { + // Replace ? with just the dotted filename (not tokenized_name) + replaceAll(androidPath, "?", filename); + + // Load directly, don't check for existence. + handle = SDL_LoadObject(androidPath.c_str()); + } + + if (!handle) + { +#endif // LOVE_ANDROID + for (const std::string &el : inst->getCRequirePath()) { for (const char *ext : library_extensions) @@ -811,6 +832,10 @@ int extloader(lua_State *L) break; } +#ifdef LOVE_ANDROID + } // if (!handle) +#endif + if (!handle) { lua_pushfstring(L, "\n\tno file '%s' in LOVE paths.", tokenized_name.c_str()); From 3a18a2ab0d40a13e986d6032b0cb2c53b8283094 Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Fri, 5 Nov 2021 13:55:14 +0800 Subject: [PATCH 04/22] Use GameActivity.buildFileLookup via JNI to build file tree. Turns out AAssetDir_getNextFilename() intentionally excludes directories, thus the custom archive backend only sees the top-level files. --- src/common/android.cpp | 167 +++++++++++++++++++++++++++-------------- 1 file changed, 112 insertions(+), 55 deletions(-) diff --git a/src/common/android.cpp b/src/common/android.cpp index e926737a5..8f4c2cf84 100644 --- a/src/common/android.cpp +++ b/src/common/android.cpp @@ -333,24 +333,59 @@ void showRecordingPermissionMissingDialog() env->DeleteLocalRef(activity); } +/* A container for AssetManager Java object */ +class AssetManagerObject +{ +public: + AssetManagerObject() + { + JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv(); + jobject am = getLocalAssetManager(env); + + assetManager = env->NewGlobalRef(am); + env->DeleteLocalRef(am); + } + + ~AssetManagerObject() + { + JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv(); + env->DeleteGlobalRef(assetManager); + } + + static jobject getLocalAssetManager(JNIEnv *env) { + jobject self = (jobject) SDL_AndroidGetActivity(); + jclass activity = env->GetObjectClass(self); + jmethodID method = env->GetMethodID(activity, "getAssets", "()Landroid/content/res/AssetManager;"); + jobject am = env->CallObjectMethod(self, method); + + env->DeleteLocalRef(self); + env->DeleteLocalRef(activity); + return am; + } + + explicit operator jobject() + { + return assetManager; + }; +private: + jobject assetManager; +}; + /* * Helper functions to aid new fusing method */ + +// This returns *global* reference, no need to free it. +static jobject getJavaAssetManager() +{ + static AssetManagerObject assetManager; + return (jobject) assetManager; +} + static AAssetManager *getAssetManager() { JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); - jobject self = (jobject) SDL_AndroidGetActivity(); - jclass activity = env->GetObjectClass(self); - jmethodID method = env->GetMethodID(activity, "getAssetManager", "()Landroid/content/res/AssetManager;"); - - jobject assetManager = env->CallObjectMethod(self, method); - AAssetManager *assetManagerObject = AAssetManager_fromJava(env, assetManager); - - env->DeleteLocalRef(assetManager); - env->DeleteLocalRef(activity); - env->DeleteLocalRef(self); - - return assetManagerObject; + return AAssetManager_fromJava(env, (jobject) getJavaAssetManager()); } namespace aasset @@ -368,35 +403,6 @@ struct AssetInfo static std::unordered_map fileTree; -// Workaround AAsset can't detect whetever something is a directory or doesn't exist -static void buildFileLookup( - AAssetManager *assetManager, - std::unordered_map &out, - const std::string &path = "" -) -{ - if (!path.empty()) - { - AAsset *test = AAssetManager_open(assetManager, path.c_str(), AASSET_MODE_STREAMING); - if (test) - { - AAsset_close(test); - out[path] = PHYSFS_FILETYPE_REGULAR; - return; - } - - out[path] = PHYSFS_FILETYPE_DIRECTORY; - } - - AAssetDir *dir = AAssetManager_openDir(assetManager, path.c_str()); - const char *file; - - while ((file = AAssetDir_getNextFileName(dir)) != nullptr) - buildFileLookup(assetManager, out, file); - - AAssetDir_close(dir); -} - PHYSFS_sint64 read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len) { AAsset *asset = ((AssetInfo *) io->opaque)->asset; @@ -505,7 +511,31 @@ void *openArchive(PHYSFS_Io *io, const char *name, int forWrite, int *claimed) AAssetManager *assetManager = getAssetManager(); if (io::fileTree.empty()) - io::buildFileLookup(assetManager, io::fileTree); + { + // AAssetDir_getNextFileName intentionally excludes directories, so + // we have to use JNI that calls AssetManager.list() recursively. + JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv(); + jobject activity = (jobject) SDL_AndroidGetActivity(); + jclass clazz = env->GetObjectClass(activity); + + jmethodID method = env->GetMethodID(clazz, "buildFileTree", "()[Ljava/lang/String;"); + jobjectArray list = (jobjectArray) env->CallObjectMethod(activity, method); + + for (jsize i = 0; i < env->GetArrayLength(list); i++) + { + jstring jstr = (jstring) env->GetObjectArrayElement(list, i); + const char *str = env->GetStringUTFChars(jstr, nullptr); + + io::fileTree[str + 1] = str[0] == 'd' ? PHYSFS_FILETYPE_DIRECTORY : PHYSFS_FILETYPE_REGULAR; + + env->ReleaseStringUTFChars(jstr, str); + env->DeleteLocalRef(jstr); + } + + env->DeleteLocalRef(list); + env->DeleteLocalRef(clazz); + env->DeleteLocalRef(activity); + } return assetManager; } @@ -518,33 +548,60 @@ PHYSFS_EnumerateCallbackResult enumerate( void *callbackdata ) { + using FileTreeIterator = std::unordered_map::iterator; + LOVE_UNUSED(opaque); + const char *path = dirname; if (path == nullptr || (path[0] == '/' && path[1] == 0)) path = ""; - AAssetManager *assetManager = (AAssetManager *) opaque; - AAssetDir *dir = AAssetManager_openDir(assetManager, path); - - if (dir == nullptr) + if (path[0] != 0) { - PHYSFS_setErrorCode(PHYSFS_ERR_NOT_FOUND); - return PHYSFS_ENUM_ERROR; + FileTreeIterator result = io::fileTree.find(path); + + if (result == io::fileTree.end() || result->second != PHYSFS_FILETYPE_DIRECTORY) + { + PHYSFS_setErrorCode(PHYSFS_ERR_NOT_FOUND); + return PHYSFS_ENUM_ERROR; + } } + JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv(); + jobject assetManager = getJavaAssetManager(); + jclass clazz = env->GetObjectClass(assetManager); + jmethodID method = env->GetMethodID(clazz, "list", "(Ljava/lang/String;)[Ljava/lang/String"); + + jstring jstringDir = env->NewStringUTF(path); + jobjectArray dir = (jobjectArray) env->CallObjectMethod(assetManager, method, jstringDir); + PHYSFS_EnumerateCallbackResult ret = PHYSFS_ENUM_OK; - while (ret == PHYSFS_ENUM_OK) + if (env->ExceptionCheck()) { - const char *name = AAssetDir_getNextFileName(dir); + // IOException occured + ret = PHYSFS_ENUM_ERROR; + env->ExceptionClear(); + } + else + { + jsize i = 0; + jsize len = env->GetArrayLength(dir); - // No more files? - if (name == nullptr) - break; + while (ret == PHYSFS_ENUM_OK && i < len) { + jstring jstr = (jstring) env->GetObjectArrayElement(dir, i++); + const char *name = env->GetStringUTFChars(jstr, nullptr); - ret = cb(callbackdata, origdir, name); + ret = cb(callbackdata, origdir, name); + + env->ReleaseStringUTFChars(jstr, name); + env->DeleteLocalRef(jstr); + } + + env->DeleteLocalRef(dir); } - AAssetDir_close(dir); + env->DeleteLocalRef(jstringDir); + env->DeleteLocalRef(clazz); return ret; } From 1bb22d2e90eb43146b4e577055064260b4649c2d Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Fri, 5 Nov 2021 15:22:03 +0800 Subject: [PATCH 05/22] Set game source path when using virtual archive in Android. This will also prevent double `love.filesystem.setSource()` call in that case. --- src/modules/filesystem/physfs/Filesystem.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/modules/filesystem/physfs/Filesystem.cpp b/src/modules/filesystem/physfs/Filesystem.cpp index 62504780e..12ce395dd 100644 --- a/src/modules/filesystem/physfs/Filesystem.cpp +++ b/src/modules/filesystem/physfs/Filesystem.cpp @@ -232,15 +232,13 @@ bool Filesystem::setSource(const char *source) PHYSFS_Io *gameLoveIO; bool hasFusedGame = love::android::checkFusedGame((void **) &gameLoveIO); + bool isAAssetMounted = false; if (hasFusedGame) { if (gameLoveIO) - { // Actually we should just be able to mount gameLoveIO, but that's experimental. gameLoveIO->destroy(gameLoveIO); - goto oldschool; - } else { if (!love::android::initializeVirtualArchive()) @@ -248,11 +246,15 @@ bool Filesystem::setSource(const char *source) SDL_Log("Unable to mount AAsset: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); return false; } + + // See love::android::initializeVirtualArchive() + new_search_path = "ASET.AASSET"; + isAAssetMounted = true; } } - else + + if (!isAAssetMounted) { - oldschool: new_search_path = love::android::getSelectedGameFile(); // try mounting first, if that fails, load to memory and mount From 888051d01eb9108174d9a3baa385e17bdec097f5 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 12 Nov 2021 21:58:49 -0400 Subject: [PATCH 06/22] Potential very hacky workaround for arm64 JIT allocation issues. Try to reserve blocks of executable memory before external library code claims the address space. LuaJIT on arm64 currently has a very limited range of memory it can use for JIT code. --- .../xcode/liblove.xcodeproj/project.pbxproj | 2 + src/love.cpp | 24 ++++--- src/modules/love/jitsetup.lua | 71 +++++++++++++++++++ src/modules/love/love.cpp | 27 +++++-- src/modules/love/love.h | 3 + 5 files changed, 115 insertions(+), 12 deletions(-) create mode 100644 src/modules/love/jitsetup.lua diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index 3e3226bc0..113fd36ff 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -1849,6 +1849,7 @@ FA620A311AA2F8DB005DB4C2 /* wrap_Texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Texture.h; sourceTree = ""; }; FA620A391AA305F6005DB4C2 /* types.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = types.cpp; sourceTree = ""; }; FA665DC321C34C900074BBD6 /* wrap_GraphicsShader.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = wrap_GraphicsShader.lua; sourceTree = ""; }; + FA69B918273828DD00CDC2E7 /* jitsetup.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = jitsetup.lua; sourceTree = ""; }; FA6A2B641F5F7B6B0074C308 /* wrap_Data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Data.h; sourceTree = ""; }; FA6A2B651F5F7B6B0074C308 /* wrap_Data.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Data.cpp; sourceTree = ""; }; FA6A2B681F5F7F560074C308 /* DataView.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DataView.cpp; sourceTree = ""; }; @@ -2966,6 +2967,7 @@ FA1E95B4271F932B0044CF08 /* arg.lua */, FA577A8D16C71D3600860150 /* boot.lua */, FA1E95B5271F932B0044CF08 /* callbacks.lua */, + FA69B918273828DD00CDC2E7 /* jitsetup.lua */, FA0B7BFE1A95902C000E1D17 /* love.cpp */, FA0B7BFF1A95902C000E1D17 /* love.h */, ); diff --git a/src/love.cpp b/src/love.cpp index 089440a47..3245d73f6 100644 --- a/src/love.cpp +++ b/src/love.cpp @@ -142,14 +142,6 @@ enum DoneAction static DoneAction runlove(int argc, char **argv, int &retval) { -#ifdef LOVE_LEGENDARY_APP_ARGV_HACK - int hack_argc = 0; - char **hack_argv = 0; - get_app_arguments(argc, argv, hack_argc, hack_argv); - argc = hack_argc; - argv = hack_argv; -#endif // LOVE_LEGENDARY_APP_ARGV_HACK - // Oh, you just want the version? Okay! if (argc > 1 && strcmp(argv[1], "--version") == 0) { @@ -166,6 +158,22 @@ static DoneAction runlove(int argc, char **argv, int &retval) lua_State *L = luaL_newstate(); luaL_openlibs(L); + // LuaJIT-specific setup needs to be done as early as possible - before + // get_app_arguments because that loads external library code. This is also + // loaded inside require("love"). Note that it doesn't use the love table. + love_preload(L, luaopen_love_jitsetup, "love.jitsetup"); + lua_getglobal(L, "require"); + lua_pushstring(L, "love.jitsetup"); + lua_call(L, 1, 0); + +#ifdef LOVE_LEGENDARY_APP_ARGV_HACK + int hack_argc = 0; + char **hack_argv = nullptr; + get_app_arguments(argc, argv, hack_argc, hack_argv); + argc = hack_argc; + argv = hack_argv; +#endif // LOVE_LEGENDARY_APP_ARGV_HACK + // Add love to package.preload for easy requiring. love_preload(L, luaopen_love, "love"); diff --git a/src/modules/love/jitsetup.lua b/src/modules/love/jitsetup.lua new file mode 100644 index 000000000..d87afa3ce --- /dev/null +++ b/src/modules/love/jitsetup.lua @@ -0,0 +1,71 @@ +R"luastring"--( +-- DO NOT REMOVE THE ABOVE LINE. It is used to load this file as a C++ string. +-- There is a matching delimiter at the bottom of the file. + +--[[ +Copyright (c) 2006-2021 LOVE Development Team + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +--]] + +if type(jit) ~= "table" or not jit.status() then + return +end + +-- Double the defaults. +jit.opt.start("maxtrace=2000", "maxrecord=8000") + +-- Somewhat arbitrary value. Needs to be higher than the combined sizes below, +-- and higher than the default (512) because that's already too low. +jit.opt.start("maxmcode=16384") + +if jit.arch == "arm64" then + -- https://github.com/LuaJIT/LuaJIT/issues/285 + -- LuaJIT 2.1 on arm64 currently (as of commit b4b2dce) can only use memory + -- for JIT compilation within a certain short range. Other libraries such as + -- SDL can take all the usable space in that range and cause attempts at JIT + -- compilation to both fail and take a long time. + -- This is a very hacky attempt at a workaround. LuaJIT allocates executable + -- code in pools. We'll try "reserving" pools before any external code is + -- executed, by causing JIT compilation via a small loop. We can't easily + -- tell if JIT compilation succeeded, so we do several successively smaller + -- pool allocations in case previous ones fail. + -- This is a really hacky hack and by no means foolproof - there are a lot of + -- potential situations (especially when threads are used) where previously + -- executed external code will still take up space that LuaJIT needed for itself. + + jit.opt.start("sizemcode=2048") + for i=1, 100 do end + + jit.opt.start("sizemcode=1024") + for i=1, 100 do end + + jit.opt.start("sizemcode=512") + for i=1, 100 do end + + jit.opt.start("sizemcode=256") + for i=1, 100 do end + + jit.opt.start("sizemcode=128") + for i=1, 100 do end +else + -- Somewhat arbitrary value (>= the default). + jit.opt.start("sizemcode=128") +end + +-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string. +--)luastring"--" diff --git a/src/modules/love/love.cpp b/src/modules/love/love.cpp index 5728514ad..a70125f91 100644 --- a/src/modules/love/love.cpp +++ b/src/modules/love/love.cpp @@ -97,6 +97,10 @@ static const char boot_lua[] = #include "boot.lua" ; +static const char jit_setup_lua[] = +#include "jitsetup.lua" +; + // All modules define a c-accessible luaopen // so let's make use of those, instead // of addressing implementations directly. @@ -160,6 +164,7 @@ extern "C" extern int luaopen_love_window(lua_State*); #endif extern int luaopen_love_nogame(lua_State*); + extern int luaopen_love_jitsetup(lua_State*); extern int luaopen_love_arg(lua_State*); extern int luaopen_love_callbacks(lua_State*); extern int luaopen_love_boot(lua_State*); @@ -224,6 +229,7 @@ static const luaL_Reg modules[] = { { "love.window", luaopen_love_window }, #endif { "love.nogame", luaopen_love_nogame }, + { "love.jitsetup", luaopen_love_jitsetup }, { "love.arg", luaopen_love_arg }, { "love.callbacks", luaopen_love_callbacks }, { "love.boot", luaopen_love_boot }, @@ -404,6 +410,15 @@ static void luax_addcompatibilityalias(lua_State *L, const char *module, const c int luaopen_love(lua_State *L) { + // Preload module loaders. + for (int i = 0; modules[i].name != nullptr; i++) + love::luax_preload(L, modules[i].func, modules[i].name); + + // jitsetup is also loaded in the love executable runlove function. It's + // needed here too for threads. Note that it doesn't use the love table. + love::luax_require(L, "love.jitsetup"); + lua_pop(L, 1); + love::luax_insistpinnedthread(L); love::luax_insistglobal(L, "love"); @@ -501,10 +516,6 @@ int luaopen_love(lua_State *L) lua_setfield(L, -2, "hasDeprecationOutput"); } - // Preload module loaders. - for (int i = 0; modules[i].name != nullptr; i++) - love::luax_preload(L, modules[i].func, modules[i].name); - // Necessary for Data-creating methods to work properly in Data subclasses. love::luax_require(L, "love.data"); lua_pop(L, 1); @@ -657,6 +668,14 @@ int luaopen_love_nogame(lua_State *L) return 1; } +int luaopen_love_jitsetup(lua_State *L) +{ + if (luaL_loadbuffer(L, jit_setup_lua, sizeof(jit_setup_lua), "jitsetup.lua") == 0) + lua_call(L, 0, 1); + + return 1; +} + int luaopen_love_arg(lua_State *L) { if (luaL_loadbuffer(L, arg_lua, sizeof(arg_lua), "arg.lua") == 0) diff --git a/src/modules/love/love.h b/src/modules/love/love.h index ee057f5b4..149bb3eb7 100644 --- a/src/modules/love/love.h +++ b/src/modules/love/love.h @@ -36,6 +36,9 @@ LOVE_EXPORT const char *love_version(); LOVE_EXPORT const char *love_codename(); LOVE_EXPORT int luaopen_love(lua_State *L); LOVE_EXPORT int luaopen_love_nogame(lua_State *L); +LOVE_EXPORT int luaopen_love_jitsetup(lua_State *L); +LOVE_EXPORT int luaopen_love_arg(lua_State *L); +LOVE_EXPORT int luaopen_love_callbacks(lua_State *L); LOVE_EXPORT int luaopen_love_boot(lua_State *L); #ifdef LOVE_LEGENDARY_CONSOLE_IO_HACK From 0f9e598ebb5f77a38124ab7ac8c4a92a1403ee47 Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Sat, 13 Nov 2021 14:34:54 +0800 Subject: [PATCH 07/22] Fixed love.filesystem.getDirectoryItems() in Android with new fusing mehod. --- src/common/android.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/android.cpp b/src/common/android.cpp index 8f4c2cf84..1c3cdf11b 100644 --- a/src/common/android.cpp +++ b/src/common/android.cpp @@ -569,7 +569,7 @@ PHYSFS_EnumerateCallbackResult enumerate( JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv(); jobject assetManager = getJavaAssetManager(); jclass clazz = env->GetObjectClass(assetManager); - jmethodID method = env->GetMethodID(clazz, "list", "(Ljava/lang/String;)[Ljava/lang/String"); + jmethodID method = env->GetMethodID(clazz, "list", "(Ljava/lang/String;)[Ljava/lang/String;"); jstring jstringDir = env->NewStringUTF(path); jobjectArray dir = (jobjectArray) env->CallObjectMethod(assetManager, method, jstringDir); From bd741a8c780aaf7795499be1b2f8883109749f06 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 19 Nov 2021 21:44:04 -0400 Subject: [PATCH 08/22] Fix incorrect particle offsets when Quads are used without setOffset. Fixes #1741. --- src/modules/graphics/ParticleSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/graphics/ParticleSystem.cpp b/src/modules/graphics/ParticleSystem.cpp index 800da3aca..304b0edb0 100644 --- a/src/modules/graphics/ParticleSystem.cpp +++ b/src/modules/graphics/ParticleSystem.cpp @@ -177,7 +177,7 @@ void ParticleSystem::resetOffset() else { Quad::Viewport v = quads[0]->getViewport(); - offset = love::Vector2(v.x*0.5f, v.y*0.5f); + offset = love::Vector2(v.w*0.5f, v.h*0.5f); } } From 7b6012891d0495fa38fba451fddfe67a07b28690 Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Sat, 20 Nov 2021 11:42:33 +0800 Subject: [PATCH 09/22] Replace AppImage packaging method. The new AppImage packaging method compiles all the dependencies from source instead of using system-provided libraries, which can be problematic in certain situations (see #1710). Fixes #1710 and closes #1700 --- .github/workflows/main.yml | 45 ++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 65f5b4a63..e601f3b64 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,37 +9,30 @@ jobs: run: sudo apt-get update - name: Install Dependencies run: | - sudo apt-get install --assume-yes build-essential autotools-dev automake libtool pkg-config \ - libfreetype6-dev libluajit-5.1-dev libsdl2-dev libopenal-dev \ - libogg-dev libvorbis-dev libmodplug-dev libmpg123-dev libtheora-dev - - name: Checkout - uses: actions/checkout@v2 - - name: Pre-Configure - run: $PWD/platform/unix/automagic - - name: Configure - run: mkdir build && cd build && ../configure - - name: Build - run: cd build && make -j2 - - name: Prepare appimagetool - run: | - cd build && - wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O appimagetool && - chmod +x appimagetool && - sudo apt install -y appstream - - name: Clone love-appimages + sudo apt-get install --assume-yes build-essential git make cmake autoconf automake \ + libtool pkg-config libasound2-dev libpulse-dev libaudio-dev \ + libjack-dev libx11-dev libxext-dev libxrandr-dev libxcursor-dev \ + libxfixes-dev libxi-dev libxinerama-dev libxxf86vm-dev libxss-dev \ + libgl1-mesa-dev libdbus-1-dev libudev-dev libgles2-mesa-dev \ + libegl1-mesa-dev libibus-1.0-dev fcitx-libs-dev libsamplerate0-dev \ + libsndio-dev libwayland-dev libxkbcommon-dev libdrm-dev libgbm-dev + - name: Checkout love-appimage-source uses: actions/checkout@v2 with: - path: build/love-appimages - repository: pfirsich/love-appimages + repository: MikuAuahDark/love-appimage-source + - name: Checkout LÖVE + uses: actions/checkout@v2 + with: + path: love2d-${{ github.sha }} - name: Build AppImage - run: | - cd build && - python3 love-appimages/build.py .. AppDir --builddir build --appimage love.AppImage + run: make LOVE_BRANCH=${{ github.sha }} + - name: Print LuaJIT branch + run: git -C LuaJIT-v2.1 branch -v - name: Artifact - uses: actions/upload-artifact@v2-preview + uses: actions/upload-artifact@v2 with: - name: love.AppImage - path: build/love.AppImage + name: love-x86_64.AppImage + path: love-${{ github.sha }}.AppImage windows-os: runs-on: windows-latest strategy: From b87034404e7e165489175e85c58d53d489d25960 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 24 Nov 2021 21:15:51 -0400 Subject: [PATCH 10/22] newVideo: slightly more descriptive error when given an invalid file --- src/modules/video/theora/OggDemuxer.cpp | 12 ++++++++---- src/modules/video/theora/OggDemuxer.h | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/modules/video/theora/OggDemuxer.cpp b/src/modules/video/theora/OggDemuxer.cpp index acc6f9849..31136c897 100644 --- a/src/modules/video/theora/OggDemuxer.cpp +++ b/src/modules/video/theora/OggDemuxer.cpp @@ -43,7 +43,7 @@ OggDemuxer::~OggDemuxer() ogg_sync_clear(&sync); } -void OggDemuxer::readPage(bool throweof) +bool OggDemuxer::readPage(bool erroreof) { char *syncBuffer = nullptr; while (ogg_sync_pageout(&sync, &page) != 1) @@ -53,11 +53,13 @@ void OggDemuxer::readPage(bool throweof) syncBuffer = ogg_sync_buffer(&sync, 8192); size_t read = file->read(syncBuffer, 8192); - if (read == 0 && throweof) - throw love::Exception("Invalid stream"); + if (read == 0 && erroreof) + return false; ogg_sync_wrote(&sync, read); } + + return true; } bool OggDemuxer::readPacket(ogg_packet &packet, bool mustSucceed) @@ -129,8 +131,10 @@ OggDemuxer::StreamType OggDemuxer::findStream() while (true) { + if (!readPage(true)) + return TYPE_UNKNOWN; + // If this page isn't at the start of a stream, we've seen all streams - readPage(true); if (!ogg_page_bos(&page)) break; diff --git a/src/modules/video/theora/OggDemuxer.h b/src/modules/video/theora/OggDemuxer.h index f55a352d2..242f73717 100644 --- a/src/modules/video/theora/OggDemuxer.h +++ b/src/modules/video/theora/OggDemuxer.h @@ -67,7 +67,7 @@ private: int videoSerial; bool eos; - void readPage(bool throweof = false); + bool readPage(bool erroreof = false); StreamType determineType(); }; // OggDemuxer From 8f9d1d7f82f860e93baaef1ea0872605740d30fb Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 24 Nov 2021 21:18:45 -0400 Subject: [PATCH 11/22] xcode: address setting recommendations added in 13.1 --- platform/xcode/liblove.xcodeproj/project.pbxproj | 2 +- platform/xcode/love.xcodeproj/project.pbxproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index 113fd36ff..9a405300a 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -4141,7 +4141,7 @@ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1250; + LastUpgradeCheck = 1310; TargetAttributes = { FA0B78DC1A958B90000E1D17 = { CreatedOnToolsVersion = 6.1.1; diff --git a/platform/xcode/love.xcodeproj/project.pbxproj b/platform/xcode/love.xcodeproj/project.pbxproj index babecde81..d03d1b52e 100644 --- a/platform/xcode/love.xcodeproj/project.pbxproj +++ b/platform/xcode/love.xcodeproj/project.pbxproj @@ -328,7 +328,7 @@ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1250; + LastUpgradeCheck = 1310; TargetAttributes = { FA0B7F051A95AAF3000E1D17 = { CreatedOnToolsVersion = 6.1.1; From c5b8930a751377f5e69d6cf6166f7ffed895aefd Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 24 Nov 2021 21:30:18 -0400 Subject: [PATCH 12/22] Updated changelog --- changes.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/changes.txt b/changes.txt index 2bbb7c89e..c46ccde82 100644 --- a/changes.txt +++ b/changes.txt @@ -3,12 +3,14 @@ LOVE 11.4 [Mysterious Mysteries] Released: N/A +* Added native arm64 support on macOS. * Added Body:getLocalPoints. * Added Font:getKerning. * Added support for r16, rg16, and rgba16 pixel formats in Canvases. * Added Shader:send(name, matrixlayout, data, ...) variant, whose argument order is more consistent than Shader:send(name, data, matrixlayout, ...). * Changed love.timer.getTime to start at 0 when the module is first loaded. +* Changed certain out-of-Lua-memory situations to show a message box instead of instantly crashing. * Fixed build-time compatibility with Lua 5.4. * Fixed code compatibility with math.mod and string.gfind when LuaJIT 2.1 is used. @@ -19,21 +21,28 @@ Released: N/A * Fixed support for > 2GB dropped files on desktops. * Fixed love.physics meter scale value persisting after love.event.quit("restart"). * Fixed audio to resume properly after interruption on iOS. +* Fixed love.graphics.newVideo to error instead of crash when an invalid video file is given. * Fixed initial window creation to set the window's title during creation instead of after. * Fixed the window's screen position when exiting fullscreen via love.window.setFullscreen. +* Fixed love.displayrotated being given a boolean instead of an enum string. * Fixed memory corruption and a crash when drawing smooth lines. * Fixed a crash in Canvas:newImageData when the pixel format's pixel byte size multiplied by its width isn't a multiple of 4. * Fixed love.graphics.newVolumeImage when explicit mipmaps are provided. * Fixed freezes and crashes in automatic batching when an AMD GPU is used. * Fixed love.graphics.print and Image:replacePixels on more AMD/ATI GPUs. * Fixed Font:setFallbacks to account for different DPI scales in each fallback font. +* Fixed Font:getWrap to not remove trailing newlines. * Fixed Text:getWidth when the Text's string only contains spaces. * Fixed a crash with some Intel graphics drivers on Linux. * Fixed a hang with some Intel graphics drivers on Windows, by preventing gamma correct rendering on affected systems. * Fixed a crash with some Intel graphics drivers on Windows when mipmapped Canvases are used. * Fixed texture memory reported by love.graphics.getStats when a volume or array Canvas is created. +* Fixed DXT1 textures which use 1 bit alpha-cutout. * Fixed rare issues where textures were not sent to shaders correctly. * Fixed Shader:send(name, data, matrixlayout, ...). +* Fixed quad offsets in ParticleSystems when ParticleSystem:setOffset is not used. +* Fixed rounded rectangles breaking if the rx or ry parameters are negative. +* Fixed rounded rectangle automatic points calculation when rx or ry are more than half the rectangle's size. * Fixed source code compilation on Xcode 12+. * Fixed source code compilation on Linux systems that don't provide posix_spawn APIs. From 9a480d77527d29027b1ceaf4b975e5ed2c90debb Mon Sep 17 00:00:00 2001 From: Kai Date: Sun, 28 Nov 2021 18:36:00 +0100 Subject: [PATCH 13/22] README.md: HTTP => HTTPS --- readme.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index da777de6b..ceba05852 100644 --- a/readme.md +++ b/readme.md @@ -84,16 +84,16 @@ Dependencies - Vorbisfile - Theora -[site]: http://love2d.org -[wiki]: http://love2d.org/wiki -[forums]: http://love2d.org/forums +[site]: https://love2d.org +[wiki]: https://love2d.org/wiki +[forums]: https://love2d.org/forums [discord]: https://discord.gg/rhUets9 [irc]: irc://irc.oftc.net/love [dependencies-macos]: https://github.com/slime73/love-apple-dependencies [dependencies-ios]: https://github.com/love2d/love/releases [megasource]: https://github.com/love2d/megasource [unstableppa]: https://launchpad.net/~bartbes/+archive/love-unstable -[aur]: http://aur.archlinux.org/packages/love-git +[aur]: https://aur.archlinux.org/packages/love-git [love-experiments]: https://github.com/slime73/love-experiments [codestyle]: https://love2d.org/wiki/Code_Style [android-repository]: https://github.com/love2d/love-android From b54aaf65ca5063e99d7a14913b29ab8c6d46abcf Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 4 Dec 2021 11:58:00 -0400 Subject: [PATCH 14/22] Fix the default error handler drawing when love.graphics is inactive. love.graphics.isActive() is false on mobile devices when the app isn't in the foreground. On iOS there can be a few frames between when the app is backgrounded and when the OS pauses it, where it's not valid to call OpenGL functions or present the screen. --- src/modules/love/callbacks.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/love/callbacks.lua b/src/modules/love/callbacks.lua index 38ee277ac..320b380e7 100644 --- a/src/modules/love/callbacks.lua +++ b/src/modules/love/callbacks.lua @@ -259,6 +259,7 @@ function love.errhand(msg) p = p:gsub("%[string \"(.-)\"%]", "%1") local function draw() + if not love.graphics.isActive() then return end local pos = 70 love.graphics.clear(89/255, 157/255, 220/255) love.graphics.printf(p, pos, pos, love.graphics.getWidth() - pos) @@ -270,7 +271,6 @@ function love.errhand(msg) if not love.system then return end love.system.setClipboardText(fullErrorText) p = p .. "\nCopied to clipboard!" - draw() end if love.system then From 7310fde7b90ce4d7cb5ae05fd54efaa8af27a6a8 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 4 Dec 2021 13:11:01 -0400 Subject: [PATCH 15/22] glslang: fix compilation on certain newer compilers This is already fixed in the latest glslang source code, but updating may be too risky for love 11.x. --- src/libraries/glslang/glslang/Include/PoolAlloc.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/glslang/glslang/Include/PoolAlloc.h b/src/libraries/glslang/glslang/Include/PoolAlloc.h index 0e237a6a2..b8eccb883 100644 --- a/src/libraries/glslang/glslang/Include/PoolAlloc.h +++ b/src/libraries/glslang/glslang/Include/PoolAlloc.h @@ -304,7 +304,6 @@ public: size_type max_size() const { return static_cast(-1) / sizeof(T); } size_type max_size(int size) const { return static_cast(-1) / size; } - void setAllocator(TPoolAllocator* a) { allocator = *a; } TPoolAllocator& getAllocator() const { return allocator; } protected: From ebd5f13456729be97e42f03ad26bf683effe17df Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 7 Dec 2021 19:51:40 -0400 Subject: [PATCH 16/22] Fix missing ByteData:clone and DataView:clone implementations. Fixes #1754 --- src/modules/data/wrap_ByteData.cpp | 11 +++++++++++ src/modules/data/wrap_DataView.cpp | 13 ++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/modules/data/wrap_ByteData.cpp b/src/modules/data/wrap_ByteData.cpp index 446f62214..ed0c0d35c 100644 --- a/src/modules/data/wrap_ByteData.cpp +++ b/src/modules/data/wrap_ByteData.cpp @@ -31,8 +31,19 @@ ByteData *luax_checkbytedata(lua_State *L, int idx) return luax_checktype(L, idx); } +int w_ByteData_clone(lua_State *L) +{ + ByteData *t = luax_checkbytedata(L, 1); + ByteData *c = nullptr; + luax_catchexcept(L, [&](){ c = t->clone(); }); + luax_pushtype(L, c); + c->release(); + return 1; +} + static const luaL_Reg w_ByteData_functions[] = { + { "clone", w_ByteData_clone }, { 0, 0 } }; diff --git a/src/modules/data/wrap_DataView.cpp b/src/modules/data/wrap_DataView.cpp index 9aec29d7c..e41826b38 100644 --- a/src/modules/data/wrap_DataView.cpp +++ b/src/modules/data/wrap_DataView.cpp @@ -26,13 +26,24 @@ namespace love namespace data { -DataView *luax_checkdataView(lua_State *L, int idx) +DataView *luax_checkdataview(lua_State *L, int idx) { return luax_checktype(L, idx); } +int w_DataView_clone(lua_State *L) +{ + DataView *t = luax_checkdataview(L, 1); + DataView *c = nullptr; + luax_catchexcept(L, [&](){ c = t->clone(); }); + luax_pushtype(L, c); + c->release(); + return 1; +} + static const luaL_Reg w_DataView_functions[] = { + { "clone", w_DataView_clone }, { 0, 0 } }; From 7e271fc53ebb9710ecc31343aef5bcaffb5cd8d8 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 11 Dec 2021 11:52:42 -0400 Subject: [PATCH 17/22] Use SDL's rumble APIs for Joystick:setVibration, when available. Fixes #1756 --- src/modules/joystick/sdl/Joystick.cpp | 31 +++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/modules/joystick/sdl/Joystick.cpp b/src/modules/joystick/sdl/Joystick.cpp index 2a8a85519..3c8b69067 100644 --- a/src/modules/joystick/sdl/Joystick.cpp +++ b/src/modules/joystick/sdl/Joystick.cpp @@ -392,6 +392,11 @@ bool Joystick::checkCreateHaptic() bool Joystick::isVibrationSupported() { +#if SDL_VERSION_ATLEAST(2, 0, 18) + if (isConnected() && SDL_JoystickHasRumble(joyhandle) == SDL_TRUE) + return true; +#endif + if (!checkCreateHaptic()) return false; @@ -442,8 +447,12 @@ bool Joystick::setVibration(float left, float right, float duration) if (left == 0.0f && right == 0.0f) return setVibration(); - if (!checkCreateHaptic()) + if (!isConnected()) + { + vibration.left = vibration.right = 0.0f; + vibration.endtime = SDL_HAPTIC_INFINITY; return false; + } Uint32 length = SDL_HAPTIC_INFINITY; if (duration >= 0.0f) @@ -453,10 +462,19 @@ bool Joystick::setVibration(float left, float right, float duration) } bool success = false; + +#if SDL_VERSION_ATLEAST(2, 0, 9) + if (SDL_JoystickRumble(joyhandle, (Uint16)(left * LOVE_UINT16_MAX), (Uint16)(right * LOVE_UINT16_MAX), length) == 0) + success = true; +#endif + + if (!success && !checkCreateHaptic()) + return false; + unsigned int features = SDL_HapticQuery(haptic); int axes = SDL_HapticNumAxes(haptic); - if ((features & SDL_HAPTIC_LEFTRIGHT) != 0) + if (!success && (features & SDL_HAPTIC_LEFTRIGHT) != 0) { memset(&vibration.effect, 0, sizeof(SDL_HapticEffect)); vibration.effect.type = SDL_HAPTIC_LEFTRIGHT; @@ -528,9 +546,14 @@ bool Joystick::setVibration(float left, float right, float duration) bool Joystick::setVibration() { - bool success = true; + bool success = false; - if (SDL_WasInit(SDL_INIT_HAPTIC) && haptic && SDL_HapticIndex(haptic) != -1) +#if SDL_VERSION_ATLEAST(2, 0, 9) + if (!success) + success = isConnected() && SDL_JoystickRumble(joyhandle, 0, 0, 0) == 0; +#endif + + if (!success && SDL_WasInit(SDL_INIT_HAPTIC) && haptic && SDL_HapticIndex(haptic) != -1) success = (SDL_HapticStopEffect(haptic, vibration.id) == 0); if (success) From fb815edc282f05e7b37a588d65064725939b9401 Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Sun, 12 Dec 2021 01:26:20 +0800 Subject: [PATCH 18/22] Change luaL_loadbuffer chunkname with prefixes. --- src/libraries/luasocket/libluasocket/ftp.lua.h | 2 +- src/libraries/luasocket/libluasocket/headers.lua.h | 2 +- src/libraries/luasocket/libluasocket/http.lua.h | 2 +- src/libraries/luasocket/libluasocket/ltn12.lua.h | 2 +- src/libraries/luasocket/libluasocket/mbox.lua.h | 2 +- src/libraries/luasocket/libluasocket/mime.lua.h | 2 +- src/libraries/luasocket/libluasocket/smtp.lua.h | 2 +- src/libraries/luasocket/libluasocket/socket.lua.h | 2 +- src/libraries/luasocket/libluasocket/tp.lua.h | 2 +- src/libraries/luasocket/libluasocket/url.lua.h | 2 +- src/modules/event/wrap_Event.cpp | 2 +- src/modules/graphics/wrap_Graphics.cpp | 4 ++-- src/modules/graphics/wrap_Video.cpp | 2 +- src/modules/love/love.cpp | 10 +++++----- src/modules/math/wrap_Math.cpp | 2 +- 15 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/libraries/luasocket/libluasocket/ftp.lua.h b/src/libraries/luasocket/libluasocket/ftp.lua.h index fcb0d403a..857390980 100644 --- a/src/libraries/luasocket/libluasocket/ftp.lua.h +++ b/src/libraries/luasocket/libluasocket/ftp.lua.h @@ -540,5 +540,5 @@ static const unsigned char B1[]={ }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"ftp.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"ftp.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/libraries/luasocket/libluasocket/headers.lua.h b/src/libraries/luasocket/libluasocket/headers.lua.h index 0d8d891a2..f7958973f 100644 --- a/src/libraries/luasocket/libluasocket/headers.lua.h +++ b/src/libraries/luasocket/libluasocket/headers.lua.h @@ -192,5 +192,5 @@ static const unsigned char B1[]={ 108,101,114, 34, 44, 10,125, 10, 10,114,101,116,117,114,110, 32, 95, 77, }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"headers.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"headers.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/libraries/luasocket/libluasocket/http.lua.h b/src/libraries/luasocket/libluasocket/http.lua.h index 840cd85ca..0ecd8892e 100644 --- a/src/libraries/luasocket/libluasocket/http.lua.h +++ b/src/libraries/luasocket/libluasocket/http.lua.h @@ -668,5 +668,5 @@ static const unsigned char B1[]={ 101,110,100, 41, 10, 10,114,101,116,117,114,110, 32, 95, 77, 10, }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"http.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"http.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/libraries/luasocket/libluasocket/ltn12.lua.h b/src/libraries/luasocket/libluasocket/ltn12.lua.h index 6fcfed99a..59ac8a445 100644 --- a/src/libraries/luasocket/libluasocket/ltn12.lua.h +++ b/src/libraries/luasocket/libluasocket/ltn12.lua.h @@ -442,5 +442,5 @@ static const unsigned char B1[]={ 110,100, 10,101,110,100, 10, 10,114,101,116,117,114,110, 32, 95, 77, 10, }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"ltn12.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"ltn12.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/libraries/luasocket/libluasocket/mbox.lua.h b/src/libraries/luasocket/libluasocket/mbox.lua.h index f3edca978..2033abfc2 100644 --- a/src/libraries/luasocket/libluasocket/mbox.lua.h +++ b/src/libraries/luasocket/libluasocket/mbox.lua.h @@ -140,5 +140,5 @@ static const unsigned char B1[]={ 110,100, 10, 10,114,101,116,117,114,110, 32, 95, 77, 10, }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"mbox.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"mbox.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/libraries/luasocket/libluasocket/mime.lua.h b/src/libraries/luasocket/libluasocket/mime.lua.h index 78a14cb27..7c648b0f2 100644 --- a/src/libraries/luasocket/libluasocket/mime.lua.h +++ b/src/libraries/luasocket/libluasocket/mime.lua.h @@ -132,5 +132,5 @@ static const unsigned char B1[]={ 116,117,114,110, 32, 95, 77, }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"mime.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"mime.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/libraries/luasocket/libluasocket/smtp.lua.h b/src/libraries/luasocket/libluasocket/smtp.lua.h index 2faf479cf..212945257 100644 --- a/src/libraries/luasocket/libluasocket/smtp.lua.h +++ b/src/libraries/luasocket/libluasocket/smtp.lua.h @@ -411,5 +411,5 @@ static const unsigned char B1[]={ 110,100, 41, 10, 10,114,101,116,117,114,110, 32, 95, 77, }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"smtp.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"smtp.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/libraries/luasocket/libluasocket/socket.lua.h b/src/libraries/luasocket/libluasocket/socket.lua.h index f99e58ec9..8b2de82cf 100644 --- a/src/libraries/luasocket/libluasocket/socket.lua.h +++ b/src/libraries/luasocket/libluasocket/socket.lua.h @@ -230,5 +230,5 @@ static const unsigned char B1[]={ 116,117,114,110, 32, 95, 77, 10, }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"socket.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"socket.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/libraries/luasocket/libluasocket/tp.lua.h b/src/libraries/luasocket/libluasocket/tp.lua.h index cde8b6480..313ce92a3 100644 --- a/src/libraries/luasocket/libluasocket/tp.lua.h +++ b/src/libraries/luasocket/libluasocket/tp.lua.h @@ -196,5 +196,5 @@ static const unsigned char B1[]={ 114,110, 32, 95, 77, 10, }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"tp.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"tp.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/libraries/luasocket/libluasocket/url.lua.h b/src/libraries/luasocket/libluasocket/url.lua.h index 251472148..283b79796 100644 --- a/src/libraries/luasocket/libluasocket/url.lua.h +++ b/src/libraries/luasocket/libluasocket/url.lua.h @@ -563,5 +563,5 @@ static const unsigned char B1[]={ 110, 32, 95, 77, 10, }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"url.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"url.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/modules/event/wrap_Event.cpp b/src/modules/event/wrap_Event.cpp index ff18075dc..bf1d8075e 100644 --- a/src/modules/event/wrap_Event.cpp +++ b/src/modules/event/wrap_Event.cpp @@ -136,7 +136,7 @@ extern "C" int luaopen_love_event(lua_State *L) int ret = luax_register_module(L, w); - if (luaL_loadbuffer(L, (const char *)event_lua, sizeof(event_lua), "wrap_Event.lua") == 0) + if (luaL_loadbuffer(L, (const char *)event_lua, sizeof(event_lua), "=[love \"wrap_Event.lua\"]") == 0) lua_call(L, 0, 0); else lua_error(L); diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index f6596062a..ad96f8fb7 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -3075,12 +3075,12 @@ extern "C" int luaopen_love_graphics(lua_State *L) int n = luax_register_module(L, w); - if (luaL_loadbuffer(L, (const char *)graphics_lua, sizeof(graphics_lua), "wrap_Graphics.lua") == 0) + if (luaL_loadbuffer(L, (const char *)graphics_lua, sizeof(graphics_lua), "=[love \"wrap_Graphics.lua\"]") == 0) lua_call(L, 0, 0); else lua_error(L); - if (luaL_loadbuffer(L, (const char *)graphics_shader_lua, sizeof(graphics_shader_lua), "wrap_GraphicsShader.lua") == 0) + if (luaL_loadbuffer(L, (const char *)graphics_shader_lua, sizeof(graphics_shader_lua), "=[love \"wrap_GraphicsShader.lua\"]") == 0) lua_call(L, 0, 0); else lua_error(L); diff --git a/src/modules/graphics/wrap_Video.cpp b/src/modules/graphics/wrap_Video.cpp index 712330dbe..387aab75e 100644 --- a/src/modules/graphics/wrap_Video.cpp +++ b/src/modules/graphics/wrap_Video.cpp @@ -168,7 +168,7 @@ int luaopen_video(lua_State *L) { int ret = luax_register_type(L, &Video::type, functions, nullptr); - luaL_loadbuffer(L, video_lua, sizeof(video_lua), "Video.lua"); + luaL_loadbuffer(L, video_lua, sizeof(video_lua), "=[love \"Video.lua\"]"); luax_gettypemetatable(L, Video::type); lua_call(L, 1, 0); diff --git a/src/modules/love/love.cpp b/src/modules/love/love.cpp index a70125f91..7330c0f2d 100644 --- a/src/modules/love/love.cpp +++ b/src/modules/love/love.cpp @@ -662,7 +662,7 @@ int w__setAccelerometerAsJoystick(lua_State *L) int luaopen_love_nogame(lua_State *L) { - if (luaL_loadbuffer(L, (const char *)love::nogame_lua, sizeof(love::nogame_lua), "nogame.lua") == 0) + if (luaL_loadbuffer(L, (const char *)love::nogame_lua, sizeof(love::nogame_lua), "=[love \"nogame.lua\"]") == 0) lua_call(L, 0, 1); return 1; @@ -670,7 +670,7 @@ int luaopen_love_nogame(lua_State *L) int luaopen_love_jitsetup(lua_State *L) { - if (luaL_loadbuffer(L, jit_setup_lua, sizeof(jit_setup_lua), "jitsetup.lua") == 0) + if (luaL_loadbuffer(L, jit_setup_lua, sizeof(jit_setup_lua), "=[love \"jitsetup.lua\"]") == 0) lua_call(L, 0, 1); return 1; @@ -678,7 +678,7 @@ int luaopen_love_jitsetup(lua_State *L) int luaopen_love_arg(lua_State *L) { - if (luaL_loadbuffer(L, arg_lua, sizeof(arg_lua), "arg.lua") == 0) + if (luaL_loadbuffer(L, arg_lua, sizeof(arg_lua), "=[love \"arg.lua\"]") == 0) lua_call(L, 0, 1); return 1; @@ -686,7 +686,7 @@ int luaopen_love_arg(lua_State *L) int luaopen_love_callbacks(lua_State *L) { - if (luaL_loadbuffer(L, callbacks_lua, sizeof(callbacks_lua), "callbacks.lua") == 0) + if (luaL_loadbuffer(L, callbacks_lua, sizeof(callbacks_lua), "=[love \"callbacks.lua\"]") == 0) lua_call(L, 0, 1); return 1; @@ -694,7 +694,7 @@ int luaopen_love_callbacks(lua_State *L) int luaopen_love_boot(lua_State *L) { - if (luaL_loadbuffer(L, boot_lua, sizeof(boot_lua), "boot.lua") == 0) + if (luaL_loadbuffer(L, boot_lua, sizeof(boot_lua), "=[love \"boot.lua\"]") == 0) lua_call(L, 0, 1); return 1; diff --git a/src/modules/math/wrap_Math.cpp b/src/modules/math/wrap_Math.cpp index 390aa9c72..e8af3b2ec 100644 --- a/src/modules/math/wrap_Math.cpp +++ b/src/modules/math/wrap_Math.cpp @@ -498,7 +498,7 @@ extern "C" int luaopen_love_math(lua_State *L) int n = luax_register_module(L, w); // Execute wrap_Math.lua, sending the math table and ffifuncs pointer as args. - luaL_loadbuffer(L, math_lua, sizeof(math_lua), "wrap_Math.lua"); + luaL_loadbuffer(L, math_lua, sizeof(math_lua), "=[love \"wrap_Math.lua\"]"); lua_pushvalue(L, -2); luax_pushpointerasstring(L, &ffifuncs); lua_call(L, 2, 0); From 380cc1033e6c62af2e54cd04c96dd959a24a73c8 Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Sun, 12 Dec 2021 09:34:08 +0800 Subject: [PATCH 19/22] Change luax_runwrapper chunk name prefix. --- src/common/runtime.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/common/runtime.cpp b/src/common/runtime.cpp index 972b35753..34205b9dd 100644 --- a/src/common/runtime.cpp +++ b/src/common/runtime.cpp @@ -985,7 +985,9 @@ void luax_runwrapper(lua_State *L, const char *filedata, size_t datalen, const c // functions struct pointer as arguments. if (lua_istable(L, -1)) { - luaL_loadbuffer(L, filedata, datalen, filename); + std::string chunkname = std::string("=[love \"") + std::string(filename) + std::string("\"]"); + + luaL_loadbuffer(L, filedata, datalen, chunkname.c_str()); lua_pushvalue(L, -2); if (ffifuncs != nullptr) luax_pushpointerasstring(L, ffifuncs); From b3593118320115b2a1da12ebe38b6db9f7f3bbfb Mon Sep 17 00:00:00 2001 From: megagrump Date: Mon, 13 Dec 2021 09:20:17 +0100 Subject: [PATCH 20/22] accept Data objects in newFileData --- src/modules/filesystem/wrap_Filesystem.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/modules/filesystem/wrap_Filesystem.cpp b/src/modules/filesystem/wrap_Filesystem.cpp index 41db59725..a99f60c99 100644 --- a/src/modules/filesystem/wrap_Filesystem.cpp +++ b/src/modules/filesystem/wrap_Filesystem.cpp @@ -331,11 +331,22 @@ int w_newFileData(lua_State *L) } size_t length = 0; - const char *str = luaL_checklstring(L, 1, &length); + const void *ptr = nullptr; + if (luax_istype(L, 1, Data::type)) + { + Data *data = data::luax_checkdata(L, 1); + ptr = data->getData(); + length = data->getSize(); + } + else if (lua_isstring(L, 1)) + ptr = luaL_checklstring(L, 1, &length); + else + return luaL_argerror(L, 1, "string or Data expected"); + const char *filename = luaL_checkstring(L, 2); FileData *t = nullptr; - luax_catchexcept(L, [&](){ t = instance()->newFileData(str, length, filename); }); + luax_catchexcept(L, [&](){ t = instance()->newFileData(ptr, length, filename); }); luax_pushtype(L, t); t->release(); From ede0ad0a20a607353240f8477e5665234b84dffd Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Sun, 19 Dec 2021 09:47:45 +0800 Subject: [PATCH 21/22] Fix ENet error on certain system with >48-bit pointers. Fixes love2d/love-android#222 --- src/libraries/enet/enet.cpp | 54 +++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/src/libraries/enet/enet.cpp b/src/libraries/enet/enet.cpp index 076fcb20d..bca527cd6 100644 --- a/src/libraries/enet/enet.cpp +++ b/src/libraries/enet/enet.cpp @@ -118,11 +118,30 @@ static size_t find_peer_index(lua_State *l, ENetHost *enet_host, ENetPeer *peer) #define ENET_ALIGNOF(x) alignof(x) #endif -// For use with the enet_peers registry. -// Using the pointer directly via lightuserdata would be ideal, but LuaJIT -// cannot use lightuserdata with more than 47 bits whereas some newer arm64 -// architectures allow pointers which use more than that. -static lua_Number compute_peer_key(lua_State *L, ENetPeer *peer) +static bool supports_full_lightuserdata(lua_State *L) +{ + static bool checked = false; + static bool supported = false; + + if (!checked) + { + lua_pushcclosure(L, [](lua_State* L) -> int + { + // Try to push pointer with all bits set. + lua_pushlightuserdata(L, (void*)(~((size_t)0))); + return 1; + }, 0); + + supported = lua_pcall(L, 0, 1, 0) == 0; + checked = true; + + lua_pop(L, 1); + } + + return supported; +} + +static uintptr_t compute_peer_key(lua_State *L, ENetPeer *peer) { // ENet peers are be allocated on the heap in an array. Lua numbers // (doubles) can store all possible integers up to 2^53. We can store @@ -140,21 +159,28 @@ static lua_Number compute_peer_key(lua_State *L, ENetPeer *peer) static const size_t shift = (size_t) log2((double) minalign); - key >>= shift; + return key >> shift; +} - // Make sure our key isn't larger than 2^53. - if (key > 0x20000000000000ULL) - luaL_error(L, "Cannot push enet peer to Lua: pointer value %p is too large", peer); - - return (lua_Number) key; +static void push_peer_key(lua_State *L, uintptr_t key) +{ + // If full 64-bit lightuserdata is supported, always use that. Otherwise, + // if the key is smaller than 2^53 (which is integer precision for double + // datatype), then push number. Otherwise, throw error. + if (supports_full_lightuserdata(L)) + lua_pushlightuserdata(L, (void*) key); + else if (key > 0x20000000000000ULL) // 2^53 + luaL_error(L, "Cannot push enet peer to Lua: pointer value %p is too large", key); + else + lua_pushnumber(L, (lua_Number) key); } static void push_peer(lua_State *l, ENetPeer *peer) { - lua_Number key = compute_peer_key(l, peer); + uintptr_t key = compute_peer_key(l, peer); // try to find in peer table lua_getfield(l, LUA_REGISTRYINDEX, "enet_peers"); - lua_pushnumber(l, key); + push_peer_key(l, key); lua_gettable(l, -2); if (lua_isnil(l, -1)) { @@ -165,7 +191,7 @@ static void push_peer(lua_State *l, ENetPeer *peer) { luaL_getmetatable(l, "enet_peer"); lua_setmetatable(l, -2); - lua_pushnumber(l, key); + push_peer_key(l, key); lua_pushvalue(l, -2); lua_settable(l, -4); From cee8f8ae4854f4a7f7067b7a4b200e991a05c66f Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 24 Dec 2021 11:26:11 -0400 Subject: [PATCH 22/22] Fix a compiler warning --- src/common/runtime.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/runtime.cpp b/src/common/runtime.cpp index 34205b9dd..71638302c 100644 --- a/src/common/runtime.cpp +++ b/src/common/runtime.cpp @@ -1010,8 +1010,10 @@ int luax_resume(lua_State *L, int nargs, int* nres) #if LUA_VERSION_NUM >= 504 return lua_resume(L, nullptr, nargs, nres); #elif LUA_VERSION_NUM >= 502 + LOVE_UNUSED(nres); return lua_resume(L, nullptr, nargs); #else + LOVE_UNUSED(nres); return lua_resume(L, nargs); #endif }