diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 54ecb3e85..a2d3a03a3 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: diff --git a/changes.txt b/changes.txt index 2c2087c9f..7630b1cea 100644 --- a/changes.txt +++ b/changes.txt @@ -38,12 +38,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. @@ -54,21 +56,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. diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index b95216193..f448d911c 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -1769,6 +1769,7 @@ FA620A301AA2F8DB005DB4C2 /* wrap_Texture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Texture.cpp; sourceTree = ""; }; 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 = ""; }; + 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 = ""; }; @@ -2850,6 +2851,7 @@ FA1E95B4271F932B0044CF08 /* arg.lua */, FA577A8D16C71D3600860150 /* boot.lua */, FA1E95B5271F932B0044CF08 /* callbacks.lua */, + FA69B918273828DD00CDC2E7 /* jitsetup.lua */, FA0B7BFE1A95902C000E1D17 /* love.cpp */, FA0B7BFF1A95902C000E1D17 /* love.h */, ); @@ -4208,7 +4210,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 eac8d0087..3fb686283 100644 --- a/platform/xcode/love.xcodeproj/project.pbxproj +++ b/platform/xcode/love.xcodeproj/project.pbxproj @@ -324,7 +324,7 @@ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1250; + LastUpgradeCheck = 1310; TargetAttributes = { FA0B7F051A95AAF3000E1D17 = { CreatedOnToolsVersion = 6.1.1; diff --git a/readme.md b/readme.md index 7a1865a99..4134a8e11 100644 --- a/readme.md +++ b/readme.md @@ -83,16 +83,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 diff --git a/src/common/android.cpp b/src/common/android.cpp index 075b6b7d9..1c3cdf11b 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; } @@ -724,6 +781,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/common/runtime.cpp b/src/common/runtime.cpp index 2eb972fad..175e1644e 100644 --- a/src/common/runtime.cpp +++ b/src/common/runtime.cpp @@ -1156,7 +1156,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); @@ -1179,8 +1181,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 } 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); 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/love.cpp b/src/love.cpp index ce4e5ae0d..2755064ff 100644 --- a/src/love.cpp +++ b/src/love.cpp @@ -143,14 +143,6 @@ enum DoneAction static DoneAction runlove(int argc, char **argv, int &retval, love::Variant &restartvalue) { -#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) { @@ -167,6 +159,22 @@ static DoneAction runlove(int argc, char **argv, int &retval, love::Variant &res 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/data/wrap_ByteData.cpp b/src/modules/data/wrap_ByteData.cpp index ae82cff36..f5d8be7f2 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 9b4b29ce1..9971ffe91 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 } }; diff --git a/src/modules/event/wrap_Event.cpp b/src/modules/event/wrap_Event.cpp index c24d78e45..d13a70221 100644 --- a/src/modules/event/wrap_Event.cpp +++ b/src/modules/event/wrap_Event.cpp @@ -180,7 +180,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/filesystem/physfs/Filesystem.cpp b/src/modules/filesystem/physfs/Filesystem.cpp index ddb4b3c2c..8234aff04 100644 --- a/src/modules/filesystem/physfs/Filesystem.cpp +++ b/src/modules/filesystem/physfs/Filesystem.cpp @@ -240,15 +240,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()) @@ -256,11 +254,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 diff --git a/src/modules/filesystem/wrap_Filesystem.cpp b/src/modules/filesystem/wrap_Filesystem.cpp index 9e538039a..efcdfb6ce 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 @@ -380,11 +384,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(); @@ -849,6 +864,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) @@ -878,6 +910,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()); diff --git a/src/modules/graphics/Font.cpp b/src/modules/graphics/Font.cpp index 133bb66c3..3d5e432ef 100644 --- a/src/modules/graphics/Font.cpp +++ b/src/modules/graphics/Font.cpp @@ -901,14 +901,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) diff --git a/src/modules/graphics/ParticleSystem.cpp b/src/modules/graphics/ParticleSystem.cpp index fb01c2b73..b66ffae1c 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); } } diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 12418d625..365e8b6f2 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -3648,7 +3648,7 @@ 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); diff --git a/src/modules/graphics/wrap_Video.cpp b/src/modules/graphics/wrap_Video.cpp index 7ac91f266..0fcf6e0f7 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/joystick/sdl/Joystick.cpp b/src/modules/joystick/sdl/Joystick.cpp index f2ee5d435..e978acc66 100644 --- a/src/modules/joystick/sdl/Joystick.cpp +++ b/src/modules/joystick/sdl/Joystick.cpp @@ -440,6 +440,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; @@ -490,8 +495,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) @@ -501,10 +510,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; @@ -576,9 +594,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) diff --git a/src/modules/love/callbacks.lua b/src/modules/love/callbacks.lua index c456f4a50..69c002b2d 100644 --- a/src/modules/love/callbacks.lua +++ b/src/modules/love/callbacks.lua @@ -256,6 +256,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) @@ -267,7 +268,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 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 c205083e9..b04b532bc 100644 --- a/src/modules/love/love.cpp +++ b/src/modules/love/love.cpp @@ -102,6 +102,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. @@ -165,6 +169,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*); @@ -229,6 +234,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 }, @@ -440,6 +446,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"); @@ -543,10 +558,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); @@ -693,7 +704,15 @@ 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; +} + +int luaopen_love_jitsetup(lua_State *L) +{ + if (luaL_loadbuffer(L, jit_setup_lua, sizeof(jit_setup_lua), "=[love \"jitsetup.lua\"]") == 0) lua_call(L, 0, 1); return 1; @@ -701,7 +720,7 @@ int luaopen_love_nogame(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; @@ -709,7 +728,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; @@ -717,7 +736,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/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 diff --git a/src/modules/math/wrap_Math.cpp b/src/modules/math/wrap_Math.cpp index cb9933513..83cb93e97 100644 --- a/src/modules/math/wrap_Math.cpp +++ b/src/modules/math/wrap_Math.cpp @@ -415,7 +415,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); diff --git a/src/modules/video/theora/OggDemuxer.cpp b/src/modules/video/theora/OggDemuxer.cpp index f5a14d936..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 OggDemuxer::readPage(bool erroreof) { char *syncBuffer = nullptr; while (ogg_sync_pageout(&sync, &page) != 1) @@ -53,8 +53,13 @@ void OggDemuxer::readPage() syncBuffer = ogg_sync_buffer(&sync, 8192); size_t read = file->read(syncBuffer, 8192); + if (read == 0 && erroreof) + return false; + ogg_sync_wrote(&sync, read); } + + return true; } bool OggDemuxer::readPacket(ogg_packet &packet, bool mustSucceed) @@ -118,22 +123,25 @@ 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 (!readPage(true)) + return TYPE_UNKNOWN; + // If this page isn't at the start of a stream, we've seen all streams - readPage(); 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 +153,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..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 readPage(bool erroreof = false); StreamType determineType(); }; // OggDemuxer