Refactor main loop somewhat

This commit is contained in:
UnknownShadow200 2025-07-09 07:53:59 +10:00
parent 23aee471e5
commit 01c2e1c3fd
7 changed files with 107 additions and 68 deletions

View File

@ -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)

View File

@ -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();
}

View File

@ -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);

View File

@ -311,7 +311,6 @@ void Launcher_Finish(void) {
cc_result res = Updater_Start(&action);
if (res) Logger_SysWarn(res, action);
}
Window_Destroy();
}

View File

@ -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 */

View File

@ -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 ARG_RESULT_INVALID_ARGS;
return ARG_RESULT_RUN_GAME;
}
if (!ParseMPArgs(&r.user, &r.mppass, &r.ip, &r.port)) return 1;
RunGame();
/* --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;
}

View File

@ -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