Elaztek Developer Hub
Blamite Game Engine - Tool (Library)
A command-line utility that aids in the creation of Blamite Cache (.map) Files.
GenerateGameStubProjectCommand.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <Strings/components/logger/logger.h>
4 #include <Strings/components/utils/io/io.h>
5 #include <Strings/components/utils/string/string.h>
6 #include <Strings/components/utils/list/list.h>
7 #include <Strings/components/3rdparty/rapidxml/rapidxml.hpp>
8 #include <HEKGuerilla/components/projects/projects.h>
9 
10 #include "../ToolCommand.hpp"
11 #include "../console.h"
12 #include "components/utils/utils.h"
13 
14 #ifdef TOOL_LIB_EXPORTS
15 #define TOOL_LIB_API __declspec(dllexport)
16 #else
17 #define TOOL_LIB_API __declspec(dllimport)
18 #endif
19 
20 #define VC_DEBUG_WIN32 0
21 #define VC_DEBUG_WIN64 1
22 #define VC_RELEASE_WIN32 2
23 #define VC_RELEASE_WIN64 3
24 
33 {
34 private:
35  std::vector<std::string> reserved_lib_names = {
36  "blam.lib",
37  "Strings.lib",
38  "HEKGuerilla.lib",
39  "HEKTool.lib",
40  "HEKSapien.lib",
41  "HEKFoundry.lib",
42  "keystone.lib"
43  };
44 
45  std::string include_path_placeholders[4] = {
46  "{$__INCLUDE_DIRS_DW32__}",
47  "{$__INCLUDE_DIRS_DW64__}",
48  "{$__INCLUDE_DIRS_RW32__}",
49  "{$__INCLUDE_DIRS_RW64__}"
50  };
51 
52  std::string lib_name_placeholders[4] = {
53  "{$__GAME_LIB_DW32__}",
54  "{$__GAME_LIB_DW64__}",
55  "{$__GAME_LIB_RW32__}",
56  "{$__GAME_LIB_RW64__}"
57  };
58 
59  std::string lib_path_placeholders[4] = {
60  "{$__LIBRARY_DIRS_DW32__}",
61  "{$__LIBRARY_DIRS_DW64__}",
62  "{$__LIBRARY_DIRS_RW32__}",
63  "{$__LIBRARY_DIRS_RW64__}"
64  };
65 
66  std::string dep_dir_placeholders[4] = {
67  "{$__DEP_DIR_DW32__}",
68  "{$__DEP_DIR_DW64__}",
69  "{$__DEP_DIR_RW32__}",
70  "{$__DEP_DIR_RW64__}"
71  };
72 
73  std::string engine_lib_dir_suffixes[4] = {
74  "tag debug/Win32",
75  "tag debug/x64",
76  "cache release/Win32",
77  "cache release/x64"
78  };
79 
80  std::string vcx_library_paths[4] = { "", "", "", "" };
81  std::string vcx_library_names[4] = { "", "", "", "" };
82 
83  std::string game_libs = "blam.lib;SDL2.lib;Strings.lib";
84  std::string delay_load_dlls = "blam.dll;SDL2.dll;Strings.dll";
85  std::string delay_load_dlls_placeholder = "{$__DELAY_DLLS__}";
86 
87  bool verbose = false;
88  bool no_msbuild_warning = false;
89  bool skip_path_gen = false;
90 
91  std::vector<std::string> PreprocessArgs(std::vector<std::string> args)
92  {
93  std::vector<std::string> processed_args = std::vector<std::string>();
94 
95  for (int i = 0; i < args.size(); i++)
96  {
97  if (args[i] == "-verbose")
98  {
99  verbose = true;
100  }
101  else if (args[i] == "-no-msbuild-warning")
102  {
103  no_msbuild_warning = true;
104  }
105  else if (args[i] == "-skip-path-gen")
106  {
107  skip_path_gen = true;
108  }
109  else
110  {
111  processed_args.push_back(args[i]);
112  }
113  }
114 
115  return processed_args;
116  }
117 
118 public:
120  {
121  command = "generate-game-stub-project";
122  syntax = "generate-game-stub-project [project filename] [-verbose] [-no-msbuild-warning] [-skip-path-gen]";
123  description = "generates a stub vcxproj for the current game project";
124  }
125 
126  int execute(std::vector<std::string> args)
127  {
128  args = PreprocessArgs(args);
129 
130  std::string project_root = BlamTool::Utils::GetProjectRoot();
131  std::string project_filename = BlamStrings::Utils::IO::GetFileNameWithoutExtension(project_root) + ".blam";
132 
133  if (args.size() > 0)
134  {
135  project_filename = args[0];
136  }
137 
138  BlamProject* project = Guerilla::Projects::LoadProject(project_root + project_filename);
139 
140  if (!project->IsLoaded())
141  {
142  BlamStrings::Logger::LogEvent("failed to create stub project: could not load project info (tried to "
143  "read from file path: " + project_root + project_filename + ")", WSV_ERROR);
144 
145  if (args.size() == 0)
146  {
147  BlamStrings::Logger::LogEvent("project path was assumed from directory path - if your .blam file "
148  "has a different name, use " + syntax + " to specify the filename", WSV_WARNING);
149  }
150 
151  delete project;
152  return -1;
153  }
154 
155  std::string source_path = "./content/blam/default_stub_project";
156  std::string destination_path = project_root + "_build/_internal/game";
157 
158  std::string copy_cmd = "XCOPY \"" + source_path + "\" \"" + destination_path + "\" /S /I /Y";
159  if (verbose) BlamStrings::Logger::LogEvent("running system command :: " + copy_cmd);
160  int copy_result = system(copy_cmd.c_str());
161 
162  if (copy_result < 0)
163  {
164  BlamStrings::Logger::LogEvent("failed to create stub project: xcopy returned " + std::to_string(copy_result)
165  + " -- full xcopy command:", WSV_ERROR);
166  BlamStrings::Logger::LogEvent(copy_cmd, WSV_ERROR);
167  delete project;
168  return copy_result;
169  }
170 
171  if (!IdentifyVcxprojInfo(project->GetVcxprojPath(), project))
172  {
173  BlamStrings::Logger::LogEvent("failed to read data from vcxproj - see log for details", WSV_ERROR);
174  delete project;
175  return -1;
176  }
177 
178  if (verbose) BlamStrings::Logger::LogEvent("configuring vcxproj: " + destination_path + "/game.vcxproj");
179 
180  std::string vcxproj_file_contents = BlamStrings::Utils::IO::GetFileContentsAsString(destination_path + "/game.vcxproj");
181 
182  for (int i = 0; i < 4; i++)
183  {
184  std::string engine_dep_path = project->GetEngineDependenciesPath() + "/" + engine_lib_dir_suffixes[i] + "/";
185  std::string engine_include_path = project->GetEngineDependenciesPath() + "/include/";
186  std::string project_include_root = BlamStrings::Utils::IO::GetAbsolutePathFromRelative(project_root);
187 
188  vcxproj_file_contents = str_replace(vcxproj_file_contents, include_path_placeholders[i], engine_include_path + ";" + project_include_root);
189  vcxproj_file_contents = str_replace(vcxproj_file_contents, lib_name_placeholders[i], vcx_library_names[i] + ";" + game_libs);
190  vcxproj_file_contents = str_replace(vcxproj_file_contents, lib_path_placeholders[i],
191  vcx_library_paths[i] + ";" + engine_dep_path + "/lib");
192  vcxproj_file_contents = str_replace(vcxproj_file_contents, dep_dir_placeholders[i], engine_dep_path + "/data");
193  }
194 
195  vcxproj_file_contents = str_replace(vcxproj_file_contents, delay_load_dlls_placeholder, delay_load_dlls);
196 
197  BlamStrings::Utils::IO::CreateNewFile(destination_path + "/game.vcxproj", vcxproj_file_contents);
198 
199  if (verbose) BlamStrings::Logger::LogEvent("game project generated to " + destination_path);
200  BlamStrings::Logger::LogEvent("finished");
201 
202  delete project;
203  return 0;
204  }
205 
206  bool IdentifyVcxprojInfo(std::string vcxproj_path, BlamProject* project)
207  {
208  std::string library_file_name = BlamStrings::Utils::IO::GetFileNameWithoutExtension(vcxproj_path);
209 
210  for (int i = 0; i < 4; i++)
211  {
212  vcx_library_names[i] = library_file_name + ".lib";
213  }
214 
215  if (!no_msbuild_warning)
216  {
217  BlamStrings::Logger::LogEvent("##################################################################################", TerminalColor::Magenta);
218  BlamStrings::Logger::LogEvent("TOOL WILL NOW RUN MSBUILD AS NEEDED IN ORDER TO RUN PRE-BUILD STEPS", TerminalColor::Magenta);
219  BlamStrings::Logger::LogEvent("If you want to terminate this process, press Ctrl+C NOW (you have 8 seconds from this message)!", TerminalColor::Magenta);
220  BlamStrings::Logger::LogEvent("----------------------------------------------------------------------------------", TerminalColor::Magenta);
221  BlamStrings::Logger::LogEvent("Note that the build itself may produce errors or fail outright - this will", TerminalColor::Magenta);
222  BlamStrings::Logger::LogEvent("not affect the stub project generation process, as we only need the pre-build", TerminalColor::Magenta);
223  BlamStrings::Logger::LogEvent("step to run in order to generate library paths that we can read.", TerminalColor::Magenta);
224  BlamStrings::Logger::LogEvent("##################################################################################", TerminalColor::Magenta);
225  Sleep(8000);
226  }
227 
228  std::string msbuild_path_base = "\"" + project->GetMSBuildPath() + "\" \"" + vcxproj_path + "\" ";
229 
230  if (!BlamStrings::Utils::IO::IsDirectory(project->project_root + "_build/_internal/paths/Debug_x64") || !skip_path_gen)
231  {
232  BlamStrings::Logger::LogEvent("running msbuild with Debug|x64 config to generate build path files...");
233  std::string cmd = "\"" + msbuild_path_base + "/p:Configuration=\"Debug\" /p:Platform=\"x64\"" + "\"";
234  if (verbose) BlamStrings::Logger::LogEvent("running system command :: " + cmd);
235  system(cmd.c_str());
236  }
237 
238  if (!BlamStrings::Utils::IO::IsDirectory(project->project_root + "_build/_internal/paths/Debug_Win32") || !skip_path_gen)
239  {
240  BlamStrings::Logger::LogEvent("running msbuild with Debug|Win32 config to generate build path files...");
241  std::string cmd = "\"" + msbuild_path_base + "/p:Configuration=\"Debug\" /p:Platform=\"Win32\"" + "\"";
242  if (verbose) BlamStrings::Logger::LogEvent("running system command :: " + cmd);
243  system(cmd.c_str());
244  }
245 
246  if (!BlamStrings::Utils::IO::IsDirectory(project->project_root + "_build/_internal/paths/Release_x64") || !skip_path_gen)
247  {
248  BlamStrings::Logger::LogEvent("running msbuild with Release|x64 config to generate build path files...");
249  std::string cmd = "\"" + msbuild_path_base + "/p:Configuration=\"Release\" /p:Platform=\"x64\"" + "\"";
250  if (verbose) BlamStrings::Logger::LogEvent("running system command :: " + cmd);
251  system(cmd.c_str());
252  }
253 
254  if (!BlamStrings::Utils::IO::IsDirectory(project->project_root + "_build/_internal/paths/Release_Win32") || !skip_path_gen)
255  {
256  BlamStrings::Logger::LogEvent("running msbuild with Release|Win32 config to generate build path files...");
257  std::string cmd = "\"" + msbuild_path_base + "/p:Configuration=\"Release\" /p:Platform=\"Win32\"" + "\"";
258  if (verbose) BlamStrings::Logger::LogEvent("running system command :: " + cmd);
259  system(cmd.c_str());
260  }
261 
262  std::string required_files[] = {
263  project->project_root + "_build/_internal/paths/Debug_Win32/OUT_DIR",
264  project->project_root + "_build/_internal/paths/Debug_Win32/TARGET_FILE_NAME",
265  project->project_root + "_build/_internal/paths/Debug_x64/OUT_DIR",
266  project->project_root + "_build/_internal/paths/Debug_x64/TARGET_FILE_NAME",
267  project->project_root + "_build/_internal/paths/Release_Win32/OUT_DIR",
268  project->project_root + "_build/_internal/paths/Release_Win32/TARGET_FILE_NAME",
269  project->project_root + "_build/_internal/paths/Release_x64/OUT_DIR",
270  project->project_root + "_build/_internal/paths/Release_x64/TARGET_FILE_NAME",
271  };
272 
273  for (int i = 0; i < 8; i++)
274  {
275  if (!BlamStrings::Utils::IO::FileExists(required_files[i]))
276  {
277  BlamStrings::Logger::LogEvent("cannot read detected vcxproj file paths: file "
278  "does not exist -- " + required_files[i], WSV_ERROR);
279  return false;
280  }
281  }
282 
283  vcx_library_paths[VC_DEBUG_WIN32] = BlamStrings::Utils::IO::GetFileContentsAsString(required_files[0]);
284  vcx_library_names[VC_DEBUG_WIN32] = BlamStrings::Utils::IO::GetFileContentsAsString(required_files[1]);
285 
286  vcx_library_paths[VC_DEBUG_WIN64] = BlamStrings::Utils::IO::GetFileContentsAsString(required_files[2]);
287  vcx_library_names[VC_DEBUG_WIN64] = BlamStrings::Utils::IO::GetFileContentsAsString(required_files[3]);
288 
289  vcx_library_paths[VC_RELEASE_WIN32] = BlamStrings::Utils::IO::GetFileContentsAsString(required_files[4]);
290  vcx_library_names[VC_RELEASE_WIN32] = BlamStrings::Utils::IO::GetFileContentsAsString(required_files[5]);
291 
292  vcx_library_paths[VC_RELEASE_WIN64] = BlamStrings::Utils::IO::GetFileContentsAsString(required_files[6]);
293  vcx_library_names[VC_RELEASE_WIN64] = BlamStrings::Utils::IO::GetFileContentsAsString(required_files[7]);
294 
295  for (int i = 0; i < 4; i++)
296  {
297  if (vcx_library_paths[i].ends_with(" \n"))
298  {
299  vcx_library_paths[i] = vcx_library_paths[i].substr(0, vcx_library_paths[i].length() - 2);
300  }
301 
302  if (vcx_library_names[i].ends_with(" \n"))
303  {
304  vcx_library_names[i] = vcx_library_names[i].substr(0, vcx_library_names[i].length() - 2);
305  }
306 
307  if (BlamStrings::Utils::List::Contains<std::string>(reserved_lib_names, vcx_library_names[i]))
308  {
309  BlamStrings::Logger::LogEvent("game script library name '" + vcx_library_names[i] + "' matches "
310  "an internal library used by blamite, this may cause build errors.", WSV_WARNING);
311  BlamStrings::Logger::LogEvent("you can resolve this by changing the target name in Visual Studio.", WSV_WARNING);
312  }
313  }
314 
315  return true;
316  }
317 };
VC_DEBUG_WIN64
#define VC_DEBUG_WIN64
Definition: GenerateGameStubProjectCommand.hpp:21
GenerateGameStubProjectCommand::execute
int execute(std::vector< std::string > args)
Executes the command.
Definition: GenerateGameStubProjectCommand.hpp:126
VC_RELEASE_WIN32
#define VC_RELEASE_WIN32
Definition: GenerateGameStubProjectCommand.hpp:22
VC_DEBUG_WIN32
#define VC_DEBUG_WIN32
Definition: GenerateGameStubProjectCommand.hpp:20
utils.h
GenerateGameStubProjectCommand::GenerateGameStubProjectCommand
GenerateGameStubProjectCommand()
Definition: GenerateGameStubProjectCommand.hpp:119
GenerateGameStubProjectCommand::IdentifyVcxprojInfo
bool IdentifyVcxprojInfo(std::string vcxproj_path, BlamProject *project)
Definition: GenerateGameStubProjectCommand.hpp:206
TOOL_LIB_API
#define TOOL_LIB_API
Definition: GenerateGameStubProjectCommand.hpp:17
VC_RELEASE_WIN64
#define VC_RELEASE_WIN64
Definition: GenerateGameStubProjectCommand.hpp:23
GenerateGameStubProjectCommand
Class for the generate-game-stub-project command.
Definition: GenerateGameStubProjectCommand.hpp:32
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