2018-09-27 04:55:54 +00:00
|
|
|
#include "resources/boot.lua.h"
|
2018-09-27 04:45:45 +00:00
|
|
|
#include "version.h"
|
2018-11-14 02:18:59 +00:00
|
|
|
#include "api.h"
|
2018-09-27 04:55:54 +00:00
|
|
|
#include "luax.h"
|
2018-10-29 19:01:20 +00:00
|
|
|
#include "platform.h"
|
2018-09-27 04:55:54 +00:00
|
|
|
#include "util.h"
|
|
|
|
#include <stdbool.h>
|
2018-05-15 04:38:50 +00:00
|
|
|
#include <string.h>
|
2018-02-17 17:18:08 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
2018-10-29 20:52:50 +00:00
|
|
|
lua_State* lovrInit(lua_State* L, int argc, char** argv);
|
2019-02-14 17:22:00 +00:00
|
|
|
void lovrDestroy(void* arg);
|
2018-11-15 16:21:26 +00:00
|
|
|
int main(int argc, char** argv);
|
2018-09-27 04:55:54 +00:00
|
|
|
|
2018-10-25 03:40:11 +00:00
|
|
|
#ifndef LOVR_USE_OCULUS_MOBILE
|
|
|
|
|
2018-11-16 15:36:44 +00:00
|
|
|
#ifdef EMSCRIPTEN
|
|
|
|
#include <emscripten.h>
|
|
|
|
typedef struct {
|
|
|
|
lua_State* L;
|
|
|
|
lua_State* T;
|
|
|
|
int argc;
|
|
|
|
char** argv;
|
|
|
|
} lovrEmscriptenContext;
|
|
|
|
|
|
|
|
void lovrDestroy(void* arg) {
|
2019-02-14 17:22:00 +00:00
|
|
|
if (arg) {
|
|
|
|
lovrEmscriptenContext* context = arg;
|
|
|
|
lua_State* L = context->L;
|
|
|
|
emscripten_cancel_main_loop();
|
|
|
|
lua_close(L);
|
|
|
|
}
|
2018-11-16 15:36:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void emscriptenLoop(void* arg) {
|
|
|
|
lovrEmscriptenContext* context = arg;
|
|
|
|
lua_getglobal(context->L, "_lovrHeadsetRenderError"); // webvr.c renderCallback failed
|
|
|
|
bool haveRenderError = !lua_isnil(context->L, -1);
|
|
|
|
if (!haveRenderError) {
|
|
|
|
lua_pop(context->L, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int coroutineArgs = luax_pushLovrHeadsetRenderError(context->T);
|
|
|
|
|
|
|
|
if (lua_resume(context->T, coroutineArgs) != LUA_YIELD) {
|
|
|
|
bool restart = lua_type(context->T, -1) == LUA_TSTRING && !strcmp(lua_tostring(context->T, -1), "restart");
|
|
|
|
int status = lua_tonumber(context->T, -1);
|
|
|
|
|
|
|
|
lua_close(context->L);
|
|
|
|
emscripten_cancel_main_loop();
|
|
|
|
|
|
|
|
if (restart) {
|
|
|
|
main(context->argc, context->argv);
|
|
|
|
} else {
|
|
|
|
lovrPlatformDestroy();
|
|
|
|
exit(status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-08-08 20:51:22 +00:00
|
|
|
int main(int argc, char** argv) {
|
2018-09-27 04:45:45 +00:00
|
|
|
if (argc > 1 && (!strcmp(argv[1], "--version") || !strcmp(argv[1], "-v"))) {
|
2018-10-29 19:01:20 +00:00
|
|
|
lovrLog("LOVR %d.%d.%d (%s)\n", LOVR_VERSION_MAJOR, LOVR_VERSION_MINOR, LOVR_VERSION_PATCH, LOVR_VERSION_ALIAS);
|
2018-02-17 17:18:08 +00:00
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
2018-05-15 04:38:50 +00:00
|
|
|
int status;
|
2018-10-29 20:52:50 +00:00
|
|
|
bool restart;
|
|
|
|
|
|
|
|
do {
|
|
|
|
lua_State* L = luaL_newstate();
|
2018-11-13 07:43:36 +00:00
|
|
|
luax_setmainstate(L);
|
2018-10-29 20:52:50 +00:00
|
|
|
luaL_openlibs(L);
|
|
|
|
|
|
|
|
lua_State* T = lovrInit(L, argc, argv);
|
|
|
|
if (!T) {
|
|
|
|
return 1;
|
2018-04-26 03:07:28 +00:00
|
|
|
}
|
2018-10-29 20:52:50 +00:00
|
|
|
|
2018-11-12 01:32:55 +00:00
|
|
|
lovrSetErrorCallback((lovrErrorHandler) luax_vthrow, T);
|
|
|
|
|
2018-10-29 20:52:50 +00:00
|
|
|
#ifdef EMSCRIPTEN
|
|
|
|
lovrEmscriptenContext context = { L, T, argc, argv };
|
|
|
|
emscripten_set_main_loop_arg(emscriptenLoop, (void*) &context, 0, 1);
|
|
|
|
return 0;
|
|
|
|
#else
|
|
|
|
while (lua_resume(T, 0) == LUA_YIELD) {
|
|
|
|
lovrSleep(.001);
|
|
|
|
}
|
|
|
|
|
|
|
|
restart = lua_type(T, -1) == LUA_TSTRING && !strcmp(lua_tostring(T, -1), "restart");
|
|
|
|
status = lua_tonumber(T, -1);
|
|
|
|
lua_close(L);
|
2018-11-13 07:43:36 +00:00
|
|
|
luax_setmainstate(NULL);
|
2018-10-29 20:52:50 +00:00
|
|
|
#endif
|
|
|
|
} while (restart);
|
|
|
|
|
2018-11-16 11:59:06 +00:00
|
|
|
lovrPlatformDestroy();
|
2018-10-29 20:52:50 +00:00
|
|
|
|
|
|
|
return status;
|
2016-07-07 07:04:24 +00:00
|
|
|
}
|
2018-09-27 04:55:54 +00:00
|
|
|
|
2018-10-25 03:40:11 +00:00
|
|
|
#endif
|
|
|
|
|
2018-11-14 02:55:33 +00:00
|
|
|
typedef enum { // What flag is being searched for?
|
|
|
|
ARGFLAG_NONE, // Not processing a flag
|
|
|
|
ARGFLAG_ROOT
|
2018-11-13 20:20:04 +00:00
|
|
|
} ArgFlag;
|
|
|
|
|
2018-10-29 20:52:50 +00:00
|
|
|
lua_State* lovrInit(lua_State* L, int argc, char** argv) {
|
2018-11-16 11:59:06 +00:00
|
|
|
lovrAssert(lovrPlatformInit(), "Failed to initialize platform");
|
2018-09-27 04:55:54 +00:00
|
|
|
|
2018-11-13 21:28:56 +00:00
|
|
|
// arg table
|
|
|
|
// Args follow the lua standard https://en.wikibooks.org/wiki/Lua_Programming/command_line_parameter
|
2018-11-14 02:55:33 +00:00
|
|
|
// In this standard, the contents of argv are put in a global table named "arg", but with indices offset
|
|
|
|
// such that the "script" (in lovr, the game path) is at index 0. So all arguments (if any) intended for
|
|
|
|
// the script/game are at successive indices starting with 1, and the exe and its arguments are in normal
|
|
|
|
// order but stored in negative indices.
|
|
|
|
//
|
|
|
|
// Lovr can be run in ways normal lua can't. It can be run with an empty argv, or with no script (if fused).
|
|
|
|
// So in the case of lovr:
|
|
|
|
// * The script path will always be at index 0, but it can be nil.
|
|
|
|
// * For a fused executable, whatever is given in argv as script name is still at 0, but will be ignored.
|
|
|
|
// * The exe (argv[0]) will always be the lowest-integer index. If it's present, it will always be -1 or less.
|
|
|
|
// * Any named arguments parsed by Lovr will be stored in the arg table at their named keys.
|
|
|
|
// * An exe name will always be stored in the arg table at string key "exe", even if none was supplied in argv.
|
2018-09-27 04:55:54 +00:00
|
|
|
lua_newtable(L);
|
2018-11-13 21:28:56 +00:00
|
|
|
// push dummy "lovr" in case argv is empty
|
2018-12-16 05:45:32 +00:00
|
|
|
lua_pushliteral(L, "lovr");
|
2018-11-14 02:55:33 +00:00
|
|
|
lua_setfield(L, -2, "exe");
|
2018-11-13 21:28:56 +00:00
|
|
|
|
2018-11-14 02:55:33 +00:00
|
|
|
bool exeFound = false;
|
|
|
|
ArgFlag currentFlag = ARGFLAG_NONE;
|
|
|
|
int lovrArgs = 0; // Arg count up to but not including the game path
|
|
|
|
// One pass to parse flags
|
2018-09-27 04:55:54 +00:00
|
|
|
for (int i = 0; i < argc; i++) {
|
2018-11-14 02:55:33 +00:00
|
|
|
if (lovrArgs > 0) {
|
2018-11-13 20:20:04 +00:00
|
|
|
// This argument is an argument to a -- flag
|
2018-11-14 02:55:33 +00:00
|
|
|
if (currentFlag == ARGFLAG_ROOT) {
|
2018-11-13 20:20:04 +00:00
|
|
|
lua_pushstring(L, argv[i]);
|
2018-11-14 02:55:33 +00:00
|
|
|
lua_setfield(L, -2, "root");
|
|
|
|
currentFlag = ARGFLAG_NONE;
|
2018-11-13 20:20:04 +00:00
|
|
|
|
|
|
|
// This argument is a -- flag
|
2018-11-14 02:55:33 +00:00
|
|
|
} else if (!strcmp(argv[1], "--root") || !strcmp(argv[1], "-r")) {
|
|
|
|
currentFlag = ARGFLAG_ROOT;
|
2018-11-13 20:20:04 +00:00
|
|
|
|
2018-11-14 02:55:33 +00:00
|
|
|
// This is the game path
|
2018-11-13 20:20:04 +00:00
|
|
|
} else {
|
2018-11-14 02:55:33 +00:00
|
|
|
break;
|
2018-11-13 20:20:04 +00:00
|
|
|
}
|
2018-11-14 02:55:33 +00:00
|
|
|
} else { // Found exe name
|
|
|
|
lua_pushstring(L, argv[i]);
|
|
|
|
lua_setfield(L, -2, "exe");
|
2018-11-13 20:20:04 +00:00
|
|
|
}
|
|
|
|
|
2018-11-14 02:55:33 +00:00
|
|
|
lovrArgs++;
|
|
|
|
}
|
|
|
|
// Now that we know the negative offset to start at, copy all args in the table
|
|
|
|
for (int i = 0; i < argc; i++) {
|
2018-09-27 04:55:54 +00:00
|
|
|
lua_pushstring(L, argv[i]);
|
2018-11-14 02:55:33 +00:00
|
|
|
lua_rawseti(L, -2, -lovrArgs + i);
|
2018-09-27 04:55:54 +00:00
|
|
|
}
|
2018-11-13 21:28:56 +00:00
|
|
|
|
2018-09-27 04:55:54 +00:00
|
|
|
lua_setglobal(L, "arg");
|
|
|
|
|
2018-11-14 02:18:59 +00:00
|
|
|
lua_getglobal(L, "package");
|
|
|
|
lua_getfield(L, -1, "preload");
|
|
|
|
luaL_register(L, NULL, lovrModules);
|
|
|
|
lua_pop(L, 2);
|
2018-09-27 04:55:54 +00:00
|
|
|
|
|
|
|
lua_pushcfunction(L, luax_getstack);
|
|
|
|
if (luaL_loadbuffer(L, (const char*) boot_lua, boot_lua_len, "boot.lua") || lua_pcall(L, 0, 1, -2)) {
|
2018-10-29 19:01:20 +00:00
|
|
|
lovrWarn("%s\n", lua_tostring(L, -1));
|
2018-10-29 20:52:50 +00:00
|
|
|
return NULL;
|
2018-09-27 04:55:54 +00:00
|
|
|
}
|
|
|
|
|
2018-10-29 20:52:50 +00:00
|
|
|
lua_State* T = lua_newthread(L);
|
2018-09-27 04:55:54 +00:00
|
|
|
lua_pushvalue(L, -2);
|
2018-10-29 20:52:50 +00:00
|
|
|
lua_xmove(L, T, 1);
|
|
|
|
return T;
|
2018-09-27 04:55:54 +00:00
|
|
|
}
|