OVNI Posted April 2, 2016 Share Posted April 2, 2016 Hello, Visual Studio allows to double-click on paths logged in the output panel. For example double-clicking on "C:\MyMod\MyFile.cs(42) : Error, you can't do that !" will open MyFile.cs at line 42. Quite handy. The problem is : compilation task does not compile your source files directly, but a copy of them stored in a temporary folder (...\XCOM 2 SDK\Development\Src), and the UnrealScript compiler's output is passed to ModBuddy as is. So if you double-click on the error/warning this will open the temporary copy, and you'll have to manually open and browse the original file to fix the error/warning. The solution is to replace the compilation task, so it logs the path of original .uc file, instead of the temporary one. Let's say the SDK is stored in "C:\steam\steamapps\common\XCOM 2 SDK" 1) Create "C:\steam\steamapps\common\XCOM 2 SDK\Binaries\Win32\ModBuddy\Extensions\Application\ModdedCompileScripts.targets" (code based on decompiled XCOM2.Tasks.dll ) <Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <UsingTask TaskName="ModdedCompileScripts" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" > <ParameterGroup> <ModSafeName ParameterType="System.String" Required="true" /> <SolutionName ParameterType="System.String" Required="true" /> <SolutionDir ParameterType="System.String" Required="true" /> <OutputDir ParameterType="System.String" Required="true" /> <Config ParameterType="System.String" Required="true" /> </ParameterGroup> <Task> <Reference Include="$(MSBuildLocalExtensionPath)\XCOM2.Utilities.dll" /> <Using Namespace="Firaxis.VisualStudio.Utilities.XCOM2" /> <Using Namespace="Microsoft.Build.Framework" /> <Using Namespace="Microsoft.Build.Utilities" /> <Using Namespace="System" /> <Using Namespace="System.Collections.Generic" /> <Using Namespace="System.Diagnostics" /> <Using Namespace="System.IO" /> <Code Type="Fragment" Language="cs"> <![CDATA[ //code injection cf https://badcorporatelogo.wordpress.com/2013/09/15/code-injection-with-msbuild-inline-tasks/ //public class GeneratedTask : Microsoft.Build.Utilities.Task { //public override bool Execute() { return new InnerModdedCompileScripts(this).Execute(); } class InnerModdedCompileScripts { ModdedCompileScripts outer; private enum EScriptConfig { eScriptConfig_Unknown, eScriptConfig_Debug, eScriptConfig_Release } private static InnerModdedCompileScripts.EScriptConfig ScriptConfig; private List<string> BaseGameScriptPackages = new List<string> { "XComGame", "Core", "Engine", "GFxUI", "AkAudio", "GameFramework", "UnrealEd", "GFxUIEditor", "IpDrv", "OnlineSubsystemPC", "OnlineSubsystemLive", "OnlineSubsystemSteamworks", "OnlineSubsystemPSN" }; public InnerModdedCompileScripts( ModdedCompileScripts outer_ ) { outer = outer_; } public bool Execute() { FileInfo sdkDir = UtilitiesXCom2.GetModdingBaseDirectory(); if( sdkDir == null ) { return true; } // COPY SrcOrig to Src string developementPath = sdkDir.FullName + "\\Development\\"; string projectPath = outer.SolutionDir + outer.SolutionName + "\\"; string[] projectSourceFiles = Directory.GetFiles(projectPath, "*.uc", SearchOption.AllDirectories); if (projectSourceFiles.Length > 0) { outer.Log.LogMessage(MessageImportance.High, "**************************************************************"); outer.Log.LogMessage(MessageImportance.High, "|| GENERATING SCRIPT PACKAGES |"); outer.Log.LogMessage(MessageImportance.High, "**************************************************************\n"); outer.Log.LogMessage(MessageImportance.High, "Prepping the script source:"); if (UtilitiesXCom2.GamePath != UtilitiesXCom2.SDKPath) { outer.Log.LogMessage(MessageImportance.High, "\t\nMirroring SrcOrig to working directory (Src) ..."); string devSrcOrigPath = developementPath + "SrcOrig"; string devSrcPath = developementPath + "Src"; using (Process process = new Process()) { process.StartInfo.Arguments = string.Format("*.uc *.uci /MIR \"{0}\" \"{1}\" /NP", devSrcOrigPath, devSrcPath); process.StartInfo.FileName = "ROBOCOPY.EXE"; process.StartInfo.CreateNoWindow = true; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.OutputDataReceived += new DataReceivedEventHandler(this.OutputHandler); process.Start(); process.BeginOutputReadLine(); process.WaitForExit(); goto IL_192; } } outer.Log.LogMessage(MessageImportance.High, "\t\nRunning in development mode, no script copy necessary ..."); IL_192: // COPY project *.uc files to SDK/Src outer.Log.LogMessage(MessageImportance.High, "\t\nCopying script projectSourceFiles from workspace ..."); HashSet<string> hashSet = new HashSet<string>(); List<string> moddedSdkPackages = new List<string>(); List<string> moddedNewPackages = new List<string>(); for (int i = 0; i < projectSourceFiles.Length; i++) { string projectSourceFilePath = projectSourceFiles[i]; FileInfo fileInfo = new FileInfo(projectSourceFilePath); if (!fileInfo.IsReadOnly) { string projectSourceFileRelativePath = projectSourceFilePath.Replace(projectPath, ""); string projectSourceFileRelativeToSdkPath = developementPath + projectSourceFileRelativePath; string directoryName = Path.GetDirectoryName(projectSourceFileRelativeToSdkPath); string[] array = projectSourceFileRelativePath.Split(new char[] { '\\' }); string packageName = array[1]; if (!hashSet.Contains(directoryName)) { hashSet.Add(directoryName); if (this.BaseGameScriptPackages.Contains(packageName)) { moddedSdkPackages.Add(packageName); } else { moddedNewPackages.Add(packageName); } if (!Directory.Exists(directoryName)) { Directory.CreateDirectory(directoryName); } } outer.Log.LogMessage(MessageImportance.High, string.Concat(new string[] { "\tPackage(", packageName, ") ", projectSourceFilePath, " => ", projectSourceFileRelativeToSdkPath })); File.Copy(projectSourceFilePath, projectSourceFileRelativeToSdkPath, true); } } // Delete modded sdk packages and ??? FileInfo fileInfo2 = new FileInfo(Path.Combine(sdkDir.FullName + "\\binaries\\Win64", "XComGame.com")); //decompilation noise ? sdkDir.FullName + "\\XComGame\\Logs\\Launch.log"; outer.Log.LogMessage(MessageImportance.High, "\t\nDeleting existing compiled script packages:"); string sdk_XComGame_Script_Path = sdkDir.FullName + "\\XComGame\\Script\\"; bool isDebug = outer.Config == "Debug"; bool shouldRecompileAllSdkPackages = false; if (InnerModdedCompileScripts.ScriptConfig == InnerModdedCompileScripts.EScriptConfig.eScriptConfig_Unknown || (isDebug && InnerModdedCompileScripts.ScriptConfig == InnerModdedCompileScripts.EScriptConfig.eScriptConfig_Release) || (!isDebug && InnerModdedCompileScripts.ScriptConfig == InnerModdedCompileScripts.EScriptConfig.eScriptConfig_Debug)) { for (int j = 0; j < this.BaseGameScriptPackages.Count; j++) { string text6 = sdk_XComGame_Script_Path + this.BaseGameScriptPackages[j] + ".u"; outer.Log.LogMessage(MessageImportance.High, "\t" + text6); if (File.Exists(text6)) { File.Delete(text6); } } shouldRecompileAllSdkPackages = true; } else { for (int k = 0; k < moddedSdkPackages.Count; k++) { string text7 = sdk_XComGame_Script_Path + moddedSdkPackages[k] + ".u"; outer.Log.LogMessage(MessageImportance.High, "\t" + text7); if (File.Exists(text7)) { File.Delete(text7); } } } InnerModdedCompileScripts.ScriptConfig = (isDebug ? InnerModdedCompileScripts.EScriptConfig.eScriptConfig_Debug : InnerModdedCompileScripts.EScriptConfig.eScriptConfig_Release); // DEBUG STUFF string startDebuggingBatPath = UtilitiesXCom2.GamePath + "\\..\\Binaries\\Win64\\Launcher\\StartDebugging.bat"; if (File.Exists(startDebuggingBatPath)) { string text8 = ""; using (StreamReader streamReader = new StreamReader(startDebuggingBatPath)) { text8 = streamReader.ReadLine(); } if (isDebug) { if (!text8.Contains("-noseekfreeloading")) { text8 += " -noseekfreeloading"; } } else { text8 = text8.Replace("-noseekfreeloading", ""); } File.Delete(startDebuggingBatPath); using (StreamWriter streamWriter = new StreamWriter(startDebuggingBatPath)) { streamWriter.Write(text8); } } // Delete modded new packages for (int i = 0; i < moddedNewPackages.Count; i++) { string newPackageFilePath = sdk_XComGame_Script_Path + moddedNewPackages[i] + ".u"; outer.Log.LogMessage(MessageImportance.High, "\t" + newPackageFilePath); if (File.Exists(newPackageFilePath)) { File.Delete(newPackageFilePath); } } // Compile Process process2 = new Process(); bool shouldCompileModPackage = true; // recompile sdk packages if (moddedSdkPackages.Count > 0 || shouldRecompileAllSdkPackages) { outer.Log.LogMessage(MessageImportance.High, "\nLaunching script compiler for outer game scripts...\n"); process2.StartInfo.CreateNoWindow = true; process2.StartInfo.UseShellExecute = false; process2.StartInfo.FileName = fileInfo2.FullName; process2.StartInfo.Arguments = "make " + ((outer.Config == "Debug") ? " -debug " : "") + "-nopause -unattended"; outer.Log.LogMessage(MessageImportance.High, "\tCommand: {0} Arguments: {1}", new object[] { process2.StartInfo.FileName, process2.StartInfo.Arguments }); process2.StartInfo.RedirectStandardOutput = true; process2.OutputDataReceived += new DataReceivedEventHandler(this.OutputHandler); process2.Start(); process2.BeginOutputReadLine(); process2.WaitForExit(); // check if packages exist for (int m = 0; m < moddedSdkPackages.Count; m++) { string path2 = sdk_XComGame_Script_Path + moddedSdkPackages[m] + ".u"; if (!File.Exists(path2)) { shouldCompileModPackage = false; break; } } } // recompile mod package bool flag4 = true; if (shouldCompileModPackage) { process2 = new Process(); outer.Log.LogMessage(MessageImportance.High, "\nLaunching script compiler for new package scripts...\n"); process2.StartInfo.CreateNoWindow = true; process2.StartInfo.UseShellExecute = false; process2.StartInfo.FileName = fileInfo2.FullName; process2.StartInfo.Arguments = string.Concat(new string[] { "make ", (outer.Config == "Debug") ? "-debug " : "", "-nopause -mods ", outer.ModSafeName, " \"", outer.OutputDir, "\" " }); outer.Log.LogMessage(MessageImportance.High, "\tCommand: {0} Arguments: {1}", new object[] { process2.StartInfo.FileName, process2.StartInfo.Arguments }); process2.StartInfo.RedirectStandardOutput = true; process2.OutputDataReceived += new DataReceivedEventHandler(this.HandleModCompilationOutput); process2.Start(); process2.BeginOutputReadLine(); process2.WaitForExit(); // check if packages exist for (int n = 0; n < moddedNewPackages.Count; n++) { string newPackageFilePath = sdk_XComGame_Script_Path + moddedNewPackages[n] + ".u"; if (!File.Exists(newPackageFilePath)) { flag4 = false; break; } } } if (!shouldCompileModPackage || !flag4) { return false; } // COPY packages to output outer.Log.LogMessage(MessageImportance.High, "\n\nSUCCESS! Copying compiled script binaries...\n"); string text10 = outer.OutputDir + "Script\\"; if (Directory.Exists(text10)) { Directory.Delete(text10, true); } Directory.CreateDirectory(text10); string str3 = sdkDir.FullName + "\\XComGame\\Script\\"; for (int num = 0; num < moddedSdkPackages.Count; num++) { string text11 = str3 + moddedSdkPackages[num] + ".u"; FileInfo fileInfo3 = new FileInfo(text11); if (fileInfo3 != null && fileInfo3.Exists) { string text12 = text10 + moddedSdkPackages[num] + ".u"; outer.Log.LogMessage(MessageImportance.High, "\tPackage " + moddedSdkPackages[num] + " => " + text12); File.Copy(text11, text12); } } for (int num2 = 0; num2 < moddedNewPackages.Count; num2++) { string text13 = str3 + moddedNewPackages[num2] + ".u"; FileInfo fileInfo4 = new FileInfo(text13); if (fileInfo4 != null && fileInfo4.Exists) { string text14 = text10 + moddedNewPackages[num2] + ".u"; outer.Log.LogMessage(MessageImportance.High, "\tPackage " + moddedNewPackages[num2] + " => " + text14); File.Copy(text13, text14); } } } return true; } private void HandleModCompilationOutput(object sendingProcess, DataReceivedEventArgs outLine) { if (outLine.Data != null) { string msg = "\t"; string sdkDevPath = UtilitiesXCom2.GetModdingBaseDirectory() + "\\Development\\"; string projectPath = outer.SolutionDir + outer.SolutionName + "\\"; msg += outLine.Data.Replace( sdkDevPath, projectPath ); outer.Log.LogMessage( MessageImportance.High, msg ); } } private void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) { if (outLine.Data != null) { outer.Log.LogMessage(MessageImportance.High, "\t" + outLine.Data); } } public bool CheckProperties() { return !outer.Log.HasLoggedErrors; } } private bool IgnoreThisInjectedFunction() { //return _Success; //} //} ]]> </Code> </Task> </UsingTask> </Project> 2) Open "C:\steam\steamapps\common\XCOM 2 SDK\Binaries\Win32\ModBuddy\Extensions\Application\XCOM2.targets" in a text editor (make backup blahblahblah) 3) Add the following element after "<Project ...>" tag : <Import Project="ModdedCompileScripts.targets" /> 4) Replace "<CompileScripts" by "<ModdedCompileScripts" Link to comment Share on other sites More sharing options...
Recommended Posts