Restart-without-quit support: lovr.event.quit("restart") and return-from-run() both support the string "restart" in place of an exit code. When this happens, the program reruns itself in a new, isolated environment. In Emscripten, no reboot occurs and the program only quits.

This commit is contained in:
mcc 2018-01-25 21:32:16 -05:00
parent 9ece4a3b09
commit 8052896b33
13 changed files with 109 additions and 24 deletions

View File

@ -15,7 +15,10 @@ static int nextEvent(lua_State* L) {
switch (event.type) {
case EVENT_QUIT: {
lua_pushstring(L, "quit");
lua_pushnumber(L, event.data.quit.exitCode);
if (event.data.quit.restart)
lua_pushliteral(L, "restart");
else
lua_pushnumber(L, event.data.quit.exitCode);
return 2;
}
@ -125,11 +128,22 @@ int l_lovrEventPush(lua_State* L) {
}
int l_lovrEventQuit(lua_State* L) {
int exitCode = luaL_optint(L, 1, 0);
lua_settop(L, 0);
lua_pushliteral(L, "quit");
lua_pushinteger(L, exitCode);
return l_lovrEventPush(L);
EventData data;
int argType = lua_type(L, 1);
if (argType == LUA_TSTRING && 0 == strcmp("restart", lua_tostring(L, 1))) {
data.quit.restart = true;
data.quit.exitCode = 0;
} else if (argType == LUA_TNUMBER || lua_isnoneornil(L, 1)) {
data.quit.restart = false;
data.quit.exitCode = luaL_optint(L, 1, 0);
} else {
return luaL_argerror (L, 1, "number, nil or the exact string 'restart' expected");
}
EventType type = EVENT_QUIT;
Event event = { .type = type, .data = data };
lovrEventPush(event);
}
const luaL_Reg lovrEvent[] = {

View File

@ -3,10 +3,16 @@
#include "math/quat.h"
#include "util.h"
#include <stdlib.h>
#include "lovr.h"
static AudioState state;
static bool audioAlreadyInit = false;
void lovrAudioInit() {
if (audioAlreadyInit) { // During a reload, bring down the audio device then recreate it
lovrAudioDestroy();
}
ALCdevice* device = alcOpenDevice(NULL);
lovrAssert(device, "Unable to open default audio device");
@ -31,7 +37,10 @@ void lovrAudioInit() {
vec3_set(state.position, 0, 0, 0);
vec3_set(state.velocity, 0, 0, 0);
atexit(lovrAudioDestroy);
if (!audioAlreadyInit) {
atexit(lovrAudioDestroy);
audioAlreadyInit = true;
}
}
void lovrAudioDestroy() {

View File

@ -3,12 +3,18 @@
#include <stdlib.h>
static EventState state;
bool eventAlreadyInit = false;
void lovrEventInit() {
if (eventAlreadyInit)
lovrEventDestroy();
vec_init(&state.pumps);
vec_init(&state.events);
lovrEventAddPump(glfwPollEvents);
atexit(lovrEventDestroy);
if (!eventAlreadyInit) {
atexit(lovrEventDestroy);
eventAlreadyInit = true;
}
}
void lovrEventDestroy() {

View File

@ -14,6 +14,7 @@ typedef enum {
} EventType;
typedef struct {
bool restart;
int exitCode;
} QuitEvent;

View File

@ -4,6 +4,7 @@
#include <physfs.h>
#include <stdio.h>
#include <stdlib.h>
#include "lovr.h"
#ifdef __APPLE__
#include <mach-o/dyld.h>
#endif
@ -20,7 +21,13 @@
static FilesystemState state;
bool filesystemAlreadyInit = false;
void lovrFilesystemInit(const char* arg0, const char* arg1) {
if (filesystemAlreadyInit) // Do not change settings during a reload, and don't try to initialize PhysFS twice
return;
filesystemAlreadyInit = true;
if (!PHYSFS_init(arg0)) {
lovrThrow("Could not initialize filesystem: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
}

View File

@ -13,6 +13,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "lovr.h"
static GraphicsState state;
@ -164,8 +165,16 @@ void lovrGraphicsPrepare(Material* material, float* pose) {
lovrShaderBind(shader);
}
static bool graphicsAlreadyInit = false;
void lovrGraphicsCreateWindow(int w, int h, bool fullscreen, int msaa, const char* title, const char* icon) {
lovrAssert(!state.window, "Window is already created");
if (graphicsAlreadyInit) {
lovrGraphicsReset();
return;
} else {
lovrAssert(!state.window, "Window is already created");
graphicsAlreadyInit = true;
}
#ifdef EMSCRIPTEN
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);

View File

@ -7,6 +7,7 @@ void lovrControllerDestroy(const Ref* ref) {
}
static HeadsetInterface* headset = NULL;
static bool headsetAlreadyInit = false;
void lovrHeadsetInit(HeadsetDriver* drivers, int count) {
for (int i = 0; i < count; i++) {
@ -28,9 +29,10 @@ void lovrHeadsetInit(HeadsetDriver* drivers, int count) {
}
}
if (headset) {
if (!headsetAlreadyInit && headset) {
headset->init();
atexit(lovrHeadsetDestroy);
headsetAlreadyInit = true;
}
}

View File

@ -31,6 +31,7 @@
#include "lualib.h"
#include "lauxlib.h"
#include <enet/enet.h>
#include <stdbool.h>
#define check_host(l, idx)\
*(ENetHost**)luaL_checkudata(l, idx, "enet_host")
@ -768,9 +769,14 @@ static const struct luaL_Reg enet_peer_funcs [] = {
{NULL, NULL}
};
static bool enitAlreadyInit = false;
int luaopen_enet(lua_State *l) {
enet_initialize();
atexit(enet_deinitialize);
if (!enitAlreadyInit) {
atexit(enet_deinitialize);
enitAlreadyInit = true;
}
// create metatables
luaL_newmetatable(l, "enet_host");

View File

@ -63,6 +63,8 @@ static int lovrSetConf(lua_State* L) {
return 0;
}
static bool glfwAlreadyInit = false;
void lovrInit(lua_State* L, int argc, char** argv) {
if (argc > 1 && strcmp(argv[1], "--version") == 0) {
printf("LOVR %d.%d.%d (%s)\n", LOVR_VERSION_MAJOR, LOVR_VERSION_MINOR, LOVR_VERSION_PATCH, LOVR_VERSION_ALIAS);
@ -72,9 +74,10 @@ void lovrInit(lua_State* L, int argc, char** argv) {
glfwSetTime(0);
glfwSetErrorCallback(onGlfwError);
if (!glfwInit()) {
if (!glfwAlreadyInit && !glfwInit()) {
lovrThrow("Error initializing glfw");
}
glfwAlreadyInit = true;
// arg global
lua_newtable(L);
@ -141,7 +144,7 @@ static void emscriptenLoop(void* arg) {
lua_call(L, 0, 0);
}
void lovrRun(lua_State* L) {
bool lovrRun(lua_State* L) {
// lovr.load
lua_getglobal(L, "lovr");
@ -158,9 +161,10 @@ void lovrRun(lua_State* L) {
}
emscripten_set_main_loop_arg(emscriptenLoop, (void*) L, 0, 1);
return false;
}
#else
void lovrRun(lua_State* L) {
bool lovrRun(lua_State* L) {
lovrCatch = malloc(sizeof(jmp_buf));
// Global error handler
@ -175,7 +179,7 @@ void lovrRun(lua_State* L) {
lua_pushstring(L, lovrErrorMessage);
lua_pcall(L, 1, 1, 0);
handleError(L, lua_tostring(L, -1));
return;
return false;
}
// lovr.run()
@ -187,9 +191,21 @@ void lovrRun(lua_State* L) {
}
// Exit with return value from lovr.run
int exitCode = luaL_optint(L, -1, 0);
lua_pop(L, 2);
int exitCode = 0;
int returnType = lua_type(L, -1);
bool reloading = false;
if (returnType == LUA_TSTRING && 0 == strcmp("restart", lua_tostring(L, -1))) {
reloading = true; // Treat "restart" as special
} else if (returnType == LUA_TNUMBER || lua_isnoneornil(L, -1)) {
exitCode = luaL_optint(L, -1, 0);
} else {
luaL_argerror (L, -1, "number or the exact string 'restart' expected");
}
free(lovrCatch);
lovrDestroy(exitCode);
lovrCatch = NULL;
if (!reloading)
lovrDestroy(exitCode);
return reloading;
}
#endif

View File

@ -1,4 +1,5 @@
#include "luax.h"
#include <stdbool.h>
#define LOVR_VERSION_MAJOR 0
#define LOVR_VERSION_MINOR 9
@ -7,4 +8,4 @@
void lovrInit(lua_State* L, int argc, char** argv);
void lovrDestroy(int exitCode);
void lovrRun(lua_State* L);
bool lovrRun(lua_State* L); // Returns true to request continue

View File

@ -1,11 +1,14 @@
#include "lovr.h"
int main(int argc, char** argv) {
lua_State* L = luaL_newstate();
luaL_openlibs(L);
bool reloading;
do {
lua_State* L = luaL_newstate();
luaL_openlibs(L);
lovrInit(L, argc, argv);
lovrRun(L);
lovrInit(L, argc, argv);
reloading = lovrRun(L);
} while (reloading);
return 0;
}

View File

@ -3,14 +3,19 @@
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
static RandomGenerator* generator;
bool mathAlreadyInit = false;
void lovrMathInit() {
generator = lovrRandomGeneratorCreate();
Seed seed = { .b64 = (uint64_t) time(0) };
lovrRandomGeneratorSetSeed(generator, seed);
atexit(lovrMathDestroy);
if (!mathAlreadyInit) {
atexit(lovrMathDestroy);
mathAlreadyInit = true;
}
}
void lovrMathDestroy() {

View File

@ -28,9 +28,15 @@ static void raycastCallback(void* data, dGeomID a, dGeomID b) {
}
}
static bool odeAlreadyInit = false;
void lovrPhysicsInit() {
if (odeAlreadyInit)
return;
dInitODE();
atexit(lovrPhysicsDestroy);
odeAlreadyInit = true;
}
void lovrPhysicsDestroy() {