The Battle for Wesnoth  1.19.25+dev
wesnoth.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2025
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "addon/manager.hpp"
17 #include "build_info.hpp"
18 #include "commandline_argv.hpp"
19 #include "commandline_options.hpp" // for commandline_options, etc
20 #include "config.hpp" // for config, config::error, etc
21 #include "cursor.hpp" // for set, CURSOR_TYPE::NORMAL, etc
22 #include "events.hpp"
23 #include "filesystem.hpp" // for filesystem::file_exists, filesystem::io_exception, etc
24 #include "floating_label.hpp"
25 #include "font/error.hpp" // for error
26 #include "font/font_config.hpp" // for load_font_config, etc
27 #include "formula/formula.hpp" // for formula_error
28 #include "game_config.hpp" // for path, debug, debug_lua, etc
29 #include "game_config_manager.hpp" // for game_config_manager, etc
30 #include "game_end_exceptions.hpp"
31 #include "game_launcher.hpp" // for game_launcher, etc
32 #include "gettext.hpp"
33 #include "gui/core/event/handler.hpp" // for tmanager
35 #include "gui/dialogs/message.hpp" // for show_error_message
37 #include "gui/dialogs/title_screen.hpp" // for title_screen, etc
38 #include "gui/gui.hpp" // for init
39 #include "log.hpp" // for LOG_STREAM, general, logger, etc
44 #include "sdl/exception.hpp" // for exception
45 #include "serialization/binary_or_text.hpp" // for config_writer
46 #include "serialization/chrono.hpp"
47 #include "serialization/parser.hpp" // for read
48 #include "serialization/preprocessor.hpp" // for preproc_define, etc
49 #include "serialization/schema_validator.hpp" // for strict_validation_enabled and schema_validator
50 #include "sound.hpp" // for commit_music_changes, etc
51 #include "utils/optimer.hpp"
52 #include "formula/string_utils.hpp" // VGETTEXT
53 #include <functional>
54 #include "game_version.hpp" // for version_info
55 #include "video.hpp" // for video::error and video::quit
56 #include "wesconfig.h" // for PACKAGE
57 #include "wml_exception.hpp" // for wml_exception
58 
60 #ifdef _WIN32
61 #include "log_windows.hpp"
62 
63 #include <float.h>
64 #endif // _WIN32
65 
66 #ifndef _MSC_VER
67 #include <fenv.h>
68 #endif // _MSC_VER
69 
70 #include <SDL3/SDL.h> // for SDL_Init, SDL_INIT_TIMER
71 #include <SDL3/SDL_main.h> // Provides platform-specific entrypoint, if applicable
72 
73 #include <boost/program_options/errors.hpp> // for error
74 #include <boost/algorithm/string/predicate.hpp> // for checking cmdline options
75 #include "utils/optional_fwd.hpp"
76 
77 #include <cerrno> // for ENOMEM
78 #include <clocale> // for setlocale, LC_ALL, etc
79 #include <cstdio> // for remove, fprintf, stderr
80 #include <cstdlib> // for srand, exit
81 #include <exception> // for exception
82 #include <vector>
83 #include <iostream>
84 
85 //#define NO_CATCH_AT_GAME_END
86 
87 #ifdef _WIN32
88 
89 #ifdef INADDR_ANY
90 #undef INADDR_ANY
91 #endif
92 
93 #ifdef INADDR_BROADCAST
94 #undef INADDR_BROADCAST
95 #endif
96 
97 #ifdef INADDR_NONE
98 #undef INADDR_NONE
99 #endif
100 
101 #include <windows.h>
102 
103 #endif // _WIN32
104 
105 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
106 #include "gui/widgets/debug.hpp"
107 #endif
108 
109 // this file acts as a launcher for various gui2 dialogs
110 // so this reduces some boilerplate.
111 using namespace gui2::dialogs;
112 
113 static lg::log_domain log_config("config");
114 #define LOG_CONFIG LOG_STREAM(info, log_config)
115 
116 #define LOG_GENERAL LOG_STREAM(info, lg::general())
117 
118 static lg::log_domain log_preprocessor("preprocessor");
119 #define LOG_PREPROC LOG_STREAM(info, log_preprocessor)
120 
121 // this is needed to allow identical functionality with clean refactoring
122 // play_game only returns on an error, all returns within play_game can
123 // be replaced with this
124 static void safe_exit(int res)
125 {
126  LOG_GENERAL << "exiting with code " << res;
127  exit(res);
128 }
129 
130 static void handle_preprocess_string(const commandline_options& cmdline_opts)
131 {
132  preproc_map defines_map;
133 
134  if(cmdline_opts.preprocess_input_macros) {
135  std::string file = *cmdline_opts.preprocess_input_macros;
136  if(!filesystem::file_exists(file)) {
137  PLAIN_LOG << "please specify an existing file. File " << file << " doesn't exist.";
138  return;
139  }
140 
141  PLAIN_LOG << "Reading cached defines from: " << file;
142 
143  config cfg;
144 
145  try {
147  } catch(const config::error& e) {
148  PLAIN_LOG << "Caught a config error while parsing file '" << file << "':\n" << e.message;
149  }
150 
151  int read = 0;
152 
153  for(const auto [_, cfg] : cfg.all_children_view()) {
154  preproc_define::insert(defines_map, cfg);
155  ++read;
156  }
157 
158  PLAIN_LOG << "Read " << read << " defines.";
159  }
160 
161  if(cmdline_opts.preprocess_defines) {
162  // add the specified defines
163  for(const std::string& define : *cmdline_opts.preprocess_defines) {
164  if(define.empty()) {
165  PLAIN_LOG << "empty define supplied";
166  continue;
167  }
168 
169  LOG_PREPROC << "adding define: " << define;
170  defines_map.try_emplace(define, define);
171  }
172  }
173 
174  // add the WESNOTH_VERSION define
175  defines_map.try_emplace("WESNOTH_VERSION", game_config::wesnoth_version.str());
176 
177  // preprocess resource
178  PLAIN_LOG << "added " << defines_map.size() << " defines.";
179  PLAIN_LOG << "preprocessing specified string: " << *cmdline_opts.preprocess_source_string;
180 
181  const utils::ms_optimer timer(
182  [](const auto& timer) { PLAIN_LOG << "preprocessing finished. Took " << timer << " ticks."; });
183 
184  const auto input_stream = preprocess_string(*cmdline_opts.preprocess_source_string, "wesnoth", defines_map);
185  io::write(std::cout, io::read(*input_stream), 0, true);
186 }
187 
188 static void handle_preprocess_command(const commandline_options& cmdline_opts)
189 {
190  preproc_map input_macros;
191 
192  if(cmdline_opts.preprocess_input_macros) {
193  std::string file = *cmdline_opts.preprocess_input_macros;
194  if(filesystem::file_exists(file) == false) {
195  PLAIN_LOG << "please specify an existing file. File " << file << " doesn't exist.";
196  return;
197  }
198 
199  PLAIN_LOG << "Reading cached defines from: " << file;
200 
201  config cfg;
202 
203  try {
205  } catch(const config::error& e) {
206  PLAIN_LOG << "Caught a config error while parsing file '" << file << "':\n" << e.message;
207  }
208 
209  int read = 0;
210 
211  for(const auto [_, cfg] : cfg.all_children_view()) {
212  preproc_define::insert(input_macros, cfg);
213  ++read;
214  }
215 
216  PLAIN_LOG << "Read " << read << " defines.";
217  }
218 
219  const std::string resourceToProcess(*cmdline_opts.preprocess_path);
220  const std::string targetDir(*cmdline_opts.preprocess_target);
221 
222  const utils::ms_optimer timer(
223  [](const auto& timer) { PLAIN_LOG << "preprocessing finished. Took " << timer << " ticks."; });
224 
225  // If the users add the SKIP_CORE define we won't preprocess data/core
226  bool skipCore = false;
227  bool skipTerrainGFX = false;
228 
229  // The 'core_defines_map' is the one got from data/core macros
230  preproc_map defines_map(input_macros);
231 
232  if(cmdline_opts.preprocess_defines) {
233  // add the specified defines
234  for(const std::string& define : *cmdline_opts.preprocess_defines) {
235  if(define.empty()) {
236  PLAIN_LOG << "empty define supplied";
237  continue;
238  }
239 
240  LOG_PREPROC << "adding define: " << define;
241  defines_map.try_emplace(define, define);
242 
243  if(define == "SKIP_CORE") {
244  PLAIN_LOG << "'SKIP_CORE' defined.";
245  skipCore = true;
246  } else if(define == "NO_TERRAIN_GFX") {
247  PLAIN_LOG << "'NO_TERRAIN_GFX' defined.";
248  skipTerrainGFX = true;
249  }
250  }
251  }
252 
253  // add the WESNOTH_VERSION define
254  defines_map.try_emplace("WESNOTH_VERSION", game_config::wesnoth_version.str());
255 
256  PLAIN_LOG << "added " << defines_map.size() << " defines.";
257 
258  // preprocess core macros first if we don't skip the core
259  if(skipCore == false) {
260  PLAIN_LOG << "preprocessing common macros from 'data/core' ...";
261 
262  // process each folder explicitly to gain speed
263  preprocess_resource(game_config::path + "/data/core/macros", &defines_map);
264 
265  if(skipTerrainGFX == false) {
266  preprocess_resource(game_config::path + "/data/core/terrain-graphics", &defines_map);
267  }
268 
269  PLAIN_LOG << "acquired " << (defines_map.size() - input_macros.size()) << " 'data/core' defines.";
270  } else {
271  PLAIN_LOG << "skipped 'data/core'";
272  }
273 
274  // preprocess resource
275  PLAIN_LOG << "preprocessing specified resource: " << resourceToProcess << " ...";
276 
277  preprocess_resource(resourceToProcess, &defines_map, true, true, targetDir);
278  PLAIN_LOG << "acquired " << (defines_map.size() - input_macros.size()) << " total defines.";
279 
280  if(cmdline_opts.preprocess_output_macros) {
281  std::string outputFileName = "_MACROS_.cfg";
282  if(!cmdline_opts.preprocess_output_macros->empty()) {
283  outputFileName = *cmdline_opts.preprocess_output_macros;
284  }
285 
286  std::string outputPath = targetDir + "/" + outputFileName;
287 
288  PLAIN_LOG << "writing '" << outputPath << "' with " << defines_map.size() << " defines.";
289 
291  if(!out->fail()) {
292  config_writer writer(*out, false);
293 
294  for(auto& define_pair : defines_map) {
295  define_pair.second.write(writer, define_pair.first);
296  }
297  } else {
298  PLAIN_LOG << "couldn't open the file.";
299  }
300  }
301 }
302 
303 static int handle_validate_command(const std::string& file, abstract_validator& validator, const std::vector<std::string>& defines)
304 {
305  preproc_map defines_map;
306  defines_map.try_emplace("WESNOTH_VERSION", game_config::wesnoth_version.str());
307  defines_map.try_emplace("SCHEMA_VALIDATION");
308 
309  for(const std::string& define : defines) {
310  if(define.empty()) {
311  PLAIN_LOG << "empty define supplied";
312  continue;
313  }
314 
315  LOG_PREPROC << "adding define: " << define;
316  defines_map.try_emplace(define, define);
317  }
318 
319  PLAIN_LOG << "Validating " << file << " against schema " << validator.name_;
321  io::read(*preprocess_file(file, defines_map), &validator);
322  if(lg::broke_strict()) {
323  std::cout << "validation failed\n";
324  } else {
325  std::cout << "validation succeeded\n";
326  }
327  return lg::broke_strict();
328 }
329 
330 /** Process commandline-arguments */
331 static int process_command_args(commandline_options& cmdline_opts)
332 {
333  // Options that don't change behavior based on any others should be checked alphabetically below.
334 
335  if(cmdline_opts.no_log_sanitize) {
336  lg::set_log_sanitize(false);
337  }
338 
339  if(cmdline_opts.no_simd) {
340  game_config::no_simd = true;
341  }
342 
343  if(cmdline_opts.usercache_dir) {
345  }
346 
347  if(cmdline_opts.userdata_dir) {
349  }
350 
351  // earliest possible point to ensure the userdata directory is known
353  filesystem::set_user_data_dir(std::string());
354  }
355 
356  // userdata is initialized, so initialize logging to file if enabled
357  // If true, output will be redirected to file, else output be written to console.
358  // On Windows, if Wesnoth was not started from a console, one will be allocated.
359  if(cmdline_opts.log_to_file
360  || (!cmdline_opts.no_log_to_file
361  && !getenv("WESNOTH_NO_LOG_FILE")
362  // command line options that imply not redirecting output to a log file
363  && !cmdline_opts.print_data_path
364  && !cmdline_opts.print_userdata_path
365  && !cmdline_opts.print_usercache_path
366  && !cmdline_opts.report
367  && !cmdline_opts.do_diff
368  && !cmdline_opts.do_patch
369  && !cmdline_opts.preprocess
370  && !cmdline_opts.render_image
371  && !cmdline_opts.screenshot
372  && !cmdline_opts.nogui
373  && !cmdline_opts.headless_unit_test
374  && !cmdline_opts.validate_schema
375  && !cmdline_opts.validate_wml
376  )
377  )
378  {
380  }
381 #ifdef _WIN32
382  // This forces a Windows console to be attached to the process even
383  // if Wesnoth is an IMAGE_SUBSYSTEM_WINDOWS_GUI executable because it
384  // turns Wesnoth into a CLI application. (unless --wnoconsole is given)
385  else if(!cmdline_opts.no_console) {
387  }
388 #endif
389 
390  // Options that output info unaffected by other options and return.
391  if(cmdline_opts.help) {
392  std::cout << cmdline_opts;
393  return 0;
394  }
395 
396  if(cmdline_opts.logdomains) {
397  std::cout << lg::list_log_domains(*cmdline_opts.logdomains);
398  return 0;
399  }
400 
401  if(cmdline_opts.version) {
402  std::cout << "Battle for Wesnoth" << " " << game_config::wesnoth_version.str() << "\n\n";
403  std::cout << "Library versions:\n" << game_config::library_versions_report() << '\n';
404  std::cout << "Optional features:\n" << game_config::optional_features_report();
405  return 0;
406  }
407 
408  if(cmdline_opts.simple_version) {
409  std::cout << game_config::wesnoth_version.str() << "\n";
410  return 0;
411  }
412 
413  if(cmdline_opts.log) {
414  for(const auto& log_pair : *cmdline_opts.log) {
415  const std::string log_domain = log_pair.second;
416  const lg::severity severity = log_pair.first;
417  if(!lg::set_log_domain_severity(log_domain, severity)) {
418  PLAIN_LOG << "unknown log domain: " << log_domain;
419  return 2;
420  }
421  }
422  }
423 
424  if(!cmdline_opts.nobanner) {
425  const auto now = std::chrono::system_clock::now();
426  PLAIN_LOG << "Battle for Wesnoth v" << game_config::revision << " " << game_config::build_arch();
427  PLAIN_LOG << "Started on " << chrono::format_local_timestamp(now, "%a %b %d %T %Y") << '\n';
428  }
429 
430  if(cmdline_opts.print_usercache_path) {
431  std::cout << filesystem::get_cache_dir() << std::endl;
432  return 0;
433  }
434 
435  if(cmdline_opts.print_userdata_path) {
436  std::cout << filesystem::get_user_data_dir() << std::endl;
437  return 0;
438  }
439 
440  if(cmdline_opts.data_dir) {
441  game_config::path = filesystem::normalize_path(*cmdline_opts.data_dir, true, true);
442  if(!cmdline_opts.nobanner) {
443  PLAIN_LOG << "Overriding data directory with '" << game_config::path << "'";
444  }
445  } else {
446 #if defined(__ANDROID__) && !defined(WESNOTH_PATH)
447  if(const char* ext_path = SDL_GetAndroidExternalStoragePath()) {
448  game_config::path = ext_path + std::string("/gamedata");
449  PLAIN_LOG << "Determined game data directory: " << game_config::path;
450  } else {
451  PLAIN_LOG << "Cannot find game data directory, specify one with --data-dir. SDL_GetAndroidExternalStoragePath() failed: " << SDL_GetError();
452  }
453 #endif
454  // if a pre-defined path does not exist this will empty it
456  if(game_config::path.empty()) {
457  if(std::string exe_dir = filesystem::get_exe_dir(); !exe_dir.empty()) {
458  if(std::string auto_dir = filesystem::autodetect_game_data_dir(std::move(exe_dir)); !auto_dir.empty()) {
459  if(!cmdline_opts.nobanner) {
460  PLAIN_LOG << "Automatically found a possible data directory at: " << auto_dir;
461  }
462  game_config::path = filesystem::normalize_path(auto_dir, true, true);
463  }
464  } else {
465  PLAIN_LOG << "Cannot find game data directory. Specify one with --data-dir";
466  return 1;
467  }
468  }
469  }
470 
472  PLAIN_LOG << "Could not find game data directory '" << game_config::path << "'";
473  return 1;
474  }
475 
476  if(cmdline_opts.print_data_path) {
477  std::cout << game_config::path << std::endl;
478  return 0;
479  }
480 
481  if(cmdline_opts.debug_lua) {
482  game_config::debug_lua = true;
483  }
484 
485  if(cmdline_opts.allow_insecure) {
487  }
488 
489  if(cmdline_opts.addon_server_info) {
491  }
492 
493  if(cmdline_opts.strict_lua) {
495  }
496 
497  if(cmdline_opts.log_precise_timestamps) {
499  }
500 
501  if(cmdline_opts.rng_seed) {
502  srand(*cmdline_opts.rng_seed);
503  }
504 
505  if(cmdline_opts.render_image) {
506  SDL_setenv_unsafe("SDL_VIDEODRIVER", "dummy", 1);
507  }
508 
509  if(cmdline_opts.strict_validation) {
511  }
512 
513  if(cmdline_opts.report) {
514  std::cout << "\n========= BUILD INFORMATION =========\n\n" << game_config::full_build_report();
515  return 0;
516  }
517 
518  if(cmdline_opts.validate_schema) {
520  validator.set_create_exceptions(false); // Don't crash if there's an error, just go ahead anyway
521  return handle_validate_command(*cmdline_opts.validate_schema, validator, {});
522  }
523 
524  if(cmdline_opts.do_diff) {
525  std::ifstream in_left(cmdline_opts.diff_left);
526  std::ifstream in_right(cmdline_opts.diff_right);
527  config left = io::read(in_left);
528  config right = io::read(in_right);
529  std::ostream* os = &std::cout;
530  if(cmdline_opts.output_file) {
531  os = new std::ofstream(*cmdline_opts.output_file);
532  }
534  out.write(right.get_diff(left));
535  if(os != &std::cout) delete os;
536  return 0;
537  }
538 
539  if(cmdline_opts.do_patch) {
540  std::ifstream in_base(cmdline_opts.diff_left);
541  std::ifstream in_diff(cmdline_opts.diff_right);
542  config base = io::read(in_base);
543  config diff = io::read(in_diff);
544  base.apply_diff(diff);
545  std::ostream* os = &std::cout;
546  if(cmdline_opts.output_file) {
547  os = new std::ofstream(*cmdline_opts.output_file);
548  }
550  out.write(base);
551  if(os != &std::cout) delete os;
552  return 0;
553  }
554 
555  if(cmdline_opts.generate_spritesheet) {
556  PLAIN_LOG << "sheet path " << *cmdline_opts.generate_spritesheet;
558  return 0;
559  }
560 
561  // Options changing their behavior dependent on some others should be checked below.
562 
563  if(cmdline_opts.preprocess) {
564  handle_preprocess_command(cmdline_opts);
565  return 0;
566  }
567 
568  if(cmdline_opts.preprocess_source_string.has_value()) {
569  handle_preprocess_string(cmdline_opts);
570  return 0;
571  }
572 
573  if(cmdline_opts.validate_wml) {
574  std::string schema_path;
575  if(cmdline_opts.validate_with) {
576  schema_path = *cmdline_opts.validate_with;
577  if(!filesystem::file_exists(schema_path)) {
578  if(auto check = filesystem::get_wml_location(schema_path)) {
579  schema_path = check.value();
580  } else {
581  PLAIN_LOG << "Could not find schema file: " << schema_path;
582  }
583  } else {
584  schema_path = filesystem::normalize_path(schema_path);
585  }
586  } else {
587  schema_path = filesystem::get_wml_location("schema/game_config.cfg").value();
588  }
590  validator.set_create_exceptions(false); // Don't crash if there's an error, just go ahead anyway
591  return handle_validate_command(*cmdline_opts.validate_wml, validator,
592  cmdline_opts.preprocess_defines.value_or<decltype(cmdline_opts.preprocess_defines)::value_type>({}));
593  }
594 
595  if(cmdline_opts.preprocess_defines || cmdline_opts.preprocess_input_macros || cmdline_opts.preprocess_path) {
596  // It would be good if this was supported for running tests too, possibly for other uses.
597  // For the moment show an error message instead of leaving the user wondering why it doesn't work.
598  PLAIN_LOG << "That --preprocess-* option is only supported when using --preprocess or --validate.";
599  return 2;
600  }
601 
602  // Not the most intuitive solution, but I wanted to leave current semantics for now
603  return -1;
604 }
605 
606 /**
607  * I would prefer to setup locale first so that early error
608  * messages can get localized, but we need the game_launcher
609  * initialized to have filesystem::get_intl_dir() to work. Note: setlocale()
610  * does not take GUI language setting into account.
611  */
612 static void init_locale()
613 {
614 #if defined _WIN32 || defined __APPLE__
615  setlocale(LC_ALL, "English");
616 #else
617  std::setlocale(LC_ALL, "C");
618 #endif
619 
620  const std::string& intl_dir = filesystem::get_intl_dir();
621 
622  translation::bind_textdomain(PACKAGE, intl_dir.c_str(), "UTF-8");
623  translation::bind_textdomain(PACKAGE "-lib", intl_dir.c_str(), "UTF-8");
625 }
626 
627 /**
628  * Print an alert and instructions to stderr about early initialization errors.
629  *
630  * This is provided as an aid for users dealing with potential data dir
631  * configuration issues. The first code to read core WML *has* the
632  * responsibility to call this function in the event of a problem, to inform
633  * the user of the most likely possible cause and suggest a course of action
634  * to solve the issue.
635  */
637 {
638  // NOTE: wrap output to 80 columns.
639  PLAIN_LOG << '\n'
640  << "An error at this point during initialization usually indicates that the data\n"
641  << "directory above was not correctly set or detected. Try passing the correct path\n"
642  << "in the command line with the --data-dir switch or as the only argument.";
643 }
644 
645 /**
646  * Handles the lua script command line arguments if present.
647  * This function will only run once.
648  */
650 {
651  static bool first_time = true;
652 
653  if(!first_time) {
654  return;
655  }
656 
657  first_time = false;
658 
659  if(!game->init_lua_script()) {
660  // PLAIN_LOG << "error when loading lua scripts at startup";
661  // PLAIN_LOG << "could not load lua script: " << *cmdline_opts.script_file;
662  }
663 }
664 
665 #ifdef _MSC_VER
666 static void check_fpu()
667 {
668  uint32_t f_control;
669 
670  if(_controlfp_s(&f_control, 0, 0) == 0) {
671  uint32_t unused;
672  uint32_t rounding_mode = f_control & _MCW_RC;
673 
674  if(rounding_mode != _RC_NEAR) {
675  PLAIN_LOG << "Floating point rounding mode is currently '"
676  << ((rounding_mode == _RC_CHOP)
677  ? "chop"
678  : (rounding_mode == _RC_UP)
679  ? "up"
680  : (rounding_mode == _RC_DOWN)
681  ? "down"
682  : (rounding_mode == _RC_NEAR) ? "near" : "unknown")
683  << "' setting to 'near'";
684 
685  if(_controlfp_s(&unused, _RC_NEAR, _MCW_RC)) {
686  PLAIN_LOG << "failed to set floating point rounding type to 'near'";
687  }
688  }
689 
690 #ifndef _M_AMD64
691  uint32_t precision_mode = f_control & _MCW_PC;
692  if(precision_mode != _PC_53) {
693  PLAIN_LOG << "Floating point precision mode is currently '"
694  << ((precision_mode == _PC_53)
695  ? "double"
696  : (precision_mode == _PC_24)
697  ? "single"
698  : (precision_mode == _PC_64) ? "double extended" : "unknown")
699  << "' setting to 'double'";
700 
701  if(_controlfp_s(&unused, _PC_53, _MCW_PC)) {
702  PLAIN_LOG << "failed to set floating point precision type to 'double'";
703  }
704  }
705 #endif
706 
707  } else {
708  PLAIN_LOG << "_controlfp_s failed.";
709  }
710 }
711 #else
712 static void check_fpu()
713 {
714  switch(fegetround()) {
715  case FE_TONEAREST:
716  break;
717  case FE_DOWNWARD:
718  STREAMING_LOG << "Floating point precision mode is currently 'downward'";
719  goto reset_fpu;
720  case FE_TOWARDZERO:
721  STREAMING_LOG << "Floating point precision mode is currently 'toward-zero'";
722  goto reset_fpu;
723  case FE_UPWARD:
724  STREAMING_LOG << "Floating point precision mode is currently 'upward'";
725  goto reset_fpu;
726  default:
727  STREAMING_LOG << "Floating point precision mode is currently 'unknown'";
728  goto reset_fpu;
729  reset_fpu:
730  STREAMING_LOG << " - setting to 'nearest'\n";
731  fesetround(FE_TONEAREST);
732  break;
733  }
734 }
735 #endif
736 
737 /** Gets the appropriate action code for the current iteration of the game loop. */
739 {
740  // If loading a game, skip the titlescreen entirely
741  if(game.has_load_data()) {
743  }
744 
745  title_screen dlg{game};
746 
747  // Allows re-layout on resize.
748  // Since RELOAD_UI is not checked here, it causes
749  // the dialog to be closed and reshown with changes.
750  while(dlg.get_retval() == title_screen::REDRAW_BACKGROUND) {
751  dlg.show();
752  }
753 
754  return dlg.get_retval();
755 }
756 
757 /**
758  * Setups the game environment and enters
759  * the titlescreen or game loops.
760  */
761 static int do_gameloop(commandline_options& cmdline_opts)
762 {
763  srand(std::time(nullptr));
764 
765  const auto game = std::make_unique<game_launcher>(cmdline_opts);
766 
767  init_locale();
768 
769  bool res;
770 
771  // Do initialize fonts before reading the game config, to have game
772  // config error messages displayed. fonts will be re-initialized later
773  // when the language is read from the game config.
774  res = font::load_font_config();
775  if(res == false) {
776  PLAIN_LOG << "could not initialize fonts";
777  // The most common symptom of a bogus data dir path -- warn the user.
779  return 1;
780  }
781 
782  res = game->init_language();
783  if(res == false) {
784  PLAIN_LOG << "could not initialize the language";
785  return 1;
786  }
787 
788  res = game->init_video();
789  if(res == false) {
790  PLAIN_LOG << "could not initialize display";
791  return 1;
792  }
793 
794  check_fpu();
795  const cursor::manager cursor_manager;
797 
798  gui2::init();
799  gui2::switch_theme(prefs::get().gui2_theme());
800  const gui2::event::manager gui_event_manager;
801 
802  // if the log directory is not writable, then this is the error condition so show the error message.
803  // if the log directory is writable, then there's no issue.
804  // if the optional isn't set, then logging to file has been disabled, so there's no issue.
805  if(!lg::log_dir_writable().value_or(true)) {
806  utils::string_map symbols;
807  symbols["logdir"] = filesystem::get_logs_dir();
808  std::string msg = VGETTEXT("Unable to create log files in directory $logdir. This is often caused by incorrect folder permissions, anti-virus software restricting folder access, or using OneDrive to manage your My Documents folder.", symbols);
809  gui2::show_message(_("Logging Failure"), msg, message::ok_button);
810  }
811 
812  game_config_manager& config_manager = game->config_manager();
813 
817  }
818 
819  loading_screen::display([&res, &config_manager, &cmdline_opts]() {
822 
823  if(res == false) {
824  PLAIN_LOG << "could not initialize game config";
825  return;
826  }
827 
829 
830  res = font::load_font_config();
831  if(res == false) {
832  PLAIN_LOG << "could not re-initialize fonts for the current language";
833  return;
834  }
835 
836  if(!game_config::no_addons && !cmdline_opts.noaddons) {
838 
840  }
841  });
842 
843  if(res == false) {
844  return 1;
845  }
846 
847  plugins_manager plugins_man(new application_lua_kernel);
848 
849  const plugins_context::reg_vec callbacks {
850  {"play_multiplayer", std::bind(&game_launcher::play_multiplayer, game.get(), game_launcher::mp_mode::CONNECT)},
851  {"play_local", std::bind(&game_launcher::play_multiplayer, game.get(), game_launcher::mp_mode::LOCAL)},
852  {"play_campaign", std::bind(&game_launcher::play_campaign, game.get())},
853  };
854 
855  const plugins_context::areg_vec accessors {
856  {"command_line", std::bind(&commandline_options::to_config, &cmdline_opts)},
857  };
858 
859  plugins_context plugins("titlescreen", callbacks, accessors);
860 
861  plugins.set_callback("exit", [](const config& cfg) { safe_exit(cfg["code"].to_int(0)); }, false);
862 
863  while(true) {
864  if(!game->has_load_data()) {
865  auto cfg = config_manager.game_config().optional_child("titlescreen_music");
866  if(cfg) {
867  for(const config& i : cfg->child_range("music")) {
869  }
870 
871  config title_music_config;
872  title_music_config["name"] = game_config::title_music;
873  title_music_config["append"] = true;
874  title_music_config["immediate"] = true;
875  sound::play_music_config(title_music_config);
876  } else {
879  }
880  }
881 
882  handle_lua_script_args(&*game, cmdline_opts);
883 
884  plugins.play_slice();
885  plugins.play_slice();
886 
887  if(!cmdline_opts.unit_test.empty()) {
888  return static_cast<int>(game->unit_test());
889  }
890 
891  if(game->play_test() == false) {
892  return 0;
893  }
894 
895  if(game->play_screenshot_mode() == false) {
896  return 0;
897  }
898 
899  if(game->play_render_image_mode() == false) {
900  return 0;
901  }
902 
903  // Start directly a campaign
904  if(game->goto_campaign() == false) {
905  if(game->jump_to_campaign_id().empty())
906  continue; // Go to main menu
907  else
908  return 1; // we got an error starting the campaign from command line
909  }
910 
911  // Start directly a multiplayer
912  // Eventually with a specified server
913  if(game->goto_multiplayer() == false) {
914  continue; // Go to main menu
915  }
916 
917  // Start directly a commandline multiplayer game
918  if(game->play_multiplayer_commandline() == false) {
919  return 0;
920  }
921 
922  if(game->goto_editor() == false) {
923  return 0;
924  }
925 
926  const font::floating_label_context label_manager;
927 
929 
930  switch(get_gameloop_action(*game)) {
932  LOG_GENERAL << "quitting game...";
933  return 0;
935  game->play_multiplayer(game_launcher::mp_mode::CONNECT);
936  break;
938  game->play_multiplayer(game_launcher::mp_mode::HOST);
939  break;
941  game->play_multiplayer(game_launcher::mp_mode::LOCAL);
942  break;
944  loading_screen::display([&config_manager]() {
945  config_manager.reload_changed_game_config();
946  gui2::init();
947  gui2::switch_theme(prefs::get().gui2_theme());
948  });
949  break;
951  game->start_editor();
952  break;
954  if(!game->load_prepared_game()) {
955  break;
956  }
957  [[fallthrough]];
960  break;
962  break;
964  gui2::switch_theme(prefs::get().gui2_theme());
965  break;
966  }
967  }
968 }
969 
970 #ifdef _WIN32
971 #define error_exit(res) \
972  do { \
973  if(lg::using_own_console()) { \
974  std::cerr << "Press enter to continue..." << std::endl; \
975  std::cin.get(); \
976  } \
977  return res; \
978  } while(false)
979 #else
980 #define error_exit(res) return res
981 #endif
982 
983 #if defined(__APPLE__) && !defined(__IPHONEOS__)
984 extern "C" int wesnoth_main(int argc, char** argv);
985 int wesnoth_main(int argc, char** argv)
986 #else
987 int main(int argc, char** argv)
988 #endif
989 {
991  auto args = read_argv(argc, argv);
992  assert(!args.empty());
993 
994 #ifdef _WIN32
995  _putenv("PANGOCAIRO_BACKEND=fontconfig");
996  _putenv("FONTCONFIG_PATH=fonts");
997 #endif
998 #ifdef __APPLE__
999  // Using setenv with overwrite disabled so we can override this in the
1000  // original process environment for research/testing purposes.
1001  setenv("PANGOCAIRO_BACKEND", "fontconfig", 0);
1002 #endif
1003 #ifdef __ANDROID__
1004  setenv("PANGOCAIRO_BACKEND", "fontconfig", 0);
1005  setenv("SDL_HINT_AUDIODRIVER", "android", 0);
1006  setenv("SDL_HINT_ANDROID_TRAP_BACK_BUTTON", "1", 0);
1007 #endif
1008 
1009  try {
1010  commandline_options cmdline_opts = commandline_options(args);
1011  int finished = process_command_args(cmdline_opts);
1012 
1013  if(finished != -1) {
1014 #ifdef _WIN32
1015  if(lg::using_own_console()) {
1016  std::cerr << "Press enter to continue..." << std::endl;
1017  std::cin.get();
1018  }
1019 #endif
1020  safe_exit(finished);
1021  }
1022 
1023  SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1");
1024  atexit(SDL_Quit);
1025 
1026  // Mac's touchpad generates touch events too.
1027  // Ignore them until Macs have a touchscreen: https://forums.libsdl.org/viewtopic.php?p=45758
1028 #if defined(__APPLE__) && !defined(__IPHONEOS__)
1029  SDL_SetEventEnabled(SDL_EVENT_FINGER_MOTION, false);
1030  SDL_SetEventEnabled(SDL_EVENT_FINGER_DOWN, false);
1031  SDL_SetEventEnabled(SDL_EVENT_FINGER_UP, false);
1032 #endif
1033 
1034 #ifdef _WIN32
1035  SDL_SetWindowsMessageHook(&events::handle_windows_message, nullptr);
1036 #endif
1037 
1038  // declare this here so that it will always be at the front of the event queue.
1039  events::event_context global_context;
1040  const int res = do_gameloop(cmdline_opts);
1041  safe_exit(res);
1042  } catch(const boost::program_options::error& e) {
1043  // logging hasn't been initialized by this point
1044  std::cerr << "Error in command line: " << e.what() << std::endl;
1045  std::string error = "Error parsing command line arguments: ";
1046  error += e.what();
1047  SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", error.c_str(), nullptr);
1048  error_exit(2);
1049  } catch(const video::error& e) {
1050  PLAIN_LOG << "Video system error: " << e.what();
1051  error_exit(1);
1052  } catch(const font::error& e) {
1053  PLAIN_LOG << "Could not initialize fonts.\n\n" << e.what() << "\n\nExiting.";
1054  error_exit(1);
1055  } catch(const config::error& e) {
1056  PLAIN_LOG << e.message;
1057  error_exit(1);
1058  } catch(const video::quit&) {
1059  // just means the game should quit
1060  } catch(const return_to_play_side_exception&) {
1061  PLAIN_LOG << "caught return_to_play_side_exception, please report this bug (quitting)";
1062  } catch(const quit_game_exception&) {
1063  PLAIN_LOG << "caught quit_game_exception (quitting)";
1064  } catch(const wml_exception& e) {
1065  PLAIN_LOG << "WML exception:\nUser message: " << e.user_message << "\nDev message: " << e.dev_message;
1066  error_exit(1);
1067  } catch(const wfl::formula_error& e) {
1068  PLAIN_LOG << e.what() << "\n\nGame will be aborted.";
1069  error_exit(1);
1070  } catch(const sdl::exception& e) {
1071  PLAIN_LOG << e.what();
1072  error_exit(1);
1073  } catch(const game::error& e) {
1074  PLAIN_LOG << "Game error: " << e.what();
1075  error_exit(1);
1076  } catch(const std::bad_alloc&) {
1077  PLAIN_LOG << "Ran out of memory. Aborted.";
1078  error_exit(ENOMEM);
1079 #if !defined(NO_CATCH_AT_GAME_END)
1080  } catch(const std::exception& e) {
1081  // Try to catch unexpected exceptions.
1082  PLAIN_LOG << "Caught general '" << typeid(e).name() << "' exception:\n" << e.what();
1083  error_exit(1);
1084  } catch(const std::string& e) {
1085  PLAIN_LOG << "Caught a string thrown as an exception:\n" << e;
1086  error_exit(1);
1087  } catch(const char* e) {
1088  PLAIN_LOG << "Caught a string thrown as an exception:\n" << e;
1089  error_exit(1);
1090  } catch(...) {
1091  // Ensure that even when we terminate with `throw 42`, the exception
1092  // is caught and all destructors are actually called. (Apparently,
1093  // some compilers will simply terminate without calling destructors if
1094  // the exception isn't caught.)
1095  PLAIN_LOG << "Caught general exception " << utils::get_unknown_exception_type() << ". Terminating.";
1096  error_exit(1);
1097 #endif
1098  }
1099 
1100  return 0;
1101 } // end main
int wesnoth_main(int argc, char **argv)
void refresh_addon_version_info_cache()
Refreshes the per-session cache of add-on's version information structs.
Definition: manager.cpp:381
Used in parsing config file.
Definition: validator.hpp:38
bool nogui
True if –nogui was given on the command line.
bool print_userdata_path
True if –userdata-path was given on the command line.
utils::optional< std::string > validate_wml
Non-empty if –validate was given on the command line.
bool simple_version
True if –simple-version was given on the command line.
bool report
True if –report was given on the command line.
bool headless_unit_test
True if –unit is used and –showgui is not present.
bool no_log_sanitize
True if –no-log-sanitize was given on the command line.
bool strict_lua
True if –strict-lua was given in the commandline.
bool print_usercache_path
True if –usercache-path was given on the command line.
utils::optional< std::vector< std::string > > preprocess_defines
Defines that were given to the –preprocess option.
utils::optional< std::string > usercache_dir
Non-empty if –usercache-dir was given on the command line.
bool no_simd
True if –no-simd was given on the command line.
utils::optional< std::string > validate_schema
Non-empty if –validate-schema was given on the command line.
utils::optional< std::string > userdata_dir
Non-empty if –userdata-dir was given on the command line.
bool nobanner
True if –nobanner was given on the command line.
utils::optional< std::vector< std::pair< lg::severity, std::string > > > log
Contains parsed arguments of –log-* (e.g.
utils::optional< std::string > generate_spritesheet
Path of which to generate a spritesheet.
utils::optional< std::string > render_image
Image path to render.
utils::optional< std::string > logdomains
Non-empty if –logdomains was given on the command line.
utils::optional< std::string > preprocess_input_macros
Non-empty if –preprocess-input-macros was given on the command line.
bool preprocess
True if –preprocess was given on the command line.
utils::optional< unsigned int > rng_seed
RNG seed specified by –rng-seed option.
std::string diff_left
Files for diffing or patching.
bool version
True if –version was given on the command line.
bool allow_insecure
True if –allow-insecure was given in the commandline.
utils::optional< std::string > validate_with
Non-empty if –use-schema was given on the command line.
bool noaddons
True if –noaddons was given on the command line.
utils::optional< std::string > output_file
Output filename for WML diff or preprocessing.
utils::optional< std::string > data_dir
Non-empty if –data-dir was given on the command line.
utils::optional< std::string > preprocess_target
Target (output) path that was given to the –preprocess option.
bool screenshot
True if –screenshot was given on the command line.
bool log_to_file
True if –log-to-file was given on the command line.
bool debug_lua
True if –debug-lua was given in the commandline.
std::vector< std::string > unit_test
Non-empty if –unit was given on the command line.
bool log_precise_timestamps
True if –log-precise was given on the command line.
utils::optional< std::string > preprocess_source_string
String to preprocess.
bool no_log_to_file
True if –no-log-to-file was given on the command line.
utils::optional< std::string > preprocess_output_macros
Non-empty if –preprocess-output-macros was given on the command line.
bool strict_validation
True if –strict-validation was given on the command line.
utils::optional< std::string > preprocess_path
Path to parse that was given to the –preprocess option.
bool help
True if –help was given on the command line.
bool print_data_path
True if –data-path was given on the command line.
Class for writing a config out to a file in pieces.
void write(const config &cfg, bool strong_quotes=false)
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:157
auto all_children_view() const
In-order iteration over all children.
Definition: config.hpp:795
child_itors child_range(std::string_view key)
Definition: config.cpp:268
void apply_diff(const config &diff, bool track=false)
A function to apply a diff config onto this config object.
Definition: config.cpp:1000
config get_diff(const config &c) const
A function to get the differences between this object, and 'c', as another config object.
Definition: config.cpp:884
@ NO_FORCE_RELOAD
Don't reload if the previous defines equal the new defines.
bool init_game_config(FORCE_RELOAD_CONFIG force_reload)
const game_config_view & game_config() const
optional_const_config optional_child(std::string_view key) const
bool play_multiplayer(mp_mode mode)
static void progress(loading_stage stage=loading_stage::none)
Report what is being loaded to the loading screen.
static void display(const std::function< void()> &f)
@ ok_button
Shows an ok button.
Definition: message.hpp:73
This class implements the title screen.
void play_slice()
Definition: context.cpp:103
std::vector< Reg > reg_vec
Definition: context.hpp:40
std::vector< aReg > areg_vec
Definition: context.hpp:41
void set_callback(const std::string &name, callback_function)
Definition: context.cpp:53
static prefs & get()
Exception used to escape form the ai or ui code to playsingle_controller::play_side.
Realization of serialization/validator.hpp abstract validator.
std::string str() const
Serializes the version number into string form.
Type that can be thrown as an exception to quit to desktop.
Definition: video.hpp:328
std::vector< std::string > read_argv([[maybe_unused]] int argc, [[maybe_unused]] char **argv)
Definitions for the interface to Wesnoth Markup Language (WML).
const config * cfg
Declarations for File-IO.
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
std::size_t i
Definition: function.cpp:1031
Contains the exception interfaces used to signal completion of a scenario, campaign or turn.
Interfaces for manipulating version numbers of engine, add-ons, etc.
static std::string _(const char *str)
Definition: gettext.hpp:100
Standard logging facilities (interface).
#define STREAMING_LOG
Definition: log.hpp:297
#define PLAIN_LOG
Definition: log.hpp:296
auto format_local_timestamp(const std::chrono::system_clock::time_point &time, std::string_view format="%F %T")
Definition: chrono.hpp:70
@ WAIT
Definition: cursor.hpp:28
@ NORMAL
Definition: cursor.hpp:28
void set(CURSOR_TYPE type)
Use the default parameter to reset cursors.
Definition: cursor.cpp:171
void set_main_thread()
Definition: events.cpp:468
std::string get_cache_dir()
Definition: filesystem.cpp:880
filesystem::scoped_istream istream_file(const std::string &fname, bool treat_failure_as_error)
std::string get_user_data_dir()
Definition: filesystem.cpp:870
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:344
std::string get_exe_dir()
bool is_directory(const std::string &fname)
Returns true if the given file is a directory.
utils::optional< std::string > get_wml_location(const std::string &path, const utils::optional< std::string > &current_dir)
Returns a translated path to the actual file or directory, if it exists.
filesystem::scoped_ostream ostream_file(const std::string &fname, std::ios_base::openmode mode, bool create_directory)
std::string autodetect_game_data_dir(std::string exe_dir)
Try to autodetect the location of the game data dir.
void set_cache_dir(const std::string &newcachedir)
Definition: filesystem.cpp:838
std::string get_logs_dir()
Definition: filesystem.cpp:875
std::unique_ptr< std::ostream > scoped_ostream
Definition: filesystem.hpp:53
bool is_userdata_initialized()
Definition: filesystem.cpp:627
std::string get_intl_dir()
std::string normalize_path(const std::string &fpath, bool normalize_separators, bool resolve_dot_entries)
Returns the absolute path of a file.
void set_user_data_dir(std::string newprefdir)
Definition: filesystem.cpp:740
bool load_font_config()
Definition: font_config.cpp:78
std::string path
Definition: filesystem.cpp:106
bool addon_server_info
Definition: game_config.cpp:79
std::string full_build_report()
Produce a bug report-style info dump.
Definition: build_info.cpp:655
std::string library_versions_report()
Produce a plain-text report of library versions suitable for stdout/stderr.
Definition: build_info.cpp:645
const version_info wesnoth_version(VERSION)
bool allow_insecure
Definition: game_config.cpp:78
std::string title_music
std::string build_arch()
Obtain the processor architecture for this build.
Definition: build_info.cpp:312
std::string optional_features_report()
Produce a plain-text report of features suitable for stdout/stderr.
Definition: build_info.cpp:650
const std::string revision
bool check_migration
Definition: filesystem.cpp:114
void init()
Initializes the GUI subsystems.
Definition: gui.cpp:108
void switch_theme(const std::string &theme_id)
Set and activate the given gui2 theme.
Definition: gui.cpp:149
void show_message(const std::string &title, const std::string &msg, const std::string &button_caption, const bool auto_close, const bool message_use_markup, const bool title_use_markup)
Shows a message to the user.
Definition: message.cpp:148
void build_spritesheet_from(const std::string &entry_point)
config read(std::istream &in, abstract_validator *validator)
Definition: parser.cpp:610
void write(std::ostream &out, const configr_of &cfg, unsigned int level, bool strong_quotes)
Definition: parser.cpp:748
bool using_own_console()
Returns true if a console was allocated by the Wesnoth process.
severity
Definition: log.hpp:82
std::string list_log_domains(const std::string &filter)
Definition: log.cpp:410
bool broke_strict()
Definition: log.cpp:430
void set_log_to_file()
Do the initial redirection to a log file if the logs directory is writable.
Definition: log.cpp:266
void set_log_sanitize(bool sanitize)
toggle log sanitization
Definition: log.cpp:434
utils::optional< bool > log_dir_writable()
Returns the result set by check_log_dir_writable().
Definition: log.cpp:312
void do_console_redirect()
Allocates a console if needed and redirects output to CONOUT.
void precise_timestamps(bool pt)
Definition: log.cpp:337
bool set_log_domain_severity(const std::string &name, severity severity)
Definition: log.cpp:379
void set_strict_severity(severity severity)
Definition: log.cpp:420
void empty_playlist()
Definition: sound.cpp:531
void play_music_config(const config &music_node, bool allow_interrupt_current_track, int i)
Definition: sound.cpp:619
void stop_music()
Definition: sound.cpp:487
void bind_textdomain(const char *domain, const char *directory, const char *)
Definition: gettext.cpp:479
void set_default_textdomain(const char *domain)
Definition: gettext.cpp:487
std::string get_unknown_exception_type()
Utility function for finding the type of thing caught with catch(...).
Definition: general.cpp:23
std::map< std::string, t_string > string_map
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
filesystem::scoped_istream preprocess_string(const std::string &contents, const std::string &textdomain)
void preprocess_resource(const std::string &res_name, preproc_map *defines_map, bool write_cfg, bool write_plain_cfg, const std::string &parent_directory)
filesystem::scoped_istream preprocess_file(const std::string &fname, preproc_map &defines)
Function to use the WML preprocessor on a file.
std::map< std::string, struct preproc_define > preproc_map
One of the realizations of serialization/validator.hpp abstract validator.
Contains a basic exception class for SDL operations.
structure which will hide all current floating labels, and cause floating labels instantiated after i...
Base class for all the errors encountered by the engine.
Definition: exceptions.hpp:29
static void insert(preproc_map &, const config &)
Reports time elapsed at the end of an object scope.
Definition: optimer.hpp:37
An error specifically indicating video subsystem problems.
Definition: video.hpp:321
Helper class, don't construct this directly.
bool strict_validation_enabled
Definition: validator.cpp:21
Some defines: VERSION, PACKAGE, MIN_SAVEGAME_VERSION.
#define PACKAGE
Definition: wesconfig.h:23
static lg::log_domain log_preprocessor("preprocessor")
static void handle_preprocess_string(const commandline_options &cmdline_opts)
Definition: wesnoth.cpp:130
static void safe_exit(int res)
Definition: wesnoth.cpp:124
static int get_gameloop_action(game_launcher &game)
Gets the appropriate action code for the current iteration of the game loop.
Definition: wesnoth.cpp:738
static int do_gameloop(commandline_options &cmdline_opts)
Setups the game environment and enters the titlescreen or game loops.
Definition: wesnoth.cpp:761
static int handle_validate_command(const std::string &file, abstract_validator &validator, const std::vector< std::string > &defines)
Definition: wesnoth.cpp:303
int main(int argc, char **argv)
Definition: wesnoth.cpp:987
static int process_command_args(commandline_options &cmdline_opts)
Process commandline-arguments.
Definition: wesnoth.cpp:331
static void handle_preprocess_command(const commandline_options &cmdline_opts)
Definition: wesnoth.cpp:188
static void check_fpu()
Definition: wesnoth.cpp:712
#define LOG_PREPROC
Definition: wesnoth.cpp:119
static void init_locale()
I would prefer to setup locale first so that early error messages can get localized,...
Definition: wesnoth.cpp:612
static void handle_lua_script_args(game_launcher *game, commandline_options &)
Handles the lua script command line arguments if present.
Definition: wesnoth.cpp:649
#define error_exit(res)
Definition: wesnoth.cpp:980
static void warn_early_init_failure()
Print an alert and instructions to stderr about early initialization errors.
Definition: wesnoth.cpp:636
#define LOG_GENERAL
Definition: wesnoth.cpp:116
static lg::log_domain log_config("config")
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
#define e