Jump to content

ModBuddy : goto error/warning in 2 clicks


OVNI

Recommended Posts

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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...