1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
#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
|