// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Tools.DotNETCommon;
namespace UnrealBuildTool
{
///
/// The version format for .uproject files. This rarely changes now; project descriptors should maintain backwards compatibility automatically.
///
enum ProjectDescriptorVersion
{
///
/// Invalid
///
Invalid = 0,
///
/// Initial version
///
Initial = 1,
///
/// Adding SampleNameHash
///
NameHash = 2,
///
/// Unifying plugin/project files (since abandoned, but backwards compatibility maintained)
///
ProjectPluginUnification = 3,
///
/// This needs to be the last line, so we can calculate the value of Latest below
///
LatestPlusOne,
///
/// The latest plugin descriptor version
///
Latest = LatestPlusOne - 1
}
///
/// In-memory representation of a .uproject file
///
public class ProjectDescriptor
{
///
/// Descriptor version number.
///
public int FileVersion;
///
/// The engine to open this project with.
///
public string EngineAssociation;
///
/// Category to show under the project browser
///
public string Category;
///
/// Description to show in the project browser
///
public string Description;
///
/// List of all modules associated with this project
///
public ModuleDescriptor[] Modules;
///
/// List of plugins for this project (may be enabled/disabled)
///
public PluginReferenceDescriptor[] Plugins;
///
/// List of additional plugin directories to scan for available plugins
///
public string[] AdditionalPluginDirectories;
///
/// Array of platforms that this project is targeting
///
public string[] TargetPlatforms;
///
/// A hash that is used to determine if the project was forked from a sample
///
public uint EpicSampleNameHash;
///
/// Steps to execute before building targets in this project
///
public CustomBuildSteps PreBuildSteps;
///
/// Steps to execute before building targets in this project
///
public CustomBuildSteps PostBuildSteps;
///
/// Indicates if this project is an Enterprise project
///
public bool IsEnterpriseProject;
///
/// Constructor.
///
public ProjectDescriptor()
{
FileVersion = (int)ProjectDescriptorVersion.Latest;
IsEnterpriseProject = false;
}
///
/// Constructor
///
/// Raw JSON object to parse
public ProjectDescriptor(JsonObject RawObject)
{
// Read the version
if (!RawObject.TryGetIntegerField("FileVersion", out FileVersion))
{
if (!RawObject.TryGetIntegerField("ProjectFileVersion", out FileVersion))
{
throw new BuildException("Project does not contain a valid FileVersion entry");
}
}
// Check it's not newer than the latest version we can parse
if (FileVersion > (int)PluginDescriptorVersion.Latest)
{
throw new BuildException("Project descriptor appears to be in a newer version ({0}) of the file format that we can load (max version: {1}).", FileVersion, (int)ProjectDescriptorVersion.Latest);
}
// Read simple fields
RawObject.TryGetStringField("EngineAssociation", out EngineAssociation);
RawObject.TryGetStringField("Category", out Category);
RawObject.TryGetStringField("Description", out Description);
RawObject.TryGetBoolField("Enterprise", out IsEnterpriseProject);
// Read the modules
JsonObject[] ModulesArray;
if (RawObject.TryGetObjectArrayField("Modules", out ModulesArray))
{
Modules = Array.ConvertAll(ModulesArray, x => ModuleDescriptor.FromJsonObject(x));
}
// Read the plugins
JsonObject[] PluginsArray;
if (RawObject.TryGetObjectArrayField("Plugins", out PluginsArray))
{
Plugins = Array.ConvertAll(PluginsArray, x => PluginReferenceDescriptor.FromJsonObject(x));
}
// Read the additional plugin directories
RawObject.TryGetStringArrayField("AdditionalPluginDirectories", out AdditionalPluginDirectories);
// Read the target platforms
RawObject.TryGetStringArrayField("TargetPlatforms", out TargetPlatforms);
// Get the sample name hash
RawObject.TryGetUnsignedIntegerField("EpicSampleNameHash", out EpicSampleNameHash);
// Read the pre and post-build steps
CustomBuildSteps.TryRead(RawObject, "PreBuildSteps", out PreBuildSteps);
CustomBuildSteps.TryRead(RawObject, "PostBuildSteps", out PostBuildSteps);
}
///
/// Creates a plugin descriptor from a file on disk
///
/// The filename to read
/// New plugin descriptor
public static ProjectDescriptor FromFile(FileReference FileName)
{
JsonObject RawObject = JsonObject.Read(FileName);
try
{
return new ProjectDescriptor(RawObject);
}
catch (JsonParseException ParseException)
{
throw new JsonParseException("{0} (in {1})", ParseException.Message, FileName);
}
}
///
/// Saves the descriptor to disk
///
/// The filename to write to
public void Save(string FileName)
{
using (JsonWriter Writer = new JsonWriter(FileName))
{
Writer.WriteObjectStart();
Write(Writer);
Writer.WriteObjectEnd();
}
}
///
/// Writes the plugin descriptor to an existing Json writer
///
/// The writer to receive plugin data
public void Write(JsonWriter Writer)
{
Writer.WriteValue("FileVersion", (int)ProjectDescriptorVersion.Latest);
Writer.WriteValue("EngineAssociation", EngineAssociation);
Writer.WriteValue("Category", Category);
Writer.WriteValue("Description", Description);
// Write the enterprise flag
if (IsEnterpriseProject)
{
Writer.WriteValue("Enterprise", IsEnterpriseProject);
}
// Write the module list
ModuleDescriptor.WriteArray(Writer, "Modules", Modules);
// Write the plugin list
PluginReferenceDescriptor.WriteArray(Writer, "Plugins", Plugins);
// Write out the additional plugin directories to scan
if(AdditionalPluginDirectories != null && AdditionalPluginDirectories.Length > 0)
{
Writer.WriteStringArrayField("AdditionalPluginDirectories", AdditionalPluginDirectories);
}
// Write the target platforms
if(TargetPlatforms != null && TargetPlatforms.Length > 0)
{
Writer.WriteStringArrayField("TargetPlatforms", TargetPlatforms);
}
// If it's a signed sample, write the name hash
if(EpicSampleNameHash != 0)
{
Writer.WriteValue("EpicSampleNameHash", (uint)EpicSampleNameHash);
}
// Write the custom build steps
if(PreBuildSteps != null)
{
PreBuildSteps.Write(Writer, "PreBuildSteps");
}
if(PostBuildSteps != null)
{
PostBuildSteps.Write(Writer, "PostBuildSteps");
}
}
}
}