aboutsummaryrefslogtreecommitdiff
path: root/src/headless/main.cpp
blob: e15005bd96d80a46ea10946734b46dac78d78a71 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include <cstring>

#include <openvic-simulation/GameManager.hpp>
#include <openvic-simulation/dataloader/Dataloader.hpp>
#include <openvic-simulation/utility/Logger.hpp>
#include <openvic-simulation/testing/Testing.hpp>

using namespace OpenVic;

static char const* get_program_name(char const* name) {
   static constexpr char const* missing_name = "<program>";
   if (name == nullptr) return missing_name;
   char const* last_separator = name;
   while (*name != '\0') {
      if (*name == '/' || *name == '\\') {
         last_separator = name + 1;
      }
      ++name;
   }
   if (*last_separator == '\0') return missing_name;
   return last_separator;
}

static void print_help(char const* program_name) {
   std::cout
      << "Usage: " << program_name << " [-h] [-t] [-b <path>] [path]+\n"
      << "    -h : Print this help message and exit the program.\n"
      << "    -t : Run tests after loading defines.\n"
      << "    -b : Use the following path as the base directory (instead of searching for one).\n"
      << "Any following paths are read as mod directories, with priority starting at one above the base directory.\n"
      << "(Paths with spaces need to be enclosed in \"quotes\").\n";
}

static void setup_logger_funcs() {
   Logger::set_info_func([](std::string&& str) { std::cout << str; });
   Logger::set_warning_func([](std::string&& str) { std::cerr << str; });
   Logger::set_error_func([](std::string&& str) { std::cerr << str; });
}

static bool headless_load(GameManager& game_manager, Dataloader const& dataloader) {
   bool ret = true;

   if (!dataloader.load_defines(game_manager)) {
      Logger::error("Failed to load defines!");
      ret = false;
   }
   if (!game_manager.load_hardcoded_defines()) {
      Logger::error("Failed to load hardcoded defines!");
      ret = false;
   }
   if (!dataloader.load_localisation_files(
      [](std::string_view key, Dataloader::locale_t locale, std::string_view localisation) -> bool {
         return true;
      }
   )) {
      Logger::error("Failed to load localisation!");
      ret = false;
   }

   return ret;
}

static bool run_headless(Dataloader::path_vector_t const& roots, bool run_tests) {
   bool ret = true;

   setup_logger_funcs();

   Dataloader dataloader;
   if (!dataloader.set_roots(roots)) {
      Logger::error("Failed to set dataloader roots!");
      ret = false;
   }

   GameManager game_manager { []() {
      Logger::info("State updated");
   } };

   ret &= headless_load(game_manager, dataloader);

   if (run_tests) {
      Testing testing = Testing(&game_manager);
      std::cout << std::endl << "Testing Loaded" << std::endl << std::endl;
      testing.execute_all_scripts();
      testing.report_results();
      std::cout << "Testing Executed" << std::endl << std::endl;
   }

   return ret;
}

/*
   $ program [-h] [-t] [-b] [path]+
*/

int main(int argc, char const* argv[]) {
   char const* program_name = get_program_name(argc > 0 ? argv[0] : nullptr);

   fs::path root;
   bool run_tests = false;

   int argn = 0;
   while (++argn < argc) {
      char const* arg = argv[argn];
      if (strcmp(arg, "-h") == 0) {
         print_help(program_name);
         return 0;
      } else if (strcmp(arg, "-t") == 0) {
         run_tests = true;
      } else if (strcmp(arg, "-b") == 0) {
         if (root.empty())  {
            if (++argn < argc) {
               root = argv[argn];
               if (!root.empty()) {
                  continue;
               } else {
                  std::cerr << "Empty path after base directory command line argument \"-b\"." << std::endl;
               }
            } else {
               std::cerr << "Missing path after base directory command line argument \"-b\"." << std::endl;
            }
         } else {
            std::cerr << "Duplicate base directory command line argument \"-b\"." << std::endl;
         }
         print_help(program_name);
         return -1;
      } else {
         break;
      }
   }
   if (root.empty()) {
      root = Dataloader::search_for_game_path();
      if (root.empty()) {
         std::cerr << "Search for base directory path failed!" << std::endl;
         print_help(program_name);
         return -1;
      }
   }
   Dataloader::path_vector_t roots = { root };
   while (argn < argc) {
      roots.emplace_back(root / argv[argn++]);
   }

   std::cout << "!!! HEADLESS SIMULATION START !!!" << std::endl;

   const bool ret = run_headless(roots, run_tests);

   std::cout << "!!! HEADLESS SIMULATION END !!!" << std::endl;

   std::cout << "\nLoad returned: " << (ret ? "SUCCESS" : "FAILURE") << std::endl;

   return ret ? 0 : -1;
}