diff --git a/Makefile b/Makefile index 4c1107ce5..d464b72b6 100644 --- a/Makefile +++ b/Makefile @@ -61,6 +61,7 @@ ifeq ($(PLAT),web) CFLAGS = -g LDFLAGS = -g -s WASM=1 -s NO_EXIT_RUNTIME=1 -s ABORTING_MALLOC=0 -s ALLOW_MEMORY_GROWTH=1 -s TOTAL_STACK=256Kb --js-library $(SOURCE_DIR)/interop_web.js BUILD_DIR = build/web + BEARSSL = 0 endif ifeq ($(PLAT),mingw) diff --git a/src/Game.c b/src/Game.c index ad3d22b26..4bb0c25df 100644 --- a/src/Game.c +++ b/src/Game.c @@ -44,7 +44,7 @@ struct _GameData Game; static cc_uint64 frameStart; -cc_bool Game_UseCPEBlocks; +cc_bool Game_UseCPEBlocks, Game_Running; struct RayTracer Game_SelectedPos; int Game_ViewDistance = DEFAULT_VIEWDIST; @@ -53,7 +53,6 @@ int Game_MaxViewDistance = DEFAULT_MAX_VIEWDIST; int Game_FpsLimit, Game_Vertices; cc_bool Game_SimpleArmsAnim; -static cc_bool gameRunning; static float gfx_minFrameMs; static cc_bool autoPause; @@ -410,7 +409,7 @@ static void LoadPlugins(void) { static void LoadPlugins(void) { } #endif -static void Game_PendingClose(void* obj) { gameRunning = false; } +static void Game_PendingClose(void* obj) { Game_Running = false; } static void Game_Load(void) { struct IGameComponent* comp; Game_UpdateDimensions(); @@ -844,8 +843,7 @@ static CC_INLINE void Game_RenderFrame(void) { if (gfx_minFrameMs) LimitFPS(); } - -static void Game_Free(void) { +void Game_Free(void) { struct IGameComponent* comp; /* Most components will call OnContextLost in their Free functions */ /* Set to false so components will always free managed textures too */ @@ -858,7 +856,7 @@ static void Game_Free(void) { if (comp->Free) comp->Free(); } - gameRunning = false; + Game_Running = false; Logger_WarnFunc = Logger_DialogWarn; Gfx_Free(); Options_SaveIfChanged(); @@ -867,7 +865,7 @@ static void Game_Free(void) { #ifdef CC_BUILD_WEB void Game_DoFrame(void) { - if (gameRunning) { + if (Game_Running) { Game_RenderFrame(); } else if (tasksCount) { Game_Free(); @@ -881,7 +879,7 @@ static void Game_RunLoop(void) { } cc_bool Game_ShouldClose(void) { - if (!gameRunning) return true; + if (!Game_Running) return true; if (Server.IsSinglePlayer) { /* Close if map was saved within last 5 seconds */ @@ -895,15 +893,15 @@ cc_bool Game_ShouldClose(void) { } #else static void Game_RunLoop(void) { - while (gameRunning) + while (Game_Running) { Game_RenderFrame(); } - Game_Free(); } #endif -void Game_Setup(const cc_string* title) { +void Game_Setup(void) { + cc_string title; char titleBuffer[STRING_SIZE]; int width = Options_GetInt(OPT_WINDOW_WIDTH, 0, DisplayInfo.Width, 0); int height = Options_GetInt(OPT_WINDOW_HEIGHT, 0, DisplayInfo.Height, 0); @@ -913,19 +911,21 @@ void Game_Setup(const cc_string* title) { if (DisplayInfo.Width < 854) width = 640; } + String_InitArray(title, titleBuffer); + String_Format2(&title, "%c (%s)", GAME_APP_TITLE, &Game_Username); + Window_Create3D(width, height); - Window_SetTitle(title); + Window_SetTitle(&title); Window_Show(); - gameRunning = true; + Game_Running = true; Game.CurrentState = 0; Game_Load(); Event_RaiseVoid(&WindowEvents.Resized); + frameStart = Stopwatch_Measure(); } void Game_Run(void) { - frameStart = Stopwatch_Measure(); Game_RunLoop(); - Window_Destroy(); } diff --git a/src/Game.h b/src/Game.h index 7d6d91cde..b872d0d85 100644 --- a/src/Game.h +++ b/src/Game.h @@ -24,7 +24,7 @@ CC_VAR extern struct _GameData { } Game; extern struct RayTracer Game_SelectedPos; -extern cc_bool Game_UseCPEBlocks; +extern cc_bool Game_UseCPEBlocks, Game_Running; extern cc_string Game_Username; extern cc_string Game_Mppass; @@ -124,10 +124,12 @@ cc_bool Game_ValidateBitmap(const cc_string* file, struct Bitmap* bmp); /* NOTE: Game_ValidateBitmap should nearly always be used instead of this */ cc_bool Game_ValidateBitmapPow2(const cc_string* file, struct Bitmap* bmp); -/* Initialises and loads state, and creates the main window */ -void Game_Setup(const cc_string* title); -/* Runs the main game loop until the window is closed. */ +/* Initialises and loads state, and creates the main game window */ +void Game_Setup(void); +/* Runs the main game loop until the game loop is finished. */ +/* (e.g. by the user pressing Quit Game, or closing the game window) */ void Game_Run(void); +void Game_Free(void); /* Whether the game should be allowed to automatically close */ cc_bool Game_ShouldClose(void); diff --git a/src/Launcher.c b/src/Launcher.c index de7e0551b..454405db5 100644 --- a/src/Launcher.c +++ b/src/Launcher.c @@ -311,7 +311,6 @@ void Launcher_Finish(void) { cc_result res = Updater_Start(&action); if (res) Logger_SysWarn(res, action); } - Window_Destroy(); } diff --git a/src/Platform_Web.c b/src/Platform_Web.c index dfa4a933b..7bd9509cf 100644 --- a/src/Platform_Web.c +++ b/src/Platform_Web.c @@ -353,9 +353,8 @@ cc_bool Process_OpenSupported = true; void Process_Exit(cc_result code) { /* 'Window' (i.e. the web canvas) isn't implicitly closed when process is exited */ - if (code) Window_RequestClose(); - /* game normally calls exit with code = 0 due to async IndexedDB loading */ - if (code) exit(code); + Window_Free(); + exit(code); } extern int interop_OpenTab(const char* url); @@ -439,11 +438,20 @@ static char** _argv; /* webclient does some asynchronous initialisation first, then kickstarts the game after that */ static void web_main(void) { SetupProgram(_argc, _argv); - cc_result res = RunProgram(_argc, _argv); - if (!res) return; - Window_Free(); - Process_Exit(res); + switch (ProcessProgramArgs(_argc, _argv)) + { + case ARG_RESULT_RUN_LAUNCHER: + String_AppendConst(&Game_Username, DEFAULT_USERNAME); + /* fallthrough */ + case ARG_RESULT_RUN_GAME: + Game_Setup(); + Game_Run(); + return; + + default: + Process_Exit(1); + } } @@ -451,7 +459,7 @@ extern void interop_FS_Init(void); extern void interop_DirectorySetWorking(const char* path); extern void interop_AsyncDownloadTexturePack(const char* path); -int main(int argc, char** argv) { +EMSCRIPTEN_KEEPALIVE int main(int argc, char** argv) { _argc = argc; _argv = argv; /* Game loads resources asynchronously, then actually starts itself */ diff --git a/src/main_impl.h b/src/main_impl.h index 99dd479d4..5a4e2cfda 100644 --- a/src/main_impl.h +++ b/src/main_impl.h @@ -76,22 +76,18 @@ void DirectUrl_ExtractAddress(const cc_string* addr, cc_string* ip, cc_string* p *------------------------------------------------------Game setup/run-----------------------------------------------------* *#########################################################################################################################*/ static void RunGame(void) { - cc_string title; char titleBuffer[STRING_SIZE]; - String_InitArray(title, titleBuffer); - - String_Format2(&title, "%c (%s)", GAME_APP_TITLE, &Game_Username); - Game_Setup(&title); + Game_Setup(); Game_Run(); + Game_Free(); + Window_Destroy(); } static void RunLauncher(void) { -#ifdef CC_BUILD_WEB - String_AppendConst(&Game_Username, DEFAULT_USERNAME); - RunGame(); -#else +#ifndef CC_BUILD_WEB Launcher_Setup(); Launcher_Run(); Launcher_Finish(); + Window_Destroy(); #endif } @@ -160,8 +156,12 @@ static int ParseMPArgs(const cc_string* user, const cc_string* mppass, const cc_ return true; } -static int RunProgram(int argc, char** argv) { - cc_string args[GAME_MAX_CMDARGS]; +#define ARG_RESULT_RUN_LAUNCHER 1 +#define ARG_RESULT_RUN_GAME 2 +#define ARG_RESULT_INVALID_ARGS 3 + +static int ProcessProgramArgs(int argc, char** argv) { +cc_string args[GAME_MAX_CMDARGS]; int argsCount = Platform_GetCommandLineArgs(argc, argv, args); struct ResumeInfo r; cc_string host; @@ -173,52 +173,81 @@ static int RunProgram(int argc, char** argv) { //argsCount = String_UNSAFE_Split(&rawArgs, ' ', args, 4); #endif - if (argsCount == 0) { - RunLauncher(); + if (argsCount == 0) + return ARG_RESULT_RUN_LAUNCHER; + #ifndef CC_BUILD_WEB /* :[hash] - auto join server with the given hash */ - } else if (argsCount == 1 && args[0].buffer[0] == ':') { + if (argsCount == 1 && args[0].buffer[0] == ':') { args[0] = String_UNSAFE_SubstringAt(&args[0], 1); String_Copy(&Launcher_AutoHash, &args[0]); - RunLauncher(); + return ARG_RESULT_RUN_LAUNCHER; + } + /* --resume - try to resume to last server */ - } else if (argsCount == 1 && String_CaselessEqualsConst(&args[0], DEFAULT_RESUME_ARG)) { + if (argsCount == 1 && String_CaselessEqualsConst(&args[0], DEFAULT_RESUME_ARG)) { if (!Resume_Parse(&r, true)) { WarnInvalidArg("No server to resume to", &args[0]); - return 1; + return ARG_RESULT_INVALID_ARGS; } - if (!ParseMPArgs(&r.user, &r.mppass, &r.ip, &r.port)) return 1; - RunGame(); + if (!ParseMPArgs(&r.user, &r.mppass, &r.ip, &r.port)) + return ARG_RESULT_INVALID_ARGS; + return ARG_RESULT_RUN_GAME; + } + /* --singleplayer' - run singleplayer with default user */ - } else if (argsCount == 1 && String_CaselessEqualsConst(&args[0], DEFAULT_SINGLEPLAYER_ARG)) { + if (argsCount == 1 && String_CaselessEqualsConst(&args[0], DEFAULT_SINGLEPLAYER_ARG)) { Options_Get(LOPT_USERNAME, &Game_Username, DEFAULT_USERNAME); - RunGame(); + return ARG_RESULT_RUN_GAME; + } + /* [file path] - run singleplayer with auto loaded map */ - } else if (argsCount == 1 && IsOpenableFile(&args[0])) { + if (argsCount == 1 && IsOpenableFile(&args[0])) { Options_Get(LOPT_USERNAME, &Game_Username, DEFAULT_USERNAME); String_Copy(&SP_AutoloadMap, &args[0]); /* TODO: don't copy args? */ - RunGame(); + return ARG_RESULT_RUN_GAME; + } #endif + /* mc://[addr]:[port]/[user]/[mppass] - run multiplayer using direct URL form arguments */ - } else if (argsCount == 1 && DirectUrl_Claims(&args[0], &host, &r.user, &r.mppass)) { + if (argsCount == 1 && DirectUrl_Claims(&args[0], &host, &r.user, &r.mppass)) { DirectUrl_ExtractAddress(&host, &r.ip, &r.port); - if (!ParseMPArgs(&r.user, &r.mppass, &r.ip, &r.port)) return 1; - RunGame(); - /* [user] - run multiplayer using explicit username */ - } else if (argsCount == 1) { - String_Copy(&Game_Username, &args[0]); - RunGame(); - /* 2 to 3 arguments - unsupported at present */ - } else if (argsCount < 4) { - WarnMissingArgs(argsCount, args); - return 1; - /* [user] [mppass] [address] [port] - run multiplayer using explicit arguments */ - } else { - if (!ParseMPArgs(&args[0], &args[1], &args[2], &args[3])) return 1; - RunGame(); + if (!ParseMPArgs(&r.user, &r.mppass, &r.ip, &r.port)) + return ARG_RESULT_INVALID_ARGS; + return ARG_RESULT_RUN_GAME; + } + + /* [user] - run multiplayer using explicit username */ + if (argsCount == 1) { + String_Copy(&Game_Username, &args[0]); + return ARG_RESULT_RUN_GAME; + } + + /* 2 to 3 arguments - unsupported at present */ + if (argsCount < 4) { + WarnMissingArgs(argsCount, args); + return ARG_RESULT_INVALID_ARGS; + } + + /* [user] [mppass] [address] [port] - run multiplayer using explicit arguments */ + if (!ParseMPArgs(&args[0], &args[1], &args[2], &args[3])) + return ARG_RESULT_INVALID_ARGS; + return ARG_RESULT_RUN_GAME; +} + +static int RunProgram(int argc, char** argv) { + switch (ProcessProgramArgs(argc, argv)) + { + case ARG_RESULT_RUN_LAUNCHER: + RunLauncher(); + return 0; + case ARG_RESULT_RUN_GAME: + RunGame(); + return 0; + default: + return 1; } - return 0; } diff --git a/src/psvita/Window_PSVita.c b/src/psvita/Window_PSVita.c index d725edfb5..6cc8e773d 100644 --- a/src/psvita/Window_PSVita.c +++ b/src/psvita/Window_PSVita.c @@ -209,7 +209,7 @@ static void ProcessCircleInput(int port, int axis, int x, int y, float delta) { } static void ProcessPadInput(float delta) { - int port = Gamepad_Connect(0x503, PadBind_Defaults); + int port = Gamepad_Connect(0x503, vita_padbinds); SceCtrlData pad; // sceCtrlReadBufferPositive is blocking (seems to block until vblank), and don't want that