128 lines
5.8 KiB
Python
128 lines
5.8 KiB
Python
#!/usr/bin/env python3
|
|
# Copyright (c) The OpenRA Developers and Contributors
|
|
# 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.
|
|
|
|
import io
|
|
import sys
|
|
import json
|
|
from collections import OrderedDict
|
|
|
|
def format_type_name(typeName, isKnownType):
|
|
name = typeName
|
|
if name.endswith("Info"):
|
|
name = name[0:-4]
|
|
|
|
return f'[`{name}`](#{name.lower()})' if isKnownType else f'`{name}`'
|
|
|
|
def is_known_type(typeName, types):
|
|
name = typeName
|
|
if name.endswith("Info"):
|
|
name = name[0:-4]
|
|
|
|
result = [t for t in types if name == t["Name"]]
|
|
return len(result) > 0
|
|
|
|
def format_docs(version, collectionName, types, relatedEnums):
|
|
|
|
typesByNamespace = OrderedDict()
|
|
for currentType in types:
|
|
if currentType["Namespace"] in typesByNamespace:
|
|
typesByNamespace[currentType["Namespace"]].append(currentType)
|
|
else:
|
|
typesByNamespace[currentType["Namespace"]] = [currentType]
|
|
|
|
# Map the `relatedEnums` collection to a list of strings.
|
|
enumNames = [enum['Name'] for enum in relatedEnums]
|
|
enumReferences = OrderedDict()
|
|
|
|
title = ""
|
|
explanation = ""
|
|
if collectionName == "TraitInfos":
|
|
title = "Traits"
|
|
explanation = "all traits with their properties and their default values plus developer commentary"
|
|
elif collectionName == "WeaponTypes":
|
|
title = "Weapons"
|
|
explanation = "a template for weapon definitions and the types it can use (warheads and projectiles) with default values and developer commentary"
|
|
elif collectionName == "SpriteSequenceTypes":
|
|
title = "Sprite sequences"
|
|
explanation = "all sprite sequence types with their properties and their default values plus developer commentary"
|
|
|
|
print(f"# {title}\n")
|
|
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")
|
|
|
|
print(f"Listed below are {explanation}.")
|
|
print(f"Related types with their possible values are listed [at the bottom](#related-value-types-enums).")
|
|
|
|
for namespace in typesByNamespace:
|
|
print(f'\n## {namespace}')
|
|
|
|
for currentType in typesByNamespace[namespace]:
|
|
print(f'\n### {currentType["Name"]}')
|
|
|
|
if currentType["Description"]:
|
|
print(f'**{currentType["Description"]}**')
|
|
|
|
if "InheritedTypes" in currentType and currentType["InheritedTypes"]:
|
|
inheritedTypes = [t for t in currentType["InheritedTypes"] if t not in ['TraitInfo', 'Warhead']] # Remove blacklisted types.
|
|
if inheritedTypes:
|
|
print("\n> Inherits from: " + ", ".join([format_type_name(x, is_known_type(x, types)) for x in inheritedTypes]) + '.')
|
|
|
|
if "RequiresTraits" in currentType and currentType["RequiresTraits"]:
|
|
formattedRequiredTraits = [format_type_name(x, is_known_type(x, types)) for x in currentType["RequiresTraits"]]
|
|
print("\n> Requires trait(s): " + ", ".join(sorted(formattedRequiredTraits)) + '.')
|
|
|
|
if len(currentType["Properties"]) > 0:
|
|
print()
|
|
print(f'| Property | Default Value | Type | Description |')
|
|
print(f'| -------- | ------------- | ---- | ----------- |')
|
|
|
|
for prop in currentType["Properties"]:
|
|
|
|
# Use the user-friendly type name unless we're certain this is a known enum,
|
|
# in which case get a link to the enum's definition.
|
|
typeName = prop["UserFriendlyType"]
|
|
if prop["InternalType"] in enumNames:
|
|
typeName = format_type_name(prop["InternalType"], True)
|
|
if prop["InternalType"] in enumReferences:
|
|
enumReferences[prop["InternalType"]].append(currentType["Name"])
|
|
else:
|
|
enumReferences[prop["InternalType"]] = [currentType["Name"]]
|
|
|
|
if "OtherAttributes" in prop:
|
|
attributes = []
|
|
for attribute in prop["OtherAttributes"]:
|
|
attributes.append(attribute["Name"])
|
|
|
|
defaultValue = ''
|
|
if prop["DefaultValue"]:
|
|
defaultValue = prop["DefaultValue"]
|
|
elif 'Require' in attributes:
|
|
defaultValue = '*(required)*'
|
|
|
|
print(f'| {prop["PropertyName"]} | {defaultValue} | {typeName} | {prop["Description"]} |')
|
|
else:
|
|
print(f'| {prop["PropertyName"]} | {prop["DefaultValue"] or ""} | {typeName} | {prop["Description"]} |')
|
|
|
|
if len(relatedEnums) > 0:
|
|
print('\n# Related value types (enums):\n')
|
|
for relatedEnum in relatedEnums:
|
|
values = [f"`{value['Value']}`" for value in relatedEnum["Values"]]
|
|
print(f"### {relatedEnum['Name']}")
|
|
print(f"Possible values: {', '.join(values)}\n")
|
|
distinctReferencingTypes = sorted(set(enumReferences[relatedEnum['Name']]))
|
|
formattedReferencingTypes = [format_type_name(x, is_known_type(x, types)) for x in distinctReferencingTypes]
|
|
print(f"Referenced by: {', '.join(formattedReferencingTypes)}\n")
|
|
|
|
if __name__ == "__main__":
|
|
input_stream = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8-sig')
|
|
jsonInfo = json.load(input_stream)
|
|
|
|
keys = list(jsonInfo)
|
|
if len(keys) == 3 and keys[0] == 'Version':
|
|
format_docs(jsonInfo[keys[0]], keys[1], jsonInfo[keys[1]], jsonInfo[keys[2]])
|