Elaztek Developer Hub
Blamite Game Engine - Tool (Library)
A command-line utility that aids in the creation of Blamite Cache (.map) Files.
ParseScriptsCommand.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <regex>
4 #include <Strings/components/logger/logger.h>
5 #include <Strings/components/utils/io/io.h>
6 #include <Strings/components/utils/string/string.h>
7 #include <Strings/components/utils/list/list.h>
8 #include <Strings/components/3rdparty/rapidxml/rapidxml.hpp>
9 #include <Strings/components/classes/map/map.h>
10 #include <Strings/components/utils/converters/converters.h>
11 #include <HEKGuerilla/components/projects/projects.h>
12 
13 #include "../ToolCommand.hpp"
14 #include "../console.h"
15 #include "components/utils/utils.h"
16 
17 #ifdef TOOL_LIB_EXPORTS
18 #define TOOL_LIB_API __declspec(dllexport)
19 #else
20 #define TOOL_LIB_API __declspec(dllimport)
21 #endif
22 
29 {
30  bool parse_debug = false;
31 
32  std::vector<std::string> PreprocessArgs(std::vector<std::string> args)
33  {
34  std::vector<std::string> processed_args = std::vector<std::string>();
35 
36  for (int i = 0; i < args.size(); i++)
37  {
38  if (args[i] == "-parse-debug")
39  {
40  parse_debug = true;
41  }
42  else
43  {
44  processed_args.push_back(args[i]);
45  }
46  }
47 
48  return processed_args;
49  }
50 
51 public:
53  {
54  command = "parse-scripts";
55  syntax = "parse-scripts [project filename] [-parse-debug]";
56  description = "preprocess scripts, ensures that scripts can be referenced by the game engine and editing kit";
57  }
58 
59  int execute(std::vector<std::string> args)
60  {
61  args = PreprocessArgs(args);
62 
63  std::string project_root = BlamTool::Utils::GetProjectRoot();
64  std::string project_filename = BlamStrings::Utils::IO::GetFileNameWithoutExtension(project_root) + ".blam";
65 
66  if (args.size() > 0)
67  {
68  project_filename = args[0];
69  }
70 
71  BlamProject* project_info = Guerilla::Projects::LoadProject(project_root + project_filename);
72 
73  if (!project_info->IsLoaded())
74  {
75  BlamStrings::Logger::LogEvent("failed to create stub project: could not load project info (tried to "
76  "read from file path: " + project_root + project_filename + ")", WSV_ERROR);
77 
78  if (args.size() == 0)
79  {
80  BlamStrings::Logger::LogEvent("project path was assumed from directory path - if your .blam file "
81  "has a different name, use " + syntax + " to specify the filename", WSV_WARNING);
82  }
83 
84  delete project_info;
85  return -1;
86  }
87 
88  std::vector<std::string> sources = GetSourceFilesFromVcx(project_info->GetVcxprojPath());
89  std::vector<std::string> sources_raw = GetSourceFilesFromVcx(project_info->GetVcxprojPath(), true);
90  std::vector<std::string> script_names = std::vector<std::string>();
91 
92  for (std::string file_path : sources)
93  {
94  std::string file_contents = BlamStrings::Utils::IO::GetFileContentsAsString(file_path);
95  BlamStrings::Logger::LogEvent("analyzing '" + file_path + "'...");
96 
97  while (str_contains(file_contents, "/*", true))
98  {
99  int start = file_contents.find("/*");
100 
101  if (start == std::string::npos)
102  {
103  break;
104  }
105 
106  int end = file_contents.find("*/", start);
107 
108  if (end == std::string::npos)
109  {
110  break;
111  }
112 
113  file_contents = file_contents.erase(start, end - start);
114  }
115 
116  file_contents = str_replace(file_contents, "public", "");
117  file_contents = str_replace(file_contents, "protected", "");
118  file_contents = str_replace(file_contents, "private", "");
119  file_contents = str_replace(file_contents, "class", "class:");
120  file_contents = str_replace(file_contents, " ", "");
121  file_contents = str_replace(file_contents, "\r", "");
122  file_contents = str_replace(file_contents, "\n", "");
123  file_contents = str_replace(file_contents, "\t", "");
124 
125  if (parse_debug)
126  {
127  BlamStrings::Utils::IO::CreateNewFile(file_path + ".PARSED", file_contents);
128  }
129 
130  int offset = 0;
131  while (true)
132  {
133  int pos = file_contents.find("BSCRIPTclass:", offset);
134 
135  if (pos == std::string::npos)
136  {
137  break;
138  }
139 
140  pos = pos + sizeof("BSCRIPTclass:") - 1;
141 
142  int end_pos = pos + 1;
143  bool is_script = false;
144 
145  while (end_pos != std::string::npos && end_pos < file_contents.length())
146  {
147  if (file_contents.at(end_pos) == ':')
148  {
149  is_script = true;
150  break;
151  }
152 
153  end_pos++;
154  }
155 
156  if (is_script)
157  {
158  std::string script_name = file_contents.substr(pos, end_pos - pos);
159 
160  if (!BlamStrings::Utils::List::Contains(script_names, script_name))
161  {
162  script_names.push_back(script_name);
163  }
164  }
165 
166  offset = end_pos;
167  }
168  }
169 
170  // Create scripts.db file
171  {
172  std::string db_contents = "";
173 
174  for (std::string script_name : script_names)
175  {
176  db_contents += script_name + "\n";
177  }
178 
179  BlamStrings::Utils::IO::CreateNewFile(project_root + "/_build/scripts.db", db_contents);
180  }
181 
182  // Generate gamescripts.cpp file
183  {
184  std::string template_file = BlamStrings::Utils::IO::GetFileContentsAsString("./content/blam/default_stub_project/gamescripts.cpp.template");
185 
186  std::string includes = "";
187  std::string creation_functions = "";
188  std::string registry_lines = "";
189 
190  for (std::string source_file : sources_raw)
191  {
192  if (!source_file.ends_with(".h"))
193  {
194  continue;
195  }
196 
197  includes += "#include <" + source_file + ">\n";
198  }
199 
200  for (std::string script_name : script_names)
201  {
202  std::string function_name = "__blam_create_script__" + script_name;
203  creation_functions += script_name + "* " + function_name + "() { return new " + script_name + "(); }\n";
204  registry_lines += " BlamAPI::Scripts::RegisterScriptType(\"" + script_name + "\", &" + function_name + ");\n";
205  }
206 
207  template_file = str_replace(template_file, "%%FUNCTIONS%%", creation_functions);
208  template_file = str_replace(template_file, "%%REGISTRATIONS%%", registry_lines);
209  template_file = str_replace(template_file, "%%INCLUDES%%", includes);
210 
211  BlamStrings::Utils::IO::CreateNewFile(project_root + "_build/_internal/game/gamescripts.cpp", template_file);
212  }
213 
214  BlamStrings::Logger::LogEvent("finished");
215 
216  delete project_info;
217  return 0;
218  }
219 
220  std::vector<std::string> GetSourceFilesFromVcx(std::string vcxproj_path, bool preserve_relative_paths = false)
221  {
222  std::vector<std::string> files = std::vector<std::string>();
223  std::string vcxproj_dir = BlamStrings::Utils::IO::GetContainingFolder(vcxproj_path);
224 
225  char* data = nullptr;
226  int64_t data_size = 0;
227 
228  if (!BlamStrings::Utils::IO::ReadFile(vcxproj_path, (void**)&data, &data_size))
229  {
230  BlamStrings::Logger::LogEvent("cannot load vcxproj: ReadFile() returned false", WSV_WARNING);
231  return files;
232  }
233 
234  rapidxml::xml_document<char>* document = new rapidxml::xml_document();
235  document->parse<0>(data);
236 
237  rapidxml::xml_node<>* root = document->first_node();
238 
239  for (rapidxml::xml_node<>* node = root->first_node(); node; node = node->next_sibling())
240  {
241  if (str_tolower(node->name()) != "itemgroup")
242  {
243  continue;
244  }
245 
246  for (rapidxml::xml_node<>* child_node = node->first_node(); child_node; child_node = child_node->next_sibling())
247  {
248  if (str_tolower(child_node->name()) == "clinclude" || str_tolower(child_node->name()) == "clcompile")
249  {
250  if (preserve_relative_paths)
251  {
252  files.push_back(child_node->first_attribute("Include")->value());
253  }
254  else
255  {
256  files.push_back(BlamStrings::Utils::IO::NormalizePath(vcxproj_dir + "/"
257  + child_node->first_attribute("Include")->value()));
258  }
259  }
260  }
261  }
262 
263  delete document;
264  free(data);
265 
266  return files;
267  }
268 };
ParseScriptsCommand::execute
int execute(std::vector< std::string > args)
Executes the command.
Definition: ParseScriptsCommand.hpp:59
ParseScriptsCommand::GetSourceFilesFromVcx
std::vector< std::string > GetSourceFilesFromVcx(std::string vcxproj_path, bool preserve_relative_paths=false)
Definition: ParseScriptsCommand.hpp:220
utils.h
ParseScriptsCommand
Class for the parse-scripts command.
Definition: ParseScriptsCommand.hpp:28
ParseScriptsCommand::ParseScriptsCommand
ParseScriptsCommand()
Definition: ParseScriptsCommand.hpp:52
TOOL_LIB_API
#define TOOL_LIB_API
Definition: ParseScriptsCommand.hpp:20
ToolCommand
Base class representing a Tool command.
Definition: ToolCommand.hpp:15
BlamTool::Utils::GetProjectRoot
TOOL_LIB_API std::string GetProjectRoot()
Retrieves the current project root.
Definition: utils.cpp:6