From b001b2e1d526c86ab930b7f8c3171fd9e2b13439 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 28 Dec 2019 22:43:39 -0500 Subject: [PATCH] Add love.event.restart(optionalvalue) as a shorthand for love.event.quit("restart", optionalvalue). If a Lua value is provided as an argument, a new love.restart field will contain the value after restarting. --HG-- branch : minor --- src/common/Variant.cpp | 12 +++++++++--- src/common/Variant.h | 2 +- src/love.cpp | 28 ++++++++++++++++++++++------ src/modules/event/wrap_Event.cpp | 25 +++++++++++++++++++++++-- src/scripts/boot.lua | 6 +++--- src/scripts/boot.lua.h | 12 +++++++----- 6 files changed, 65 insertions(+), 20 deletions(-) diff --git a/src/common/Variant.cpp b/src/common/Variant.cpp index 93753869c..3c3b6fb65 100644 --- a/src/common/Variant.cpp +++ b/src/common/Variant.cpp @@ -152,7 +152,7 @@ Variant &Variant::operator = (const Variant &v) return *this; } -Variant Variant::fromLua(lua_State *L, int n, std::set *tableSet) +Variant Variant::fromLua(lua_State *L, int n, bool allowuserdata, std::set *tableSet) { size_t len; const char *str; @@ -173,6 +173,11 @@ Variant Variant::fromLua(lua_State *L, int n, std::set *tableSet) case LUA_TLIGHTUSERDATA: return Variant(lua_touserdata(L, n)); case LUA_TUSERDATA: + if (!allowuserdata) + { + luax_typerror(L, n, "copyable Lua value"); + return Variant(); + } p = tryextractproxy(L, n); if (p != nullptr) return Variant(p->type, p->object); @@ -187,7 +192,6 @@ Variant Variant::fromLua(lua_State *L, int n, std::set *tableSet) { bool success = true; std::set topTableSet; - SharedTable *table = new SharedTable(); // We can use a pointer to a stack-allocated variable because it's // never used after the stack-allocated variable is destroyed. @@ -202,6 +206,8 @@ Variant Variant::fromLua(lua_State *L, int n, std::set *tableSet) throw love::Exception("Cycle detected in table"); } + SharedTable *table = new SharedTable(); + size_t len = luax_objlen(L, -1); if (len > 0) table->pairs.reserve(len); @@ -210,7 +216,7 @@ Variant Variant::fromLua(lua_State *L, int n, std::set *tableSet) while (lua_next(L, n)) { - table->pairs.emplace_back(fromLua(L, -2, tableSet), fromLua(L, -1, tableSet)); + table->pairs.emplace_back(fromLua(L, -2, allowuserdata, tableSet), fromLua(L, -1, allowuserdata, tableSet)); lua_pop(L, 1); const auto &p = table->pairs.back(); diff --git a/src/common/Variant.h b/src/common/Variant.h index 420562283..2144338a6 100644 --- a/src/common/Variant.h +++ b/src/common/Variant.h @@ -111,7 +111,7 @@ public: Type getType() const { return type; } const Data &getData() const { return data; } - static Variant fromLua(lua_State *L, int n, std::set *tableSet = nullptr); + static Variant fromLua(lua_State *L, int n, bool allowuserdata = true, std::set *tableSet = nullptr); void toLua(lua_State *L) const; private: diff --git a/src/love.cpp b/src/love.cpp index ddd86e8e9..ffdb6c083 100644 --- a/src/love.cpp +++ b/src/love.cpp @@ -20,6 +20,7 @@ #include "common/version.h" #include "common/runtime.h" +#include "common/Variant.h" #include "modules/love/love.h" #include @@ -139,7 +140,7 @@ enum DoneAction DONE_RESTART, }; -static DoneAction runlove(int argc, char **argv, int &retval) +static DoneAction runlove(int argc, char **argv, int &retval, love::Variant &restartvalue) { #ifdef LOVE_LEGENDARY_APP_ARGV_HACK int hack_argc = 0; @@ -203,6 +204,11 @@ static DoneAction runlove(int argc, char **argv, int &retval) lua_setfield(L, -2, "_exe"); } + // Set love.restart = restartvalue, and clear restartvalue. + restartvalue.toLua(L); + lua_setfield(L, -2, "restart"); + restartvalue = love::Variant(); + // Pop the love table returned by require "love". lua_pop(L, 1); @@ -223,10 +229,19 @@ static DoneAction runlove(int argc, char **argv, int &retval) // if love.boot() returns "restart", we'll start up again after closing this // Lua state. - if (lua_type(L, -1) == LUA_TSTRING && strcmp(lua_tostring(L, -1), "restart") == 0) - done = DONE_RESTART; - if (lua_isnumber(L, -1)) - retval = (int) lua_tonumber(L, -1); + int retidx = stackpos; + if (!lua_isnoneornil(L, retidx)) + { + if (lua_type(L, retidx) == LUA_TSTRING && strcmp(lua_tostring(L, retidx), "restart") == 0) + done = DONE_RESTART; + if (lua_isnumber(L, retidx)) + retval = (int) lua_tonumber(L, retidx); + + // Disallow userdata (love objects) from being referenced by the restart + // value. + if (retidx < lua_gettop(L)) + restartvalue = love::Variant::fromLua(L, retidx + 1, false); + } lua_close(L); @@ -253,10 +268,11 @@ int main(int argc, char **argv) int retval = 0; DoneAction done = DONE_QUIT; + love::Variant restartvalue; do { - done = runlove(argc, argv, retval); + done = runlove(argc, argv, retval, restartvalue); #ifdef LOVE_IOS // on iOS we should never programmatically exit the app, so we'll just diff --git a/src/modules/event/wrap_Event.cpp b/src/modules/event/wrap_Event.cpp index 280245530..197c84c34 100644 --- a/src/modules/event/wrap_Event.cpp +++ b/src/modules/event/wrap_Event.cpp @@ -22,9 +22,10 @@ // LOVE #include "common/runtime.h" - #include "sdl/Event.h" +#include + // Shove the wrap_Event.lua code directly into a raw string literal. static const char event_lua[] = #include "wrap_Event.lua" @@ -95,7 +96,26 @@ int w_clear(lua_State *L) int w_quit(lua_State *L) { luax_catchexcept(L, [&]() { - std::vector args = {Variant::fromLua(L, 1)}; + std::vector args; + for (int i = 1; i <= std::max(1, lua_gettop(L)); i++) + args.push_back(Variant::fromLua(L, i)); + + StrongRef m(new Message("quit", args), Acquire::NORETAIN); + instance()->push(m); + }); + + luax_pushboolean(L, true); + return 1; +} + +int w_restart(lua_State *L) +{ + luax_catchexcept(L, [&]() { + std::vector args; + args.emplace_back("restart", strlen("restart")); + + for (int i = 1; i <= lua_gettop(L); i++) + args.push_back(Variant::fromLua(L, i)); StrongRef m(new Message("quit", args), Acquire::NORETAIN); instance()->push(m); @@ -114,6 +134,7 @@ static const luaL_Reg functions[] = { "push", w_push }, { "clear", w_clear }, { "quit", w_quit }, + { "restart", w_restart }, { 0, 0 } }; diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua index e402ef38f..345ed049d 100644 --- a/src/scripts/boot.lua +++ b/src/scripts/boot.lua @@ -598,7 +598,7 @@ function love.run() for name, a,b,c,d,e,f in love.event.poll() do if name == "quit" then if not love.quit or not love.quit() then - return a or 0 + return a or 0, b end end love.handlers[name](a,b,c,d,e,f) @@ -799,8 +799,8 @@ return function() func = earlyinit while func do - local _, retval = xpcall(func, deferErrhand) - if retval then return retval end + local _, retval, restartvalue = xpcall(func, deferErrhand) + if retval then return retval, restartvalue end coroutine.yield() end diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h index 0b61d2b26..1cdf671bc 100644 --- a/src/scripts/boot.lua.h +++ b/src/scripts/boot.lua.h @@ -1208,7 +1208,7 @@ const unsigned char boot_lua[] = 0x75, 0x69, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x71, 0x75, 0x69, 0x74, 0x28, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, 0x6f, 0x72, 0x20, - 0x30, 0x0a, + 0x30, 0x2c, 0x20, 0x62, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x5b, @@ -1581,11 +1581,13 @@ const unsigned char boot_lua[] = 0x09, 0x66, 0x75, 0x6e, 0x63, 0x20, 0x3d, 0x20, 0x65, 0x61, 0x72, 0x6c, 0x79, 0x69, 0x6e, 0x69, 0x74, 0x0a, 0x0a, 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x20, 0x64, 0x6f, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x5f, 0x2c, 0x20, 0x72, 0x65, 0x74, 0x76, 0x61, 0x6c, 0x20, - 0x3d, 0x20, 0x78, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x2c, 0x20, 0x64, 0x65, 0x66, - 0x65, 0x72, 0x45, 0x72, 0x72, 0x68, 0x61, 0x6e, 0x64, 0x29, 0x0a, + 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x5f, 0x2c, 0x20, 0x72, 0x65, 0x74, 0x76, 0x61, 0x6c, 0x2c, + 0x20, 0x72, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x3d, 0x20, 0x78, 0x70, + 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x2c, 0x20, 0x64, 0x65, 0x66, 0x65, 0x72, 0x45, 0x72, + 0x72, 0x68, 0x61, 0x6e, 0x64, 0x29, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x72, 0x65, 0x74, 0x76, 0x61, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, - 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x76, 0x61, 0x6c, 0x20, 0x65, 0x6e, 0x64, 0x0a, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x76, 0x61, 0x6c, 0x2c, 0x20, 0x72, 0x65, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x63, 0x6f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x65, 0x2e, 0x79, 0x69, 0x65, 0x6c, 0x64, 0x28, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a,