From 006dc256ca772ed837496f81b55d15038924b679 Mon Sep 17 00:00:00 2001 From: Iridar Date: Wed, 17 Nov 2021 11:13:00 +0300 Subject: [PATCH] Squashed '.scripts/X2ModBuildCommon/' content from commit c7e3945 git-subtree-dir: .scripts/X2ModBuildCommon git-subtree-split: c7e3945067903304bf74599b763675ffecd43f79 --- CHANGELOG.md | 26 + EmptyUMap | Bin 0 -> 5204 bytes InvokePowershellTask.cs | 122 ++++ LICENSE | 21 + README.md | 383 +++++++++++ XCOM2.targets | 92 +++ build_common.ps1 | 1384 +++++++++++++++++++++++++++++++++++++++ clean.ps1 | 41 ++ junction.exe | Bin 0 -> 216736 bytes 9 files changed, 2069 insertions(+) create mode 100644 CHANGELOG.md create mode 100644 EmptyUMap create mode 100644 InvokePowershellTask.cs create mode 100644 LICENSE create mode 100644 README.md create mode 100644 XCOM2.targets create mode 100644 build_common.ps1 create mode 100644 clean.ps1 create mode 100644 junction.exe diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..a53fdb6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,26 @@ +## Next + +## 1.1.1 (2021-08-11) + +* Support Rebuild ModBuddy target +* Internal improvements and fixes to asset cooking functionality +* Support projects with spaces in path (#55) +* Fix cryptic error about `SteamPublishID` for some projects (#56) +* Fail the build in case cooking cleanup fails, preventing silent SDK corruption (#54) +* Properly rewrite error messages originating from `IncludeSrc`-ed files (#45) + + +## 1.1.0 (2021-06-15) + +* Remove compiled script packages when switching between debug and release mode to prevent compiler error (#16) +* Remove compiled script packages when modifying macros (#20) +* Overridden Steam UGC IDs can now be `long` (`int64`) (#22) +* Use error syntax `file(line)` for compiler errors to be compatible with both ModBuddy and VS Code (#26) +* Add a `clean.ps1` script, ModBuddy configuration and VS Code example task to remove all cached build artifacts (#24) +* Remove project file verification. Consider using [Xymanek/X2ProjectGenerator](https://github.com/Xymanek/X2ProjectGenerator) instead (#28) +* Catch macro name clashes through `extra_globals.uci` (#30) +* Add debugging option to profile build times (#35) + +## 1.0.0 (2021-05-22) + +* Initial release diff --git a/EmptyUMap b/EmptyUMap new file mode 100644 index 0000000000000000000000000000000000000000..0cf3c476824dbee4450e9828afa9f0bf3a5ca706 GIT binary patch literal 5204 zcmcJROK;p%6o8$irRCYsQl5pjG>B3PLV^_th%y0M)TE=PgbIWrXU3fvJa+JS3e#0k zB`P7hKrFhTf*pSVHf*R+cI=SK;~$g-8=j>t5YA`cW8d*ODGPF>>+`(lb908RY@L+4RC( zb~Cbrp`Z9};GguGeTs=F3hHsR=!w5vA=x_{M5qOBr^tL8k|+rLjvs}CQMRY*_M#gnZK?Q(-}0LiQM1UIv#3Q@h*Z#> zFJe-|q<7ry2Fcu9e|gkkR8wx^#nLH}I1Z^2+34yEy^i1L%tk@CUHGNvlfBSw`wjM_ zn>Go4E^PTS8!943Cejc^@wDTR+w~ z7><%r5#<(9PKo{8jQ3{O3mZjljHhNLWL5(yOhrvA1&(vtZF>U)vk?Us0ibF0`tbbg zULzT>rCoKm@rK(f%;`uf_-z#e3bkH7~X?UR~W*gj{8~E*R z;3hI%6>g}t9tFL^F}2oXzwO4o)U~k1JRI>B1GnKZiP*^1I#CouGY2|+JHjNE;cCgf z4Fc(mWHMJfh}*nnV$rQ=nY=}uqi!oVCBo4K@8u{C`fu~B-+3X9x{H%;;^x-W)^B=) zN)Cp{quh?!IVLx+(g{j{RDfSrR#s>cpgN`i5Y-An0p4Z+rw*`BeN^exN0pAD0;+Vk zWvWUYHwUQNr!U$n-2>US%6$*7q1(TP?h&KYp51BqpQSI{Pe60IH)GSM+E?kgA;90_ z13V&&9&4YG4LMH?|0uZpB|>MzU&aStB+i0!`zM!ea6T3OBJ;BbTru{H>3t=;A$d8x zBF@ifAtk-CmyHj2yAF7KoD+QUCb-o>eb5hPKxc~`>f@9SF~SP?)5?Qcp(X`<)Fru{ zdT^>JVf8^C_|Ut689tbSNDmQV1za+D;Ny;x9v`&g^fi3^Vb$_bg^%||_Te>r{BGsJ zoZDw3c?|ECv)#F^(|x93>* z@NR;}jt@07vR`E{_Q(Ke{D5^_xnnHA7kT!!18XOCzz8T0*2ydDh>UlDNR=?4*lW!A zv;jI#8d2L{*6VfA8LrCap3G(XBs29{wnaW>Y|A>teD8nYQRXj6L%!hnTP1%z_sLLTBL0`$-Q#Wj4ksBaaOpIC^N-RiU*E zVe>;qr$>TZD}vS|z-Bf0V8dqH?P_N0E2nVnY$;Mr_;h{$*=sc|Nb$Ha*16H|oATT< zr4?&Km8W@Q#?OVBPqsW$`)T@1f9A>$V^?29jNK}^nOzyuoD`26t=`6RZcL2kpjZz| zd0dPcKl3{doZb4lclcfByRR>7KeGohzBM;$)g|O|v6jvYZNbvB79-@+c@xjtlkcbZ z$iX(f?3nM6#^-&eAhr`D@+csWIiAVjv!(k*u5rKux+ld;sVIN+<*a$>e)y`j9yx0q ziLLo+k^_C$K3jVR@)SS040^qC&U~k-YMv=x5)sQl-e+>wJxVJ^Zqw_Lv&JBffoy)1 z%W!rE);wcx=VtRtXLx<)d0FDK4AA51Ik9rqJ>Z%w#Ws!XfA2Hz59>Y(m;Imcu2MPg zOQlCJSQAc?^D6M)b+htS%$@z0izXkrRb{d`jExc#=T?X$d v>317mG2H;l)emV~_;v#tKsPGBrUP}9xfzV)>@}M5PuG4UR|m91X?6B5_ke79 literal 0 HcmV?d00001 diff --git a/InvokePowershellTask.cs b/InvokePowershellTask.cs new file mode 100644 index 0000000..2717a45 --- /dev/null +++ b/InvokePowershellTask.cs @@ -0,0 +1,122 @@ +using System; +using System.IO; +using System.Threading; +using System.Management.Automation; + +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +public class InvokePowershellTask : Task, ICancelableTask +{ + [Required] public string EntryPs1 { get; set; } + [Required] public string SolutionRoot { get; set; } + [Required] public string SdkInstallPath { get; set; } + [Required] public string GameInstallPath { get; set; } + [Required] public ITaskItem[] AdditionalArgs { get; set; } + + private PowerShell _ps; + + private ManualResetEventSlim _startingMre = new ManualResetEventSlim(false); + + public override bool Execute() + { + bool isSuccess = false; + + try + { + _ps = PowerShell.Create(); + + _ps + .AddCommand("Set-ExecutionPolicy") + .AddArgument("Unrestricted") + .AddParameter("Scope","CurrentUser"); + + _ps + .AddStatement() + .AddCommand(EntryPs1) + .AddParameter("srcDirectory", TrimEndingDirectorySeparator(SolutionRoot)) + .AddParameter("sdkPath", TrimEndingDirectorySeparator(SdkInstallPath)) + .AddParameter("gamePath", TrimEndingDirectorySeparator(GameInstallPath)); + + foreach (ITaskItem Arg in AdditionalArgs) + { + string Val = Arg.GetMetadata("Value"); + if (string.IsNullOrEmpty(Val)) + { + _ps.AddParameter(Arg.ItemSpec); + } + else + { + _ps.AddParameter(Arg.ItemSpec, Val); + } + } + + BindStreamEntryCallback(_ps.Streams.Debug, record => LogOutput(record.ToString())); + BindStreamEntryCallback(_ps.Streams.Information, record => LogOutput(record.ToString())); + BindStreamEntryCallback(_ps.Streams.Verbose, record => LogOutput(record.ToString())); + BindStreamEntryCallback(_ps.Streams.Warning, record => LogOutput(record.ToString())); // TODO: More flashy output? + + BindStreamEntryCallback(_ps.Streams.Error, record => + { + // TODO: Less info than when from console + // TODO: More flashy output? + LogOutput(record.ToString()); + Log.LogError(record.ToString()); + isSuccess = false; + }); + + _ps.InvocationStateChanged += (sender, args) => + { + if (args.InvocationStateInfo.State == PSInvocationState.Running) + { + _startingMre.Set(); + } + }; + + isSuccess = true; + _ps.Invoke(); + } + catch (System.Exception e) + { + Log.LogError(e.Message); + isSuccess = false; + } + + return isSuccess; + } + + public void Cancel() + { + // Log.LogMessage(MessageImportance.High, "Got cancel"); + + // Do not call Stop() until we know that we've actually started + // This could be more elaborate, but the time interval between Execute() and Invoke() being called is extremely small + + _startingMre.Wait(); + _ps.Stop(); + } + + private void LogOutput (string output) + { + // This is required to keep the empty lines in the output + if (string.IsNullOrEmpty(output)) output = " "; + + Log.LogMessage(MessageImportance.High, output); + } + + private static readonly char[] DirectorySeparatorsForTrimming = new char[] + { + Path.DirectorySeparatorChar, + Path.AltDirectorySeparatorChar + }; + + private static string TrimEndingDirectorySeparator(string path) + { + return path.TrimEnd(DirectorySeparatorsForTrimming); + } + + private static void BindStreamEntryCallback(PSDataCollection stream, Action handler) + { + stream.DataAdded += (object sender, DataAddedEventArgs e) => handler(stream[e.Index]); + } +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..cacdc4d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 X2CommunityCore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..40b12b3 --- /dev/null +++ b/README.md @@ -0,0 +1,383 @@ +# X2ModBuildCommon +An improved XCOM 2 mod build system. The following (in no praticular order) are its features/improvements over the default one: + +* Path rewriting for script errors/warnings so that they no longer point to the temporary copies of files in SDK/Developement/Src +* Automated including of compile-time dependencies (including CHL) so that you no longer need to pollute your SrcOrig with them +* Caching of `ModShaderCache` and invoking the shader precompiler only when the mod content files have changed +* Proper cancelling of the build mid-way (instead of waiting until it completes) +* Configurable mod workshop ID +* Automated including of SDK's content packages (for those which are missing in the cooked game) so that you don't need to store them in your project +* Full HL building: final release compiling and cooking of native script packages +* Scriptable hooks in the build process +* Conversion of localization file(s) encoding (UTF8 in the project for correct git merging and UTF16 for correct game loading) +* Mod asset cooking (experimental) +* Correct removal of files from the steamapps/XCOM2/WOTC/XComGame/Mods (built mod) when they are deleted from the project +* Mod-defined global macros (without explicit `include`s and without messing with your `SrcOrig`) +* Most features are configurable! + +# Getting started +Foreword: the build system was designed to be flexible in how you want to set it up. This section describes +the most common/basic setup that should work for 95% of mods out there. If you want to customize it, read the next section + +## Getting the files +First, create a `.scripts` folder in the root of your mod project (next to the `.XCOM_sln` file) - from now on referred +to as `[modRoot]`. The next step depends on whether you are using git or not. Git is preferable but the build system +will work just fine without it. + +### Your mod uses git +Open a command line prompt (cmd or powershell, does not matter) in the `[modRoot]`. Ensure that +your working tree is clean and run the following command: + +``` +git subtree add --prefix .scripts/X2ModBuildCommon https://github.com/X2CommunityCore/X2ModBuildCommon v1.1.1 --squash +``` + +### Your mod does not use git +Download the source code of this repository from the latest release on the [Releases page](https://github.com/X2CommunityCore/X2ModBuildCommon/releases/latest). +Unzip it and place so that `build_common.ps1` resides at `[modRoot]\.scripts\X2ModBuildCommon\build_common.ps1`. + +## Ignoring the `BuildCache` +The build system will create a `[modRoot]\BuildCache` folder which is used for various file-based operations (such +as recompiling the `ModShaderCache` only when mod's content has changed). This folder is fully managed by the build +system and normally you should never open it. It is also safe to delete at any time (e.g. if you want to +force a full rebuild). + +As such, this folder is not meant to be shared with other developers working on the project or stored in +backups/previous versions (e.g. when using a VCS) - this can lead to incorrect behaviour. + +If you are using git, you should add it (`BuildCache/`) to your `.gitignore` + +## Setting up the build entrypoint +Create `[modRoot]\.scripts\build.ps1` with the following content: + +```ps1 +Param( + [string] $srcDirectory, # the path that contains your mod's .XCOM_sln + [string] $sdkPath, # the path to your SDK installation ending in "XCOM 2 War of the Chosen SDK" + [string] $gamePath, # the path to your XCOM 2 installation ending in "XCOM2-WaroftheChosen" + [string] $config # build configuration +) + +$ScriptDirectory = Split-Path $MyInvocation.MyCommand.Path +$common = Join-Path -Path $ScriptDirectory "X2ModBuildCommon\build_common.ps1" +Write-Host "Sourcing $common" +. ($common) + +$builder = [BuildProject]::new("YourProjectName", $srcDirectory, $sdkPath, $gamePath) + +switch ($config) +{ + "debug" { + $builder.EnableDebug() + } + "default" { + # Nothing special + } + "" { ThrowFailure "Missing build configuration" } + default { ThrowFailure "Unknown build configuration $config" } +} + +$builder.InvokeBuild() +``` + +Replace `YourProjectName` with the mod project name (e.g. the name of your `.XCOM_sln` file without the extension). + +If you're transitioning an existing mod to X2ModBuildCommon, this advice might come too late, but we recommend that +the project name contain only ASCII alphabetic characters, numbers and underscores (matching the regular expression `^[A-Za-z][A-Za-z0-9_]*$`). +The ModBuddy project generator lets you create projects with a large variety of characters that will break the ModBuddy +build already (like brackets and dashes), but spaces and semicolons are allowed and work fine with the Firaxis ModBuddy plugin. +`X2ModBuildCommon` will do its best to support project names with spaces, but it's historically been a common source of bugs +and you may run into fewer of them if you keep your mod name simple. + +## IDE integration +At this point your mod is actually ready for building but invoking the powershell script with all the arguments each time manually +is not convinient. Instead, we would like it to be invoked automatically when we press the build button in our IDE + +### ModBuddy +Close Modbuddy (or at least the solution) if you have it open. Open your `.x2proj` (in something like notepad++) and find the follwing line: + +```xml + +``` + +Replace it with following: + +```xml + + $(MSBuildProjectDirectory)\..\ + $(SolutionRoot).scripts\ + $(ScriptsDir)X2ModBuildCommon\ + + +``` + +Note that the build tool does not care about most of the `.x2proj` file and will +copy and compile files not referenced by the project file without issuing warnings. +Consider using a tool like [Xymanek/X2ProjectGenerator](https://github.com/Xymanek/X2ProjectGenerator) +to automatically ensure the file list in ModBuddy accurately lists the files part of the project. + + +### VSCode + +> FIXME(#1): Rename variables to remove HL references? + +First, you need to tell Visual Studio code where to find the game and SDK (similar to the first-time ModBuddy setup). +To do that, open the "Settings (JSON)" file by using the "Ctrl+Shift+P" shortcut and running "Preferences: Open Settings (JSON)" +or by clicking "File->Preferences->Settings" and clicking the "Open Settings (JSON)" button on the tab bar. Add the following +two entries, adjusting paths as necessary. + +```json + "xcom.highlander.sdkroot": "d:\\Steam\\SteamApps\\common\\XCOM 2 War of the Chosen SDK", + "xcom.highlander.gameroot": "d:\\Steam\\SteamApps\\common\\XCOM 2\\XCom2-WarOfTheChosen" +``` + +VS Code may tell you that the configuration settings are unknown. This is acceptable and can be ignored. + +Next up, you have to tell VS code about your build tasks. Create a folder `.vscode` next to the `.scripts` folder, +and within it create a `tasks.json` file with the following content (replacing `MY_MOD_NAME` with the mod project +name in the "Clean" task): + +```json +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build", + "type": "shell", + "command": "powershell.exe –NonInteractive –ExecutionPolicy Unrestricted -file '${workspaceRoot}\\.scripts\\build.ps1' -srcDirectory '${workspaceRoot}' -sdkPath '${config:xcom.highlander.sdkroot}' -gamePath '${config:xcom.highlander.gameroot}' -config 'default'", + "group": "build", + "problemMatcher": [] + }, + { + "label": "Build debug", + "type": "shell", + "command": "powershell.exe –NonInteractive –ExecutionPolicy Unrestricted -file '${workspaceRoot}\\.scripts\\build.ps1' -srcDirectory '${workspaceRoot}' -sdkPath '${config:xcom.highlander.sdkroot}' -gamePath '${config:xcom.highlander.gameroot}' -config 'debug'", + "group": "build", + "problemMatcher": [] + }, + { + "label": "Clean", + "type": "shell", + "command": "powershell.exe –NonInteractive –ExecutionPolicy Unrestricted -file '${workspaceRoot}\\.scripts\\clean.ps1' -modName 'MY_MOD_NAME' -srcDirectory '${workspaceRoot}' -sdkPath '${config:xcom.highlander.sdkroot}' -gamePath '${config:xcom.highlander.gameroot}'", + "group": "build", + "problemMatcher": [] + }, + { + "label": "Full rebuild", + "dependsOrder": "sequence", + "dependsOn": ["Clean", "Build"] + } + ] +} +``` + +Note that the `-config 'debug'` or `-config 'default'` build configurations correspond to +the build configurations in the `build.ps1` entry point created earlier. You can easily add +existing build tasks with custom configurations by modifying `build.ps1` and configuring the +`$builder` (see just below!) + +> FIXME(microsoft/vscode#24865): Add problem matchers when they can be shared between tasks. + +## Ready! +You can now successfully build your mod from your IDE using X2ModBuildCommon. Keep reading on to find about what you can configure. + +## Updating +The build system is desinged to be version-pinned against your mod - you can continue using the old version as long as it suits your needs, even if a new one is released. If you would like to get the new features/improvements/bugfixes of the new version, the update procedure is simple. + +If you don't use git, simply download the new version and overwrite the old files inside the `X2ModBuildCommon` folder. + +If you use git, run the same command as before, replacing `add` with `pull`: + +``` +git subtree pull --prefix .scripts/X2ModBuildCommon https://github.com/X2CommunityCore/X2ModBuildCommon v1.1.1 --squash +``` + +# Configuration options + +All the following examples are modifications that could be made to your `build.ps1`. + +## ThrowFailure + +> FIXME: `ThrowFailure` vs `FailureMessage`? + +Throw a failure. Example usage: + +```ps1 +switch ($config) { + # ... + "" { ThrowFailure "Missing build configuration" } +} +``` + +## SetWorkshopID + +Override the workshop ID from the x2proj file. Example usage: + +```ps1 +# make sure beta builds are never uploaded to the stable workshop page +if ($config -eq "stable") { + $builder.SetWorkshopID(1234567890) +} +else { + $builder.SetWorkshopID(6789012345) +} +``` + +## EnableFinalRelease + +Pass the `-final_release` flag to the compiler for base-game script packages and the Highlander cooker. +Can only be used for Highlander-style mods that modify native packages. Example usage: + +```ps1 +switch ($config) { + # ... + "final_release" { + $builder.EnableFinalRelease() + } + "stable" { + $builder.EnableFinalRelease() + } +} +``` + +## EnableDebug + +Pass the `-debug` flag to all script compiler invocations. Incompatible with `EnableFinalRelease`, and will skip +Highlander cooking process (accordingly you have to use `-noseekfreeloading` when launching the game). Example usage: + +```ps1 +switch ($config) { + # ... + "debug" { + $builder.EnableDebug() + } +} +``` + +## AddPreMakeHook + +Add a callback to be executed after all script sources have been added to `Src` but before the compiler is run. +Example usage: + +```ps1 +# Checks if a certain automatically generated file actually compiles, but only with the "compiletest" configuration +if ($compiletest) { + $builder.AddPreMakeHook({ + Write-Host "Including CHL_Event_Compiletest" + # n.b. this copies from the `target` directory where it is generated into, see tasks.json + Copy-Item "..\target\CHL_Event_Compiletest.uc" "$sdkPath\Development\Src\X2WOTCCommunityHighlander\Classes\" -Force -WarningAction SilentlyContinue + }) +} +``` + +The Highlander also uses it to embed the current git commit hash in some source files. + +## IncludeSrc + +Add dependencies' source files to `Src`. This removes the step where mods whose sources you want to have available +have to be copied to `SrcOrig`. Example usage (from Covert Infiltration): + +``` +$builder.IncludeSrc("$srcDirectory\X2WOTCCommunityHighlander\X2WOTCCommunityHighlander\Src") +$builder.IncludeSrc("$srcDirectory\X2WOTCCommunityHighlander\Components\DLC2CommunityHighlander\DLC2CommunityHighlander\Src") +$builder.IncludeSrc("$srcDirectory\SquadSelectAnyTime\SquadSelectAtAnyTime\Src") +``` + +## AddToClean + +Deletes certain built mods from `SDK/XComGame/Mods`. Usually necessary for dependencies since their script compiler configuration +files can cause the script compiler to choke. Covert Infiltration does this: + +```ps1 +$builder.AddToClean("SquadSelectAtAnyTime") +``` + +## Content options + +You can provide a "content options" file that will determine some additional content-related steps. This file should be checked +in to your VSC (e.g. tracked by git) and must reside next to your `.x2proj` (note that the file will not be included in the +final built mod). If using Modbuddy, you can add the file to the project for easier editing. + +Assuming the file is named `ContentOptions.json`: + +```ps1 +$builder.SetContentOptionsJsonFilename("ContentOptions.json") +``` + +Four options are available: `missingUncooked`, `sfStandalone`, `sfMaps`, `sfCollectionMaps`. Omitting an option (or the file entirely) +is treated the same as setting it to an empty array + +### Including missing uncooked + +In case your mod depends on some assets that were not shipped in a seek free package, you can automatically include it with your mod. +Example from Covert Infiltration: + +```json +{ + "missingUncooked": [ + "CIN_TroopTransport.upk", + "PCP_Archetypes_XPACK.upk" + ] +} +``` + +**IMPORTANT**: you need to be on the `full_content` branch of the SDK for this to work. + +### Asset cooking + +The rest of the options are for the mod assets cooking. Because it is such a complex process, the package and map configuration is +described in a separate file. See [Asset Cooking](https://github.com/X2CommunityCore/X2ModBuildCommon/wiki/Asset-cooking) for details. + +# Additional features + +## extra_globals + +This isn't a configuration option, but mods can create an `extra_globals.uci` file in the +`Src` folder to have the build tool append its contents to `Globals.uci`. This allows mods +to use custom macros. + +Moreover, the `extra_globals.uci` files of any dependencies added via `IncludeSrc` will be merged into `Globals.uci` too. This allows dependency mods to safely use custom macros +without causing compilation problems for dependent mods. + +## Localization Encoding + +Any files in the `Localization` folder will have its encoding rewritten from UTF-8 to UTF-16. This allows tracking +localization files in the git-compatible UTF-8 text encoding even though the game only supports ASCII and UTF-16. + +# ModBuddy project customization + +You can customize your `.x2proj` using the following properties: + +Property | Default value | Notes +-------- | ------------- | ----- +`SolutionRoot` | None (**required**) | The path to folder which houses your `.XCOM_sln` file +`ScriptsDir` | None | Required if you don't set `BuildEntryPs1`. Ignored otherwise +`BuildCommonRoot` | None (**required**) | The path to folder which houses the `InvokePowershellBuild.cs` file +`BuildEntryFileName` | `build.ps1` | Required if you don't set `BuildEntryPs1`. Ignored otherwise +`BuildEntryPs1` | `$(ScriptsDir)$(BuildEntryFileName)` | +`BuildEntryConfig` | `default` or `debug` | Will be passed to your build entrypoint. Default is derived from `$(Configuration)` (build configuration dropdown) + +Hint: if you want to add other build configurations, you can let the `default` and `debug` ones be handeled +by the provided `XCOM2.targets`. Example from CHL: + +```xml + + $(MSBuildProjectDirectory)\..\ + $(SolutionRoot).scripts\ + $(ScriptsDir)X2ModBuildCommon\ + + + final_release + compiletest + stable + +``` + +# Things to watch out for + +Note that you can always check the issue tracker: https://github.com/X2CommunityCore/X2ModBuildCommon/issues?q=is%3Aissue+is%3Aopen+label%3Abug + +## Deleting content files + +If you **delete** content files (e.g. moved to a different mod or just completely removed) the current caching logic (e.g. for the +shader cache) might not recognize it. As such, it's recommended that you simply delete the `BuildCache` folder in such cases. diff --git a/XCOM2.targets b/XCOM2.targets new file mode 100644 index 0000000..b3d0bd6 --- /dev/null +++ b/XCOM2.targets @@ -0,0 +1,92 @@ + + + + + Program + $(XCOM2_GamePath)\..\Binaries\Win64\Launcher\StartDebugging.bat + + + . + + + . + + + . + + + $(MSBuildProjectDirectory) + $(XCOM2_UserPath)\Mods\ + $(ModsDir)$(SafeName)\ + + + + + + + + + + build.ps1 + $(ScriptsDir)$(BuildEntryFileName) + + + + + default + debug + + + + + + + $(SafeName) + + + + + + + + + + + + + + + $(BuildEntryConfig) + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build_common.ps1 b/build_common.ps1 new file mode 100644 index 0000000..95f9756 --- /dev/null +++ b/build_common.ps1 @@ -0,0 +1,1384 @@ +Write-Host "Build Common Loading" + +$ErrorActionPreference = "Stop" +Set-StrictMode -Version 3.0 + +$global:def_robocopy_args = @("/S", "/E", "/COPY:DAT", "/PURGE", "/MIR", "/NP", "/R:1000000", "/W:30") +$global:buildCommonSelfPath = split-path -parent $MyInvocation.MyCommand.Definition +# list of all native script packages +$global:nativescriptpackages = @("XComGame", "Core", "Engine", "GFxUI", "AkAudio", "GameFramework", "UnrealEd", "GFxUIEditor", "IpDrv", "OnlineSubsystemPC", "OnlineSubsystemLive", "OnlineSubsystemSteamworks", "OnlineSubsystemPSN") + +$global:invarCulture = [System.Globalization.CultureInfo]::InvariantCulture + +class BuildProject { + [string] $modNameCanonical + [string] $modNameFull + [string] $projectRoot + [string] $sdkPath + [string] $gamePath + [string] $finalModPath + [string] $contentOptionsJsonFilename + [long] $publishID = -1 + [bool] $debug = $false + [bool] $final_release = $false + [string[]] $include = @() + [string[]] $clean = @() + [object[]] $preMakeHooks = @() + + # internals + [hashtable] $macroDefs = @{} + [object[]] $timings = @() + + # lazily set + [string] $modSrcRoot + [string] $modX2projPath + [string] $devSrcRoot + [string] $stagingPath + [string] $xcomModPath + [string] $commandletHostPath + [string] $buildCachePath + [string] $modcookdir + [string] $makeFingerprintsPath + [string[]] $thismodpackages + [bool] $isHl + [bool] $cookHL + [PSCustomObject] $contentOptions + + BuildProject( + [string]$mod, + [string]$projectRoot, + [string]$sdkPath, + [string]$gamePath + ){ + $this.modNameFull = $mod + $this.modNameCanonical = $mod -Replace '[\s;]','' + $this.projectRoot = $projectRoot + $this.sdkPath = $sdkPath + $this.gamePath = $gamePath + } + + [void]SetContentOptionsJsonFilename($filename) { + $this.contentOptionsJsonFilename = $filename + } + + [void]SetWorkshopID([long] $publishID) { + if ($publishID -le 0) { ThrowFailure "publishID must be >0" } + $this.publishID = $publishID + } + + [void]EnableFinalRelease() { + $this.final_release = $true + $this._CheckFlags() + } + + [void]EnableDebug() { + $this.debug = $true + $this._CheckFlags() + } + + [void]AddPreMakeHook([Action[]] $action) { + $this.preMakeHooks += $action + } + + [void]AddToClean([string] $modName) { + $this.clean += $modName + } + + [void]IncludeSrc([string] $src) { + if (!(Test-Path $src)) { ThrowFailure "include path $src doesn't exist" } + $this.include += $src + } + + [void]InvokeBuild() { + try { + $fullStopwatch = [Diagnostics.Stopwatch]::StartNew() + $this._ConfirmPaths() + $this._SetupUtils() + $this._LoadContentOptions() + $this._PerformStep({ ($_)._CleanAdditional() }, "Cleaning", "Cleaned", "additional mods") + $this._PerformStep({ ($_)._CopyModToSdk() }, "Mirroring", "Mirrored", "mod to SDK") + $this._PerformStep({ ($_)._ConvertLocalization() }, "Converting", "Converted", "Localization UTF-8 -> UTF-16") + $this._PerformStep({ ($_)._CopyToSrc() }, "Populating", "Populated", "Development\Src folder") + $this._PerformStep({ ($_)._RunPreMakeHooks() }, "Running", "Ran", "Pre-Make hooks") + $this._PerformStep({ ($_)._CheckCleanCompiled() }, "Verifying", "Verified", "compiled script packages") + $this._PerformStep({ ($_)._RunMakeBase() }, "Compiling", "Compiled", "base-game script packages") + $this._PerformStep({ ($_)._RunMakeMod() }, "Compiling", "Compiled", "mod script packages") + $this._RecordCoreTimestamp() + if ($this.isHl) { + if (-not $this.debug) { + $this._PerformStep({ ($_)._RunCookHL() }, "Cooking", "Cooked", "Highlander packages") + } else { + Write-Host "Skipping cooking as debug build" + } + } + $this._PerformStep({ ($_)._CopyScriptPackages() }, "Copying", "Copied", "compiled script packages") + + # The shader step needs to happen before cooking - precompiler gets confused by some inlined materials + $this._PerformStep({ ($_)._PrecompileShaders() }, "Precompiling", "Precompiled", "shaders") + + $this._PerformStep({ ($_)._RunCookAssets() }, "Cooking", "Cooked", "mod assets") + + # Do this last as there is no need for it earlier - the cooker obviously has access to the game assets + # and precompiling shaders seems to do nothing (I assume they are included in the game's GlobalShaderCache) + $this._PerformStep({ ($_)._CopyMissingUncooked() }, "Copying", "Copied", "requested uncooked packages") + + $this._PerformStep({ ($_)._FinalCopy() }, "Copying", "Copied", "built mod to game directory") + $fullStopwatch.Stop() + $this._ReportTimings($fullStopwatch) + SuccessMessage "*** SUCCESS! ($(FormatElapsed $fullStopwatch.Elapsed)) ***" $this.modNameCanonical + } + catch { + [System.Media.SystemSounds]::Hand.Play() + throw + } + } + + [void]_PerformStep([scriptblock]$stepCallback, [string]$progressWord, [string]$completedWord, [string]$description) { + Write-Host "$($progressWord) $($description)..." + $sw = [Diagnostics.Stopwatch]::StartNew() + + # HACK: Set $_ for $stepCallback with Foreach-Object on only one object + $this | ForEach-Object $stepCallback + + $sw.Stop() + + $record = [PSCustomObject]@{ + Description = "$($progressWord) $($description)" + Seconds = $sw.Elapsed.TotalSeconds + } + + $this.timings += $record + + Write-Host -ForegroundColor DarkGreen "$($completedWord) $($description) in $(FormatElapsed $sw.Elapsed)" + } + + [void]_ReportTimings([Diagnostics.Stopwatch]$fullStopwatch) { + if (-not [string]::IsNullOrEmpty($env:X2MBC_REPORT_TIMINGS)) { + $fullTime = $fullStopwatch.Elapsed.TotalSeconds + $accountedTime = $this.timings | Measure-Object -Sum -Property Seconds | Select-Object -ExpandProperty Sum + $this.timings += [PSCustomObject]@{ + Description = "Total Duration" + Seconds = $fullTime + } + $this.timings += [PSCustomObject]@{ + Description = "Unaccounted time" + Seconds = $fullTime - $accountedTime + } + + $this.timings | Sort-Object -Descending -Property { $_.Seconds } | ForEach-Object { + $_ | Add-Member -NotePropertyName "Share" -NotePropertyValue ($_.Seconds / $fullTime).ToString("0.00%", $global:invarCulture) + $_.Seconds = $_.Seconds.ToString("0.00s", $global:invarCulture) + $_ + } | Format-Table | Out-String | Write-Host + } + } + + [void]_CheckFlags() { + if ($this.debug -eq $true -and $this.final_release -eq $true) + { + ThrowFailure "-debug and -final_release cannot be used together" + } + } + + [void]_ConfirmPaths() { + Write-Host "SDK Path: $($this.sdkPath)" + Write-Host "Game Path: $($this.gamePath)" + + # Check if the user config is set up correctly + if (([string]::IsNullOrEmpty($this.sdkPath) -or $this.sdkPath -eq '${config:xcom.highlander.sdkroot}') -or ([string]::IsNullOrEmpty($this.gamePath) -or $this.gamePath -eq '${config:xcom.highlander.gameroot}')) + { + ThrowFailure "Please set up user config xcom.highlander.sdkroot and xcom.highlander.gameroot" + } + elseif (!(Test-Path $this.sdkPath)) # Verify the SDK and game paths exist before proceeding + { + ThrowFailure ("The path '{}' doesn't exist. Please adjust the xcom.highlander.sdkroot variable in your user config and retry." -f $this.sdkPath) + } + elseif (!(Test-Path $this.gamePath)) + { + ThrowFailure ("The path '{}' doesn't exist. Please adjust the xcom.highlander.gameroot variable in your user config and retry." -f $this.gamePath) + } + } + + [void]_SetupUtils() { + $this.modSrcRoot = "$($this.projectRoot)\$($this.modNameFull)" + $this.modX2projPath = "$($this.modSrcRoot)\$($this.modNameFull).x2proj" + $this.stagingPath = "$($this.sdkPath)\XComGame\Mods\$($this.modNameCanonical)" + $this.xcomModPath = "$($this.stagingPath)\$($this.modNameCanonical).XComMod" + $this.finalModPath = "$($this.gamePath)\XComGame\Mods\$($this.modNameCanonical)" + $this.devSrcRoot = "$($this.sdkPath)\Development\Src" + $this.commandletHostPath = "$($this.sdkPath)/binaries/Win64/XComGame.com" + + # build package lists we'll need later and delete as appropriate + # the mod's packages + $this.thismodpackages = Get-ChildItem "$($this.modSrcRoot)/Src" -Directory + + $this.isHl = $this._HasNativePackages() + $this.cookHL = $this.isHl -and -not $this.debug + + if (-not $this.isHl -and $this.final_release) { + ThrowFailure "-final_release only makes sense if the mod in question is a Highlander" + } + + $this.modcookdir = [io.path]::combine($this.sdkPath, 'XComGame', 'Published', 'CookedPCConsole') + + $this.buildCachePath = [io.path]::combine($this.projectRoot, 'BuildCache') + if (!(Test-Path $this.buildCachePath)) + { + New-Item -ItemType "directory" -Path $this.buildCachePath + } + + $this.makeFingerprintsPath = "$($this.sdkPath)\XComGame\lastBuildDetails.json" + $lastBuildDetails = if (Test-Path $this.makeFingerprintsPath) { + Get-Content $this.makeFingerprintsPath | ConvertFrom-Json + } else { + [PSCustomObject]@{} + } + + @("buildMode", "globalsHash", "coreTimestamp") | ForEach-Object { + if(-not (Get-Member -InputObject $lastBuildDetails -name $_ -Membertype Properties)) { + $lastBuildDetails | Add-Member -NotePropertyName $_ -NotePropertyValue "unknown" + } + } + + $lastBuildDetails | ConvertTo-Json | Set-Content -Path $this.makeFingerprintsPath + } + + [void]_LoadContentOptions() { + Write-Host "Preparing content options" + + if ([string]::IsNullOrEmpty($this.contentOptionsJsonFilename)) + { + $this.contentOptions = [PSCustomObject]@{} + } + else + { + $contentOptionsJsonPath = Join-Path $this.modSrcRoot $this.contentOptionsJsonFilename + + if (!(Test-Path $contentOptionsJsonPath)) { + ThrowFailure "ContentOptionsJsonPath $contentOptionsJsonPath doesn't exist" + } + + $this.contentOptions = Get-Content $contentOptionsJsonPath | ConvertFrom-Json + Write-Host "Loaded $($contentOptionsJsonPath)" + } + + if (($this.contentOptions.PSobject.Properties | ForEach-Object {$_.Name}) -notcontains "missingUncooked") + { + Write-Host "No missing uncooked" + $this.contentOptions | Add-Member -MemberType NoteProperty -Name 'missingUncooked' -Value @() + } + + if (($this.contentOptions.PSobject.Properties | ForEach-Object {$_.Name}) -notcontains "sfStandalone") + { + Write-Host "No packages to make SF" + $this.contentOptions | Add-Member -MemberType NoteProperty -Name 'sfStandalone' -Value @() + } + + if (($this.contentOptions.PSobject.Properties | ForEach-Object {$_.Name}) -notcontains "sfMaps") + { + Write-Host "No umaps to cook" + $this.contentOptions | Add-Member -MemberType NoteProperty -Name 'sfMaps' -Value @() + } + + if (($this.contentOptions.PSobject.Properties | ForEach-Object {$_.Name}) -notcontains "sfCollectionMaps") + { + Write-Host "No collection maps to cook" + $this.contentOptions | Add-Member -MemberType NoteProperty -Name 'sfCollectionMaps' -Value @() + } + } + + [void]_CopyModToSdk() { + $xf = @("*.x2proj") + + if (![string]::IsNullOrEmpty($this.contentOptionsJsonFilename)) { + $xf += $this.contentOptionsJsonFilename + } + + Write-Host "Copying mod project to staging..." + Robocopy.exe "$($this.modSrcRoot)" "$($this.stagingPath)" *.* $global:def_robocopy_args /XF @xf /XD "ContentForCook" + Write-Host "Copied project to staging." + + New-Item "$($this.stagingPath)/Script" -ItemType Directory + + # read mod metadata from the x2proj file + Write-Host "Reading mod metadata from $($this.modX2ProjPath)" + [xml]$x2projXml = Get-Content -Path "$($this.modX2ProjPath)" + $xmlPropertyGroup = $x2projXml.Project.PropertyGroup + $modProperties = if ($xmlPropertyGroup -is [array]) { $xmlPropertyGroup[0] } else { $xmlPropertyGroup } + $publishedId = $modProperties.SteamPublishID + if ($this.publishID -ne -1) { + $publishedId = $this.publishID + Write-Host "Using override workshop ID of $publishedId" + } + $title = $modProperties.Name + $description = $modProperties.Description + Write-Host "Read." + + Write-Host "Writing mod metadata..." + Set-Content "$($this.xcomModPath)" "[mod]`npublishedFileId=$publishedId`nTitle=$title`nDescription=$description`nRequiresXPACK=true" + Write-Host "Written." + + # Create CookedPCConsole folder for the mod + if ($this.cookHL) { + New-Item "$($this.stagingPath)/CookedPCConsole" -ItemType Directory + } + } + + [void]_CleanAdditional() { + # clean + foreach ($modName in $this.clean) { + $cleanDir = "$($this.sdkPath)/XComGame/Mods/$($modName)" + if (Test-Path $cleanDir) { + Write-Host "Cleaning $($modName)..." + Remove-Item -Recurse -Force $cleanDir + } + } + } + + [void]_ConvertLocalization() { + Get-ChildItem "$($this.stagingPath)\Localization" -Recurse -File | + Foreach-Object { + $content = Get-Content $_.FullName -Encoding UTF8 + $content | Out-File $_.FullName -Encoding Unicode + } + } + + [void]_CopyToSrc() { + # mirror the SDK's SrcOrig to its Src + Write-Host "Mirroring SrcOrig to Src..." + Robocopy.exe "$($this.sdkPath)\Development\SrcOrig" "$($this.devSrcRoot)" *.uc *.uci $global:def_robocopy_args + Write-Host "Mirrored SrcOrig to Src." + + $this._ParseMacroFile("$($this.devSrcRoot)\Core\Globals.uci") + + # Copy dependencies + Write-Host "Copying dependency sources to Src..." + foreach ($depfolder in $this.include) { + Get-ChildItem "$($depfolder)" -Directory -Name | Write-Host + $this._CopySrcFolder($depfolder) + } + Write-Host "Copied dependency sources to Src." + + # copying the mod's scripts to the script staging location + Write-Host "Copying the mod's sources to Src..." + $this._CopySrcFolder("$($this.modSrcRoot)\Src") + Write-Host "Copied mod sources to Src." + } + + [void]_CopySrcFolder([string] $includeDir) { + Copy-Item "$($includeDir)\*" "$($this.devSrcRoot)\" -Force -Recurse -WarningAction SilentlyContinue + $extraGlobalsFile = "$($includeDir)\extra_globals.uci" + if (Test-Path $extraGlobalsFile) { + # append extra_globals.uci to globals.uci + "// Macros included from $($extraGlobalsFile)" | Add-Content "$($this.devSrcRoot)\Core\Globals.uci" + Get-Content $extraGlobalsFile | Add-Content "$($this.devSrcRoot)\Core\Globals.uci" + + $this._ParseMacroFile($extraGlobalsFile) + } + } + + [void]_ParseMacroFile([string]$file) { + $lines = Get-Content $file + # check for dupes + $redefine = $false + $lineNr = 1 + foreach ($line in $lines) { + $defineMatch = $line | Select-String -Pattern '^\s*`define\s*([a-zA-Z][a-zA-Z0-9_]*)' + if ($null -ne $defineMatch -and $defineMatch.Matches.Success) { + [string]$macroName = $defineMatch.Matches.Groups[1] + $prevDef = $this.macroDefs[$macroName] + if ($null -ne $prevDef -and + -not $redefine -and + $prevDef.file -ne $file) { + Write-Host -ForegroundColor Red "Error: Implicit redefinition of macro $($macroName)" + $defineWord = if ($prevDef.redefine) { "redefined" } else { "defined" } + Write-Host " Note: Previously $($defineWord) at $($prevDef.file)($($prevDef.lineNr))" + Write-Host " Note: Implicitly redefined at $($file)($($lineNr))" + Write-Host " Help: Rename the macro, or add ``// X2MBC-Redefine`` above to explicitly redefine and silence this warning." + ThrowFailure "Implicit macro redefinition." + } + $macroDef = [PSCustomObject]@{ + file = $file + lineNr = $lineNr + redefine = $redefine + } + $this.macroDefs[$macroName] = $macroDef + } elseif ($line -match '^\s*`define') { + ThrowFailure "Unrecognized macro at $($file)($($line)). This is a bug in X2ModBuildCommon." + } + + $redefine = $line -match "X2MBC-Redefine" + $lineNr += 1 + } + } + + [void]_RunPreMakeHooks() { + foreach ($hook in $this.preMakeHooks) { + $hook.Invoke() + } + } + + [string]_GetCoreMtime() { + if (Test-Path "$($this.sdkPath)/XComGame/Script/Core.u") { + return Get-Item "$($this.sdkPath)/XComGame/Script/Core.u" | Select-Object -ExpandProperty LastWriteTime + } else { + return "missing" + } + } + + [void]_CheckCleanCompiled() { + # #16: Switching between debug and release causes an error in the make commandlet if script packages aren't deleted. + # #20: Changes to Globals.uci aren't tracked by UCC, so we must delete script packages if Globals.uci changes. + $lastBuildDetails = Get-Content $this.makeFingerprintsPath | ConvertFrom-Json + + $buildMode = if ($this.debug -eq $true) { "debug" } else { "release" } + $globalsHash = Get-FileHash "$($this.sdkPath)\Development\Src\Core\Globals.uci" | Select-Object -ExpandProperty Hash + $coreTimeStamp = $this._GetCoreMtime() + + $rebuild = if ($lastBuildDetails.buildMode -ne $buildMode) { + Write-Host "Detected switch between debug and non-debug build." + $true + } elseif ($lastBuildDetails.coreTimestamp -ne $coreTimeStamp) { + Write-Host "Detected previous external rebuild." + $true + } elseif ($lastBuildDetails.globalsHash -ne $globalsHash) { + Write-Host "Detected change in macros (Globals.uci)." + $true + } else { + $false + } + + # Order: Deleting first cannot cause an issue because the compiler will just rebuild. + if ($rebuild) { + Write-Host "Cleaning all compiled scripts from $($this.sdkPath)/XComGame/Script to avoid compiler error..." + Remove-Item "$($this.sdkPath)/XComGame/Script/*.u" + Write-Host "Cleaned." + } + + $lastBuildDetails.buildMode = $buildMode + $lastBuildDetails.globalsHash = $globalsHash + + # Similarly, recording the previous invocation fingerprints before the build is complete + # cannot cause an issue because the compiler will simply continue an interrupted build. + $lastBuildDetails | ConvertTo-Json | Set-Content -Path $this.makeFingerprintsPath + } + + [void]_RecordCoreTimestamp() { + # Unfortunately, ModBuddy with Fxs' plugin can rebuild the packages under our nose. + # As a last resort, record the Core.u timestamp + $lastBuildDetails = Get-Content $this.makeFingerprintsPath | ConvertFrom-Json + $lastBuildDetails.coreTimestamp = $this._GetCoreMtime() + $lastBuildDetails | ConvertTo-Json | Set-Content -Path $this.makeFingerprintsPath + } + + [void]_RunMakeBase() { + # build the base game scripts + $scriptsMakeArguments = "make -nopause -unattended" + if ($this.final_release -eq $true) + { + $scriptsMakeArguments = "$scriptsMakeArguments -final_release" + } + if ($this.debug -eq $true) + { + $scriptsMakeArguments = "$scriptsMakeArguments -debug" + } + + $handler = [MakeStdoutReceiver]::new($this) + $handler.processDescr = "compiling base game scripts" + $this._InvokeEditorCmdlet($handler, $scriptsMakeArguments, 50) + + # If we build in final release, we must build the normal scripts too + if ($this.final_release -eq $true) + { + Write-Host "Compiling base game scripts without final_release..." + $scriptsMakeArguments = "make -nopause -unattended" + $handler = [MakeStdoutReceiver]::new($this) + $handler.processDescr = "compiling base game scripts" + $this._InvokeEditorCmdlet($handler, $scriptsMakeArguments, 50) + } + } + + [void]_RunMakeMod() { + # build the mod's scripts + $scriptsMakeArguments = "make -nopause -mods $($this.modNameCanonical) $($this.stagingPath)" + if ($this.debug -eq $true) + { + $scriptsMakeArguments = "$scriptsMakeArguments -debug" + } + $handler = [MakeStdoutReceiver]::new($this) + $handler.processDescr = "compiling mod scripts" + $this._InvokeEditorCmdlet($handler, $scriptsMakeArguments, 50) + } + + [bool]_HasNativePackages() { + # Check if this is a Highlander and we need to cook things + $anynative = $false + foreach ($name in $this.thismodpackages) + { + if ($global:nativescriptpackages.Contains($name)) { + $anynative = $true + break + } + } + return $anynative + } + + [void]_CopyScriptPackages() { + # copy packages to staging + foreach ($name in $this.thismodpackages) { + if ($this.cookHL -and $global:nativescriptpackages.Contains($name)) + { + # This is a native (cooked) script package -- copy important upks + Copy-Item "$($this.modcookdir)\$name.upk" "$($this.stagingPath)\CookedPCConsole" -Force -WarningAction SilentlyContinue + Copy-Item "$($this.modcookdir)\$name.upk.uncompressed_size" "$($this.stagingPath)\CookedPCConsole" -Force -WarningAction SilentlyContinue + Write-Host "$($this.modcookdir)\$name.upk" + } + else + { + # Or this is a non-native package + Copy-Item "$($this.sdkPath)\XComGame\Script\$name.u" "$($this.stagingPath)\Script" -Force -WarningAction SilentlyContinue + Write-Host "$($this.sdkPath)\XComGame\Script\$name.u" + } + } + } + + [void]_PrecompileShaders() { + Write-Host "Checking the need to PrecompileShaders" + $contentfiles = @() + + if (Test-Path "$($this.modSrcRoot)/Content") + { + $contentfiles = $contentfiles + (Get-ChildItem "$($this.modSrcRoot)/Content" -Include *.upk, *.umap -Recurse -File) + } + + # Turns out that seekfree packages contain an inlined shader cache, so there is no need to pass them through the shader precompiler + # if (Test-Path "$($this.modSrcRoot)/ContentForCook") + # { + # $contentfiles = $contentfiles + (Get-ChildItem "$($this.modSrcRoot)/ContentForCook" -Include *.upk, *.umap -Recurse -File) + # } + + if ($contentfiles.length -eq 0) { + Write-Host "No content files, skipping PrecompileShaders." + return + } + + # for ($i = 0; $i -lt $contentfiles.Length; $i++) { + # Write-Host $contentfiles[$i] + # } + + $need_shader_precompile = $false + $shaderCacheName = "$($this.modNameCanonical)_ModShaderCache.upk" + $cachedShaderCachePath = "$($this.buildCachePath)/$($shaderCacheName)" + + # Try to find a reason to precompile the shaders + if (!(Test-Path -Path $cachedShaderCachePath)) + { + $need_shader_precompile = $true + } + elseif ($contentfiles.length -gt 0) + { + $shader_cache = Get-Item $cachedShaderCachePath + + foreach ($file in $contentfiles) + { + if ($file.LastWriteTime -gt $shader_cache.LastWriteTime -Or $file.CreationTime -gt $shader_cache.LastWriteTime) + { + $need_shader_precompile = $true + break + } + } + } + + if ($need_shader_precompile) + { + # build the mod's shader cache + Write-Host "Precompiling Shaders..." + $precompileShadersFlags = "precompileshaders -nopause platform=pc_sm4 DLC=$($this.modNameCanonical)" + + $handler = [PassthroughReceiver]::new() + $handler.processDescr = "precompiling shaders" + $this._InvokeEditorCmdlet($handler, $precompileShadersFlags, 10) + + Write-Host "Generated Shader Cache." + + Copy-Item -Path "$($this.stagingPath)/Content/$shaderCacheName" -Destination $this.buildCachePath + } + else + { + Write-Host "No reason to precompile shaders, using existing" + Copy-Item -Path $cachedShaderCachePath -Destination "$($this.stagingPath)/Content" + } + } + + [void]_RunCookAssets() { + $step = [ModAssetsCookStep]::new($this) + $step.Execute() + } + + [void]_RunCookHL() { + # Cook it + # Normally, the mod tools create a symlink in the SDK directory to the game CookedPCConsole directory, + # but we'll just be using the game one to make it more robust + $cookedpcconsoledir = [io.path]::combine($this.gamePath, 'XComGame', 'CookedPCConsole') + if(-not(Test-Path $this.modcookdir)) + { + Write-Host "Creating Published/CookedPCConsole directory..." + New-Item $this.modcookdir -ItemType Directory + } + + [System.String[]]$files = "GuidCache.upk", "GlobalPersistentCookerData.upk", "PersistentCookerShaderData.bin" + foreach ($name in $files) { + if(-not(Test-Path ([io.path]::combine($this.modcookdir, $name)))) + { + Write-Host "Copying $name..." + Copy-Item ([io.path]::combine($cookedpcconsoledir, $name)) $this.modcookdir + } + } + + # Ideally, the cooking process wouldn't modify the big *.tfc files, but it does, so we don't overwrite existing ones (/XC /XN /XO) + # In order to "reset" the cooking direcory, just delete it and let the script recreate them + Write-Host "Copying Texture File Caches..." + Robocopy.exe "$cookedpcconsoledir" "$($this.modcookdir)" *.tfc /NJH /XC /XN /XO + Write-Host "Copied Texture File Caches." + + # Prepare editor args + $cook_args = @("cookpackages", "-platform=pcconsole", "-quickanddirty", "-modcook", "-sha", "-multilanguagecook=INT+FRA+ITA+DEU+RUS+POL+KOR+ESN", "-singlethread", "-nopause") + if ($this.final_release -eq $true) + { + $cook_args += "-final_release" + } + + # The CookPackages commandlet generally is super unhelpful. The output is basically always the same and errors + # don't occur -- it rather just crashes the game. Hence, we just buffer the output and present it to user only + # if something went wrong + + # TODO: Filter more lines for HL cook? `Hashing`? `SHA: package not found`? `Couldn't find localized resource`? + # `Warning, Texture file cache waste exceeds`? `Warning, Package _ is not conformed`? + $handler = [BufferingReceiver]::new() + $handler.processDescr = "cooking native packages" + + # Cook it! + Write-Host "Invoking CookPackages (this may take a while)" + $this._InvokeEditorCmdlet($handler, $cook_args, 10) + } + + [void]_CopyMissingUncooked() { + if ($this.contentOptions.missingUncooked.Length -lt 1) + { + Write-Host "Skipping Missing Uncooked logic" + return + } + + Write-Host "Including MissingUncooked" + + $missingUncookedPath = [io.path]::Combine($this.stagingPath, "Content", "MissingUncooked") + $sdkContentPath = [io.path]::Combine($this.sdkPath, "XComGame", "Content") + + if (!(Test-Path $missingUncookedPath)) + { + New-Item -ItemType "directory" -Path $missingUncookedPath + } + + foreach ($fileName in $this.contentOptions.missingUncooked) + { + (Get-ChildItem -Path $sdkContentPath -Filter $fileName -Recurse).FullName | Copy-Item -Destination $missingUncookedPath + } + } + + [void]_FinalCopy() { + # copy all staged files to the actual game's mods folder + # TODO: Is the string interpolation required in the robocopy calls? + Robocopy.exe "$($this.stagingPath)" "$($this.finalModPath)" *.* $global:def_robocopy_args + } + + [void]_InvokeEditorCmdlet([StdoutReceiver] $receiver, [string] $makeFlags, [int] $sleepMsDuration) { + # Create a ProcessStartInfo object to hold the details of the make command, its arguments, and set up + # stdout/stderr redirection. + $pinfo = New-Object System.Diagnostics.ProcessStartInfo + $pinfo.FileName = $this.commandletHostPath + $pinfo.RedirectStandardOutput = $true + $pinfo.RedirectStandardError = $true + $pinfo.UseShellExecute = $false + $pinfo.Arguments = $makeFlags + $pinfo.WorkingDirectory = $this.commandletHostPath | Split-Path + + + # Set the exited flag on our exit object on process exit. + # We need another object for the Exited event to set a flag we can monitor from this function. + $exitData = New-Object psobject -property @{ exited = $false } + $exitAction = { + $event.MessageData.exited = $true + } + + # An action for handling data written to stderr. The Cmdlets don't seem to write anything here, + # or at least not diagnostics, so we can just pass it through. + $errAction = { + $errTxt = $Event.SourceEventArgs.Data + Write-Host $errTxt + } + + $messageData = New-Object psobject -property @{ + handler = $receiver + } + + # Create an stdout filter action delegating to the actual implementation + $outAction = { + [StdoutReceiver] $handler = $event.MessageData.handler + [string] $outTxt = $Event.SourceEventArgs.Data + $handler.ParseLine($outTxt) + } + + # Create the process and register for the various events we care about. + $process = New-Object System.Diagnostics.Process + Register-ObjectEvent -InputObject $process -EventName OutputDataReceived -Action $outAction -MessageData $messageData | Out-Null + Register-ObjectEvent -InputObject $process -EventName ErrorDataReceived -Action $errAction | Out-Null + Register-ObjectEvent -InputObject $process -EventName Exited -Action $exitAction -MessageData $exitData | Out-Null + $process.StartInfo = $pinfo + + # All systems go! + $process.Start() | Out-Null + $process.BeginOutputReadLine() + $process.BeginErrorReadLine() + + # Wait for the process to exit. This is horrible, but using $process.WaitForExit() blocks + # the powershell thread so we get no output from make echoed to the screen until the process finishes. + # By polling we get regular output as it goes. + try { + if ($sleepMsDuration -lt 1) { + while (!$exitData.exited) { + # Just spin + } + } else { + while (!$exitData.exited) { + Start-Sleep -m $sleepMsDuration + } + } + } + finally { + # If we are stopping MSBuild hosted build, we need to kill the editor manually + if (!$exitData.exited) { + Write-Host "Killing $($receiver.processDescr) tree" + KillProcessTree $process.Id + } + } + + $exitCode = $process.ExitCode + $receiver.Finish($exitCode) + } +} + +class ModAssetsCookStep { + [BuildProject] $project + + [string] $tfcSuffix + [string[]] $cookedMaps + [bool] $firstCook = $false + + [string] $contentForCookPath + [string] $collectionMapsPath + + [string] $cookerOutputPath + [string] $cachedCookerOutputPath + + [string] $cachedReleaseScriptPackagesDir + + [string] $sdkEngineIniPath + [string] $sdkEngineIniContentOriginal + [string] $sdkEngineIniChangesPreamble = "HACKS FOR MOD ASSETS COOKING" + + [string[]] $filesRequiredToSkipFirstPass + + [string] $sdkEngineIniContentNewFirstPass + [string] $sdkEngineIniContentNewNormalPass + + [string] $previousCookerOutputDirPath = $null + + [string] $editorArgsFirstPass + [string] $editorArgsNormalPass + + # Doesn't include the editor-only packages and the missing ones (e.g. PSN subsystem) + [string[]] $cookedNativeScriptPackages = @("XComGame", "Core", "Engine", "GFxUI", "AkAudio", "GameFramework", "IpDrv", "OnlineSubsystemSteamworks") + + ModAssetsCookStep ([BuildProject] $project) { + $this.project = $project + } + + [void] Execute() { + if (($this.project.contentOptions.sfStandalone.Length -lt 1) -and ($this.project.contentOptions.sfMaps.Length -lt 1) -and ($this.project.contentOptions.sfCollectionMaps.Length -lt 1)) { + Write-Host "No asset cooking is requested, skipping" + return + } + + Write-Host "Initializing assets cooking" + + $this._Init() + $this._Verify() + + Write-Host "Preparing assets cooking" + + $this._PrepareReleaseScriptPackages() + $this._PrepareProjectCache() + $this._PrepareSdkEngineIni() + $this._PrepareSdkFolders() + $this._PrepareEditorArgs() + + Write-Host "Starting assets cooking" + + $this._ExecuteCore() + $this._StageArtifacts() + + Write-Host "Assets cook completed" + } + + [void] _Init() { + $this.tfcSuffix = "_Mod_$($this.project.modNameCanonical)_" + + $this.cookerOutputPath = [io.path]::combine($this.project.sdkPath, 'XComGame', 'Published', 'CookedPCConsole') + $this.cachedCookerOutputPath = [io.path]::combine($this.project.buildCachePath, 'PublishedCookedPCConsole') + + $this.contentForCookPath = "$($this.project.modSrcRoot)\ContentForCook" + $this.collectionMapsPath = [io.path]::combine($this.project.buildCachePath, 'CollectionMaps') + + $this.cachedReleaseScriptPackagesDir = [io.path]::combine($this.project.buildCachePath, 'ReleaseScriptPackages') + + $this.sdkEngineIniPath = "$($this.project.sdkPath)/XComGame/Config/DefaultEngine.ini" + $this.sdkEngineIniContentOriginal = Get-Content $this.sdkEngineIniPath | Out-String + + $this.filesRequiredToSkipFirstPass = @("GlobalPersistentCookerData.upk", "gfxCommon_SF.upk") + foreach ($package in $this.cookedNativeScriptPackages) { + $this.filesRequiredToSkipFirstPass += "$package.upk" + $this.filesRequiredToSkipFirstPass += "$package.upk.uncompressed_size" + } + + $this.cookedMaps = $this.project.contentOptions.sfMaps + foreach ($mapDef in $this.project.contentOptions.sfCollectionMaps) { + $this.cookedMaps += $mapDef.name + } + } + + [void] _Verify() { + if (-not(Test-Path $this.contentForCookPath)) + { + ThrowFailure "Asset cooking is requested, but no ContentForCook folder is present" + } + + if ($this.sdkEngineIniContentOriginal.Contains($this.sdkEngineIniChangesPreamble)) + { + ThrowFailure "Another cook is already in progress (DefaultEngine.ini)" + } + } + + [void] _PrepareReleaseScriptPackages () { + if (!(Test-Path $this.cachedReleaseScriptPackagesDir)) + { + New-Item -ItemType "directory" -Path $this.cachedReleaseScriptPackagesDir + } + + if (!$this.project.debug) { + # Store the release packages for next potential debug builds + Robocopy.exe "$($this.project.sdkPath)\XComGame\Script" $this.cachedReleaseScriptPackagesDir *.* $global:def_robocopy_args + } + else { + # Figure out which packages we need + $required = $this.cookedNativeScriptPackages + + # Make sure we have all of them ready for use + $missing = @() + + foreach ($package in $required) { + if (!(Test-Path "$($this.cachedReleaseScriptPackagesDir)\$package.u")) { + $missing += $package + } + } + + if ($missing.Length -gt 0) { + Write-Host "Missing cached release script packages: $missing" + ThrowFailure "Missing cached release script packages - cannot cook assets. Please build the mod in release (aka default) once to cache them" + } + + Write-Host "" + Write-Host "Using cached release script packages" + Write-Host "If you've made changes to (or added) classes which are referenced by assets, please rebuild the mod in release (aka default) once to cache them" + Write-Host "" + } + } + + [void] _PrepareProjectCache() { + if (!(Test-Path $this.cachedCookerOutputPath)) + { + New-Item -ItemType "directory" -Path $this.cachedCookerOutputPath + $this.firstCook = $true + } else { + $this.firstCook = $this._IsFirstPassRequired() + + if ($this.firstCook) { + # Empty the cooker output dir + Remove-Item "$($this.cachedCookerOutputPath)\*" -Force -Recurse + } + } + + # Prep the folder for the collection maps + # Not the most efficient approach, but there are bigger time saves to be had + Remove-Item $this.collectionMapsPath -Force -Recurse -WarningAction SilentlyContinue -ErrorAction SilentlyContinue + New-Item -ItemType "directory" -Path $this.collectionMapsPath + + # Collection maps also need the actual empty umap file created + # (unless it's already provided for w/e reason) + foreach ($mapDef in $this.project.contentOptions.sfCollectionMaps) { + if ($null -eq (Get-ChildItem -Path $this.contentForCookPath -Filter $mapDef.name -Recurse)) { + # Important: we cannot use .umap extension here - git lfs (if in use) gets confused during git subtree add + # See https://github.com/X2CommunityCore/X2ModBuildCommon/wiki/Do-not-use-.umap-for-files-in-this-repo + Copy-Item "$global:buildCommonSelfPath\EmptyUMap" "$($this.collectionMapsPath)\$($mapDef.name).umap" + } + } + } + + [bool] _IsFirstPassRequired() { + foreach ($file in $this.filesRequiredToSkipFirstPass) { + $path = [io.path]::combine($this.cachedCookerOutputPath, $file) + + if (!(Test-Path $path)) { + Write-Host "$file is missing, forcing first cook" + return $true + } + } + + return $false + } + + [void] _PrepareSdkEngineIni() { + $original = $this.sdkEngineIniContentOriginal + "`n" + $additionsShared = $this._BuildEngineIniAdditionsShared() + "`n" + + $this.sdkEngineIniContentNewFirstPass = $original + $additionsShared + $this.sdkEngineIniContentNewNormalPass = $original + $additionsShared + $this._BuildEngineIniAdditionsNormalPass() + + # Backup the DefaultEngine.ini + Copy-Item $this.sdkEngineIniPath "$($this.sdkEngineIniPath).bak_PRE_ASSET_COOKING" + } + + [string] _BuildEngineIniAdditionsShared () { + $lines = @() + + # Denote the beginning of our changes (this marker is used by _Verify to detect unfinished cook) + $lines += "; $($this.sdkEngineIniChangesPreamble) - $($this.project.modNameCanonical)" + + # "Inject" our assets into the SDK to make them visible to the cooker + $lines += "[Core.System]" + $lines += "+Paths=$($this.contentForCookPath)" + $lines += "+Paths=$($this.collectionMapsPath)" + + # Redirect to cached release script packages to support debug builds + $lines += "ScriptPaths=$($this.cachedReleaseScriptPackagesDir)" + + # Remove default seek free packages + # This will trump the rest of file content as it's all the way at the bottom + $lines += "[Engine.PackagesToAlwaysCook]" + $lines += "!SeekFreePackage=Empty" + + return $lines -join "`n" + } + + [string] _BuildEngineIniAdditionsNormalPass () { + $lines = @() + + # Don't re-cook the startup (cooker doesn't cache it) + $lines += "[Engine.StartupPackages]" + $lines += "!Package=Empty" + + # SF Standalone packages + $lines += "[Engine.PackagesToAlwaysCook]" + foreach ($package in $this.project.contentOptions.sfStandalone) { + $lines += "+SeekFreePackage=$package" + } + + # Collection maps + $lines += "[Engine.PackagesToForceCookPerMap]" + foreach ($mapDef in $this.project.contentOptions.sfCollectionMaps) { + $lines += "+Map=$($mapDef.name)" + + foreach ($package in $mapDef.packages) { + $lines += "+Package=$package" + } + } + + return $lines -join "`n" + } + + [void] _PrepareSdkFolders () { + $cookOutputParentDir = [io.path]::combine($this.project.sdkPath, 'XComGame', 'Published') + + if (-not (Test-Path -Path $cookOutputParentDir)) { + New-Item -Path $cookOutputParentDir -Type Directory + } + elseif (Test-Path $this.cookerOutputPath) { + $previousCookerOutputDirName = "Pre_$($this.project.modNameCanonical)_Cook_CookedPCConsole" + $this.previousCookerOutputDirPath = [io.path]::combine($this.project.sdkPath, 'XComGame', 'Published', $previousCookerOutputDirName) + + Rename-Item $this.cookerOutputPath $this.previousCookerOutputDirPath + } + } + + [void] _PrepareEditorArgs () { + $cookerFlags = "-platform=pcconsole -skipmaps -modcook -TFCSUFFIX=$($this.tfcSuffix) -singlethread -unattended -usermode" + + $mapsString = "" + for ($i = 0; $i -lt $this.cookedMaps.Length; $i++) + { + $umap = $this.cookedMaps[$i] + $mapsString = "$mapsString $umap.umap " + } + + $this.editorArgsFirstPass = "CookPackages $cookerFlags" + $this.editorArgsNormalPass = "CookPackages $mapsString $cookerFlags" + } + + [void] _ExecuteCore () { + # This try block needs to be kept as small as possible as it puts the SDK into a (temporary) invalid state + try { + # Redirect all the cook output to our local cache + # This allows us to not recook everything when switching between projects (e.g. CHL) + New-Junction $this.cookerOutputPath $this.cachedCookerOutputPath + + if ($this.firstCook) { + # First do a cook without our assets since gfxCommon.upk still get included in the cook, polluting the TFCs, depsite the config hacks + + Write-Host "Running first time mod assets cook" + $this._InvokeAssetCooker($this.editorArgsFirstPass, $this.sdkEngineIniContentNewFirstPass) + + # Now delete the polluted TFCs + Get-ChildItem -Path $this.cachedCookerOutputPath -Filter "*$($this.tfcSuffix).tfc" | Remove-Item + + # And make sure scripts are never cooked again + $this._SetTimestampOnCookedScript() + + Write-Host "First time cook done, proceeding with normal" + } + + $this._InvokeAssetCooker($this.editorArgsNormalPass, $this.sdkEngineIniContentNewNormalPass) + } + finally { + Write-Host "Cleaning up the asset cooking hacks" + $cleanupFailed = $false + + # Revert ini + try { + $this.sdkEngineIniContentOriginal | Set-Content $this.sdkEngineIniPath -NoNewline + Write-Host "Reverted $($this.sdkEngineIniPath)" + } + catch { + FailureMessage "Failed to revert $($this.sdkEngineIniPath)" + FailureMessage $_ + + $cleanupFailed = $true + } + + # Revert junctions + + try { + Remove-Junction $this.cookerOutputPath + Write-Host "Removed $($this.cookerOutputPath) junction" + } + catch { + FailureMessage "Failed to remove $($this.cookerOutputPath) junction" + FailureMessage $_ + + $cleanupFailed = $true + } + + if (![string]::IsNullOrEmpty($this.previousCookerOutputDirPath)) + { + try { + if (Test-Path $this.cookerOutputPath) { + ThrowFailure "$($this.cookerOutputPath) still exists, cannot restore previous" + } + + Rename-Item $this.previousCookerOutputDirPath "CookedPCConsole" + Write-Host "Restored previous $($this.cookerOutputPath)" + } + catch { + FailureMessage "Failed to restore previous $($this.cookerOutputPath)" + FailureMessage $_ + + $cleanupFailed = $true + } + } + + if ($cleanupFailed) { + Write-Host "" + Write-Host "" + ThrowFailure "Failed to clean up the asset cooking hacks - your SDK is now in a corrupted state. Please preform the cleanup manually before building a mod or opening the editor." + } + } + } + + [void] _InvokeAssetCooker ([string] $editorArguments, [string] $engineIniContentNew) { + Write-Host $editorArguments + + $engineIniContentNew | Set-Content $this.sdkEngineIniPath -NoNewline + + $handler = [ModcookReceiver]::new() + $handler.processDescr = "cooking mod packages" + + # Even a sleep of 1 ms causes a noticable delay between cooker being done (files created) + # and output completing. So, just spin + $this.project._InvokeEditorCmdlet($handler, $editorArguments, 0) + } + + [void] _SetTimestampOnCookedScript () { + $newTimestamp = (Get-Date).AddYears(30) + $files = @() + + foreach ($package in $this.cookedNativeScriptPackages) { + $files += "$package.upk" + $files += "$package.upk.uncompressed_size" + } + + foreach ($file in $files) { + $path = [io.path]::Combine($this.cachedCookerOutputPath, $file) + + if (Test-Path $path) { + (Get-Item $path).LastWriteTime = $newTimestamp + } + } + } + + [void] _StageArtifacts () { + # Prepare the folder for cooked stuff + $stagingCookedDir = [io.path]::combine($this.project.stagingPath, 'CookedPCConsole') + if (!(Test-Path $stagingCookedDir)) { + New-Item -ItemType "directory" -Path $stagingCookedDir + } + + # Copy over the TFC files + Get-ChildItem -Path $this.cachedCookerOutputPath -Filter "*$($this.tfcSuffix).tfc" | Copy-Item -Destination $stagingCookedDir + + # Copy over the maps + for ($i = 0; $i -lt $this.cookedMaps.Length; $i++) + { + $umap = $this.cookedMaps[$i]; + Copy-Item "$($this.cachedCookerOutputPath)\$umap.upk" -Destination $stagingCookedDir + } + + # Copy over the SF packages + for ($i = 0; $i -lt $this.project.contentOptions.sfStandalone.Length; $i++) + { + $package = $this.project.contentOptions.sfStandalone[$i]; + $dest = [io.path]::Combine($stagingCookedDir, "${package}.upk"); + + # Since we don't ship the GuidCache with the mod, we need to remove the _SF suffix. + # Otherwise the game won't find the package + Copy-Item "$($this.cachedCookerOutputPath)\${package}_SF.upk" -Destination $dest + } + } +} + +class StdoutReceiver { + [bool] $crashDetected = $false + [string] $processDescr = "" + + [void]ParseLine([string] $outTxt) { + if ($outTxt.Contains("Crash Detected") -or $outTxt.Contains("(filename not found)")) { + $this.crashDetected = $true + } + } + + [void]Finish([int] $exitCode) { + if ($this.crashDetected) { + ThrowFailure "Crash detected while $($this.processDescr)" + } + + if ($exitCode -ne 0) { + ThrowFailure "Failed $($this.processDescr)" + } + } +} + +class PassthroughReceiver : StdoutReceiver { + PassthroughReceiver(){ + } + + [void]ParseLine([string] $outTxt) { + ([StdoutReceiver]$this).ParseLine($outTxt) + Write-Host $outTxt + } + + [void]Finish([int] $exitCode) { + ([StdoutReceiver]$this).Finish($exitCode) + } +} + +class BufferingReceiver : StdoutReceiver { + [object] $logLines + BufferingReceiver(){ + $this.logLines = New-Object System.Collections.Generic.List[System.Object] + } + + [void]ParseLine([string] $outTxt) { + ([StdoutReceiver]$this).ParseLine($outTxt) + $this.logLines.Add($outTxt) + } + + [void]Finish([int] $exitCode) { + if (($exitCode -ne 0) -or $this.crashDetected) { + foreach ($line in $this.logLines) { + Write-Host $line + } + } + ([StdoutReceiver]$this).Finish($exitCode) + } +} + + +class MakeStdoutReceiver : StdoutReceiver { + [BuildProject] $proj + [string[]] $reversePaths + + MakeStdoutReceiver( + [BuildProject]$proj + ){ + $this.proj = $proj + # Since later paths overwrite earlier files, check paths in reverse order + $this.reversePaths = @("$($this.proj.sdkPath)\Development\SrcOrig") + + $this.proj.include + @("$($this.proj.modSrcRoot)\Src") + [array]::Reverse($this.reversePaths) + } + + [void]ParseLine([string] $outTxt) { + ([StdoutReceiver]$this).ParseLine($outTxt) + $messagePattern = "^(.*)\(([0-9]*)\) : (.*)$" + if (($outTxt -Match "Error|Warning") -And ($outTxt -Match $messagePattern)) { + # extract original path from $matches automatic variable created by above -Match + $origPath = $matches[1] + + # create regex pattern specifically from the part we're interested in replacing + $pattern = [regex]::Escape("$($this.proj.sdkPath)\Development\Src") + + $found = $false + foreach ($checkPath in $this.reversePaths) { + $testPath = $origPath -Replace $pattern,$checkPath + # if the file exists, it's certainly the one that caused the error + if (Test-Path $testPath) { + # Normalize path to get rid of `..`s + $testPath = [IO.Path]::GetFullPath($testPath) + # this syntax works with both VS Code and ModBuddy + $outTxt = $outTxt -Replace $messagePattern, ($testPath + '($2) : $3') + $found = $true + break + } + } + if (-not $found) { + $outTxt = $outTxt -Replace $messagePattern, ($origPath + '($2) : $3') + } + } + + $summPattern = "^(Success|Failure) - ([0-9]+) error\(s\), ([0-9]+) warning\(s\) \(([0-9]+) Unique Errors, ([0-9]+) Unique Warnings\)" + if (-Not ($outTxt -Match "Warning/Error Summary") -And $outTxt -Match "Warning|Error") { + if ($outTxt -Match $summPattern) { + $numErr = $outTxt -Replace $summPattern, '$2' + $numWarn = $outTxt -Replace $summPattern, '$3' + if (([int]$numErr) -gt 0) { + $clr = "Red" + } elseif (([int]$numWarn) -gt 0) { + $clr = "Yellow" + } else { + $clr = "Green" + } + } else { + if ($outTxt -Match "Error") { + $clr = "Red" + } else { + $clr = "Yellow" + } + } + Write-Host $outTxt -ForegroundColor $clr + } else { + Write-Host $outTxt + } + } + + [void]Finish([int] $exitCode) { + ([StdoutReceiver]$this).Finish($exitCode) + } +} + +class ModcookReceiver : StdoutReceiver { + [bool] $lastLineWasAdding = $false + [bool] $permitAdditional = $false + + ModcookReceiver(){ + } + + [void]ParseLine([string] $outTxt) { + ([StdoutReceiver]$this).ParseLine($outTxt) + $permitLine = $true # Default to true in case there is something we don't handle + + if ($outTxt.StartsWith("Adding package") -or $outTxt.StartsWith("Adding level") -or $outTxt.StartsWith("GFx movie package")) { + if ($outTxt.Contains("\BuildCache\") -or $outTxt.Contains("\ContentForCook\")) { + $permitLine = $true + } else { + $permitLine = $false + + if (!$this.lastLineWasAdding) { + Write-Host "[Adding sdk assets ...]" + } + } + + $this.lastLineWasAdding = !$permitLine + $this.permitAdditional = $permitLine + } elseif ($outTxt.StartsWith("Adding additional")) { + $permitLine = $this.permitAdditional + } else { + $this.lastLineWasAdding = $false + $permitLine = $true + } + + if ($permitLine) { + Write-Host $outTxt + } + } + + [void]Finish([int] $exitCode) { + ([StdoutReceiver]$this).Finish($exitCode) + } +} + +function FailureMessage($message) +{ + [System.Media.SystemSounds]::Hand.Play() + Write-Host $message -ForegroundColor "Red" +} + +function ThrowFailure($message) +{ + throw $message +} + +function SuccessMessage($message, $modNameCanonical) +{ + [System.Media.SystemSounds]::Asterisk.Play() + Write-Host $message -ForegroundColor "Green" + Write-Host "$modNameCanonical ready to run." -ForegroundColor "Green" +} + +function FormatElapsed($elapsed) { + return $elapsed.TotalSeconds.ToString("0.00s", $global:invarCulture) +} + +function New-Junction ([string] $source, [string] $destination) { + Write-Host "Creating Junction: $source -> $destination" + &"$global:buildCommonSelfPath\junction.exe" -nobanner -accepteula "$source" "$destination" +} + +function Remove-Junction ([string] $path) { + Write-Host "Removing Junction: $path" + &"$global:buildCommonSelfPath\junction.exe" -nobanner -accepteula -d "$path" +} + +# https://stackoverflow.com/a/55942155/2588539 +# $process.Kill() works but we really need to kill the child as well, since it's the one which is actually doing work +# Unfotunately, $process.Kill($true) does nothing +function KillProcessTree ([int] $ppid) { + Get-CimInstance Win32_Process | Where-Object { $_.ParentProcessId -eq $ppid } | ForEach-Object { KillProcessTree $_.ProcessId } + Stop-Process -Id $ppid +} diff --git a/clean.ps1 b/clean.ps1 new file mode 100644 index 0000000..95fb301 --- /dev/null +++ b/clean.ps1 @@ -0,0 +1,41 @@ +Param( + [string] $modName, # mod folder name + [string] $srcDirectory, # the path that contains your mod's .XCOM_sln + [string] $sdkPath, # the path to your SDK installation ending in "XCOM 2 War of the Chosen SDK" + [string] $gamePath # the path to your XCOM 2 installation ending in "XCOM2-WaroftheChosen" +) + +$ErrorActionPreference = "Stop" +Set-StrictMode -Version 3.0 + +if ($null -eq $modName -or $modName -eq "") { + throw "`$modName empty???" +} + +Write-Host "Deleting all cached build artifacts..." + +$files = @( + "$sdkPath\XComGame\lastBuildDetails.json", + "$sdkPath\XComGame\Script\*.u", + "$sdkPath\XComGame\ScriptFinalRelease\*.u", + "$sdkPath\XComGame\Content\LocalShaderCache-PC-D3D-SM4.upk" +) + +$folders = @( + "$srcDirectory\BuildCache", + "$sdkPath\Development\Src\*", + "$sdkPath\XComGame\Mods\*", + "$gamePath\XComGame\Mods\$modName" +) + +$files | ForEach-Object { + Write-Host "Removing file(s) $($_)" + Remove-Item -Force $_ -WarningAction SilentlyContinue -ErrorAction SilentlyContinue +} + +$folders | ForEach-Object { + Write-Host "Removing folders(s) $($_)" + Remove-Item -Recurse -Force $_ -WarningAction SilentlyContinue -ErrorAction SilentlyContinue +} + +Write-Host "Cleaned." diff --git a/junction.exe b/junction.exe new file mode 100644 index 0000000000000000000000000000000000000000..29e42c8b6c5712e02f1aed9e8ea734e9ec9604c3 GIT binary patch literal 216736 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

vVl%`S(Ym#psj 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