(ded4a3e0a) v0.9.0.7
This commit is contained in:
@@ -0,0 +1,504 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework.Content.Pipeline;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGame.Framework.Content.Pipeline.Builder;
|
||||
|
||||
|
||||
namespace MGCB
|
||||
{
|
||||
class BuildContent
|
||||
{
|
||||
[CommandLineParameter(
|
||||
Name = "launchdebugger",
|
||||
Flag = "d",
|
||||
Description = "Wait for debugger to attach before building content.")]
|
||||
public bool LaunchDebugger = false;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "quiet",
|
||||
Flag = "q",
|
||||
Description = "Only output content build errors.")]
|
||||
public bool Quiet = false;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "@",
|
||||
Flag = "@",
|
||||
ValueName = "responseFile",
|
||||
Description = "Read a text response file with additional command line options and switches.")]
|
||||
// This property only exists for documentation.
|
||||
// The actual handling of '/@' is done in the preprocess step.
|
||||
public List<string> ResponseFiles
|
||||
{
|
||||
get { throw new InvalidOperationException(); }
|
||||
set { throw new InvalidOperationException(); }
|
||||
}
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "workingDir",
|
||||
Flag = "w",
|
||||
ValueName = "directoryPath",
|
||||
Description = "The working directory where all source content is located.")]
|
||||
public void SetWorkingDir(string path)
|
||||
{
|
||||
Directory.SetCurrentDirectory(path);
|
||||
}
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "outputDir",
|
||||
Flag = "o",
|
||||
ValueName = "path",
|
||||
Description = "The directory where all content is written.")]
|
||||
public string OutputDir = string.Empty;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "intermediateDir",
|
||||
Flag = "n",
|
||||
ValueName = "path",
|
||||
Description = "The directory where all intermediate files are written.")]
|
||||
public string IntermediateDir = string.Empty;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "rebuild",
|
||||
Flag = "r",
|
||||
Description = "Forces a full rebuild of all content.")]
|
||||
public bool Rebuild = false;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "clean",
|
||||
Flag = "c",
|
||||
Description = "Delete all previously built content and intermediate files.")]
|
||||
public bool Clean = false;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "incremental",
|
||||
Flag = "I",
|
||||
Description = "Skip cleaning files not included in the current build.")]
|
||||
public bool Incremental = false;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "reference",
|
||||
Flag = "f",
|
||||
ValueName = "assembly",
|
||||
Description = "Adds an assembly reference for resolving content importers, processors, and writers.")]
|
||||
public readonly List<string> References = new List<string>();
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "platform",
|
||||
Flag = "t",
|
||||
ValueName = "targetPlatform",
|
||||
Description = "Set the target platform for this build. Defaults to Windows desktop DirectX.")]
|
||||
public TargetPlatform Platform = TargetPlatform.Windows;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "profile",
|
||||
Flag = "g",
|
||||
ValueName = "graphicsProfile",
|
||||
Description = "Set the target graphics profile for this build. Defaults to HiDef.")]
|
||||
public GraphicsProfile Profile = GraphicsProfile.HiDef;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "config",
|
||||
ValueName = "string",
|
||||
Description = "The optional build config string from the build system.")]
|
||||
public string Config = string.Empty;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "importer",
|
||||
Flag = "i",
|
||||
ValueName = "className",
|
||||
Description = "Defines the class name of the content importer for reading source content.")]
|
||||
public string Importer = null;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "processor",
|
||||
Flag = "p",
|
||||
ValueName = "className",
|
||||
Description = "Defines the class name of the content processor for processing imported content.")]
|
||||
public void SetProcessor(string processor)
|
||||
{
|
||||
_processor = processor;
|
||||
|
||||
// If you are changing the processor then reset all
|
||||
// the processor parameters.
|
||||
_processorParams.Clear();
|
||||
}
|
||||
|
||||
private string _processor = null;
|
||||
private readonly OpaqueDataDictionary _processorParams = new OpaqueDataDictionary();
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "processorParam",
|
||||
Flag = "P",
|
||||
ValueName = "name=value",
|
||||
Description = "Defines a parameter name and value to set on a content processor.")]
|
||||
public void AddProcessorParam(string nameAndValue)
|
||||
{
|
||||
var keyAndValue = nameAndValue.Split('=', ':');
|
||||
if (keyAndValue.Length != 2)
|
||||
{
|
||||
// Do we error out or something?
|
||||
return;
|
||||
}
|
||||
|
||||
_processorParams.Remove(keyAndValue[0]);
|
||||
_processorParams.Add(keyAndValue[0], keyAndValue[1]);
|
||||
}
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "build",
|
||||
Flag = "b",
|
||||
ValueName = "sourceFile",
|
||||
Description = "Build the content source file using the previously set switches and options. Optional destination path may be specified with \"sourceFile;destFile\" if you wish to change the output filepath.")]
|
||||
public void OnBuild(string sourceFile)
|
||||
{
|
||||
string link = null;
|
||||
if (sourceFile.Contains(";"))
|
||||
{
|
||||
var split = sourceFile.Split(';');
|
||||
sourceFile = split[0];
|
||||
|
||||
if(split.Length > 0)
|
||||
link = split[1];
|
||||
}
|
||||
|
||||
// Make sure the source file is absolute.
|
||||
if (!Path.IsPathRooted(sourceFile))
|
||||
sourceFile = Path.Combine(Directory.GetCurrentDirectory(), sourceFile);
|
||||
|
||||
// link should remain relative, absolute path will get set later when the build occurs
|
||||
|
||||
sourceFile = PathHelper.Normalize(sourceFile);
|
||||
|
||||
// Remove duplicates... keep this new one.
|
||||
var previous = _content.FindIndex(e => string.Equals(e.SourceFile, sourceFile, StringComparison.InvariantCultureIgnoreCase));
|
||||
if (previous != -1)
|
||||
_content.RemoveAt(previous);
|
||||
|
||||
// Create the item for processing later.
|
||||
var item = new ContentItem
|
||||
{
|
||||
SourceFile = sourceFile,
|
||||
OutputFile = link,
|
||||
Importer = Importer,
|
||||
Processor = _processor,
|
||||
ProcessorParams = new OpaqueDataDictionary()
|
||||
};
|
||||
_content.Add(item);
|
||||
|
||||
// Copy the current processor parameters blind as we
|
||||
// will validate and remove invalid parameters during
|
||||
// the build process later.
|
||||
foreach (var pair in _processorParams)
|
||||
item.ProcessorParams.Add(pair.Key, pair.Value);
|
||||
}
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "copy",
|
||||
ValueName = "sourceFile",
|
||||
Description = "Copy the content source file verbatim to the output directory.")]
|
||||
public void OnCopy(string sourceFile)
|
||||
{
|
||||
string link = null;
|
||||
if (sourceFile.Contains(";"))
|
||||
{
|
||||
var split = sourceFile.Split(';');
|
||||
sourceFile = split[0];
|
||||
|
||||
if (split.Length > 0)
|
||||
link = split[1];
|
||||
}
|
||||
|
||||
if (!Path.IsPathRooted(sourceFile))
|
||||
sourceFile = Path.Combine(Directory.GetCurrentDirectory(), sourceFile);
|
||||
|
||||
sourceFile = PathHelper.Normalize(sourceFile);
|
||||
|
||||
// Remove duplicates... keep this new one.
|
||||
var previous = _copyItems.FindIndex(e => string.Equals(e.SourceFile, sourceFile, StringComparison.InvariantCultureIgnoreCase));
|
||||
if (previous != -1)
|
||||
_copyItems.RemoveAt(previous);
|
||||
|
||||
_copyItems.Add(new CopyItem { SourceFile = sourceFile, Link = link });
|
||||
}
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "compress",
|
||||
Description = "Compress the XNB files for smaller file sizes.")]
|
||||
public bool CompressContent = false;
|
||||
|
||||
public class ContentItem
|
||||
{
|
||||
public string SourceFile;
|
||||
|
||||
// This refers to the "Link" which can override the default output location
|
||||
public string OutputFile;
|
||||
public string Importer;
|
||||
public string Processor;
|
||||
public OpaqueDataDictionary ProcessorParams;
|
||||
}
|
||||
|
||||
public class CopyItem
|
||||
{
|
||||
public string SourceFile;
|
||||
public string Link;
|
||||
}
|
||||
|
||||
private readonly List<ContentItem> _content = new List<ContentItem>();
|
||||
|
||||
private readonly List<CopyItem> _copyItems = new List<CopyItem>();
|
||||
|
||||
private PipelineManager _manager;
|
||||
|
||||
public bool HasWork
|
||||
{
|
||||
get { return _content.Count > 0 || _copyItems.Count > 0 || Clean; }
|
||||
}
|
||||
|
||||
string ReplaceSymbols(string parameter)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(parameter))
|
||||
return parameter;
|
||||
return parameter
|
||||
.Replace("$(Platform)", Platform.ToString())
|
||||
.Replace("$(Configuration)", Config)
|
||||
.Replace("$(Config)", Config)
|
||||
.Replace("$(Profile)", this.Profile.ToString());
|
||||
}
|
||||
|
||||
public void Build(out int successCount, out int errorCount)
|
||||
{
|
||||
var projectDirectory = PathHelper.Normalize(Directory.GetCurrentDirectory());
|
||||
|
||||
var outputPath = ReplaceSymbols (OutputDir);
|
||||
if (!Path.IsPathRooted(outputPath))
|
||||
outputPath = PathHelper.Normalize(Path.GetFullPath(Path.Combine(projectDirectory, outputPath)));
|
||||
|
||||
var intermediatePath = ReplaceSymbols (IntermediateDir);
|
||||
if (!Path.IsPathRooted(intermediatePath))
|
||||
intermediatePath = PathHelper.Normalize(Path.GetFullPath(Path.Combine(projectDirectory, intermediatePath)));
|
||||
|
||||
_manager = new PipelineManager(projectDirectory, outputPath, intermediatePath);
|
||||
_manager.Logger = new ConsoleLogger();
|
||||
_manager.CompressContent = CompressContent;
|
||||
|
||||
// If the intent is to debug build, break at the original location
|
||||
// of any exception, eg, within the actual importer/processor.
|
||||
if (LaunchDebugger)
|
||||
_manager.RethrowExceptions = false;
|
||||
|
||||
// Feed all the assembly references to the pipeline manager
|
||||
// so it can resolve importers, processors, writers, and types.
|
||||
foreach (var r in References)
|
||||
{
|
||||
var assembly = r;
|
||||
if (!Path.IsPathRooted(assembly))
|
||||
assembly = Path.GetFullPath(Path.Combine(projectDirectory, assembly));
|
||||
_manager.AddAssembly(assembly);
|
||||
}
|
||||
|
||||
// Load the previously serialized list of built content.
|
||||
var contentFile = Path.Combine(intermediatePath, PipelineBuildEvent.Extension);
|
||||
var previousContent = SourceFileCollection.Read(contentFile);
|
||||
|
||||
// If the target changed in any way then we need to force
|
||||
// a full rebuild even under incremental builds.
|
||||
var targetChanged = previousContent.Config != Config ||
|
||||
previousContent.Platform != Platform ||
|
||||
previousContent.Profile != Profile;
|
||||
|
||||
// First clean previously built content.
|
||||
for(int i = 0; i < previousContent.SourceFiles.Count; i++)
|
||||
{
|
||||
var sourceFile = previousContent.SourceFiles[i];
|
||||
|
||||
// This may be an old file (prior to MG 3.7) which doesn't have destination files:
|
||||
string destFile = null;
|
||||
if(i < previousContent.DestFiles.Count)
|
||||
{
|
||||
destFile = previousContent.DestFiles[i];
|
||||
}
|
||||
|
||||
var inContent = _content.Any(e => string.Equals(e.SourceFile, sourceFile, StringComparison.InvariantCultureIgnoreCase));
|
||||
var cleanOldContent = !inContent && !Incremental;
|
||||
var cleanRebuiltContent = inContent && (Rebuild || Clean);
|
||||
if (cleanRebuiltContent || cleanOldContent || targetChanged)
|
||||
_manager.CleanContent(sourceFile, destFile);
|
||||
}
|
||||
|
||||
// TODO: Should we be cleaning copy items? I think maybe we should.
|
||||
|
||||
var newContent = new SourceFileCollection
|
||||
{
|
||||
Profile = _manager.Profile = Profile,
|
||||
Platform = _manager.Platform = Platform,
|
||||
Config = _manager.Config = Config
|
||||
};
|
||||
errorCount = 0;
|
||||
successCount = 0;
|
||||
|
||||
// Before building the content, register all files to be built. (Necessary to
|
||||
// correctly resolve external references.)
|
||||
foreach (var c in _content)
|
||||
{
|
||||
try
|
||||
{
|
||||
_manager.RegisterContent(c.SourceFile, c.OutputFile, c.Importer, c.Processor, c.ProcessorParams);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore exception. Exception will be handled below.
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var c in _content)
|
||||
{
|
||||
try
|
||||
{
|
||||
_manager.BuildContent(c.SourceFile,
|
||||
c.OutputFile,
|
||||
c.Importer,
|
||||
c.Processor,
|
||||
c.ProcessorParams);
|
||||
|
||||
newContent.SourceFiles.Add(c.SourceFile);
|
||||
newContent.DestFiles.Add(c.OutputFile);
|
||||
|
||||
++successCount;
|
||||
}
|
||||
catch (InvalidContentException ex)
|
||||
{
|
||||
var message = string.Empty;
|
||||
if (ex.ContentIdentity != null && !string.IsNullOrEmpty(ex.ContentIdentity.SourceFilename))
|
||||
{
|
||||
message = ex.ContentIdentity.SourceFilename;
|
||||
if (!string.IsNullOrEmpty(ex.ContentIdentity.FragmentIdentifier))
|
||||
message += "(" + ex.ContentIdentity.FragmentIdentifier + ")";
|
||||
message += ": ";
|
||||
}
|
||||
message += ex.Message;
|
||||
Console.WriteLine(message);
|
||||
++errorCount;
|
||||
}
|
||||
catch (PipelineException ex)
|
||||
{
|
||||
Console.Error.WriteLine("{0}: error: {1}", c.SourceFile, ex.Message);
|
||||
if (ex.InnerException != null)
|
||||
Console.Error.WriteLine(ex.InnerException.ToString());
|
||||
++errorCount;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine("{0}: error: {1}", c.SourceFile, ex.Message);
|
||||
if (ex.InnerException != null)
|
||||
Console.Error.WriteLine(ex.InnerException.ToString());
|
||||
++errorCount;
|
||||
}
|
||||
}
|
||||
|
||||
// If this is an incremental build we merge the list
|
||||
// of previous content with the new list.
|
||||
if (Incremental && !targetChanged)
|
||||
{
|
||||
newContent.Merge(previousContent);
|
||||
_manager.ContentStats.MergePreviousStats();
|
||||
}
|
||||
|
||||
// Delete the old file and write the new content
|
||||
// list if we have any to serialize.
|
||||
FileHelper.DeleteIfExists(contentFile);
|
||||
if (newContent.SourceFiles.Count > 0)
|
||||
newContent.Write(contentFile);
|
||||
|
||||
// Process copy items (files that bypass the content pipeline)
|
||||
foreach (var c in _copyItems)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Figure out an asset name relative to the project directory,
|
||||
// retaining the file extension.
|
||||
// Note that replacing a sub-path like this requires consistent
|
||||
// directory separator characters.
|
||||
var relativeName = c.Link;
|
||||
if (string.IsNullOrWhiteSpace(relativeName))
|
||||
relativeName = c.SourceFile.Replace(projectDirectory, string.Empty)
|
||||
.TrimStart(Path.DirectorySeparatorChar)
|
||||
.TrimStart(Path.AltDirectorySeparatorChar);
|
||||
var dest = Path.Combine(outputPath, relativeName);
|
||||
|
||||
// Only copy if the source file is newer than the destination.
|
||||
// We may want to provide an option for overriding this, but for
|
||||
// nearly all cases this is the desired behavior.
|
||||
if (File.Exists(dest) && !Rebuild)
|
||||
{
|
||||
var srcTime = File.GetLastWriteTimeUtc(c.SourceFile);
|
||||
var dstTime = File.GetLastWriteTimeUtc(dest);
|
||||
if (srcTime <= dstTime)
|
||||
{
|
||||
if (string.IsNullOrEmpty(c.Link))
|
||||
Console.WriteLine("Skipping {0}", c.SourceFile);
|
||||
else
|
||||
Console.WriteLine("Skipping {0} => {1}", c.SourceFile, c.Link);
|
||||
|
||||
// Copy the stats from the previous stats collection.
|
||||
_manager.ContentStats.CopyPreviousStats(c.SourceFile);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var startTime = DateTime.UtcNow;
|
||||
|
||||
// Create the destination directory if it doesn't already exist.
|
||||
var destPath = Path.GetDirectoryName(dest);
|
||||
if (!Directory.Exists(destPath))
|
||||
Directory.CreateDirectory(destPath);
|
||||
|
||||
File.Copy(c.SourceFile, dest, true);
|
||||
|
||||
// Destination file should not be read-only even if original was.
|
||||
var fileAttr = File.GetAttributes(dest);
|
||||
fileAttr = fileAttr & (~FileAttributes.ReadOnly);
|
||||
File.SetAttributes(dest, fileAttr);
|
||||
|
||||
var buildTime = DateTime.UtcNow - startTime;
|
||||
|
||||
if (string.IsNullOrEmpty(c.Link))
|
||||
Console.WriteLine("{0}", c.SourceFile);
|
||||
else
|
||||
Console.WriteLine("{0} => {1}", c.SourceFile, c.Link);
|
||||
|
||||
// Record content stats on the copy.
|
||||
_manager.ContentStats.RecordStats(c.SourceFile, dest, "CopyItem", typeof(File), (float)buildTime.TotalSeconds);
|
||||
|
||||
++successCount;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine("{0}: error: {1}", c, ex.Message);
|
||||
if (ex.InnerException != null)
|
||||
Console.Error.WriteLine(ex.InnerException.ToString());
|
||||
|
||||
++errorCount;
|
||||
}
|
||||
}
|
||||
|
||||
// Dump the content build stats.
|
||||
_manager.ContentStats.Write(intermediatePath);
|
||||
}
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "help",
|
||||
Flag = "h",
|
||||
Description = "Displays this help.")]
|
||||
public void Help()
|
||||
{
|
||||
MGBuildParser.Instance.ShowError(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,680 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace MGCB
|
||||
{
|
||||
/// <summary>
|
||||
/// Adapted from this generic command line argument parser:
|
||||
/// http://blogs.msdn.com/b/shawnhar/archive/2012/04/20/a-reusable-reflection-based-command-line-parser.aspx
|
||||
/// </summary>
|
||||
public class MGBuildParser
|
||||
{
|
||||
public static MGBuildParser Instance;
|
||||
|
||||
#region Supporting Types
|
||||
|
||||
public class PreprocessorProperty
|
||||
{
|
||||
public string Name;
|
||||
public string CurrentValue;
|
||||
|
||||
public PreprocessorProperty()
|
||||
{
|
||||
Name = string.Empty;
|
||||
CurrentValue = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public class PreprocessorPropertyCollection
|
||||
{
|
||||
private readonly List<PreprocessorProperty> _properties;
|
||||
|
||||
public PreprocessorPropertyCollection()
|
||||
{
|
||||
_properties = new List<PreprocessorProperty>();
|
||||
}
|
||||
|
||||
public string this[string name]
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var i in _properties)
|
||||
{
|
||||
if (i.Name.Equals(name))
|
||||
return i.CurrentValue;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
foreach (var i in _properties)
|
||||
{
|
||||
if (i.Name.Equals(name))
|
||||
{
|
||||
i.CurrentValue = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var prop = new PreprocessorProperty()
|
||||
{
|
||||
Name = name,
|
||||
CurrentValue = value,
|
||||
};
|
||||
_properties.Add(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private readonly object _optionsObject;
|
||||
private readonly Queue<MemberInfo> _requiredOptions;
|
||||
private readonly Dictionary<string, MemberInfo> _optionalOptions;
|
||||
private readonly Dictionary<string, string> _flags;
|
||||
private readonly List<string> _requiredUsageHelp;
|
||||
|
||||
public readonly PreprocessorPropertyCollection _properties;
|
||||
|
||||
public delegate void ErrorCallback(string msg, object[] args);
|
||||
public event ErrorCallback OnError;
|
||||
|
||||
public MGBuildParser(object optionsObject)
|
||||
{
|
||||
Instance = this;
|
||||
|
||||
_optionsObject = optionsObject;
|
||||
_requiredOptions = new Queue<MemberInfo>();
|
||||
_optionalOptions = new Dictionary<string, MemberInfo>();
|
||||
_requiredUsageHelp = new List<string>();
|
||||
|
||||
_properties = new PreprocessorPropertyCollection();
|
||||
|
||||
// Reflect to find what commandline options are available...
|
||||
|
||||
// Fields
|
||||
foreach (var field in optionsObject.GetType().GetFields())
|
||||
{
|
||||
var param = GetAttribute<CommandLineParameterAttribute>(field);
|
||||
if (param == null)
|
||||
continue;
|
||||
|
||||
CheckReservedPrefixes(param.Name);
|
||||
|
||||
if (param.Required)
|
||||
{
|
||||
// Record a required option.
|
||||
_requiredOptions.Enqueue(field);
|
||||
|
||||
_requiredUsageHelp.Add(string.Format("<{0}>", param.Name));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Record an optional option.
|
||||
_optionalOptions.Add(param.Name.ToLowerInvariant(), field);
|
||||
}
|
||||
}
|
||||
|
||||
// Properties
|
||||
foreach (var property in optionsObject.GetType().GetProperties())
|
||||
{
|
||||
var param = GetAttribute<CommandLineParameterAttribute>(property);
|
||||
if (param == null)
|
||||
continue;
|
||||
|
||||
CheckReservedPrefixes(param.Name);
|
||||
|
||||
if (param.Required)
|
||||
{
|
||||
// Record a required option.
|
||||
_requiredOptions.Enqueue(property);
|
||||
|
||||
_requiredUsageHelp.Add(string.Format("<{0}>", param.Name));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Record an optional option.
|
||||
_optionalOptions.Add(param.Name.ToLowerInvariant(), property);
|
||||
}
|
||||
}
|
||||
|
||||
// Methods
|
||||
foreach (var method in optionsObject.GetType().GetMethods())
|
||||
{
|
||||
var param = GetAttribute<CommandLineParameterAttribute>(method);
|
||||
if (param == null)
|
||||
continue;
|
||||
|
||||
CheckReservedPrefixes(param.Name);
|
||||
|
||||
// Only accept methods that take less than 1 parameter.
|
||||
if (method.GetParameters().Length > 1)
|
||||
throw new NotSupportedException("Methods must have one or zero parameters.");
|
||||
|
||||
if (param.Required)
|
||||
{
|
||||
// Record a required option.
|
||||
_requiredOptions.Enqueue(method);
|
||||
|
||||
_requiredUsageHelp.Add(string.Format("<{0}>", param.Name));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Record an optional option.
|
||||
_optionalOptions.Add(param.Name.ToLowerInvariant(), method);
|
||||
}
|
||||
}
|
||||
|
||||
_flags = new Dictionary<string, string>();
|
||||
foreach(var pair in _optionalOptions)
|
||||
{
|
||||
var fi = GetAttribute<CommandLineParameterAttribute>(pair.Value);
|
||||
if(!string.IsNullOrEmpty(fi.Flag))
|
||||
_flags.Add(fi.Flag, fi.Name);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Parse(IEnumerable<string> args)
|
||||
{
|
||||
args = Preprocess(args);
|
||||
|
||||
var showUsage = true;
|
||||
var success = true;
|
||||
foreach (var arg in args)
|
||||
{
|
||||
showUsage = false;
|
||||
|
||||
if (!ParseFlags(arg))
|
||||
{
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var missingRequiredOption = _requiredOptions.FirstOrDefault(field => !IsList(field) || GetList(field).Count == 0);
|
||||
if (missingRequiredOption != null)
|
||||
{
|
||||
ShowError("Missing argument '{0}'", GetAttribute<CommandLineParameterAttribute>(missingRequiredOption).Name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (showUsage)
|
||||
ShowError(null);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private IEnumerable<string> Preprocess(IEnumerable<string> args)
|
||||
{
|
||||
var output = new List<string>();
|
||||
var lines = new List<string>(args);
|
||||
var ifstack = new Stack<Tuple<string, string>>();
|
||||
var fileStack = new Stack<string>();
|
||||
|
||||
while (lines.Count > 0)
|
||||
{
|
||||
var arg = lines[0];
|
||||
lines.RemoveAt(0);
|
||||
|
||||
if (arg.StartsWith("# Begin:"))
|
||||
{
|
||||
var file = arg.Substring(8);
|
||||
fileStack.Push(file);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg.StartsWith("# End:"))
|
||||
{
|
||||
fileStack.Pop();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg.StartsWith("$endif"))
|
||||
{
|
||||
ifstack.Pop();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ifstack.Count > 0)
|
||||
{
|
||||
var skip = false;
|
||||
foreach (var i in ifstack)
|
||||
{
|
||||
var val = _properties[i.Item1];
|
||||
if (!(i.Item2).Equals(val))
|
||||
{
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg.StartsWith("$set"))
|
||||
{
|
||||
var words = arg.Substring(5).Split('=');
|
||||
var name = words[0];
|
||||
var value = words[1];
|
||||
|
||||
_properties[name] = value;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg.StartsWith("$if"))
|
||||
{
|
||||
if (fileStack.Count == 0)
|
||||
throw new Exception("$if is invalid outside of a response file.");
|
||||
|
||||
var words = arg.Substring(4).Split('=');
|
||||
var name = words[0];
|
||||
var value = words[1];
|
||||
|
||||
var condition = new Tuple<string, string>(name, value);
|
||||
ifstack.Push(condition);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg.StartsWith("/define:") || arg.StartsWith("--define:"))
|
||||
{
|
||||
var words = arg.Substring(8).Split('=');
|
||||
var name = words[0];
|
||||
var value = words[1];
|
||||
|
||||
_properties[name] = value;
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (arg.StartsWith("/@") || arg.StartsWith("--@") || arg.StartsWith("-@")
|
||||
|| (arg.EndsWith(".mgcb") && File.Exists(arg)))
|
||||
{
|
||||
var file = arg;
|
||||
if (!File.Exists(arg))
|
||||
file = arg.Substring(arg.StartsWith("--@") ? 4 : 3);
|
||||
|
||||
var commands = File.ReadAllLines(file);
|
||||
var offset = 0;
|
||||
lines.Insert(0, string.Format("# Begin:{0} ", file));
|
||||
offset++;
|
||||
|
||||
for (var j = 0; j < commands.Length; j++)
|
||||
{
|
||||
var line = commands[j];
|
||||
if (string.IsNullOrEmpty(line))
|
||||
continue;
|
||||
if (line.StartsWith("#"))
|
||||
continue;
|
||||
|
||||
lines.Insert(offset, line);
|
||||
offset++;
|
||||
}
|
||||
|
||||
lines.Insert(offset, string.Format("# End:{0}", file));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
output.Add(arg);
|
||||
}
|
||||
|
||||
return output.ToArray();
|
||||
}
|
||||
|
||||
private bool ParseFlags(string arg)
|
||||
{
|
||||
// Filename detected, redo with a build command
|
||||
if (File.Exists(arg))
|
||||
return ParseFlags("/build=" + arg);
|
||||
|
||||
// Only one flag
|
||||
if (arg.Length >= 3 &&
|
||||
(arg[0] == '-' || arg[0] == '/') &&
|
||||
(arg[2] == '=' || arg[2] == ':'))
|
||||
{
|
||||
string name;
|
||||
if (!_flags.TryGetValue(arg[1].ToString(), out name))
|
||||
{
|
||||
ShowError("Unknown option '{0}'", arg[1].ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
ParseArgument("/" + name + arg.Substring(2));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Multiple flags
|
||||
if (arg.Length >= 2 &&
|
||||
((arg[0] == '-' && arg[1] != '-') || arg[0] == '/') &&
|
||||
!arg.Contains(":") && !arg.Contains("=") &&
|
||||
!_optionalOptions.ContainsKey(arg.Substring(1)))
|
||||
{
|
||||
for (int i = 1; i < arg.Length; i++)
|
||||
{
|
||||
string name;
|
||||
if (!_flags.TryGetValue(arg[i].ToString(), out name))
|
||||
{
|
||||
ShowError("Unknown option '{0}'", arg[i].ToString());
|
||||
break;
|
||||
}
|
||||
|
||||
ParseArgument("/" + name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Not a flag, parse argument
|
||||
return ParseArgument(arg);
|
||||
}
|
||||
|
||||
private bool ParseArgument(string arg)
|
||||
{
|
||||
if (arg.StartsWith("/") || arg.StartsWith("--"))
|
||||
{
|
||||
// After the first escaped argument we can no
|
||||
// longer read non-escaped arguments.
|
||||
if (_requiredOptions.Count > 0)
|
||||
return false;
|
||||
|
||||
// Parse an optional argument.
|
||||
char[] separators = { ':', '=' };
|
||||
|
||||
var split = arg.Substring(arg.StartsWith("/") ? 1 : 2).Split(separators, 2, StringSplitOptions.None);
|
||||
|
||||
var name = split[0];
|
||||
var value = (split.Length > 1) ? split[1] : "true";
|
||||
|
||||
MemberInfo member;
|
||||
|
||||
if (!_optionalOptions.TryGetValue(name.ToLowerInvariant(), out member))
|
||||
{
|
||||
ShowError("Unknown option '{0}'", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
return SetOption(member, value);
|
||||
}
|
||||
|
||||
if (_requiredOptions.Count > 0)
|
||||
{
|
||||
// Parse the next non escaped argument.
|
||||
var field = _requiredOptions.Peek();
|
||||
|
||||
if (!IsList(field))
|
||||
_requiredOptions.Dequeue();
|
||||
|
||||
return SetOption(field, arg);
|
||||
}
|
||||
|
||||
ShowError("Too many arguments");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SetOption(MemberInfo member, string value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (IsList(member))
|
||||
{
|
||||
// Append this value to a list of options.
|
||||
GetList(member).Add(ChangeType(value, ListElementType(member)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the value of a single option.
|
||||
if (member is MethodInfo)
|
||||
{
|
||||
var method = member as MethodInfo;
|
||||
var parameters = method.GetParameters();
|
||||
if (parameters.Length == 0)
|
||||
method.Invoke(_optionsObject, null);
|
||||
else
|
||||
method.Invoke(_optionsObject, new[] { ChangeType(value, parameters[0].ParameterType) });
|
||||
}
|
||||
else if (member is FieldInfo)
|
||||
{
|
||||
var field = member as FieldInfo;
|
||||
field.SetValue(_optionsObject, ChangeType(value, field.FieldType));
|
||||
}
|
||||
else
|
||||
{
|
||||
var property = member as PropertyInfo;
|
||||
property.SetValue(_optionsObject, ChangeType(value, property.PropertyType), null);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
ShowError("Invalid value '{0}' for option '{1}'", value, GetAttribute<CommandLineParameterAttribute>(member).Name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static readonly string[] ReservedPrefixes = new[]
|
||||
{
|
||||
"$",
|
||||
"/",
|
||||
"#",
|
||||
"--",
|
||||
"-"
|
||||
};
|
||||
|
||||
static void CheckReservedPrefixes(string str)
|
||||
{
|
||||
foreach (var i in ReservedPrefixes)
|
||||
{
|
||||
if (str.StartsWith(i))
|
||||
throw new Exception(string.Format("'{0}' is a reserved prefix and cannot be used at the start of an argument name.", i));
|
||||
}
|
||||
}
|
||||
|
||||
static object ChangeType(string value, Type type)
|
||||
{
|
||||
var converter = TypeDescriptor.GetConverter(type);
|
||||
|
||||
return converter.ConvertFromInvariantString(value);
|
||||
}
|
||||
|
||||
|
||||
static bool IsList(MemberInfo member)
|
||||
{
|
||||
if (member is MethodInfo)
|
||||
return false;
|
||||
|
||||
if (member is FieldInfo)
|
||||
return typeof(IList).IsAssignableFrom((member as FieldInfo).FieldType);
|
||||
|
||||
return typeof(IList).IsAssignableFrom((member as PropertyInfo).PropertyType);
|
||||
}
|
||||
|
||||
|
||||
IList GetList(MemberInfo member)
|
||||
{
|
||||
if (member is PropertyInfo)
|
||||
return (IList)(member as PropertyInfo).GetValue(_optionsObject, null);
|
||||
|
||||
if (member is FieldInfo)
|
||||
return (IList)(member as FieldInfo).GetValue(_optionsObject);
|
||||
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
|
||||
static Type ListElementType(MemberInfo member)
|
||||
{
|
||||
if (member is FieldInfo)
|
||||
{
|
||||
var field = member as FieldInfo;
|
||||
var interfaces = from i in field.FieldType.GetInterfaces()
|
||||
where i.IsGenericType && i.GetGenericTypeDefinition() == typeof (IEnumerable<>)
|
||||
select i;
|
||||
|
||||
return interfaces.First().GetGenericArguments()[0];
|
||||
}
|
||||
|
||||
if (member is PropertyInfo)
|
||||
{
|
||||
var property = member as PropertyInfo;
|
||||
var interfaces = from i in property.PropertyType.GetInterfaces()
|
||||
where i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>)
|
||||
select i;
|
||||
|
||||
return interfaces.First().GetGenericArguments()[0];
|
||||
}
|
||||
|
||||
throw new ArgumentException("Only FieldInfo and PropertyInfo are valid arguments.", "member");
|
||||
}
|
||||
|
||||
public string Title { get; set; }
|
||||
|
||||
bool IsWindows()
|
||||
{
|
||||
switch (Environment.OSVersion.Platform)
|
||||
{
|
||||
case PlatformID.Win32NT:
|
||||
case PlatformID.Win32S:
|
||||
case PlatformID.Win32Windows:
|
||||
case PlatformID.WinCE:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void ShowError(string message, params object[] args)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(message) && OnError != null)
|
||||
{
|
||||
OnError(message, args);
|
||||
return;
|
||||
}
|
||||
|
||||
var name = Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().ProcessName);
|
||||
|
||||
if (!string.IsNullOrEmpty(Title))
|
||||
{
|
||||
Console.Error.WriteLine(Title);
|
||||
Console.Error.WriteLine();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(message))
|
||||
{
|
||||
Console.Error.WriteLine(message, args);
|
||||
Console.Error.WriteLine();
|
||||
}
|
||||
|
||||
var defaultParamPrefix = IsWindows() ? "/" : "--";
|
||||
Console.Error.WriteLine("Usage: {0} {1}{2}",
|
||||
name,
|
||||
_requiredUsageHelp.Count > 0 ? string.Join(" ", _requiredUsageHelp) + " " : string.Empty,
|
||||
_optionalOptions.Count > 0 ? "<Options>" : string.Empty);
|
||||
|
||||
if (_optionalOptions.Count > 0)
|
||||
{
|
||||
Console.Error.WriteLine();
|
||||
Console.Error.WriteLine("Options:");
|
||||
|
||||
var data = _optionalOptions.Values.ToList();
|
||||
data.Sort((x, y) => {
|
||||
var px = GetAttribute<CommandLineParameterAttribute>(x);
|
||||
var py = GetAttribute<CommandLineParameterAttribute>(y);
|
||||
|
||||
return px.Name.CompareTo(py.Name);
|
||||
});
|
||||
|
||||
foreach(var d in data)
|
||||
{
|
||||
var attr = GetAttribute<CommandLineParameterAttribute>(d);
|
||||
var field = d as FieldInfo;
|
||||
var prop = d as PropertyInfo;
|
||||
var method = d as MethodInfo;
|
||||
var hasValue = false;
|
||||
|
||||
if (field != null && field.FieldType != typeof (bool))
|
||||
hasValue = true;
|
||||
if (prop != null && prop.PropertyType != typeof (bool))
|
||||
hasValue = true;
|
||||
if (method != null && method.GetParameters().Length != 0)
|
||||
hasValue = true;
|
||||
|
||||
var s = " ";
|
||||
|
||||
s += (!string.IsNullOrEmpty(attr.Flag)) ? (IsWindows() ? "/" : "-") + attr.Flag + "," : " ";
|
||||
s += " " + defaultParamPrefix + attr.Name;
|
||||
|
||||
if (hasValue)
|
||||
{
|
||||
if (IsWindows())
|
||||
s += ":<" + attr.ValueName + ">";
|
||||
else
|
||||
s += "=" + attr.ValueName.Replace("=", ":").ToUpper();
|
||||
}
|
||||
|
||||
s = s.PadRight(35, ' ');
|
||||
|
||||
// Wrap text description
|
||||
var bw = Math.Max(60, Console.BufferWidth);
|
||||
var desc = attr.Description.Split(' ');
|
||||
|
||||
foreach(var dw in desc)
|
||||
{
|
||||
if (s.Length + dw.Length >= bw)
|
||||
{
|
||||
Console.WriteLine(s);
|
||||
s = string.Empty.PadRight(37, ' ');
|
||||
}
|
||||
|
||||
s += " " + dw;
|
||||
}
|
||||
|
||||
Console.WriteLine(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static T GetAttribute<T>(ICustomAttributeProvider provider) where T : Attribute
|
||||
{
|
||||
return provider.GetCustomAttributes(typeof(T), false).OfType<T>().FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
// Used on an optionsObject field or method to rename the corresponding commandline option.
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property)]
|
||||
public sealed class CommandLineParameterAttribute : Attribute
|
||||
{
|
||||
public CommandLineParameterAttribute()
|
||||
{
|
||||
ValueName = "value";
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Flag { get; set; }
|
||||
|
||||
public bool Required { get; set; }
|
||||
|
||||
public string ValueName { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using Microsoft.Xna.Framework.Content.Pipeline;
|
||||
|
||||
namespace MonoGame.Framework.Content.Pipeline.Builder
|
||||
{
|
||||
public class ConsoleLogger : ContentBuildLogger
|
||||
{
|
||||
public override void LogMessage(string message, params object[] messageArgs)
|
||||
{
|
||||
Console.WriteLine(IndentString + message, messageArgs);
|
||||
}
|
||||
|
||||
public override void LogImportantMessage(string message, params object[] messageArgs)
|
||||
{
|
||||
// TODO: How do i make it high importance?
|
||||
Console.WriteLine(IndentString + message, messageArgs);
|
||||
}
|
||||
|
||||
public override void LogWarning(string helpLink, ContentIdentity contentIdentity, string message, params object[] messageArgs)
|
||||
{
|
||||
var warning = string.Empty;
|
||||
if (contentIdentity != null && !string.IsNullOrEmpty(contentIdentity.SourceFilename))
|
||||
{
|
||||
warning = contentIdentity.SourceFilename;
|
||||
if (!string.IsNullOrEmpty(contentIdentity.FragmentIdentifier))
|
||||
warning += "(" + contentIdentity.FragmentIdentifier + ")";
|
||||
warning += ": ";
|
||||
}
|
||||
|
||||
if (messageArgs != null && messageArgs.Length != 0)
|
||||
warning += string.Format(message, messageArgs);
|
||||
else if (!string.IsNullOrEmpty(message))
|
||||
warning += message;
|
||||
|
||||
Console.WriteLine(warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.monogame.mgcb</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>10.0.0</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{4243474D-4C2E-6E69-7578-4D4743422E4C}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>MGCB</RootNamespace>
|
||||
<AssemblyName>MGCB</AssemblyName>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<NoWarn>1591,0436</NoWarn>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile />
|
||||
<LangVersion>Default</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<Optimize>false</Optimize>
|
||||
<DebugType>full</DebugType>
|
||||
<EnableUnmanagedDebugging>true</EnableUnmanagedDebugging>
|
||||
<OutputPath>bin\Linux\AnyCPU\Debug</OutputPath>
|
||||
<IntermediateOutputPath>obj\Linux\AnyCPU\Debug</IntermediateOutputPath>
|
||||
<DocumentationFile>bin\Linux\AnyCPU\Debug\MGCB.xml</DocumentationFile>
|
||||
<DefineConstants>DEBUG;TRACE;LINUX</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>none</DebugType>
|
||||
<OutputPath>bin\Linux\AnyCPU\Release</OutputPath>
|
||||
<IntermediateOutputPath>obj\Linux\AnyCPU\Release</IntermediateOutputPath>
|
||||
<DocumentationFile>bin\Linux\AnyCPU\Release\MGCB.xml</DocumentationFile>
|
||||
<DefineConstants>TRACE;LINUX</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="CommandLineParser.cs" />
|
||||
<Compile Include="BuildContent.cs" />
|
||||
<Compile Include="ConsoleLogger.cs" />
|
||||
<Compile Include="SourceFileCollection.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<_PostBuildHookTimestamp>@(IntermediateAssembly->'%(FullPath).timestamp')</_PostBuildHookTimestamp>
|
||||
<_PostBuildHookHostPlatform>$(Platform)</_PostBuildHookHostPlatform>
|
||||
</PropertyGroup>
|
||||
<Target Name="PostBuildHooks" Inputs="@(IntermediateAssembly);@(ReferencePath)" Outputs="@(IntermediateAssembly);$(_PostBuildHookTimestamp)" AfterTargets="CoreCompile" BeforeTargets="AfterCompile">
|
||||
<Touch Files="$(_PostBuildHookTimestamp)" AlwaysCreate="True" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\MonoGame.Framework\MonoGame.Framework.Linux.csproj">
|
||||
<Project>{35253CE1-C864-4CD3-8249-4D1319748E8F}</Project>
|
||||
<Name>MonoGame.Framework.Linux</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\MonoGame.Framework.Content.Pipeline\MonoGame.Framework.Content.Pipeline.Linux.csproj">
|
||||
<Project>{57696462-CE5E-4BC5-80AB-1B959E2420EA}</Project>
|
||||
<Name>MonoGame.Framework.Content.Pipeline.Linux</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<MonoDevelop>
|
||||
<Properties><Policies>
|
||||
<TextStylePolicy inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
|
||||
<CSharpFormattingPolicy IndentSwitchSection="True" NewLinesForBracesInProperties="True" NewLinesForBracesInAccessors="True" NewLinesForBracesInAnonymousMethods="True" NewLinesForBracesInControlBlocks="True" NewLinesForBracesInAnonymousTypes="True" NewLinesForBracesInObjectCollectionArrayInitializers="True" NewLinesForBracesInLambdaExpressionBody="True" NewLineForElse="True" NewLineForCatch="True" NewLineForFinally="True" NewLineForMembersInObjectInit="True" NewLineForMembersInAnonymousTypes="True" NewLineForClausesInQuery="True" SpacingAfterMethodDeclarationName="False" SpaceAfterMethodCallName="False" SpaceBeforeOpenSquareBracket="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
|
||||
</Policies>
|
||||
</Properties>
|
||||
</MonoDevelop>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
@@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>10.0.0</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{4243474D-572E-6E69-646F-77734D474342}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>MGCB</RootNamespace>
|
||||
<AssemblyName>MGCB</AssemblyName>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<NoWarn>1591,0436</NoWarn>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile />
|
||||
<LangVersion>Default</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<Optimize>false</Optimize>
|
||||
<DebugType>full</DebugType>
|
||||
<EnableUnmanagedDebugging>true</EnableUnmanagedDebugging>
|
||||
<OutputPath>bin\Windows\AnyCPU\Debug</OutputPath>
|
||||
<IntermediateOutputPath>obj\Windows\AnyCPU\Debug</IntermediateOutputPath>
|
||||
<DocumentationFile>bin\Windows\AnyCPU\Debug\MGCB.xml</DocumentationFile>
|
||||
<DefineConstants>DEBUG;TRACE;WINDOWS</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>none</DebugType>
|
||||
<OutputPath>bin\Windows\AnyCPU\Release</OutputPath>
|
||||
<IntermediateOutputPath>obj\Windows\AnyCPU\Release</IntermediateOutputPath>
|
||||
<DocumentationFile>bin\Windows\AnyCPU\Release\MGCB.xml</DocumentationFile>
|
||||
<DefineConstants>TRACE;WINDOWS</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="CommandLineParser.cs" />
|
||||
<Compile Include="BuildContent.cs" />
|
||||
<Compile Include="ConsoleLogger.cs" />
|
||||
<Compile Include="SourceFileCollection.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<_PostBuildHookTimestamp>@(IntermediateAssembly->'%(FullPath).timestamp')</_PostBuildHookTimestamp>
|
||||
<_PostBuildHookHostPlatform>$(Platform)</_PostBuildHookHostPlatform>
|
||||
</PropertyGroup>
|
||||
<Target Name="PostBuildHooks" Inputs="@(IntermediateAssembly);@(ReferencePath)" Outputs="@(IntermediateAssembly);$(_PostBuildHookTimestamp)" AfterTargets="CoreCompile" BeforeTargets="AfterCompile">
|
||||
<Touch Files="$(_PostBuildHookTimestamp)" AlwaysCreate="True" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\MonoGame.Framework\MonoGame.Framework.Windows.csproj">
|
||||
<Project>{7DE47032-A904-4C29-BD22-2D235E8D91BA}</Project>
|
||||
<Name>MonoGame.Framework.Windows</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\MonoGame.Framework.Content.Pipeline\MonoGame.Framework.Content.Pipeline.Windows.csproj">
|
||||
<Project>{B950DE10-AC5D-4BD9-B817-51247C4A732D}</Project>
|
||||
<Name>MonoGame.Framework.Content.Pipeline.Windows</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<MonoDevelop>
|
||||
<Properties><Policies>
|
||||
<TextStylePolicy inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
|
||||
<CSharpFormattingPolicy IndentSwitchSection="True" NewLinesForBracesInProperties="True" NewLinesForBracesInAccessors="True" NewLinesForBracesInAnonymousMethods="True" NewLinesForBracesInControlBlocks="True" NewLinesForBracesInAnonymousTypes="True" NewLinesForBracesInObjectCollectionArrayInitializers="True" NewLinesForBracesInLambdaExpressionBody="True" NewLineForElse="True" NewLineForCatch="True" NewLineForFinally="True" NewLineForMembersInObjectInit="True" NewLineForMembersInAnonymousTypes="True" NewLineForClausesInQuery="True" SpacingAfterMethodDeclarationName="False" SpaceAfterMethodCallName="False" SpaceBeforeOpenSquareBracket="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
|
||||
</Policies>
|
||||
</Properties>
|
||||
</MonoDevelop>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
@@ -0,0 +1,73 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MGCB
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static int Main(string[] args)
|
||||
{
|
||||
// We force all stderr to redirect to stdout
|
||||
// to avoid any out of order console output.
|
||||
Console.SetError(Console.Out);
|
||||
|
||||
if (!Environment.Is64BitProcess && Environment.OSVersion.Platform != PlatformID.Unix)
|
||||
{
|
||||
Console.Error.WriteLine("The MonoGame content tools only work on a 64bit OS.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
var content = new BuildContent();
|
||||
|
||||
// Parse the command line.
|
||||
var parser = new MGBuildParser(content)
|
||||
{
|
||||
Title = "MonoGame Content Builder\n" +
|
||||
"Builds optimized game content for MonoGame projects."
|
||||
};
|
||||
|
||||
if (!parser.Parse(args))
|
||||
return -1;
|
||||
|
||||
// Launch debugger if requested.
|
||||
if (content.LaunchDebugger)
|
||||
{
|
||||
try {
|
||||
System.Diagnostics.Debugger.Launch();
|
||||
} catch (NotImplementedException) {
|
||||
// not implemented under Mono
|
||||
}
|
||||
}
|
||||
|
||||
if (content.HasWork)
|
||||
{
|
||||
// Print a startup message.
|
||||
var buildStarted = DateTime.Now;
|
||||
if (!content.Quiet)
|
||||
Console.WriteLine("Build started {0}\n", buildStarted);
|
||||
|
||||
// Let the content build.
|
||||
int successCount, errorCount;
|
||||
content.Build(out successCount, out errorCount);
|
||||
|
||||
// Print the finishing info.
|
||||
if (!content.Quiet)
|
||||
{
|
||||
Console.WriteLine("\nBuild {0} succeeded, {1} failed.\n", successCount, errorCount);
|
||||
Console.WriteLine("Time elapsed {0:hh\\:mm\\:ss\\.ff}.", DateTime.Now - buildStarted);
|
||||
}
|
||||
|
||||
// Return the error count.
|
||||
return errorCount;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MGCB")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MGCB")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("b64484a5-f0ca-47cb-8149-59272a68966d")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
using Microsoft.Xna.Framework.Content.Pipeline;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace MGCB
|
||||
{
|
||||
[XmlRoot(ElementName = "SourceFileCollection")]
|
||||
public sealed class SourceFileCollection
|
||||
{
|
||||
public GraphicsProfile Profile { get; set; }
|
||||
|
||||
public TargetPlatform Platform { get; set; }
|
||||
|
||||
public string Config { get; set; }
|
||||
|
||||
[XmlArrayItem("File")]
|
||||
public List<string> SourceFiles { get; set; }
|
||||
|
||||
[XmlArrayItem("File")]
|
||||
public List<string> DestFiles { get; set; }
|
||||
|
||||
|
||||
public SourceFileCollection()
|
||||
{
|
||||
SourceFiles = new List<string>();
|
||||
DestFiles = new List<string>();
|
||||
Config = string.Empty;
|
||||
}
|
||||
|
||||
static public SourceFileCollection Read(string filePath)
|
||||
{
|
||||
var deserializer = new XmlSerializer(typeof(SourceFileCollection));
|
||||
try
|
||||
{
|
||||
using (var textReader = new StreamReader(filePath))
|
||||
return (SourceFileCollection)deserializer.Deserialize(textReader);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
return new SourceFileCollection();
|
||||
}
|
||||
|
||||
public void Write(string filePath)
|
||||
{
|
||||
var serializer = new XmlSerializer(typeof(SourceFileCollection));
|
||||
using (var textWriter = new StreamWriter(filePath, false, new UTF8Encoding(false)))
|
||||
serializer.Serialize(textWriter, this);
|
||||
}
|
||||
|
||||
public void Merge(SourceFileCollection other)
|
||||
{
|
||||
foreach (var sourceFile in other.SourceFiles)
|
||||
{
|
||||
var inContent = SourceFiles.Any(e => string.Equals(e, sourceFile, StringComparison.InvariantCultureIgnoreCase));
|
||||
if (!inContent)
|
||||
SourceFiles.Add(sourceFile);
|
||||
}
|
||||
|
||||
foreach (var destFile in other.DestFiles)
|
||||
{
|
||||
var inContent = DestFiles.Any(e => string.Equals(e, destFile, StringComparison.InvariantCultureIgnoreCase));
|
||||
if (!inContent)
|
||||
DestFiles.Add(destFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup></configuration>
|
||||
Reference in New Issue
Block a user