#include "Application.hpp"
#include "Environment.hpp"
-#include "PreloadState.hpp"
#include "Runtime.hpp"
+#include "ServerState.hpp"
#include "WorldState.hpp"
#include "init.hpp"
+#include "../client/MasterState.hpp"
+#include "../io/filesystem.hpp"
+#include "../io/WorldSave.hpp"
#include <cctype>
#include <cstdlib>
+#include <fstream>
#include <iostream>
#include <SDL.h>
namespace {
-string get_asset_path() {
+string default_asset_path() {
char *base = SDL_GetBasePath();
string assets(base);
assets += "assets/";
return assets;
}
+string default_save_path() {
+#ifndef NDEBUG
+ char *base = SDL_GetBasePath();
+ string save(base);
+ save += "saves/";
+ SDL_free(base);
+ return save;
+#else
+ char *pref = SDL_GetPrefPath("localhorst", "blank");
+ string save(pref);
+ SDL_free(pref);
+ return save;
+#endif
+}
+
}
namespace blank {
-Environment::Environment(Window &win)
-: audio()
+HeadlessEnvironment::HeadlessEnvironment(const Config &config)
+: config(config)
+, loader(config.asset_path)
+, counter()
+, state() {
+
+}
+
+string HeadlessEnvironment::Config::GetWorldPath(const string &world_name) const {
+ return save_path + "worlds/" + world_name + '/';
+}
+
+string HeadlessEnvironment::Config::GetWorldPath(const string &world_name, const string &host_name) const {
+ return save_path + "cache/" + host_name + '/' + world_name + '/';
+}
+
+Environment::Environment(Window &win, const Config &config)
+: HeadlessEnvironment(config)
+, assets(loader)
+, audio()
, viewport()
, window(win)
-, assets(get_asset_path())
-, counter() {
+, keymap() {
+ viewport.Clear();
+ window.Flip();
+ keymap.LoadDefault();
+ string keys_path = config.save_path + "keys.conf";
+ if (!is_file(keys_path)) {
+ std::ofstream file(keys_path);
+ keymap.Save(file);
+ } else {
+ std::ifstream file(keys_path);
+ keymap.Load(file);
+ }
}
Runtime::Runtime() noexcept
: name("blank")
, mode(NORMAL)
+, target(STANDALONE)
, n(0)
, t(0)
, config() {
// stopper
options = false;
} else {
+ const char *param = arg + 2;
// long option
- if (strcmp(arg + 2, "no-vsync") == 0) {
+ if (strcmp(param, "no-vsync") == 0) {
config.vsync = false;
- } else if (strcmp(arg + 2, "no-keyboard") == 0) {
+ } else if (strcmp(param, "no-keyboard") == 0) {
config.interface.keyboard_disabled = true;
- } else if (strcmp(arg + 2, "no-mouse") == 0) {
+ } else if (strcmp(param, "no-mouse") == 0) {
config.interface.mouse_disabled = true;
- } else if (strcmp(arg + 2, "no-hud") == 0) {
+ } else if (strcmp(param, "no-hud") == 0) {
config.interface.visual_disabled = true;
- } else if (strcmp(arg + 2, "no-audio") == 0) {
+ } else if (strcmp(param, "no-audio") == 0) {
config.interface.audio_disabled = true;
+ } else if (strcmp(param, "standalone") == 0) {
+ target = STANDALONE;
+ } else if (strcmp(param, "server") == 0) {
+ target = SERVER;
+ } else if (strcmp(param, "client") == 0) {
+ target = CLIENT;
+ } else if (strcmp(param, "asset-path") == 0) {
+ ++i;
+ if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
+ cerr << "missing argument to --asset-path" << endl;
+ error = true;
+ } else {
+ config.env.asset_path = argv[i];
+ }
+ } else if (strcmp(param, "host") == 0) {
+ ++i;
+ if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
+ cerr << "missing argument to --host" << endl;
+ error = true;
+ } else {
+ config.client.host = argv[i];
+ }
+ } else if (strcmp(param, "port") == 0) {
+ ++i;
+ if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
+ cerr << "missing argument to --port" << endl;
+ error = true;
+ } else {
+ config.server.port = strtoul(argv[i], nullptr, 10);
+ config.client.port = config.server.port;
+ }
+ } else if (strcmp(param, "player-name") == 0) {
+ ++i;
+ if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
+ cerr << "missing argument to --player-name" << endl;
+ error = true;
+ } else {
+ config.interface.player_name = argv[i];
+ }
+ } else if (strcmp(param, "save-path") == 0) {
+ ++i;
+ if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
+ cerr << "missing argument to --save-path" << endl;
+ error = true;
+ } else {
+ config.env.save_path = argv[i];
+ }
+ } else if (strcmp(param, "world-name") == 0) {
+ ++i;
+ if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
+ cerr << "missing argument to --world-name" << endl;
+ error = true;
+ } else {
+ config.world.name = argv[i];
+ }
} else {
cerr << "unknown option " << arg << endl;
error = true;
cerr << "missing argument to -s" << endl;
error = true;
} else {
- config.world.gen.solid_seed = strtoul(argv[i], nullptr, 10);
- config.world.gen.type_seed = config.world.gen.solid_seed;
+ config.gen.seed = strtoul(argv[i], nullptr, 10);
}
break;
case 't':
return;
}
+ if (config.env.asset_path.empty()) {
+ config.env.asset_path = default_asset_path();
+ } else if (
+ config.env.asset_path[config.env.asset_path.size() - 1] != '/' &&
+ config.env.asset_path[config.env.asset_path.size() - 1] != '\\'
+ ) {
+ config.env.asset_path += '/';
+ }
+ if (config.env.save_path.empty()) {
+ config.env.save_path = default_save_path();
+ } else if (
+ config.env.save_path[config.env.save_path.size() - 1] != '/' &&
+ config.env.save_path[config.env.save_path.size() - 1] != '\\'
+ ) {
+ config.env.save_path += '/';
+ }
+
if (n > 0) {
if (t > 0) {
mode = FIXED_FRAME_LIMIT;
return 1;
}
+ InitHeadless init_headless;
+
+ switch (target) {
+ default:
+ case STANDALONE:
+ RunStandalone();
+ break;
+ case SERVER:
+ RunServer();
+ break;
+ case CLIENT:
+ RunClient();
+ break;
+ }
+
+ return 0;
+}
+
+void Runtime::RunStandalone() {
Init init(config.doublebuf, config.multisampling);
- Environment env(init.window);
+ Environment env(init.window, config.env);
env.viewport.VSync(config.vsync);
- Application app(env);
+ WorldSave save(config.env.GetWorldPath(config.world.name));
+ if (save.Exists()) {
+ save.Read(config.world);
+ save.Read(config.gen);
+ } else {
+ save.Write(config.world);
+ save.Write(config.gen);
+ }
- WorldState world_state(env, config.interface, config.world);
+ Application app(env);
+ WorldState world_state(env, config.gen, config.interface, config.world, save);
app.PushState(&world_state);
+ Run(app);
+}
- PreloadState preloader(env, world_state.GetWorld().Loader());
- app.PushState(&preloader);
+void Runtime::RunServer() {
+ HeadlessEnvironment env(config.env);
+ WorldSave save(config.env.GetWorldPath(config.world.name));
+ if (save.Exists()) {
+ save.Read(config.world);
+ save.Read(config.gen);
+ } else {
+ save.Write(config.world);
+ save.Write(config.gen);
+ }
+
+ HeadlessApplication app(env);
+ ServerState server_state(env, config.gen, config.world, save, config.server);
+ app.PushState(&server_state);
+ Run(app);
+}
+
+void Runtime::RunClient() {
+ Init init(config.doublebuf, config.multisampling);
+
+ Environment env(init.window, config.env);
+ env.viewport.VSync(config.vsync);
+
+ Application app(env);
+ client::MasterState client_state(env, config.world, config.interface, config.client);
+ app.PushState(&client_state);
+ Run(app);
+}
+
+void Runtime::Run(HeadlessApplication &app) {
switch (mode) {
default:
case NORMAL:
app.RunS(n, t);
break;
}
-
- return 0;
}
}