From c52913716c528f2ade35f9db5a7b62e724d7988c Mon Sep 17 00:00:00 2001 From: penev92 Date: Sat, 3 Sep 2022 01:05:57 +0300 Subject: [PATCH] Added SpriteSequence documentation generation --- .github/workflows/documentation.yml | 2 + .../ExtractSequenceDocsCommand.cs | 98 +++++++++++++++++++ packaging/format-docs.py | 4 +- 3 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 OpenRA.Mods.Common/UtilityCommands/ExtractSequenceDocsCommand.cs diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 0c8327d595..4e2e4de50a 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -93,6 +93,7 @@ jobs: run: | ./utility.sh all --docs "${GIT_TAG}" | python3 ./packaging/format-docs.py > "docs/api/playtest/traits.md" ./utility.sh all --weapon-docs "${GIT_TAG}" | python3 ./packaging/format-docs.py > "docs/api/playtest/weapons.md" + ./utility.sh all --sequence-docs "${GIT_TAG}" | python3 ./packaging/format-docs.py > "docs/api/playtest/sequences.md" ./utility.sh all --lua-docs "${GIT_TAG}" > "docs/api/playtest/lua.md" - name: Update docs.openra.net (Release) @@ -102,6 +103,7 @@ jobs: run: | ./utility.sh all --docs "${GIT_TAG}" | python3 ./packaging/format-docs.py > "docs/api/release/traits.md" ./utility.sh all --weapon-docs "${GIT_TAG}" | python3 ./packaging/format-docs.py > "docs/api/release/weapons.md" + ./utility.sh all --sequence-docs "${GIT_TAG}" | python3 ./packaging/format-docs.py > "docs/api/release/sequences.md" ./utility.sh all --lua-docs "${GIT_TAG}" > "docs/api/release/lua.md" - name: Push docs.openra.net diff --git a/OpenRA.Mods.Common/UtilityCommands/ExtractSequenceDocsCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ExtractSequenceDocsCommand.cs new file mode 100644 index 0000000000..a6ae326192 --- /dev/null +++ b/OpenRA.Mods.Common/UtilityCommands/ExtractSequenceDocsCommand.cs @@ -0,0 +1,98 @@ +#region Copyright & License Information +/* + * Copyright 2007-2022 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.Reflection; +using Newtonsoft.Json; +using OpenRA.Graphics; +using OpenRA.Mods.Common.Graphics; +using OpenRA.Primitives; + +namespace OpenRA.Mods.Common.UtilityCommands +{ + class ExtractSequenceDocsCommand : IUtilityCommand + { + string IUtilityCommand.Name => "--sequence-docs"; + + bool IUtilityCommand.ValidateArguments(string[] args) + { + return true; + } + + [Desc("[VERSION]", "Generate sprite sequence documentation in JSON format.")] + void IUtilityCommand.Run(Utility utility, string[] args) + { + // HACK: The engine code assumes that Game.modData is set. + Game.ModData = utility.ModData; + + var version = utility.ModData.Manifest.Metadata.Version; + if (args.Length > 1) + version = args[1]; + + var objectCreator = utility.ModData.ObjectCreator; + var spriteSequenceTypes = objectCreator.GetTypesImplementing().OrderBy(t => t.Namespace); + + var json = GenerateJson(version, spriteSequenceTypes); + Console.WriteLine(json); + } + + static string GenerateJson(string version, IEnumerable sequenceTypes) + { + var sequenceTypesInfo = sequenceTypes.Where(x => !x.ContainsGenericParameters && !x.IsAbstract) + .Where(x => x.Name != nameof(FileNotFoundSequence)) // NOTE: This is the simplest way to exclude FileNotFoundSequence, which shouldn't be added. + .Select(type => new + { + type.Namespace, + type.Name, + Description = string.Join(" ", type.GetCustomAttributes(false).SelectMany(d => d.Lines)), + InheritedTypes = type.BaseTypes() + .Select(y => y.Name) + .Where(y => y != type.Name && y != "Object"), + Properties = type.GetFields(BindingFlags.NonPublic | BindingFlags.Static) + .Where(fi => fi.FieldType.GetGenericTypeDefinition() == typeof(SpriteSequenceField<>)) + .Select(fi => + { + var description = string.Join(" ", fi.GetCustomAttributes(false) + .SelectMany(d => d.Lines)); + + var valueType = fi.FieldType.GetGenericArguments()[0]; + + var key = (string)fi.FieldType + .GetField(nameof(SpriteSequenceField.Key))? + .GetValue(fi.GetValue(null)); + + var defaultValue = fi.FieldType + .GetField(nameof(SpriteSequenceField.DefaultValue))? + .GetValue(fi.GetValue(null)); + + return new + { + PropertyName = key, + DefaultValue = defaultValue?.ToString(), + InternalType = Util.InternalTypeName(valueType), + UserFriendlyType = Util.FriendlyTypeName(valueType), + Description = description + }; + }) + }); + + var result = new + { + Version = version, + SpriteSequenceTypes = sequenceTypesInfo + }; + + return JsonConvert.SerializeObject(result); + } + } +} diff --git a/packaging/format-docs.py b/packaging/format-docs.py index 859c8f8317..a5f6c174d3 100644 --- a/packaging/format-docs.py +++ b/packaging/format-docs.py @@ -39,8 +39,8 @@ def format_docs(version, collectionName, types): explanation = "all traits with their properties and their default values plus developer commentary" elif collectionName == "WeaponTypes": explanation = "a template for weapon definitions and the types it can use (warheads and projectiles) with default values and developer commentary" - elif collectionName == "SequenceTypes": - explanation = "all sequence types with their properties and their default values plus developer commentary" + elif collectionName == "SpriteSequenceTypes": + explanation = "all sprite sequence types with their properties and their default values plus developer commentary" print(f"This documentation is aimed at modders and has been automatically generated for version `{version}` of OpenRA. " + "Please do not edit it directly, but instead add new `[Desc(\"String\")]` tags to the source code.\n")