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