diff --git a/.gitignore b/.gitignore index ec75ed10b5..eb55c74cf3 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,7 @@ OpenRA.Launcher.Mac/OpenRA.xcodeproj/*.mode1v3 # auto-generated documentation DOCUMENTATION.md +WEAPONS.md Lua-API.md *.html openra.6 diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 102e27aac3..2d95e53c59 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -553,6 +553,7 @@ + diff --git a/OpenRA.Mods.Common/Util.cs b/OpenRA.Mods.Common/Util.cs index 829cd9340c..eaeb61e7e3 100644 --- a/OpenRA.Mods.Common/Util.cs +++ b/OpenRA.Mods.Common/Util.cs @@ -201,7 +201,10 @@ namespace OpenRA.Mods.Common return "Mapping of {0} to {1}".F(t.GetGenericArguments().Select(FriendlyTypeName).ToArray()); if (t.IsSubclassOf(typeof(Array))) - return "Multiple {0}".F(FriendlyTypeName(t.GetElementType())); + return "Collection of {0}".F(FriendlyTypeName(t.GetElementType())); + + if (t.IsGenericType && t.GetGenericTypeDefinition().GetInterfaces().Any(e => e.IsGenericType && e.GetGenericTypeDefinition() == typeof(IEnumerable<>))) + return "Collection of {0}".F(FriendlyTypeName(t.GetGenericArguments().First())); if (t == typeof(int) || t == typeof(uint)) return "Integer"; @@ -239,6 +242,12 @@ namespace OpenRA.Mods.Common if (t == typeof(HSLColor) || t == typeof(Color)) return "Color (RRGGBB[AA] notation)"; + if (t == typeof(IProjectileInfo)) + return "Projectile"; + + if (t == typeof(IWarhead)) + return "Warhead"; + return t.Name; } } diff --git a/OpenRA.Mods.Common/UtilityCommands/ExtractWeaponDocsCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ExtractWeaponDocsCommand.cs new file mode 100644 index 0000000000..b778e7573e --- /dev/null +++ b/OpenRA.Mods.Common/UtilityCommands/ExtractWeaponDocsCommand.cs @@ -0,0 +1,106 @@ +#region Copyright & License Information +/* + * Copyright 2007-2017 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRA.GameRules; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.UtilityCommands +{ + class ExtractWeaponDocsCommand : IUtilityCommand + { + string IUtilityCommand.Name { get { return "--weapon-docs"; } } + + bool IUtilityCommand.ValidateArguments(string[] args) + { + return true; + } + + [Desc("Generate weaponry documentation in MarkDown format.")] + void IUtilityCommand.Run(Utility utility, string[] args) + { + // HACK: The engine code assumes that Game.modData is set. + Game.ModData = utility.ModData; + + Console.WriteLine( + "This documentation is aimed at modders. It displays a template for weapon definitions " + + "as well as its contained types (warheads and projectiles) with default values and developer commentary. " + + "Please do not edit it directly, but add new `[Desc(\"String\")]` tags to the source code. This file has been " + + "automatically generated for version {0} of OpenRA.", utility.ModData.Manifest.Metadata.Version); + Console.WriteLine(); + + var toc = new StringBuilder(); + var doc = new StringBuilder(); + + var currentNamespace = ""; + + var objectCreator = utility.ModData.ObjectCreator; + var weaponInfo = objectCreator.GetTypesImplementing(); + var warheads = objectCreator.GetTypesImplementing().OrderBy(t => t.Namespace); + var projectiles = objectCreator.GetTypesImplementing().OrderBy(t => t.Namespace); + + var weaponTypes = Enumerable.Concat(weaponInfo, Enumerable.Concat(projectiles, warheads)); + foreach (var t in weaponTypes) + { + // skip helpers like TraitInfo + if (t.ContainsGenericParameters || t.IsAbstract) + continue; + + if (currentNamespace != t.Namespace) + { + currentNamespace = t.Namespace; + doc.AppendLine(); + doc.AppendLine("## {0}".F(currentNamespace)); + toc.AppendLine("* [{0}](#{1})".F(currentNamespace, currentNamespace.Replace(".", "").ToLowerInvariant())); + } + + var traitName = t.Name.EndsWith("Info") ? t.Name.Substring(0, t.Name.Length - 4) : t.Name; + toc.AppendLine(" * [{0}](#{1})".F(traitName, traitName.ToLowerInvariant())); + doc.AppendLine(); + doc.AppendLine("### {0}".F(traitName)); + + var traitDescLines = t.GetCustomAttributes(false).SelectMany(d => d.Lines); + foreach (var line in traitDescLines) + doc.AppendLine(line); + + var infos = FieldLoader.GetTypeLoadInfo(t); + if (!infos.Any()) + continue; + + doc.AppendLine(""); + doc.AppendLine("PropertyDefault ValueTypeDescription"); + + var liveTraitInfo = t == typeof(WeaponInfo) ? null : objectCreator.CreateBasic(t); + foreach (var info in infos) + { + var fieldDescLines = info.Field.GetCustomAttributes(true).SelectMany(d => d.Lines); + var fieldType = Util.FriendlyTypeName(info.Field.FieldType); + var defaultValue = liveTraitInfo == null ? "" : FieldSaver.SaveField(liveTraitInfo, info.Field.Name).Value.Value; + doc.Append("{0}{1}{2}".F(info.YamlName, defaultValue, fieldType)); + doc.Append(""); + + foreach (var line in fieldDescLines) + doc.Append(line + " "); + + doc.AppendLine(""); + } + + doc.AppendLine(""); + } + + Console.Write(toc.ToString()); + Console.Write(doc.ToString()); + } + } +} diff --git a/make.ps1 b/make.ps1 index 498b76c47f..c475606ad0 100644 --- a/make.ps1 +++ b/make.ps1 @@ -193,6 +193,7 @@ function Docs-Command { ./make.ps1 version ./OpenRA.Utility.exe all --docs | Out-File -Encoding "UTF8" DOCUMENTATION.md + ./OpenRA.Utility.exe all --weapon-docs | Out-File -Encoding "UTF8" WEAPONS.md ./OpenRA.Utility.exe all --lua-docs | Out-File -Encoding "UTF8" Lua-API.md } else diff --git a/packaging/update-wiki.sh b/packaging/update-wiki.sh index 6678c9948d..871d7086b7 100755 --- a/packaging/update-wiki.sh +++ b/packaging/update-wiki.sh @@ -28,6 +28,7 @@ rm -rf $HOME/openra-wiki git clone git@github.com:OpenRA/OpenRA.wiki.git $HOME/openra-wiki mono --debug ../OpenRA.Utility.exe all --docs > "${HOME}/openra-wiki/Traits${TAG}.md" +mono --debug ../OpenRA.Utility.exe all --weapon-docs > "${HOME}/openra-wiki/Weapons${TAG}.md" mono --debug ../OpenRA.Utility.exe all --lua-docs > "${HOME}/openra-wiki/Lua API${TAG}.md" pushd $HOME/openra-wiki