Beispiel #1
0
 public override SourceFile AllocSourceFile(FileReference InitFilePath, DirectoryReference InitProjectSubFolder)
 {
     if (InitFilePath.GetFileName().StartsWith("."))
     {
         return(null);
     }
     return(new EddieSourceFile(InitFilePath, InitProjectSubFolder));
 }
Beispiel #2
0
 UProjectInfo(FileReference InFilePath, bool bInIsCodeProject)
 {
     GameName       = InFilePath.GetFileNameWithoutExtension();
     FileName       = InFilePath.GetFileName();
     FilePath       = InFilePath;
     Folder         = FilePath.Directory;
     bIsCodeProject = bInIsCodeProject;
 }
        /// <summary>
        /// Replaces a hot reload suffix in a filename.
        /// </summary>
        public static FileReference ReplaceSuffix(FileReference File, int Suffix)
        {
            string FileName = File.GetFileName();

            // Find the end of the target and module name
            int HyphenIdx = FileName.IndexOf('-');

            if (HyphenIdx == -1)
            {
                throw new BuildException("Hot-reloadable files are expected to contain a hyphen, eg. UE4Editor-Core");
            }

            int NameEndIdx = HyphenIdx + 1;

            while (NameEndIdx < FileName.Length && FileName[NameEndIdx] != '.' && FileName[NameEndIdx] != '-')
            {
                NameEndIdx++;
            }

            // Strip any existing suffix
            if (NameEndIdx + 1 < FileName.Length && Char.IsDigit(FileName[NameEndIdx + 1]))
            {
                int SuffixEndIdx = NameEndIdx + 2;
                while (SuffixEndIdx < FileName.Length && Char.IsDigit(FileName[SuffixEndIdx]))
                {
                    SuffixEndIdx++;
                }
                if (SuffixEndIdx == FileName.Length || FileName[SuffixEndIdx] == '-' || FileName[SuffixEndIdx] == '.')
                {
                    FileName = FileName.Substring(0, NameEndIdx) + FileName.Substring(SuffixEndIdx);
                }
            }

            string NewFileName = String.Format("{0}-{1:D4}{2}", FileName.Substring(0, NameEndIdx), Suffix, FileName.Substring(NameEndIdx));

            return(FileReference.Combine(File.Directory, NewFileName));
        }
Beispiel #4
0
        /// <summary>
        /// Execute the command
        /// </summary>
        /// <param name="Arguments">List of command line arguments</param>
        /// <returns>Always zero, or throws an exception</returns>
        public override int Execute(CommandLineArguments Arguments)
        {
            Arguments.ApplyTo(this);
            Arguments.CheckAllArgumentsUsed();

            Log.TraceInformation("{0}", OutputFile.GetFileName());

            // Read the input files
            string[]        InputFileLines = FileReference.ReadAllLines(InputFileList);
            FileReference[] InputFiles     = InputFileLines.Select(x => x.Trim()).Where(x => x.Length > 0).Select(x => new FileReference(x)).ToArray();

            // Create the combined output file, and print the diagnostics to the log
            HashSet <string> UniqueItems = new HashSet <string>();

            using (StreamWriter RawWriter = new StreamWriter(OutputFile.FullName))
            {
                foreach (FileReference InputFile in InputFiles)
                {
                    string[] Lines = File.ReadAllLines(InputFile.FullName);
                    for (int LineIdx = 0; LineIdx < Lines.Length; LineIdx++)
                    {
                        string Line = Lines[LineIdx];
                        if (!String.IsNullOrWhiteSpace(Line) && UniqueItems.Add(Line))
                        {
                            bool bCanParse = false;

                            string[] Tokens = Line.Split(new string[] { "<#~>" }, StringSplitOptions.None);
                            if (Tokens.Length >= 9)
                            {
                                //string Trial = Tokens[1];
                                string LineNumberStr  = Tokens[2];
                                string FileName       = Tokens[3];
                                string WarningCode    = Tokens[5];
                                string WarningMessage = Tokens[6];
                                string FalseAlarmStr  = Tokens[7];
                                string LevelStr       = Tokens[8];

                                int  LineNumber;
                                bool bFalseAlarm;
                                int  Level;
                                if (int.TryParse(LineNumberStr, out LineNumber) && bool.TryParse(FalseAlarmStr, out bFalseAlarm) && int.TryParse(LevelStr, out Level))
                                {
                                    bCanParse = true;

                                    // Ignore anything in ThirdParty folders
                                    if (FileName.Replace('/', '\\').IndexOf("\\ThirdParty\\", StringComparison.InvariantCultureIgnoreCase) == -1)
                                    {
                                        // Output the line to the raw output file
                                        RawWriter.WriteLine(Line);

                                        // Output the line to the log
                                        if (!bFalseAlarm && Level == 1)
                                        {
                                            Log.WriteLine(LogEventType.Warning, LogFormatOptions.NoSeverityPrefix, "{0}({1}): warning {2}: {3}", FileName, LineNumber, WarningCode, WarningMessage);
                                        }
                                    }
                                }
                            }

                            if (!bCanParse)
                            {
                                Log.WriteLine(LogEventType.Warning, LogFormatOptions.NoSeverityPrefix, "{0}({1}): warning: Unable to parse PVS output line '{2}' (tokens=|{3}|)", InputFile, LineIdx + 1, Line, String.Join("|", Tokens));
                            }
                        }
                    }
                }
            }
            Log.TraceInformation("Written {0} {1} to {2}.", UniqueItems.Count, (UniqueItems.Count == 1)? "diagnostic" : "diagnostics", OutputFile.FullName);
            return(0);
        }
        /// <summary>
        /// Writes a manifest containing all the information needed to create a live coding patch
        /// </summary>
        /// <param name="ManifestFile">File to write to</param>
        /// <param name="Actions">List of actions that are part of the graph</param>
        /// <param name="OriginalFileToPatchedFile">Map of original object files to patched object files</param>
        public static void WriteLiveCodingManifest(FileReference ManifestFile, List <Action> Actions, Dictionary <FileReference, FileReference> OriginalFileToPatchedFile)
        {
            // Find all the output object files
            HashSet <FileItem> ObjectFiles = new HashSet <FileItem>();

            foreach (Action Action in Actions)
            {
                if (Action.ActionType == ActionType.Compile)
                {
                    ObjectFiles.UnionWith(Action.ProducedItems.Where(x => x.HasExtension(".obj")));
                }
            }

            // Write the output manifest
            using (JsonWriter Writer = new JsonWriter(ManifestFile))
            {
                Writer.WriteObjectStart();

                Action LinkAction = Actions.FirstOrDefault(x => x.ActionType == ActionType.Link && x.ProducedItems.Any(y => y.HasExtension(".exe") || y.HasExtension(".dll")));
                if (LinkAction != null)
                {
                    FileReference LinkerPath = LinkAction.CommandPath;
                    if (String.Compare(LinkerPath.GetFileName(), "link-filter.exe", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        string[] Arguments = CommandLineArguments.Split(LinkAction.CommandArguments);
                        for (int Idx = 0; Idx + 1 < Arguments.Length; Idx++)
                        {
                            if (Arguments[Idx] == "--")
                            {
                                LinkerPath = new FileReference(Arguments[Idx + 1]);
                                break;
                            }
                        }
                    }
                    Writer.WriteValue("LinkerPath", LinkerPath.FullName);
                }

                Writer.WriteObjectStart("LinkerEnvironment");
                foreach (System.Collections.DictionaryEntry Entry in Environment.GetEnvironmentVariables())
                {
                    Writer.WriteValue(Entry.Key.ToString(), Entry.Value.ToString());
                }
                Writer.WriteObjectEnd();

                Writer.WriteArrayStart("Modules");
                foreach (Action Action in Actions)
                {
                    if (Action.ActionType == ActionType.Link)
                    {
                        FileItem OutputFile = Action.ProducedItems.FirstOrDefault(x => x.HasExtension(".exe") || x.HasExtension(".dll"));
                        if (OutputFile != null && Action.PrerequisiteItems.Any(x => OriginalFileToPatchedFile.ContainsKey(x.Location)))
                        {
                            Writer.WriteObjectStart();
                            Writer.WriteValue("Output", OutputFile.Location.FullName);

                            Writer.WriteArrayStart("Inputs");
                            foreach (FileItem InputFile in Action.PrerequisiteItems)
                            {
                                FileReference PatchedFile;
                                if (OriginalFileToPatchedFile.TryGetValue(InputFile.Location, out PatchedFile))
                                {
                                    Writer.WriteValue(PatchedFile.FullName);
                                }
                            }
                            Writer.WriteArrayEnd();

                            Writer.WriteObjectEnd();
                        }
                    }
                }
                Writer.WriteArrayEnd();

                Writer.WriteObjectEnd();
            }
        }
Beispiel #6
0
        /// <summary>
        /// Creates all the modules required for this target
        /// </summary>
        /// <param name="CreateModule">Delegate to create a module with a given name</param>
        /// <param name="ReferenceChain">Chain of references before reaching this module</param>
        public void RecursivelyCreateModules(CreateModuleDelegate CreateModule, string ReferenceChain)
        {
            // Get the reference chain for anything referenced by this module
            string NextReferenceChain = String.Format("{0} -> {1}", ReferenceChain, (RulesFile == null)? Name : RulesFile.GetFileName());

            // Recursively create all the public include path modules. These modules may not be added to the target (and we don't process their referenced
            // dependencies), but they need to be created to set up their include paths.
            RecursivelyCreateIncludePathModulesByName(Rules.PublicIncludePathModuleNames, ref PublicIncludePathModules, CreateModule, NextReferenceChain);

            // Create all the referenced modules. This path can be recursive, so we check against PrivateIncludePathModules to ensure we don't recurse through the
            // same module twice (it produces better errors if something fails).
            if (PrivateIncludePathModules == null)
            {
                // Create the private include path modules
                RecursivelyCreateIncludePathModulesByName(Rules.PrivateIncludePathModuleNames, ref PrivateIncludePathModules, CreateModule, NextReferenceChain);

                // Create all the dependency modules
                RecursivelyCreateModulesByName(Rules.PublicDependencyModuleNames, ref PublicDependencyModules, CreateModule, NextReferenceChain);
                RecursivelyCreateModulesByName(Rules.PrivateDependencyModuleNames, ref PrivateDependencyModules, CreateModule, NextReferenceChain);
                RecursivelyCreateModulesByName(Rules.DynamicallyLoadedModuleNames, ref DynamicallyLoadedModules, CreateModule, NextReferenceChain);
                RecursivelyCreateModulesByName(Rules.PlatformSpecificDynamicallyLoadedModuleNames, ref PlatformSpecificDynamicallyLoadedModules, CreateModule, NextReferenceChain);
            }
        }
Beispiel #7
0
        /// <summary>
        /// Dynamically compiles an assembly for the specified source file and loads that assembly into the application's
        /// current domain.  If an assembly has already been compiled and is not out of date, then it will be loaded and
        /// no compilation is necessary.
        /// </summary>
        /// <param name="OutputAssemblyPath">Full path to the assembly to be created</param>
        /// <param name="SourceFileNames">List of source file name</param>
        /// <param name="ReferencedAssembies"></param>
        /// <param name="PreprocessorDefines"></param>
        /// <param name="DoNotCompile"></param>
        /// <param name="TreatWarningsAsErrors"></param>
        /// <returns>The assembly that was loaded</returns>
        public static Assembly CompileAndLoadAssembly(FileReference OutputAssemblyPath, HashSet <FileReference> SourceFileNames, List <string> ReferencedAssembies = null, List <string> PreprocessorDefines = null, bool DoNotCompile = false, bool TreatWarningsAsErrors = false)
        {
            // Check to see if the resulting assembly is compiled and up to date
            FileReference AssemblyManifestFilePath = FileReference.Combine(OutputAssemblyPath.Directory, Path.GetFileNameWithoutExtension(OutputAssemblyPath.FullName) + "Manifest.json");

            bool bNeedsCompilation = false;

            if (!DoNotCompile)
            {
                bNeedsCompilation = RequiresCompilation(SourceFileNames, AssemblyManifestFilePath, OutputAssemblyPath);
            }

            // Load the assembly to ensure it is correct
            Assembly CompiledAssembly = null;

            if (!bNeedsCompilation)
            {
                try
                {
                    // Load the previously-compiled assembly from disk
                    CompiledAssembly = Assembly.LoadFile(OutputAssemblyPath.FullName);
                }
                catch (FileLoadException Ex)
                {
                    Log.TraceInformation(String.Format("Unable to load the previously-compiled assembly file '{0}'.  Unreal Build Tool will try to recompile this assembly now.  (Exception: {1})", OutputAssemblyPath, Ex.Message));
                    bNeedsCompilation = true;
                }
                catch (BadImageFormatException Ex)
                {
                    Log.TraceInformation(String.Format("Compiled assembly file '{0}' appears to be for a newer CLR version or is otherwise invalid.  Unreal Build Tool will try to recompile this assembly now.  (Exception: {1})", OutputAssemblyPath, Ex.Message));
                    bNeedsCompilation = true;
                }
                catch (FileNotFoundException)
                {
                    throw new BuildException("Precompiled rules assembly '{0}' does not exist.", OutputAssemblyPath);
                }
                catch (Exception Ex)
                {
                    throw new BuildException(Ex, "Error while loading previously-compiled assembly file '{0}'.  (Exception: {1})", OutputAssemblyPath, Ex.Message);
                }
            }

            // Compile the assembly if me
            if (bNeedsCompilation)
            {
                using (Timeline.ScopeEvent(String.Format("Compiling rules assembly ({0})", OutputAssemblyPath.GetFileName())))
                {
                    CompiledAssembly = CompileAssembly(OutputAssemblyPath, SourceFileNames, ReferencedAssembies, PreprocessorDefines, TreatWarningsAsErrors);
                }

                using (JsonWriter Writer = new JsonWriter(AssemblyManifestFilePath))
                {
                    ReadOnlyBuildVersion Version = ReadOnlyBuildVersion.Current;

                    Writer.WriteObjectStart();
                    // Save out a list of all the source files we compiled.  This is so that we can tell if whole files were added or removed
                    // since the previous time we compiled the assembly.  In that case, we'll always want to recompile it!
                    Writer.WriteStringArrayField("SourceFiles", SourceFileNames.Select(x => x.FullName));
                    Writer.WriteValue("EngineVersion", FormatVersionNumber(Version));
                    Writer.WriteObjectEnd();
                }
            }

#if !NET_CORE
            // Load the assembly into our app domain
            try
            {
                AppDomain.CurrentDomain.Load(CompiledAssembly.GetName());
            }
            catch (Exception Ex)
            {
                throw new BuildException(Ex, "Unable to load the compiled build assembly '{0}' into our application's domain.  (Exception: {1})", OutputAssemblyPath, Ex.Message);
            }
#endif

            return(CompiledAssembly);
        }
Beispiel #8
0
        /// <summary>
        /// Return any custom paths for VisualStudio this platform requires
        /// This include ReferencePath, LibraryPath, LibraryWPath, IncludePath and ExecutablePath.
        /// </summary>
        /// <param name="InPlatform">The UnrealTargetPlatform being built</param>
        /// <param name="InConfiguration">The configuration being built</param>
        /// <param name="TargetType">The type of target (game or program)</param>
        /// <param name="TargetRulesPath">Path to the target.cs file</param>
        /// <param name="ProjectFilePath">Path to the project file</param>
        /// <param name="NMakeOutputPath"></param>
        /// <param name="InProjectFileFormat">Format for the generated project files</param>
        /// <param name="ProjectFileBuilder">The project file content</param>
        /// <returns>The custom path lines for the project file; Empty string if it doesn't require one</returns>
        public override void GetVisualStudioPathsEntries(UnrealTargetPlatform InPlatform, UnrealTargetConfiguration InConfiguration, TargetType TargetType, FileReference TargetRulesPath, FileReference ProjectFilePath, FileReference NMakeOutputPath, VCProjectFileFormat InProjectFileFormat, StringBuilder ProjectFileBuilder)
        {
            base.GetVisualStudioPathsEntries(InPlatform, InConfiguration, TargetType, TargetRulesPath, ProjectFilePath, NMakeOutputPath, InProjectFileFormat, ProjectFileBuilder);

            if (IsVSLuminSupportInstalled(InProjectFileFormat) && TargetType == TargetType.Game && InPlatform == UnrealTargetPlatform.Lumin)
            {
                string MLSDK = Utils.CleanDirectorySeparators(Environment.GetEnvironmentVariable("MLSDK"), '\\');

                // TODO: Check if MPK name can be other than the project name.
                string GameName = TargetRulesPath.GetFileNameWithoutExtension();
                GameName = Path.GetFileNameWithoutExtension(GameName);

                string PackageFile = Utils.MakePathRelativeTo(NMakeOutputPath.Directory.FullName, ProjectFilePath.Directory.FullName);
                string PackageName = GameName;
                if (InConfiguration != UnrealTargetConfiguration.Development)
                {
                    PackageName = GameName + "-" + InPlatform.ToString() + "-" + InConfiguration.ToString();
                }
                PackageFile = Path.Combine(PackageFile, PackageName + ".mpk");

                // Can't use $(NMakeOutput) directly since that is defined after <ELFFile> tag and thus ends up being translated as an empty string.
                string ELFFile = Utils.MakePathRelativeTo(NMakeOutputPath.Directory.FullName, ProjectFilePath.Directory.FullName);
                // Provide path to stripped executable so all symbols are resolved from the external sym file instead.
                ELFFile = Path.Combine(ELFFile, "..\\..\\Intermediate\\Lumin\\Mabu\\Binaries", GetElfName(NMakeOutputPath));
                string DebuggerFlavor = "MLDebugger";

                string SymFile = Utils.MakePathRelativeTo(NMakeOutputPath.Directory.FullName, ProjectFilePath.Directory.FullName);
                SymFile = Path.Combine(SymFile, "..\\..\\Intermediate\\Lumin\\Mabu\\Binaries", Path.ChangeExtension(NMakeOutputPath.GetFileName(), ".sym"));

                // following are defaults for debugger options
                string Attach               = "false";
                string EnableAutoStop       = "true";
                string AutoStopAtFunction   = "main";
                string EnablePrettyPrinting = "true";
                string MLDownloadOnStart    = "true";

                string CustomPathEntriesTemplate = "<MLSDK>{0}</MLSDK>" + ProjectFileGenerator.NewLine +
                                                   "<PackageFile>{1}</PackageFile>" + ProjectFileGenerator.NewLine +
                                                   "<ELFFile>{2}</ELFFile>" + ProjectFileGenerator.NewLine +
                                                   "<DebuggerFlavor>{3}</DebuggerFlavor>" + ProjectFileGenerator.NewLine +
                                                   "<Attach>{4}</Attach>" + ProjectFileGenerator.NewLine +
                                                   "<EnableAutoStop>{5}</EnableAutoStop>" + ProjectFileGenerator.NewLine +
                                                   "<AutoStopAtFunction>{6}</AutoStopAtFunction>" + ProjectFileGenerator.NewLine +
                                                   "<EnablePrettyPrinting>{7}</EnablePrettyPrinting>" + ProjectFileGenerator.NewLine +
                                                   "<MLDownloadOnStart>{8}</MLDownloadOnStart>" + ProjectFileGenerator.NewLine;
                // No need to provide SymFile path. The file is automatically picked up when it resides in the same folder and has the same name as the ElfFile
                // "<SymFile>{9}</SymFile>" + ProjectFileGenerator.NewLine;
                ProjectFileBuilder.Append(ProjectFileGenerator.NewLine + string.Format(CustomPathEntriesTemplate, MLSDK, PackageFile, ELFFile, DebuggerFlavor, Attach, EnableAutoStop, AutoStopAtFunction, EnablePrettyPrinting, MLDownloadOnStart));
            }
        }
        /// <summary>
        /// For platforms that need to output multiple files per binary (ie Android "fat" binaries)
        /// this will emit multiple paths. By default, it simply makes an array from the input
        /// </summary>
        public override List <FileReference> FinalizeBinaryPaths(FileReference BinaryName, FileReference ProjectFile, ReadOnlyTargetRules Target)
        {
            List <FileReference> BinaryPaths = new List <FileReference>();

            if (Target.bIsBuildingConsoleApplication || !String.IsNullOrEmpty(BinaryName.GetExtension()))
            {
                BinaryPaths.Add(BinaryName);
            }
            else
            {
                BinaryPaths.Add(new FileReference(BinaryName.FullName + ".app/Contents/MacOS/" + BinaryName.GetFileName()));
            }
            return(BinaryPaths);
        }
Beispiel #10
0
        private void WriteLaunchFile()
        {
            JsonFile   OutFile   = new JsonFile();
            EDebugMode DebugMode = (HostPlatform == UnrealTargetPlatform.Win64) ? EDebugMode.VS : EDebugMode.GDB;

            OutFile.BeginRootObject();
            {
                OutFile.AddField("version", "0.2.0");
                OutFile.BeginArray("configurations");
                {
                    List <ProjectFile> Projects = new List <ProjectFile>(GeneratedProjectFiles);
                    Projects.Sort((A, B) => { return(A.ProjectFilePath.GetFileNameWithoutExtension().CompareTo(B.ProjectFilePath.GetFileNameWithoutExtension())); });

                    foreach (ProjectFile Project in AllProjectFiles)
                    {
                        if (Project.ProjectFilePath.GetExtension() == ProjectFileExtension)
                        {
                            foreach (ProjectTarget Target in Project.ProjectTargets)
                            {
                                List <UnrealTargetConfiguration> Configs = new List <UnrealTargetConfiguration>();
                                Target.TargetRules.GetSupportedConfigurations(ref Configs, true);

                                foreach (UnrealTargetConfiguration Config in Configs)
                                {
                                    if (SupportedConfigurations.Contains(Config))
                                    {
                                        FileReference Executable = GetExecutableFilename(Project, Target, HostPlatform, Config);
                                        string        Name       = Target.TargetRules == null?Project.ProjectFilePath.GetFileNameWithoutExtension() : Target.TargetRules.Name;

                                        string LaunchTaskName      = $"{Name} {HostPlatform} {Config} Build";
                                        string ExecutableDirectory = "${workspaceRoot}/" + Executable.Directory.MakeRelativeTo(UnrealBuildTool.RootDirectory).ToString().Replace("\\", "/");

                                        OutFile.BeginObject();
                                        {
                                            OutFile.AddField("name", Target.TargetRules.Name + " (" + Config.ToString() + ")");
                                            OutFile.AddField("request", "launch");
                                            OutFile.AddField("preLaunchTask", LaunchTaskName);
                                            OutFile.AddField("program", ExecutableDirectory + "/" + Executable.GetFileName());

                                            OutFile.BeginArray("args");
                                            {
                                            }
                                            OutFile.EndArray();
                                            OutFile.AddField("stopAtEntry", true);
                                            OutFile.AddField("cwd", ExecutableDirectory);
                                            OutFile.BeginArray("environment");
                                            {
                                            }
                                            OutFile.EndArray();
                                            OutFile.AddField("externalConsole", true);

                                            switch (DebugMode)
                                            {
                                            case EDebugMode.VS:
                                            {
                                                OutFile.AddField("type", "cppvsdbg");
                                                break;
                                            }

                                            case EDebugMode.GDB:
                                            {
                                                OutFile.AddField("type", "cppdbg");
                                                OutFile.AddField("MIMode", "lldb");
                                                break;
                                            }
                                            }
                                        }
                                        OutFile.EndObject();
                                    }
                                }
                            }
                        }
                        else if (Project.ProjectFilePath.GetExtension() == ".csproj")
                        {
                            /*
                             * foreach (ProjectTarget Target in Project.ProjectTargets)
                             * {
                             *      foreach (UnrealTargetConfiguration Config in Target.ExtraSupportedConfigurations)
                             *      {
                             *              string TaskName = $"{Project.ProjectFilePath.GetFileNameWithoutExtension()} ({Config})";
                             *              string BuildTaskName = $"{Project.ProjectFilePath.GetFileNameWithoutExtension()} {HostPlatform} {Config} Build";
                             *              FileReference Executable = GetExecutableFilename(Project, Target, HostPlatform, Config);
                             *
                             *              OutFile.BeginObject();
                             *              {
                             *                      OutFile.AddField("name", TaskName);
                             *                      OutFile.AddField("type", "coreclr");
                             *                      OutFile.AddField("request", "launch");
                             *                      OutFile.AddField("preLaunchTask", BuildTaskName);
                             *                      OutFile.AddField("program", Executable.ToString());
                             *                      OutFile.BeginArray("args");
                             *                      {
                             *
                             *                      }
                             *                      OutFile.EndArray();
                             *              }
                             *              OutFile.EndObject();
                             *      }
                             * }
                             */
                        }
                    }
                }
                OutFile.EndArray();
            }
            OutFile.EndRootObject();

            OutFile.Write(FileReference.Combine(VSCodeDir, "launch.json"));
        }
        /// <summary>
        /// Return any custom paths for VisualStudio this platform requires
        /// This include ReferencePath, LibraryPath, LibraryWPath, IncludePath and ExecutablePath.
        /// </summary>
        /// <param name="InPlatform">The UnrealTargetPlatform being built</param>
        /// <param name="InConfiguration">The configuration being built</param>
        /// <param name="TargetType">The type of target (game or program)</param>
        /// <param name="TargetRulesPath">Path to the target.cs file</param>
        /// <param name="ProjectFilePath">Path to the project file</param>
        /// <param name="NMakeOutputPath"></param>
        /// <param name="InProjectFileFormat">Format for the generated project files</param>
        /// <param name="ProjectFileBuilder">The project file content</param>
        /// <returns>The custom path lines for the project file; Empty string if it doesn't require one</returns>
        public override void GetVisualStudioPathsEntries(UnrealTargetPlatform InPlatform, UnrealTargetConfiguration InConfiguration, TargetType TargetType, FileReference TargetRulesPath, FileReference ProjectFilePath, FileReference NMakeOutputPath, VCProjectFileFormat InProjectFileFormat, StringBuilder ProjectFileBuilder)
        {
            base.GetVisualStudioPathsEntries(InPlatform, InConfiguration, TargetType, TargetRulesPath, ProjectFilePath, NMakeOutputPath, InProjectFileFormat, ProjectFileBuilder);

            if (IsVSLuminSupportInstalled(InProjectFileFormat) && TargetType == TargetType.Game && InPlatform == UnrealTargetPlatform.Lumin)
            {
                string MLSDK = Utils.CleanDirectorySeparators(Environment.GetEnvironmentVariable("MLSDK"), '\\');

                // TODO: Check if MPK name can be other than the project name.
                string GameName = TargetRulesPath.GetFileNameWithoutExtension();
                GameName = Path.GetFileNameWithoutExtension(GameName);

                string PackageFile = Utils.MakePathRelativeTo(NMakeOutputPath.Directory.FullName, ProjectFilePath.Directory.FullName);
                string PackageName = GameName;
                if (InConfiguration != UnrealTargetConfiguration.Development)
                {
                    PackageName = GameName + "-" + InPlatform.ToString() + "-" + InConfiguration.ToString();
                }
                PackageFile = Path.Combine(PackageFile, PackageName + ".mpk");

                // TODO: Fix NMakeOutput to have the the correct architecture name and then set ELFFile to $(NMakeOutput)
                string ELFFile = Utils.MakePathRelativeTo(NMakeOutputPath.Directory.FullName, ProjectFilePath.Directory.FullName);
                ELFFile = Path.Combine(ELFFile, "..\\..\\Intermediate\\Lumin\\Mabu\\Packaged\\bin\\" + GameName);
                string DebuggerFlavor = "MLDebugger";

                string SymFile = Utils.MakePathRelativeTo(NMakeOutputPath.Directory.FullName, ProjectFilePath.Directory.FullName);
                SymFile = Path.Combine(SymFile, "..\\..\\Intermediate\\Lumin\\Mabu\\Binaries", Path.ChangeExtension(NMakeOutputPath.GetFileName(), ".sym"));

                // following are defaults for debugger options
                string Attach               = "false";
                string EnableAutoStop       = "true";
                string AutoStopAtFunction   = "main";
                string EnablePrettyPrinting = "true";
                string MLDownloadOnStart    = "true";

                string CustomPathEntriesTemplate = "<MLSDK>{0}</MLSDK>" + ProjectFileGenerator.NewLine +
                                                   "<PackageFile>{1}</PackageFile>" + ProjectFileGenerator.NewLine +
                                                   "<ELFFile>{2}</ELFFile>" + ProjectFileGenerator.NewLine +
                                                   "<DebuggerFlavor>{3}</DebuggerFlavor>" + ProjectFileGenerator.NewLine +
                                                   "<Attach>{4}</Attach>" + ProjectFileGenerator.NewLine +
                                                   "<EnableAutoStop>{5}</EnableAutoStop>" + ProjectFileGenerator.NewLine +
                                                   "<AutoStopAtFunction>{6}</AutoStopAtFunction>" + ProjectFileGenerator.NewLine +
                                                   "<EnablePrettyPrinting>{7}</EnablePrettyPrinting>" + ProjectFileGenerator.NewLine +
                                                   "<MLDownloadOnStart>{8}</MLDownloadOnStart>" + ProjectFileGenerator.NewLine +
                                                   "<SymFile>{9}</SymFile>" + ProjectFileGenerator.NewLine;
                ProjectFileBuilder.Append(ProjectFileGenerator.NewLine + string.Format(CustomPathEntriesTemplate, MLSDK, PackageFile, ELFFile, DebuggerFlavor, Attach, EnableAutoStop, AutoStopAtFunction, EnablePrettyPrinting, MLDownloadOnStart, SymFile));
            }
        }