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>
10 #include "../ToolCommand.hpp"
11 #include "../console.h"
14 #ifdef TOOL_LIB_EXPORTS
15 #define TOOL_LIB_API __declspec(dllexport)
17 #define TOOL_LIB_API __declspec(dllimport)
20 #define VC_DEBUG_WIN32 0
21 #define VC_DEBUG_WIN64 1
22 #define VC_RELEASE_WIN32 2
23 #define VC_RELEASE_WIN64 3
35 std::vector<std::string> reserved_lib_names = {
45 std::string include_path_placeholders[4] = {
46 "{$__INCLUDE_DIRS_DW32__}",
47 "{$__INCLUDE_DIRS_DW64__}",
48 "{$__INCLUDE_DIRS_RW32__}",
49 "{$__INCLUDE_DIRS_RW64__}"
52 std::string lib_name_placeholders[4] = {
53 "{$__GAME_LIB_DW32__}",
54 "{$__GAME_LIB_DW64__}",
55 "{$__GAME_LIB_RW32__}",
56 "{$__GAME_LIB_RW64__}"
59 std::string lib_path_placeholders[4] = {
60 "{$__LIBRARY_DIRS_DW32__}",
61 "{$__LIBRARY_DIRS_DW64__}",
62 "{$__LIBRARY_DIRS_RW32__}",
63 "{$__LIBRARY_DIRS_RW64__}"
66 std::string dep_dir_placeholders[4] = {
67 "{$__DEP_DIR_DW32__}",
68 "{$__DEP_DIR_DW64__}",
69 "{$__DEP_DIR_RW32__}",
73 std::string engine_lib_dir_suffixes[4] = {
76 "cache release/Win32",
80 std::string vcx_library_paths[4] = {
"",
"",
"",
"" };
81 std::string vcx_library_names[4] = {
"",
"",
"",
"" };
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__}";
88 bool no_msbuild_warning =
false;
89 bool skip_path_gen =
false;
91 std::vector<std::string> PreprocessArgs(std::vector<std::string> args)
93 std::vector<std::string> processed_args = std::vector<std::string>();
95 for (
int i = 0; i < args.size(); i++)
97 if (args[i] ==
"-verbose")
101 else if (args[i] ==
"-no-msbuild-warning")
103 no_msbuild_warning =
true;
105 else if (args[i] ==
"-skip-path-gen")
107 skip_path_gen =
true;
111 processed_args.push_back(args[i]);
115 return processed_args;
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";
128 args = PreprocessArgs(args);
131 std::string project_filename = BlamStrings::Utils::IO::GetFileNameWithoutExtension(project_root) +
".blam";
135 project_filename = args[0];
138 BlamProject* project = Guerilla::Projects::LoadProject(project_root + project_filename);
140 if (!project->IsLoaded())
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);
145 if (args.size() == 0)
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);
155 std::string source_path =
"./content/blam/default_stub_project";
156 std::string destination_path = project_root +
"_build/_internal/game";
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());
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);
171 if (!IdentifyVcxprojInfo(project->GetVcxprojPath(), project))
173 BlamStrings::Logger::LogEvent(
"failed to read data from vcxproj - see log for details", WSV_ERROR);
178 if (verbose) BlamStrings::Logger::LogEvent(
"configuring vcxproj: " + destination_path +
"/game.vcxproj");
180 std::string vcxproj_file_contents = BlamStrings::Utils::IO::GetFileContentsAsString(destination_path +
"/game.vcxproj");
182 for (
int i = 0; i < 4; i++)
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);
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");
195 vcxproj_file_contents = str_replace(vcxproj_file_contents, delay_load_dlls_placeholder, delay_load_dlls);
197 BlamStrings::Utils::IO::CreateNewFile(destination_path +
"/game.vcxproj", vcxproj_file_contents);
199 if (verbose) BlamStrings::Logger::LogEvent(
"game project generated to " + destination_path);
200 BlamStrings::Logger::LogEvent(
"finished");
208 std::string library_file_name = BlamStrings::Utils::IO::GetFileNameWithoutExtension(vcxproj_path);
210 for (
int i = 0; i < 4; i++)
212 vcx_library_names[i] = library_file_name +
".lib";
215 if (!no_msbuild_warning)
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);
228 std::string msbuild_path_base =
"\"" + project->GetMSBuildPath() +
"\" \"" + vcxproj_path +
"\" ";
230 if (!BlamStrings::Utils::IO::IsDirectory(project->project_root +
"_build/_internal/paths/Debug_x64") || !skip_path_gen)
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);
238 if (!BlamStrings::Utils::IO::IsDirectory(project->project_root +
"_build/_internal/paths/Debug_Win32") || !skip_path_gen)
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);
246 if (!BlamStrings::Utils::IO::IsDirectory(project->project_root +
"_build/_internal/paths/Release_x64") || !skip_path_gen)
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);
254 if (!BlamStrings::Utils::IO::IsDirectory(project->project_root +
"_build/_internal/paths/Release_Win32") || !skip_path_gen)
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);
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",
273 for (
int i = 0; i < 8; i++)
275 if (!BlamStrings::Utils::IO::FileExists(required_files[i]))
277 BlamStrings::Logger::LogEvent(
"cannot read detected vcxproj file paths: file "
278 "does not exist -- " + required_files[i], WSV_ERROR);
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]);
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]);
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]);
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]);
295 for (
int i = 0; i < 4; i++)
297 if (vcx_library_paths[i].ends_with(
" \n"))
299 vcx_library_paths[i] = vcx_library_paths[i].substr(0, vcx_library_paths[i].length() - 2);
302 if (vcx_library_names[i].ends_with(
" \n"))
304 vcx_library_names[i] = vcx_library_names[i].substr(0, vcx_library_names[i].length() - 2);
307 if (BlamStrings::Utils::List::Contains<std::string>(reserved_lib_names, vcx_library_names[i]))
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);