2018-09-27 04:55:54 +00:00
|
|
|
#include "resources/boot.lua.h"
|
2019-05-18 00:11:22 +00:00
|
|
|
#include "api/api.h"
|
2020-02-26 22:40:40 +00:00
|
|
|
#include "event/event.h"
|
2019-12-14 03:36:46 +00:00
|
|
|
#include "core/os.h"
|
2019-12-10 21:01:28 +00:00
|
|
|
#include "core/util.h"
|
2018-09-27 04:55:54 +00:00
|
|
|
#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-11-15 16:21:26 +00:00
|
|
|
int main(int argc, char** argv);
|
2018-09-27 04:55:54 +00:00
|
|
|
|
2018-11-16 15:36:44 +00:00
|
|
|
#ifdef EMSCRIPTEN
|
|
|
|
#include <emscripten.h>
|
2020-01-29 05:38:44 +00:00
|
|
|
|
2018-11-16 15:36:44 +00:00
|
|
|
typedef struct {
|
|
|
|
lua_State* L;
|
|
|
|
lua_State* T;
|
|
|
|
int argc;
|
|
|
|
char** argv;
|
|
|
|
} lovrEmscriptenContext;
|
|
|
|
|
2020-01-29 05:38:44 +00:00
|
|
|
// Called by JS
|
2018-11-16 15:36:44 +00:00
|
|
|
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);
|
2020-10-11 14:32:02 +00:00
|
|
|
lovrPlatformDestroy();
|
2019-02-14 17:22:00 +00:00
|
|
|
}
|
2018-11-16 15:36:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void emscriptenLoop(void* arg) {
|
|
|
|
lovrEmscriptenContext* context = arg;
|
2019-03-07 09:04:45 +00:00
|
|
|
lua_State* T = context->T;
|
2018-11-16 15:36:44 +00:00
|
|
|
|
2020-08-20 19:23:00 +00:00
|
|
|
if (luax_resume(T, 0) != LUA_YIELD) {
|
2019-03-07 09:04:45 +00:00
|
|
|
bool restart = lua_type(T, -1) == LUA_TSTRING && !strcmp(lua_tostring(T, -1), "restart");
|
|
|
|
int status = lua_tonumber(T, -1);
|
2018-11-16 15:36:44 +00:00
|
|
|
|
|
|
|
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"))) {
|
2019-08-01 20:49:39 +00:00
|
|
|
lovrPlatformOpenConsole();
|
2019-08-22 02:02:02 +00:00
|
|
|
printf("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);
|
|
|
|
}
|
|
|
|
|
2020-01-29 05:38:44 +00:00
|
|
|
lovrAssert(lovrPlatformInit(), "Failed to initialize platform");
|
|
|
|
|
2018-05-15 04:38:50 +00:00
|
|
|
int status;
|
2018-10-29 20:52:50 +00:00
|
|
|
bool restart;
|
2020-02-26 22:40:40 +00:00
|
|
|
Variant cookie;
|
|
|
|
cookie.type = TYPE_NIL;
|
2018-10-29 20:52:50 +00:00
|
|
|
|
|
|
|
do {
|
2020-01-29 05:38:44 +00:00
|
|
|
lovrPlatformSetTime(0.);
|
2018-10-29 20:52:50 +00:00
|
|
|
lua_State* L = luaL_newstate();
|
2019-03-06 16:42:32 +00:00
|
|
|
luax_setmainthread(L);
|
2018-10-29 20:52:50 +00:00
|
|
|
luaL_openlibs(L);
|
|
|
|
|
2020-01-29 05:38:44 +00:00
|
|
|
// arg table
|
|
|
|
// Args follow the lua standard https://en.wikibooks.org/wiki/Lua_Programming/command_line_parameter
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
// LÖVR 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 LÖVR:
|
|
|
|
// * 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.
|
|
|
|
lua_newtable(L);
|
|
|
|
// push dummy "lovr" in case argv is empty
|
|
|
|
lua_pushliteral(L, "lovr");
|
|
|
|
lua_setfield(L, -2, "exe");
|
|
|
|
|
2020-02-26 22:40:40 +00:00
|
|
|
luax_pushvariant(L, &cookie);
|
|
|
|
lua_setfield(L, -2, "restart");
|
|
|
|
|
2020-01-29 05:38:44 +00:00
|
|
|
typedef enum { // What flag is being searched for?
|
|
|
|
ARGFLAG_NONE, // Not processing a flag
|
|
|
|
ARGFLAG_ROOT
|
|
|
|
} ArgFlag;
|
|
|
|
|
|
|
|
ArgFlag currentFlag = ARGFLAG_NONE;
|
|
|
|
int lovrArgs = 0; // Arg count up to but not including the game path
|
|
|
|
// One pass to parse flags
|
|
|
|
for (int i = 0; i < argc; i++) {
|
|
|
|
if (lovrArgs > 0) {
|
|
|
|
// This argument is an argument to a -- flag
|
|
|
|
if (currentFlag == ARGFLAG_ROOT) {
|
|
|
|
lua_pushstring(L, argv[i]);
|
|
|
|
lua_setfield(L, -2, "root");
|
|
|
|
currentFlag = ARGFLAG_NONE;
|
|
|
|
|
|
|
|
// This argument is a -- flag
|
|
|
|
} else if (!strcmp(argv[i], "--root") || !strcmp(argv[i], "-r")) {
|
|
|
|
currentFlag = ARGFLAG_ROOT;
|
|
|
|
|
|
|
|
} else if (!strcmp(argv[i], "--console")) {
|
|
|
|
lovrPlatformOpenConsole();
|
|
|
|
|
|
|
|
// This is the game path
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else { // Found exe name
|
|
|
|
lua_pushstring(L, argv[i]);
|
|
|
|
lua_setfield(L, -2, "exe");
|
|
|
|
}
|
|
|
|
|
|
|
|
lovrArgs++;
|
|
|
|
}
|
|
|
|
// Now that we know the negative offset to start at, copy all args in the table
|
|
|
|
for (int i = 0; i < argc; i++) {
|
|
|
|
lua_pushstring(L, argv[i]);
|
|
|
|
lua_rawseti(L, -2, -lovrArgs + i);
|
|
|
|
}
|
|
|
|
|
|
|
|
lua_setglobal(L, "arg");
|
|
|
|
|
|
|
|
lua_getglobal(L, "package");
|
|
|
|
lua_getfield(L, -1, "preload");
|
2020-08-19 19:12:06 +00:00
|
|
|
luax_register(L, lovrModules);
|
2020-01-29 05:38:44 +00:00
|
|
|
lua_pop(L, 2);
|
|
|
|
|
|
|
|
lua_pushcfunction(L, luax_getstack);
|
|
|
|
if (luaL_loadbuffer(L, (const char*) src_resources_boot_lua, src_resources_boot_lua_len, "@boot.lua") || lua_pcall(L, 0, 1, -2)) {
|
|
|
|
fprintf(stderr, "%s\n", lua_tostring(L, -1));
|
2018-10-29 20:52:50 +00:00
|
|
|
return 1;
|
2018-04-26 03:07:28 +00:00
|
|
|
}
|
2018-10-29 20:52:50 +00:00
|
|
|
|
2020-01-29 05:38:44 +00:00
|
|
|
lua_State* T = lua_newthread(L);
|
|
|
|
lua_pushvalue(L, -2);
|
|
|
|
lua_xmove(L, T, 1);
|
|
|
|
|
2019-09-24 14:28:34 +00:00
|
|
|
lovrSetErrorCallback(luax_vthrow, T);
|
lovr.log;
lovr.log is a new callback that is invoked whenever LÖVR wants to
send the project a message. For example, this could be a performance
warning from the graphics module, an error message from one of the
headset backends, or an API deprecation notice.
The callback's signature is (message, level, tag). The message is a
string containing the message to log, level is a string that is currently
one of "debug", "info", "warn", "error", and tag is an optional string
that is used to indicate the source of the message for grouping purposes.
The default implementation of the callback just prints the message,
but the callback can be overridden to do things like filter messages,
write them to a file, or even render them in VR. Projects can also
invoke the callback directly to log their own messages.
2020-07-06 22:20:55 +00:00
|
|
|
lovrSetLogCallback(luax_vlog, T);
|
2018-11-12 01:32:55 +00:00
|
|
|
|
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;
|
2020-01-29 05:38:44 +00:00
|
|
|
#endif
|
|
|
|
|
2020-08-19 19:12:06 +00:00
|
|
|
while (luax_resume(T, 0) == LUA_YIELD) {
|
2020-01-09 07:56:58 +00:00
|
|
|
lovrPlatformSleep(0.);
|
2018-10-29 20:52:50 +00:00
|
|
|
}
|
|
|
|
|
2020-02-26 22:40:40 +00:00
|
|
|
restart = lua_type(T, 1) == LUA_TSTRING && !strcmp(lua_tostring(T, 1), "restart");
|
|
|
|
status = lua_tonumber(T, 1);
|
|
|
|
luax_checkvariant(T, 2, &cookie);
|
|
|
|
if (cookie.type == TYPE_OBJECT) {
|
|
|
|
cookie.type = TYPE_NIL;
|
|
|
|
memset(&cookie.value, 0, sizeof(cookie.value));
|
|
|
|
}
|
2018-10-29 20:52:50 +00:00
|
|
|
lua_close(L);
|
|
|
|
} 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
|
|
|
}
|