1 #include "Application.hpp"
2 #include "ClientState.hpp"
3 #include "Environment.hpp"
5 #include "ServerState.hpp"
6 #include "WorldState.hpp"
9 #include "../io/filesystem.hpp"
10 #include "../io/WorldSave.hpp"
23 string default_asset_path() {
24 char *base = SDL_GetBasePath();
31 string default_save_path() {
33 char *base = SDL_GetBasePath();
39 char *pref = SDL_GetPrefPath("localhorst", "blank");
50 HeadlessEnvironment::HeadlessEnvironment(const string &asset_path)
57 Environment::Environment(Window &win, const string &asset_path)
58 : HeadlessEnvironment(asset_path)
70 Runtime::Runtime() noexcept
81 void Runtime::ReadArgs(int argc, const char *const *argv) {
82 if (argc <= 0) return;
88 for (int i = 1; i < argc; ++i) {
89 const char *arg = argv[i];
90 if (!arg || arg[0] == '\0') {
91 cerr << "warning: found empty argument at position " << i << endl;
94 if (options && arg[0] == '-') {
96 cerr << "warning: incomplete option list at position " << i << endl;
97 } else if (arg[1] == '-') {
102 const char *param = arg + 2;
104 if (strcmp(param, "no-vsync") == 0) {
105 config.vsync = false;
106 } else if (strcmp(param, "no-keyboard") == 0) {
107 config.interface.keyboard_disabled = true;
108 } else if (strcmp(param, "no-mouse") == 0) {
109 config.interface.mouse_disabled = true;
110 } else if (strcmp(param, "no-hud") == 0) {
111 config.interface.visual_disabled = true;
112 } else if (strcmp(param, "no-audio") == 0) {
113 config.interface.audio_disabled = true;
114 } else if (strcmp(param, "standalone") == 0) {
116 } else if (strcmp(param, "server") == 0) {
118 } else if (strcmp(param, "client") == 0) {
120 } else if (strcmp(param, "asset-path") == 0) {
122 if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
123 cerr << "missing argument to --asset-path" << endl;
126 config.asset_path = argv[i];
128 } else if (strcmp(param, "host") == 0) {
130 if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
131 cerr << "missing argument to --host" << endl;
134 config.client.host = argv[i];
136 } else if (strcmp(param, "port") == 0) {
138 if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
139 cerr << "missing argument to --port" << endl;
142 config.server.port = strtoul(argv[i], nullptr, 10);
143 config.client.port = config.server.port;
145 } else if (strcmp(param, "save-path") == 0) {
147 if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
148 cerr << "missing argument to --save-path" << endl;
151 config.save_path = argv[i];
153 } else if (strcmp(param, "world-name") == 0) {
155 if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
156 cerr << "missing argument to --world-name" << endl;
159 config.world_name = argv[i];
162 cerr << "unknown option " << arg << endl;
168 for (int j = 1; arg[j] != '\0'; ++j) {
171 config.doublebuf = false;
175 if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
176 cerr << "missing argument to -m" << endl;
179 config.multisampling = strtoul(argv[i], nullptr, 10);
184 if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
185 cerr << "missing argument to -n" << endl;
188 n = strtoul(argv[i], nullptr, 10);
193 if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
194 cerr << "missing argument to -s" << endl;
197 config.world.gen.seed = strtoul(argv[i], nullptr, 10);
202 if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
203 cerr << "missing argument to -t" << endl;
206 t = strtoul(argv[i], nullptr, 10);
214 cerr << "unknown option " << arg[j] << endl;
221 cerr << "unable to interpret argument "
222 << i << " (" << arg << ")" << endl;
232 if (config.asset_path.empty()) {
233 config.asset_path = default_asset_path();
235 config.asset_path[config.asset_path.size() - 1] != '/' &&
236 config.asset_path[config.asset_path.size() - 1] != '\\'
238 config.asset_path += '/';
240 if (config.save_path.empty()) {
241 config.save_path = default_save_path();
243 config.save_path[config.save_path.size() - 1] != '/' &&
244 config.save_path[config.save_path.size() - 1] != '\\'
246 config.save_path += '/';
251 mode = FIXED_FRAME_LIMIT;
262 int Runtime::Execute() {
267 InitHeadless init_headless;
285 void Runtime::RunStandalone() {
286 Init init(config.doublebuf, config.multisampling);
288 Environment env(init.window, config.asset_path);
289 env.viewport.VSync(config.vsync);
291 WorldSave save(config.save_path + config.world_name + '/');
293 save.Read(config.world);
295 save.Write(config.world);
298 std::string keys_path = config.save_path + "keys.conf";
299 if (!is_file(keys_path)) {
300 std::ofstream file(keys_path);
301 env.keymap.Save(file);
303 std::ifstream file(keys_path);
304 env.keymap.Load(file);
307 Application app(env);
308 WorldState world_state(env, config.interface, config.world, save);
309 app.PushState(&world_state);
313 void Runtime::RunServer() {
314 HeadlessEnvironment env(config.asset_path);
316 WorldSave save(config.save_path + config.world_name + '/');
318 save.Read(config.world);
320 save.Write(config.world);
323 HeadlessApplication app(env);
324 ServerState server_state(env, config.world, save, config.server);
325 app.PushState(&server_state);
329 void Runtime::RunClient() {
330 Init init(config.doublebuf, config.multisampling);
332 Environment env(init.window, config.asset_path);
333 env.viewport.VSync(config.vsync);
335 WorldSave save(config.save_path + config.world_name + '/');
337 save.Read(config.world);
339 save.Write(config.world);
342 std::string keys_path = config.save_path + "keys.conf";
343 if (!is_file(keys_path)) {
344 std::ofstream file(keys_path);
345 env.keymap.Save(file);
347 std::ifstream file(keys_path);
348 env.keymap.Load(file);
351 Application app(env);
352 ClientState client_state(env, config.world, save, config.client);
353 app.PushState(&client_state);
357 void Runtime::Run(HeadlessApplication &app) {
369 case FIXED_FRAME_LIMIT: