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