]> git.localhorst.tv Git - blank.git/blob - src/app/runtime.cpp
save and load world seed
[blank.git] / src / app / runtime.cpp
1 #include "Application.hpp"
2 #include "Environment.hpp"
3 #include "PreloadState.hpp"
4 #include "Runtime.hpp"
5 #include "WorldState.hpp"
6
7 #include "init.hpp"
8 #include "../world/WorldSave.hpp"
9
10 #include <cctype>
11 #include <cstdlib>
12 #include <iostream>
13 #include <SDL.h>
14
15 using namespace std;
16
17
18 namespace {
19
20 string default_asset_path() {
21         char *base = SDL_GetBasePath();
22         string assets(base);
23         assets += "assets/";
24         SDL_free(base);
25         return assets;
26 }
27
28 string default_save_path() {
29 #ifndef NDEBUG
30         char *base = SDL_GetBasePath();
31         string save(base);
32         save += "saves/";
33         SDL_free(base);
34         return save;
35 #else
36         char *pref = SDL_GetPrefPath("localhorst", "blank");
37         string save(pref);
38         SDL_free(pref);
39         return save;
40 #endif
41 }
42
43 }
44
45 namespace blank {
46
47 Environment::Environment(Window &win, const string &asset_path)
48 : audio()
49 , viewport()
50 , window(win)
51 , assets(asset_path)
52 , counter() {
53
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.Create(config.world);
240         }
241
242         Application app(env);
243
244         WorldState world_state(env, config.interface, config.world);
245         app.PushState(&world_state);
246
247         PreloadState preloader(env, world_state.GetWorld().Loader());
248         app.PushState(&preloader);
249
250         switch (mode) {
251                 default:
252                 case NORMAL:
253                         app.Run();
254                         break;
255                 case FRAME_LIMIT:
256                         app.RunN(n);
257                         break;
258                 case TIME_LIMIT:
259                         app.RunT(t);
260                         break;
261                 case FIXED_FRAME_LIMIT:
262                         app.RunS(n, t);
263                         break;
264         }
265
266         return 0;
267 }
268
269 }