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"
|
2022-03-22 07:13:21 +00:00
|
|
|
#include "util.h"
|
2022-03-30 19:13:53 +00:00
|
|
|
#include "boot.lua.h"
|
2022-07-07 06:50:43 +00:00
|
|
|
#include "nogame.lua.h"
|
2021-03-16 00:54:27 +00:00
|
|
|
#include <lua.h>
|
|
|
|
#include <lauxlib.h>
|
2021-02-07 23:51:31 +00:00
|
|
|
#include <lualib.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-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-12-25 19:18:57 +00:00
|
|
|
static void emscriptenLoop(void*);
|
2018-11-16 15:36:44 +00:00
|
|
|
#endif
|
|
|
|
|
2021-02-19 16:06:16 +00:00
|
|
|
static Variant cookie;
|
|
|
|
|
2022-07-07 06:50:43 +00:00
|
|
|
static int luaopen_lovr_nogame(lua_State* L) {
|
|
|
|
if (!luaL_loadbuffer(L, (const char*) etc_nogame_lua, etc_nogame_lua_len, "@nogame.lua")) {
|
|
|
|
lua_call(L, 0, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
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"))) {
|
2021-02-25 16:00:12 +00:00
|
|
|
os_open_console();
|
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);
|
|
|
|
}
|
|
|
|
|
2022-03-25 07:59:57 +00:00
|
|
|
if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) {
|
|
|
|
os_open_console();
|
|
|
|
printf(
|
2022-04-23 05:47:49 +00:00
|
|
|
"usage: lovr [options] [<source>]\n\n"
|
|
|
|
"options:\n"
|
2022-03-25 07:59:57 +00:00
|
|
|
" -h, --help\t\tShow help and exit\n"
|
|
|
|
" -v, --version\t\tShow version and exit\n"
|
2022-04-23 05:47:49 +00:00
|
|
|
" --console\t\tAttach Windows console\n\n"
|
|
|
|
"<source> can be a Lua file, a folder, or a zip archive\n"
|
2022-03-25 07:59:57 +00:00
|
|
|
);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
2021-06-05 17:12:00 +00:00
|
|
|
if (!os_init()) {
|
|
|
|
fprintf(stderr, "Failed to initialize platform");
|
|
|
|
exit(1);
|
|
|
|
}
|
2020-01-29 05:38:44 +00:00
|
|
|
|
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();
|
2019-03-06 16:42:32 +00:00
|
|
|
luax_setmainthread(L);
|
2018-10-29 20:52:50 +00:00
|
|
|
luaL_openlibs(L);
|
2021-03-16 00:54:27 +00:00
|
|
|
luax_preload(L);
|
2018-10-29 20:52:50 +00:00
|
|
|
|
2022-07-07 06:50:43 +00:00
|
|
|
const luaL_Reg nogame[] = {
|
|
|
|
{ "nogame", luaopen_lovr_nogame },
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
lua_getglobal(L, "package");
|
|
|
|
lua_getfield(L, -1, "preload");
|
|
|
|
luax_register(L, nogame);
|
|
|
|
lua_pop(L, 2);
|
|
|
|
|
2020-01-29 05:38:44 +00:00
|
|
|
// arg table
|
|
|
|
lua_newtable(L);
|
2020-12-25 19:18:57 +00:00
|
|
|
lua_pushstring(L, argc > 0 ? argv[0] : "lovr");
|
2020-01-29 05:38:44 +00:00
|
|
|
lua_setfield(L, -2, "exe");
|
2020-02-26 22:40:40 +00:00
|
|
|
luax_pushvariant(L, &cookie);
|
|
|
|
lua_setfield(L, -2, "restart");
|
|
|
|
|
2020-12-25 19:18:57 +00:00
|
|
|
int argOffset = 1;
|
|
|
|
for (int i = 1; i < argc; i++, argOffset++) {
|
|
|
|
if (!strcmp(argv[i], "--console")) {
|
2021-02-25 16:00:12 +00:00
|
|
|
os_open_console();
|
2020-12-25 19:18:57 +00:00
|
|
|
} else {
|
|
|
|
break; // This is the project path
|
2020-01-29 05:38:44 +00:00
|
|
|
}
|
|
|
|
}
|
2020-12-25 19:18:57 +00:00
|
|
|
|
2020-01-29 05:38:44 +00:00
|
|
|
// 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]);
|
2020-12-25 19:18:57 +00:00
|
|
|
lua_rawseti(L, -2, -argOffset + i);
|
2020-01-29 05:38:44 +00:00
|
|
|
}
|
|
|
|
lua_setglobal(L, "arg");
|
|
|
|
|
|
|
|
lua_pushcfunction(L, luax_getstack);
|
2022-03-30 19:13:53 +00:00
|
|
|
if (luaL_loadbuffer(L, (const char*) etc_boot_lua, etc_boot_lua_len, "@boot.lua") || lua_pcall(L, 0, 1, -2)) {
|
2020-01-29 05:38:44 +00:00
|
|
|
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) {
|
2021-02-25 16:00:12 +00:00
|
|
|
os_sleep(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);
|
|
|
|
|
2021-02-25 16:00:12 +00:00
|
|
|
os_destroy();
|
2018-10-29 20:52:50 +00:00
|
|
|
|
|
|
|
return status;
|
2016-07-07 07:04:24 +00:00
|
|
|
}
|
2020-12-25 19:18:57 +00:00
|
|
|
|
|
|
|
#ifdef EMSCRIPTEN
|
2021-03-16 00:54:27 +00:00
|
|
|
// Called by JS, don't delete
|
2020-12-25 19:18:57 +00:00
|
|
|
void lovrDestroy(void* arg) {
|
|
|
|
if (arg) {
|
|
|
|
lovrEmscriptenContext* context = arg;
|
|
|
|
lua_State* L = context->L;
|
|
|
|
emscripten_cancel_main_loop();
|
|
|
|
lua_close(L);
|
2021-02-25 16:00:12 +00:00
|
|
|
os_destroy();
|
2020-12-25 19:18:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void emscriptenLoop(void* arg) {
|
|
|
|
lovrEmscriptenContext* context = arg;
|
|
|
|
lua_State* T = context->T;
|
|
|
|
|
|
|
|
if (luax_resume(T, 0) != LUA_YIELD) {
|
2021-02-19 16:06:16 +00:00
|
|
|
bool restart = lua_type(T, 1) == LUA_TSTRING && !strcmp(lua_tostring(T, 1), "restart");
|
|
|
|
int 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));
|
|
|
|
}
|
2020-12-25 19:18:57 +00:00
|
|
|
|
|
|
|
lua_close(context->L);
|
|
|
|
emscripten_cancel_main_loop();
|
|
|
|
|
|
|
|
if (restart) {
|
|
|
|
main(context->argc, context->argv);
|
|
|
|
} else {
|
2021-02-25 16:00:12 +00:00
|
|
|
os_destroy();
|
2020-12-25 19:18:57 +00:00
|
|
|
exit(status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|