#include "Logger.h" #include "String.h" #include "Platform.h" #include "Window.h" #include "Constants.h" #include "Game.h" #include "Funcs.h" #include "Utils.h" #include "Launcher.h" #include "Server.h" #include "Options.h" static void RunGame(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); /* No custom resolution has been set */ if (width == 0 || height == 0) { width = 854; height = 480; if (DisplayInfo.Width < 854) width = 640; } String_InitArray(title, titleBuffer); String_Format2(&title, "%c (%s)", GAME_APP_TITLE, &Game_Username); Game_Run(width, height, &title); } /* Shows a warning dialog due to an invalid command line argument */ CC_NOINLINE static void WarnInvalidArg(const char* name, const cc_string* arg) { cc_string tmp; char tmpBuffer[256]; String_InitArray(tmp, tmpBuffer); String_Format2(&tmp, "%c '%s'", name, arg); Logger_DialogTitle = "Failed to start"; Logger_DialogWarn(&tmp); } /* Shows a warning dialog due to insufficient command line arguments */ CC_NOINLINE static void WarnMissingArgs(int argsCount, const cc_string* args) { cc_string tmp; char tmpBuffer[256]; int i; String_InitArray(tmp, tmpBuffer); String_AppendConst(&tmp, "Missing IP and/or port - "); for (i = 0; i < argsCount; i++) { String_AppendString(&tmp, &args[i]); String_Append(&tmp, ' '); } Logger_DialogTitle = "Failed to start"; Logger_DialogWarn(&tmp); } static void SetupProgram(int argc, char** argv) { static char ipBuffer[STRING_SIZE]; cc_result res; Logger_Hook(); Window_PreInit(); Platform_Init(); res = Platform_SetDefaultCurrentDirectory(argc, argv); Options_Load(); Window_Init(); if (res) Logger_SysWarn(res, "setting current directory"); Platform_LogConst("Starting " GAME_APP_NAME " .."); String_InitArray(Server.Address, ipBuffer); } #define SP_HasDir(path) (String_IndexOf(&path, '/') >= 0 || String_IndexOf(&path, '\\') >= 0) static int RunProgram(int argc, char** argv) { cc_string args[GAME_MAX_CMDARGS]; cc_uint16 port; int argsCount = Platform_GetCommandLineArgs(argc, argv, args); #ifdef _MSC_VER /* NOTE: Make sure to comment this out before pushing a commit */ //cc_string rawArgs = String_FromConst("UnknownShadow200 fffff 127.0.0.1 25565"); //cc_string rawArgs = String_FromConst("UnknownShadow200"); //argsCount = String_UNSAFE_Split(&rawArgs, ' ', args, 4); #endif if (argsCount == 0) { #ifdef CC_BUILD_WEB String_AppendConst(&Game_Username, DEFAULT_USERNAME); RunGame(); #else Launcher_Run(); /* :hash to auto join server with the given hash */ } else if (argsCount == 1 && args[0].buffer[0] == ':') { args[0] = String_UNSAFE_SubstringAt(&args[0], 1); String_Copy(&Launcher_AutoHash, &args[0]); Launcher_Run(); /* File path to auto load a map in singleplayer */ } else if (argsCount == 1 && SP_HasDir(args[0]) && File_Exists(&args[0])) { Options_Get(LOPT_USERNAME, &Game_Username, DEFAULT_USERNAME); String_Copy(&SP_AutoloadMap, &args[0]); /* TODO: don't copy args? */ RunGame(); #endif } else if (argsCount == 1) { String_Copy(&Game_Username, &args[0]); RunGame(); } else if (argsCount < 4) { WarnMissingArgs(argsCount, args); return 1; } else { String_Copy(&Game_Username, &args[0]); String_Copy(&Game_Mppass, &args[1]); String_Copy(&Server.Address,&args[2]); if (!Convert_ParseUInt16(&args[3], &port)) { WarnInvalidArg("Invalid port", &args[3]); return 1; } Server.Port = port; RunGame(); } return 0; } #if defined CC_BUILD_IOS /* ClassiCube is sort of and sort of not the executable */ /* on iOS - UIKit is responsible for kickstarting the game. */ /* (this is handled in interop_ios.m as the code is Objective C) */ int ios_main(int argc, char** argv) { SetupProgram(argc, argv); for (;;) { RunProgram(argc, argv); } return 0; } #elif defined CC_BUILD_ANDROID /* ClassiCube is just a native library on android, */ /* unlike other platforms where it is the executable. */ /* (activity java class is responsible for kickstarting the game, see Platform_Android.c for the code that actually calls this) */ void android_main(void) { Platform_LogConst("Main loop started!"); SetupProgram(0, NULL); for (;;) { RunProgram(0, NULL); } } #elif defined CC_BUILD_CONSOLE int main(int argc, char** argv) { SetupProgram(argc, argv); while (Window_Main.Exists) { RunProgram(argc, argv); } Window_Free(); return 0; } #else /* NOTE: main_real is used for when compiling with MinGW without linking to startup files. */ /* Normally, the final code produced for "main" is our "main" combined with crt's main */ /* (mingw-w64-crt/crt/gccmain.c) - alas this immediately crashes the game on startup. */ /* Using main_real instead and setting main_real as the entrypoint fixes the crash. */ #if defined CC_NOMAIN int main_real(int argc, char** argv) { #elif defined CC_BUILD_WEB /* webclient does some asynchronous initialisation first, then kickstarts the game after that */ int web_main(int argc, char** argv) { #else int main(int argc, char** argv) { #endif cc_result res; SetupProgram(argc, argv); /* If single process mode, then the loop is launcher -> game -> launcher etc */ do { res = RunProgram(argc, argv); } while (Platform_SingleProcess && Window_Main.Exists); Window_Free(); Process_Exit(res); return res; } #endif