diff --git a/src/EntityComponents.c b/src/EntityComponents.c index ee5a15b23..d064c0563 100644 --- a/src/EntityComponents.c +++ b/src/EntityComponents.c @@ -191,7 +191,7 @@ static float HacksComp_ParseFlagFloat(const char* flagRaw, struct HacksComp* hac String raw = HacksComp_UNSAFE_FlagValue(flagRaw, hacks); float value; - if (!raw.length || Game_ClassicMode) return 1.0f; + if (!raw.length || Game_ClassicMode) return 1.0f; if (!Convert_ParseFloat(&raw, &value)) return 1.0f; return value; } @@ -200,7 +200,7 @@ static int HacksComp_ParseFlagInt(const char* flagRaw, struct HacksComp* hacks) String raw = HacksComp_UNSAFE_FlagValue(flagRaw, hacks); int value; - if (!raw.length || Game_ClassicMode) return 1; + if (!raw.length || Game_ClassicMode) return 1; if (!Convert_ParseInt(&raw, &value)) return 1; return value; } diff --git a/src/Event.h b/src/Event.h index 425e45ced..3f9f1aced 100644 --- a/src/Event.h +++ b/src/Event.h @@ -165,12 +165,13 @@ CC_VAR extern struct _ChatEventsList { } ChatEvents; CC_VAR extern struct _WindowEventsList { - struct Event_Void Redraw; /* Window contents invalidated, should be redrawn */ - struct Event_Void Resized; /* Window is resized */ - struct Event_Void Closing; /* Window is about to close (should free resources/save state/etc here) */ - struct Event_Void Destroyed; /* Window has been destroyed (cannot call Window_XYZ functions anymore) */ - struct Event_Void FocusChanged; /* Focus of the window changed */ - struct Event_Void StateChanged; /* WindowState of the window changed */ + struct Event_Void Redraw; /* Window contents invalidated, should be redrawn */ + struct Event_Void Resized; /* Window is resized */ + struct Event_Void Closing; /* Window is about to close (should free resources/save state/etc here) */ + struct Event_Void Destroyed; /* Window has been destroyed (cannot call Window_XYZ functions anymore) */ + struct Event_Void FocusChanged; /* Focus of the window changed */ + struct Event_Void StateChanged; /* WindowState of the window changed */ + struct Event_Void Created; /* Window has been created, Window_Handle is valid now. */ } WindowEvents; CC_VAR extern struct _KeyEventsList { diff --git a/src/Graphics.c b/src/Graphics.c index 2652ce8d3..4a4de7113 100644 --- a/src/Graphics.c +++ b/src/Graphics.c @@ -393,6 +393,7 @@ bool Gfx_TryRestoreContext(void) { res = IDirect3DDevice9_Reset(device, &args); if (res == D3DERR_DEVICELOST) return false; + if (res) Logger_Abort2(res, "Error recreating D3D9 context"); Gfx_RecreateContext(); return true; } @@ -573,7 +574,7 @@ static bool gfx_depthTesting, gfx_depthWriting; void Gfx_SetFaceCulling(bool enabled) { D3DCULL mode = enabled ? D3DCULL_CW : D3DCULL_NONE; - D3D9_SetRenderState(D3DRS_CULLMODE, mode, "D3D9_SetFaceCulling"); + IDirect3DDevice9_SetRenderState(device, D3DRS_CULLMODE, mode); } void Gfx_SetFog(bool enabled) { diff --git a/src/Launcher.c b/src/Launcher.c index 0d5f3dde3..7d0ba5f3d 100644 --- a/src/Launcher.c +++ b/src/Launcher.c @@ -214,6 +214,38 @@ static void Launcher_Free(void) { Window_FreeFramebuffer(&Launcher_Framebuffer); } +#ifdef CC_BUILD_ANDROID +static bool winCreated; +static void OnWindowCreated(void* obj) { winCreated = true; } +int Program_Run(int argc, char** argv); + +static void SwitchToGame() { + JNIEnv* env; + JavaGetCurrentEnv(env); + + /* Reset components */ + Platform_LogConst("undoing components"); + Drawer2D_Component.Free(); + //Http_Component.Free(); + + /* Force window to be destroyed and re-created */ + /* (see comments in setupForGame for why this has to be done) */ + JavaCallVoid(env, "setupForGame", "()V", NULL); + Event_RegisterVoid(&WindowEvents.Created, NULL, OnWindowCreated); + Platform_LogConst("Entering wait for window loop.."); + + /* Loop until window gets created async */ + while (Window_Exists && !winCreated) { + Window_ProcessEvents(); + Thread_Sleep(10); + } + + Platform_LogConst("OK I'm starting the game.."); + Event_UnregisterVoid(&WindowEvents.Created, NULL, OnWindowCreated); + if (winCreated) Program_Run(0, NULL); +} +#endif + void Launcher_Run(void) { static const String title = String_FromConst(GAME_APP_TITLE); Window_Create(640, 400); @@ -259,6 +291,10 @@ void Launcher_Run(void) { Launcher_Free(); if (Launcher_ShouldUpdate) Launcher_ApplyUpdate(); + +#ifdef CC_BUILD_ANDROID + if (Launcher_ShouldExit) SwitchToGame(); +#endif if (Window_Exists) Window_Close(); } @@ -555,7 +591,11 @@ bool Launcher_StartGame(const String* user, const String* mppass, const String* res = Process_Start(&path, &args); if (res) { Logger_Warn(res, "starting game"); return false; } +#ifdef CC_BUILD_ANDROID + Launcher_ShouldExit = true; +#else Launcher_ShouldExit = Options_GetBool(OPT_AUTO_CLOSE_LAUNCHER, false); +#endif return true; } diff --git a/src/Platform.c b/src/Platform.c index 1e90f068d..0b663bdf3 100644 --- a/src/Platform.c +++ b/src/Platform.c @@ -1620,8 +1620,11 @@ ReturnCode Process_StartOpen(const String* args) { ReturnCode Process_StartShell(void) { return ERR_NOT_SUPPORTED; } ReturnCode Process_GetExePath(String* path) { return ERR_NOT_SUPPORTED; } #elif defined CC_BUILD_ANDROID +static char gameArgsBuffer[512]; +static String gameArgs = String_FromArray(gameArgsBuffer); + ReturnCode Process_Start(const String* path, const String* args) { - JavaCall_String_Void("startGame", args); + String_Copy(&gameArgs, args); return 0; /* TODO: Is there a clean way of handling an error */ } void Process_Exit(ReturnCode code) { exit(code); } @@ -1688,6 +1691,8 @@ ReturnCode Process_StartOpen(const String* args) { return Process_Start(&path, args); } ReturnCode Process_StartShell(void) { + /* There isn't a standardised way to "run command in user's preferred terminal" */ + /* xterm is pretty much universally available though */ static const String path = String_FromConst("xterm"); static const String args = String_FromConst("-e ./update.sh"); return Process_Start(&path, &args); @@ -2101,37 +2106,9 @@ jobject App_Instance; JavaVM* VM_Ptr; void Platform_Init(void) { Platform_InitCommon(); } -static String Platform_GetCmdLineArg(int i) { - String arg, copy; - JNIEnv* env; - jvalue args[1]; - jobject obj; - - JavaGetCurrentEnv(env); - args[0].i = i; - obj = JavaCallObject(env, "getCmdLineArg", "(I)Ljava/lang/String;", args); - if (!obj) return String_Empty; - - Platform_LogConst("ARGg.."); - arg = JavaGetString(env, obj); - - copy.buffer = Mem_Alloc(arg.length, 1, "cmdline arg"); - copy.length = arg.length; - copy.capacity = arg.length; - Mem_Copy(arg.buffer, copy.buffer, arg.length); - - (*env)->ReleaseStringUTFChars(env, obj, arg.buffer); - (*env)->DeleteLocalRef(env, obj); - return copy; -} - int Platform_GetCommandLineArgs(int argc, STRING_REF char** argv, String* args) { - int i; - for (i = 0; i < GAME_MAX_CMDARGS; i++) { - args[i] = Platform_GetCmdLineArg(i); - if (!args[i].buffer) break; - } - return i; + if (!gameArgs.length) return 0; + return String_UNSAFE_Split(&gameArgs, ' ', args, GAME_MAX_CMDARGS); } void Platform_SetDefaultCurrentDirectory(void) { diff --git a/src/Program.c b/src/Program.c index df0fa4580..a4908acb8 100644 --- a/src/Program.c +++ b/src/Program.c @@ -94,38 +94,16 @@ CC_NOINLINE static void ExitMissingArgs(int argsCount, const String* args) { Process_Exit(1); } -/* NOTE: This is used when compiling with MingW without linking to startup files. */ -/* The final code produced for "main" is our "main" combined with crt's main. (mingw-w64-crt/crt/gccmain.c) */ -/* This immediately crashes the game on startup. */ -/* Using main_real instead and setting main_real as the entrypoint fixes the crash. */ -#ifdef CC_NOMAIN -int main_real(int argc, char** argv) { +#ifdef CC_BUILD_ANDROID +int Program_Run(int argc, char** argv) { #else -int main(int argc, char** argv) { +static int Program_Run(int argc, char** argv) { #endif - static char ipBuffer[STRING_SIZE]; String args[GAME_MAX_CMDARGS]; - int argsCount; uint8_t ip[4]; uint16_t port; - Logger_Hook(); - Platform_Init(); - Window_Init(); - Platform_SetDefaultCurrentDirectory(); -#ifdef CC_TEST_VORBIS - main_imdct(); -#endif - Platform_LogConst("Starting " GAME_APP_NAME " .."); - String_InitArray(Server.IP, ipBuffer); - - Utils_EnsureDirectory("maps"); - Utils_EnsureDirectory("texpacks"); - Utils_EnsureDirectory("texturecache"); - Utils_EnsureDirectory("plugins"); - Options_Load(); - - argsCount = Platform_GetCommandLineArgs(argc, argv, args); + int argsCount = Platform_GetCommandLineArgs(argc, argv, args); /* NOTE: Make sure to comment this out before pushing a commit */ /* String rawArgs = String_FromConst("UnknownShadow200 fffff 127.0.0.1 25565"); */ /* String rawArgs = String_FromConst("UnknownShadow200"); */ @@ -174,6 +152,35 @@ int main(int argc, char** argv) { return 0; } +/* NOTE: This is used when compiling with MingW without linking to startup files. */ +/* The final code produced for "main" is our "main" combined with crt's main. (mingw-w64-crt/crt/gccmain.c) */ +/* This immediately crashes the game on startup. */ +/* Using main_real instead and setting main_real as the entrypoint fixes the crash. */ +#ifdef CC_NOMAIN +int main_real(int argc, char** argv) { +#else +int main(int argc, char** argv) { +#endif + static char ipBuffer[STRING_SIZE]; + Logger_Hook(); + Platform_Init(); + Window_Init(); + Platform_SetDefaultCurrentDirectory(); +#ifdef CC_TEST_VORBIS + main_imdct(); +#endif + Platform_LogConst("Starting " GAME_APP_NAME " .."); + String_InitArray(Server.IP, ipBuffer); + + Utils_EnsureDirectory("maps"); + Utils_EnsureDirectory("texpacks"); + Utils_EnsureDirectory("texturecache"); + Utils_EnsureDirectory("plugins"); + Options_Load(); + + return Program_Run(argc, argv); +} + /* ClassiCube is just a native library on android, */ /* unlike other platforms where it is the executable. */ /* As such, we have to hook into the java-side activity, */ @@ -182,7 +189,7 @@ int main(int argc, char** argv) { #ifdef CC_BUILD_ANDROID static void android_main(void) { Platform_LogConst("Main loop started!"); - main(1, NULL); + main(0, NULL); } static void JNICALL java_runGameAsync(JNIEnv* env, jobject instance) { diff --git a/src/Window.c b/src/Window.c index fed37197c..e1a1a4513 100644 --- a/src/Window.c +++ b/src/Window.c @@ -2872,6 +2872,7 @@ static void JNICALL java_processSurfaceCreated(JNIEnv* env, jobject o, jobject s win_handle = ANativeWindow_fromSurface(env, surface); Window_RefreshBounds(); /* TODO: Restore context */ + Event_RaiseVoid(&WindowEvents.Created); } static void JNICALL java_processSurfaceDestroyed(JNIEnv* env, jobject o) {