]> git.localhorst.tv Git - blank.git/blob - src/app/runtime.cpp
fix some inline TODOs
[blank.git] / src / app / runtime.cpp
1 #include "Application.hpp"
2 #include "Environment.hpp"
3 #include "Runtime.hpp"
4 #include "WorldState.hpp"
5
6 #include "init.hpp"
7 #include "../io/filesystem.hpp"
8 #include "../io/WorldSave.hpp"
9
10 #include <cctype>
11 #include <cstdlib>
12 #include <fstream>
13 #include <iostream>
14 #include <SDL.h>
15
16 using namespace std;
17
18
19 namespace {
20
21 string default_asset_path() {
22         char *base = SDL_GetBasePath();
23         string assets(base);
24         assets += "assets/";
25         SDL_free(base);
26         return assets;
27 }
28
29 string default_save_path() {
30 #ifndef NDEBUG
31         char *base = SDL_GetBasePath();
32         string save(base);
33         save += "saves/";
34         SDL_free(base);
35         return save;
36 #else
37         char *pref = SDL_GetPrefPath("localhorst", "blank");
38         string save(pref);
39         SDL_free(pref);
40         return save;
41 #endif
42 }
43
44 }
45
46 namespace blank {
47
48 Environment::Environment(Window &win, const string &asset_path)
49 : audio()
50 , viewport()
51 , window(win)
52 , assets(asset_path)
53 , counter() {
54         viewport.Clear();
55         window.Flip();
56         keymap.LoadDefault();
57 }
58
59
60 Runtime::Runtime() noexcept
61 : name("blank")
62 , mode(NORMAL)
63 , n(0)
64 , t(0)
65 , config() {
66
67 }
68
69
70 void Runtime::ReadArgs(int argc, const char *const *argv) {
71         if (argc <= 0) return;
72         name = argv[0];
73
74         bool options = true;
75         bool error = false;
76
77         for (int i = 1; i < argc; ++i) {
78                 const char *arg = argv[i];
79                 if (!arg || arg[0] == '\0') {
80                         cerr << "warning: found empty argument at position " << i << endl;
81                         continue;
82                 }
83                 if (options && arg[0] == '-') {
84                         if (arg[1] == '\0') {
85                                 cerr << "warning: incomplete option list at position " << i << endl;
86                         } else if (arg[1] == '-') {
87                                 if (arg[2] == '\0') {
88                                         // stopper
89                                         options = false;
90                                 } else {
91                                         const char *param = arg + 2;
92                                         // long option
93                                         if (strcmp(param, "no-vsync") == 0) {
94                                                 config.vsync = false;
95                                         } else if (strcmp(param, "no-keyboard") == 0) {
96                                                 config.interface.keyboard_disabled = true;
97                                         } else if (strcmp(param, "no-mouse") == 0) {
98                                                 config.interface.mouse_disabled = true;
99                                         } else if (strcmp(param, "no-hud") == 0) {
100                                                 config.interface.visual_disabled = true;
101                                         } else if (strcmp(param, "no-audio") == 0) {
102                                                 config.interface.audio_disabled = true;
103                                         } else if (strcmp(param, "asset-path") == 0) {
104                                                 ++i;
105                                                 if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
106                                                         cerr << "missing argument to --asset-path" << endl;
107                                                         error = true;
108                                                 } else {
109                                                         config.asset_path = argv[i];
110                                                 }
111                                         } else if (strcmp(param, "save-path") == 0) {
112                                                 ++i;
113                                                 if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
114                                                         cerr << "missing argument to --save-path" << endl;
115                                                         error = true;
116                                                 } else {
117                                                         config.save_path = argv[i];
118                                                 }
119                                         } else if (strcmp(param, "world-name") == 0) {
120                                                 ++i;
121                                                 if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
122                                                         cerr << "missing argument to --world-name" << endl;
123                                                         error = true;
124                                                 } else {
125                                                         config.world_name = argv[i];
126                                                 }
127                                         } else {
128                                                 cerr << "unknown option " << arg << endl;
129                                                 error = true;
130                                         }
131                                 }
132                         } else {
133                                 // short options
134                                 for (int j = 1; arg[j] != '\0'; ++j) {
135                                         switch (arg[j]) {
136                                                 case 'd':
137                                                         config.doublebuf = false;
138                                                         break;
139                                                 case 'm':
140                                                         ++i;
141                                                         if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
142                                                                 cerr << "missing argument to -m" << endl;
143                                                                 error = true;
144                                                         } else {
145                                                                 config.multisampling = strtoul(argv[i], nullptr, 10);
146                                                         }
147                                                         break;
148                                                 case 'n':
149                                                         ++i;
150                                                         if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
151                                                                 cerr << "missing argument to -n" << endl;
152                                                                 error = true;
153                                                         } else {
154                                                                 n = strtoul(argv[i], nullptr, 10);
155                                                         }
156                                                         break;
157                                                 case 's':
158                                                         ++i;
159                                                         if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
160                                                                 cerr << "missing argument to -s" << endl;
161                                                                 error = true;
162                                                         } else {
163                                                                 config.world.gen.seed = strtoul(argv[i], nullptr, 10);
164                                                         }
165                                                         break;
166                                                 case 't':
167                                                         ++i;
168                                                         if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
169                                                                 cerr << "missing argument to -t" << endl;
170                                                                 error = true;
171                                                         } else {
172                                                                 t = strtoul(argv[i], nullptr, 10);
173                                                         }
174                                                         break;
175                                                 case '-':
176                                                         // stopper
177                                                         options = false;
178                                                         break;
179                                                 default:
180                                                         cerr << "unknown option " << arg[j] << endl;
181                                                         error = true;
182                                                         break;
183                                         }
184                                 }
185                         }
186                 } else {
187                         cerr << "unable to interpret argument "
188                                 << i << " (" << arg << ")" << endl;
189                         error = true;
190                 }
191         }
192
193         if (error) {
194                 mode = ERROR;
195                 return;
196         }
197
198         if (config.asset_path.empty()) {
199                 config.asset_path = default_asset_path();
200         } else if (
201                 config.asset_path[config.asset_path.size() - 1] != '/' &&
202                 config.asset_path[config.asset_path.size() - 1] != '\\'
203         ) {
204                 config.asset_path += '/';
205         }
206         if (config.save_path.empty()) {
207                 config.save_path = default_save_path();
208         } else if (
209                 config.save_path[config.save_path.size() - 1] != '/' &&
210                 config.save_path[config.save_path.size() - 1] != '\\'
211         ) {
212                 config.save_path += '/';
213         }
214
215         if (n > 0) {
216                 if (t > 0) {
217                         mode = FIXED_FRAME_LIMIT;
218                 } else {
219                         mode = FRAME_LIMIT;
220                 }
221         } else if (t > 0) {
222                 mode = TIME_LIMIT;
223         } else {
224                 mode = NORMAL;
225         }
226 }
227
228 int Runtime::Execute() {
229         if (mode == ERROR) {
230                 return 1;
231         }
232
233         Init init(config.doublebuf, config.multisampling);
234
235         Environment env(init.window, config.asset_path);
236         env.viewport.VSync(config.vsync);
237
238         std::string keys_path = config.save_path + "keys.conf";
239         if (!is_file(keys_path)) {
240                 std::ofstream file(keys_path);
241                 env.keymap.Save(file);
242         } else {
243                 std::ifstream file(keys_path);
244                 env.keymap.Load(file);
245         }
246
247
248         WorldSave save(config.save_path + config.world_name + '/');
249         if (save.Exists()) {
250                 save.Read(config.world);
251         } else {
252                 save.Write(config.world);
253         }
254
255         Application app(env);
256
257         WorldState world_state(env, config.interface, config.world, save);
258         app.PushState(&world_state);
259
260         switch (mode) {
261                 default:
262                 case NORMAL:
263                         app.Run();
264                         break;
265                 case FRAME_LIMIT:
266                         app.RunN(n);
267                         break;
268                 case TIME_LIMIT:
269                         app.RunT(t);
270                         break;
271                 case FIXED_FRAME_LIMIT:
272                         app.RunS(n, t);
273                         break;
274         }
275
276         return 0;
277 }
278
279 }