device_options.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /*
  2. * Copyright (c) 2012-2026 Daniele Bartolini et al.
  3. * SPDX-License-Identifier: MIT
  4. */
  5. #include "config.h"
  6. #include "core/command_line.h"
  7. #include "core/filesystem/path.h"
  8. #include "core/option.inl"
  9. #include "core/strings/dynamic_string.inl"
  10. #include "device/device_options.h"
  11. #include <errno.h>
  12. #include <stdio.h> // printf
  13. #include <stdlib.h> // EXIT_SUCCESS, strto* etc.
  14. namespace crown
  15. {
  16. static void help(const char *msg = NULL)
  17. {
  18. printf(
  19. "The Flexible Game Engine\n"
  20. "Copyright (c) 2012-2026 Daniele Bartolini et al.\n"
  21. "SPDX-License-Identifier: MIT\n"
  22. "\n"
  23. "Usage:\n"
  24. " crown [options]\n"
  25. "\n"
  26. "Options:\n"
  27. " -- End of the runtime's options.\n"
  28. " -h --help Display this help.\n"
  29. " -v --version Display engine version.\n"
  30. " --source-dir <path> Specify the <path> of the project's source data.\n"
  31. " --data-dir <path> Run with the data located at <path>.\n"
  32. " --bundle-dir <path> Run with the bundles located at <path>.\n"
  33. " --map-source-dir <name> <path> Mount <path>/<name> at <source-dir>/<name>.\n"
  34. " --boot-dir <prefix> Use <prefix>/boot.config to boot the engine.\n"
  35. " --compile Compile the project's source data.\n"
  36. " --bundle Generate bundles after the data has been compiled.\n"
  37. " --platform <platform> Specify the target <platform> for data compilation.\n"
  38. " android\n"
  39. " html5\n"
  40. " linux\n"
  41. " windows\n"
  42. " --continue Run the engine after the data has been compiled.\n"
  43. " --console-port <port> Set port of the console server.\n"
  44. " --wait-console Wait for a console connection before booting the engine.\n"
  45. " --parent-window <handle> Set the parent window <handle> of the main window.\n"
  46. " --server Run the engine in server mode.\n"
  47. " --pumped Do not advance the renderer unless explicitly requested via console.\n"
  48. " --hidden Make the main window initially invisible.\n"
  49. " --window-rect <x y w h> Sets the main window's position and size.\n"
  50. " --string-id <string> Prints the 32- and 64-bits IDs of <string>.\n"
  51. " --run-unit-tests Run unit tests and quit.\n"
  52. "\n"
  53. "Full documentation at https://docs.crownengine.org/html/v" CROWN_MANUAL_VERSION "/reference/command_line.html\n"
  54. );
  55. if (msg)
  56. printf("Error: %s\n", msg);
  57. }
  58. DeviceOptions::DeviceOptions(Allocator &a, int argc, const char **argv)
  59. : _argc(argc)
  60. , _argv(argv)
  61. , _source_dir(DynamicString(a))
  62. , _map_source_dir_name(NULL)
  63. , _map_source_dir_prefix(DynamicString(a))
  64. , _data_dir(DynamicString(a))
  65. , _bundle_dir(DynamicString(a))
  66. , _boot_dir(NULL)
  67. , _platform(NULL)
  68. , _lua_string(DynamicString(a))
  69. , _wait_console(false)
  70. , _do_compile(false)
  71. , _do_continue(false)
  72. , _do_bundle(false)
  73. , _server(false)
  74. , _pumped(false)
  75. , _hidden(false)
  76. , _parent_window(0)
  77. , _console_port(CROWN_DEFAULT_CONSOLE_PORT)
  78. , _window_x(0)
  79. , _window_y(0)
  80. , _window_width(CROWN_DEFAULT_WINDOW_WIDTH)
  81. , _window_height(CROWN_DEFAULT_WINDOW_HEIGHT)
  82. #if CROWN_PLATFORM_ANDROID
  83. , _asset_manager(NULL)
  84. #endif
  85. {
  86. }
  87. DeviceOptions::~DeviceOptions()
  88. {
  89. }
  90. int DeviceOptions::parse(bool *quit)
  91. {
  92. CommandLine cl(_argc, _argv);
  93. if (cl.has_option("help", 'h')) {
  94. help();
  95. *quit = true;
  96. return EXIT_SUCCESS;
  97. }
  98. if (cl.has_option("version", 'v')) {
  99. printf("Crown " CROWN_VERSION "\n");
  100. *quit = true;
  101. return EXIT_SUCCESS;
  102. }
  103. path::reduce(_source_dir, cl.get_parameter(0, "source-dir"));
  104. path::reduce(_data_dir, cl.get_parameter(0, "data-dir"));
  105. path::reduce(_bundle_dir, cl.get_parameter(0, "bundle-dir"));
  106. _map_source_dir_name = cl.get_parameter(0, "map-source-dir");
  107. if (_map_source_dir_name) {
  108. path::reduce(_map_source_dir_prefix, cl.get_parameter(1, "map-source-dir"));
  109. if (_map_source_dir_prefix.empty()) {
  110. help("Mapped source directory must be specified.");
  111. return EXIT_FAILURE;
  112. }
  113. }
  114. _do_compile = cl.has_option("compile");
  115. _do_bundle = cl.has_option("bundle");
  116. if (_do_compile || _do_bundle) {
  117. _platform = cl.get_parameter(0, "platform");
  118. // Compile for platform the executable is built for.
  119. if (_platform == NULL)
  120. _platform = CROWN_PLATFORM_NAME;
  121. if (_source_dir.empty()) {
  122. help("Source dir must be specified.");
  123. return EXIT_FAILURE;
  124. }
  125. if (_data_dir.empty()) {
  126. _data_dir += _source_dir;
  127. _data_dir += '_';
  128. _data_dir += _platform;
  129. }
  130. if (_do_bundle) {
  131. if (_bundle_dir.empty()) {
  132. _bundle_dir += _source_dir;
  133. _bundle_dir += "_bundle_";
  134. _bundle_dir += _platform;
  135. }
  136. }
  137. }
  138. _server = cl.has_option("server");
  139. if (_server) {
  140. if (_source_dir.empty()) {
  141. help("Source dir must be specified.");
  142. return EXIT_FAILURE;
  143. }
  144. }
  145. _pumped = cl.has_option("pumped");
  146. _hidden = cl.has_option("hidden");
  147. if (!_data_dir.empty()) {
  148. if (!path::is_absolute(_data_dir.c_str())) {
  149. help("Data dir must be absolute.");
  150. return EXIT_FAILURE;
  151. }
  152. }
  153. if (!_source_dir.empty()) {
  154. if (!path::is_absolute(_source_dir.c_str())) {
  155. help("Source dir must be absolute.");
  156. return EXIT_FAILURE;
  157. }
  158. }
  159. if (!_map_source_dir_prefix.empty()) {
  160. if (!path::is_absolute(_map_source_dir_prefix.c_str())) {
  161. help("Mapped source dir must be absolute.");
  162. return EXIT_FAILURE;
  163. }
  164. }
  165. _do_continue = cl.has_option("continue");
  166. if (_do_continue) {
  167. if (strcmp(_platform, CROWN_PLATFORM_NAME) != 0) {
  168. help("Host platform can not run from the compiled data. Consider removing --continue option.");
  169. return EXIT_FAILURE;
  170. }
  171. }
  172. _boot_dir = cl.get_parameter(0, "boot-dir");
  173. if (_boot_dir) {
  174. if (!path::is_relative(_boot_dir)) {
  175. help("Boot dir must be relative.");
  176. return EXIT_FAILURE;
  177. }
  178. }
  179. _wait_console = cl.has_option("wait-console");
  180. const char *parent = cl.get_parameter(0, "parent-window");
  181. if (parent) {
  182. errno = 0;
  183. _parent_window = strtoul(parent, NULL, 10);
  184. if (errno == ERANGE || errno == EINVAL) {
  185. help("Parent window is invalid.");
  186. return EXIT_FAILURE;
  187. }
  188. }
  189. const char *port = cl.get_parameter(0, "console-port");
  190. if (port) {
  191. errno = 0;
  192. _console_port = (u16)strtoul(port, NULL, 10);
  193. if (errno == ERANGE || errno == EINVAL) {
  194. help("Console port is invalid.");
  195. return EXIT_FAILURE;
  196. }
  197. }
  198. const char *ls = cl.get_parameter(0, "lua-string");
  199. if (ls)
  200. _lua_string = ls;
  201. if (cl.has_option("string-id")) {
  202. const char *string_id_utf8 = cl.get_parameter(0, "string-id");
  203. if (string_id_utf8 == NULL) {
  204. help("Usage: string-id <utf8>");
  205. *quit = true;
  206. return EXIT_FAILURE;
  207. } else {
  208. char buf[STRING_ID64_BUF_LEN];
  209. printf("STRING_ID_32(\"%s\", UINT32_C(0x%s))\n"
  210. , string_id_utf8
  211. , StringId32(string_id_utf8).to_string(buf, sizeof(buf))
  212. );
  213. printf("STRING_ID_64(\"%s\", UINT64_C(0x%s))\n"
  214. , string_id_utf8
  215. , StringId64(string_id_utf8).to_string(buf, sizeof(buf))
  216. );
  217. *quit = true;
  218. return EXIT_SUCCESS;
  219. }
  220. }
  221. if (cl.has_option("window-rect")) {
  222. const char *rect[4];
  223. for (u32 ii = 0; ii < countof(rect); ++ii) {
  224. rect[ii] = cl.get_parameter(ii, "window-rect");
  225. if (!rect[ii]) {
  226. printf("window-rect: format must be: <x y w h>\n");
  227. *quit = true;
  228. return EXIT_FAILURE;
  229. }
  230. }
  231. _window_x = (u16)strtoul(rect[0], NULL, 10);
  232. _window_y = (u16)strtoul(rect[1], NULL, 10);
  233. _window_width.set_value((u16)strtoul(rect[2], NULL, 10));
  234. _window_height.set_value((u16)strtoul(rect[3], NULL, 10));
  235. }
  236. return EXIT_SUCCESS;
  237. }
  238. } // namespace crown