[Wiki] Подгрузка ВСЕГО на вики (#3487)

This commit is contained in:
Pok
2026-01-19 22:28:44 +02:00
committed by GitHub
parent eff710e312
commit b462533f82
8 changed files with 737 additions and 53 deletions

View File

@@ -6,15 +6,11 @@ on:
branches: [ master, jsondump ]
paths:
- '.github/workflows/update-wiki.yml'
- 'Content.Shared/Chemistry/**.cs'
- 'Content.Server/Chemistry/**.cs'
- 'Content.Server/GuideGenerator/**.cs'
- 'Content.Server/Corvax/GuideGenerator/**.cs'
- 'Resources/Prototypes/Reagents/**.yml'
- 'Resources/Prototypes/Chemistry/**.yml'
- 'Resources/Prototypes/Recipes/Reactions/**.yml'
- 'Content.Shared/'
- 'Content.Server/'
- 'Content.Clietn/'
- 'Resources/'
- 'RobustToolbox/'
- 'Resources/Locale/**.ftl'
jobs:
update-wiki:
@@ -52,52 +48,50 @@ jobs:
run: dotnet ./bin/Content.Server/Content.Server.dll --cvar autogen.destination_file=prototypes.json
continue-on-error: true
- name: Upload chem_prototypes.json to wiki
uses: jtmullen/mediawiki-edit-action@v0.1.1
with:
wiki_text_file: ./bin/Content.Server/data/chem_prototypes.json
edit_summary: Update chem_prototypes.json via GitHub Actions
page_name: "${{ secrets.WIKI_PAGE_ROOT }}/chem_prototypes.json"
api_url: ${{ secrets.WIKI_ROOT_URL }}/api.php
username: ${{ secrets.WIKI_BOT_USER }}
password: ${{ secrets.WIKI_BOT_PASS }}
# Проходит по всем JSON-файлам в директории BASE и загружает каждый файл как страницу в MediaWiki.
# Имя страницы формируется из относительного пути к файлу.
- name: Upload JSON files to wiki
shell: bash
run: |
set -euo pipefail
- name: Upload react_prototypes.json to wiki
uses: jtmullen/mediawiki-edit-action@v0.1.1
with:
wiki_text_file: ./bin/Content.Server/data/react_prototypes.json
edit_summary: Update react_prototypes.json via GitHub Actions
page_name: "${{ secrets.WIKI_PAGE_ROOT }}/react_prototypes.json"
api_url: ${{ secrets.WIKI_ROOT_URL }}/api.php
username: ${{ secrets.WIKI_BOT_USER }}
password: ${{ secrets.WIKI_BOT_PASS }}
BASE="./bin/Content.Server/data"
ROOT="${{ secrets.WIKI_PAGE_ROOT }}"
API="${{ secrets.WIKI_ROOT_URL }}/api.php"
USER="${{ secrets.WIKI_BOT_USER }}"
PASS="${{ secrets.WIKI_BOT_PASS }}"
- name: Upload entity_prototypes.json to wiki
uses: jtmullen/mediawiki-edit-action@v0.1.1
with:
wiki_text_file: ./bin/Content.Server/data/entity_prototypes.json
edit_summary: Update entity_prototypes.json via GitHub Actions
page_name: "${{ secrets.WIKI_PAGE_ROOT }}/entity_prototypes.json"
api_url: ${{ secrets.WIKI_ROOT_URL }}/api.php
username: ${{ secrets.WIKI_BOT_USER }}
password: ${{ secrets.WIKI_BOT_PASS }}
API="$(printf "%s" "$API" | tr -d '\r\n' | sed 's/[[:space:]]*$//')"
USER="$(printf "%s" "$USER" | tr -d '\r\n')"
PASS="$(printf "%s" "$PASS" | tr -d '\r\n')"
ROOT="$(printf "%s" "$ROOT" | tr -d '\r\n' | sed 's/[[:space:]]*$//')"
- name: Upload mealrecipes_prototypes.json to wiki
uses: jtmullen/mediawiki-edit-action@v0.1.1
with:
wiki_text_file: ./bin/Content.Server/data/mealrecipes_prototypes.json
edit_summary: Update mealrecipes_prototypes.json via GitHub Actions
page_name: "${{ secrets.WIKI_PAGE_ROOT }}/mealrecipes_prototypes.json"
api_url: ${{ secrets.WIKI_ROOT_URL }}/api.php
username: ${{ secrets.WIKI_BOT_USER }}
password: ${{ secrets.WIKI_BOT_PASS }}
cookiejar="$(mktemp)"
trap 'rm -f "$cookiejar"' EXIT
- name: Upload loc.json to wiki
uses: jtmullen/mediawiki-edit-action@v0.1.1
with:
wiki_text_file: ./bin/Content.Server/data/loc.json
edit_summary: Update loc.json via GitHub Actions
page_name: "${{ secrets.WIKI_PAGE_ROOT }}/loc.json"
api_url: ${{ secrets.WIKI_ROOT_URL }}/api.php
username: ${{ secrets.WIKI_BOT_USER }}
password: ${{ secrets.WIKI_BOT_PASS }}
login_token=$(curl -sS -c "$cookiejar" --data "action=query&meta=tokens&type=login&format=json" "$API" | jq -r '.query.tokens.logintoken')
curl -sS -c "$cookiejar" -b "$cookiejar" \
--data-urlencode "action=login" \
--data-urlencode "lgname=$USER" \
--data-urlencode "lgpassword=$PASS" \
--data-urlencode "lgtoken=$login_token" \
--data-urlencode "format=json" \
"$API" > /dev/null
find "$BASE" -type f -name '*.json' | while IFS= read -r file; do
rel="${file#$BASE/}"
rel="$(printf "%s" "$rel" | tr -d '\r\n' | sed 's/:/_/g')"
page="$ROOT/$rel"
echo "Uploading $rel → $page"
token=$(curl -sS -b "$cookiejar" --data "action=query&meta=tokens&format=json" "$API" | jq -r '.query.tokens.csrftoken')
curl -sS -b "$cookiejar" \
--data-urlencode "action=edit" \
--data-urlencode "title=$page" \
--data-urlencode "summary=Update $rel via GitHub Actions" \
--data-urlencode "text@${file}" \
--data-urlencode "token=$token" \
--data-urlencode "format=json" \
"$API" | jq -r '.'
done

View File

@@ -0,0 +1,90 @@
using System.Text.Encodings.Web;
using System.Text.Json;
using Robust.Shared.ContentPack;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Utility;
namespace Content.Server.Corvax.GuideGenerator;
public static class ComponentJsonGenerator
{
public static void PublishAll(IResourceManager res, ResPath destRoot)
{
var proto = IoCManager.Resolve<IPrototypeManager>();
var ser = IoCManager.Resolve<ISerializationManager>();
var compFactory = IoCManager.Resolve<IComponentFactory>();
var entMan = IoCManager.Resolve<IEntityManager>();
// Map: component name -> (entity id -> component fields)
var output = new Dictionary<string, Dictionary<string, object?>>();
foreach (var p in proto.EnumeratePrototypes(typeof(EntityPrototype)))
{
if (p is not EntityPrototype entProto)
continue;
foreach (var (compName, entry) in entProto.Components)
{
var node = ser.WriteValueAs<MappingDataNode>(entry.Component.GetType(), entry.Component);
var compFields = FieldEntry.DataNodeToObject(node);
if (!output.TryGetValue(compName, out var map))
{
map = new Dictionary<string, object?>();
output[compName] = map;
}
map[entProto.ID] = compFields;
}
}
if (output.Count == 0)
return;
foreach (var (compName, map) in output)
{
// Determine default field for this component.
object? defaultObj = null;
if (compFactory.TryGetRegistration(compName, out var registration))
{
var uid = entMan.CreateEntityUninitialized(null);
try
{
var compInstance = compFactory.GetComponent(registration.Type);
FieldEntry.EnsureFieldsCollectionsInitialized(compInstance);
entMan.AddComponent(uid, compInstance);
var node = ser.WriteValueAs<MappingDataNode>(compInstance.GetType(), compInstance, true);
defaultObj = FieldEntry.DataNodeToObject(node);
}
catch
{
defaultObj = new Dictionary<string, object?>();
}
finally
{
entMan.DeleteEntity(uid);
}
}
var outObj = new Dictionary<string, object?>
{
["default"] = defaultObj,
["id"] = map
};
var serializeOptions = new JsonSerializerOptions
{
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
res.UserData.CreateDir(destRoot);
var fileName = PrototypeUtility.CalculatePrototypeName(compName) + ".json";
var file = res.UserData.OpenWriteText(destRoot / fileName);
file.Write(JsonSerializer.Serialize(outObj, serializeOptions));
file.Flush();
}
}
}

View File

@@ -0,0 +1,43 @@
using System.IO;
using System.Text.Encodings.Web;
using System.Text.Json;
using Robust.Shared.Prototypes;
namespace Content.Server.Corvax.GuideGenerator;
public static class ComponentListGenerator
{
public static void PublishJson(StreamWriter file)
{
var proto = IoCManager.Resolve<IPrototypeManager>();
// Map: entity id -> list of component names.
var output = new Dictionary<string, List<string>>();
foreach (var p in proto.EnumeratePrototypes(typeof(EntityPrototype)))
{
if (p is not EntityPrototype entityProto)
continue;
var componentNames = new List<string>();
foreach (var (compName, _) in entityProto.Components)
{
componentNames.Add(compName);
}
if (componentNames.Count > 0)
output[entityProto.ID] = componentNames;
}
if (output.Count == 0)
return;
var serializeOptions = new JsonSerializerOptions
{
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
file.Write(JsonSerializer.Serialize(output, serializeOptions));
}
}

View File

@@ -0,0 +1,220 @@
using System.Collections;
using System.Globalization;
using System.Reflection;
using System.Text.RegularExpressions;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Value;
namespace Content.Server.Corvax.GuideGenerator;
public static class FieldEntry
{
public static object? DataNodeToObject(DataNode node)
{
if (node is MappingDataNode mapping)
{
var dict = new Dictionary<string, object?>();
foreach (var kv in mapping)
{
dict[kv.Key] = DataNodeToObject(kv.Value);
}
if (node.Tag != null)
{
var wrapped = new Dictionary<string, object?>
{
[node.Tag] = dict
};
return wrapped;
}
return dict;
}
if (node is SequenceDataNode sequence)
{
var list = new List<object?>();
foreach (var item in sequence)
{
list.Add(DataNodeToObject(item));
}
return list;
}
if (node is ValueDataNode value)
{
if (value.IsNull)
return null;
var raw = value.Value;
if (bool.TryParse(raw, out var boolRes))
return boolRes;
if (int.TryParse(raw, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intRes))
return intRes;
// Accept decimals only in a strict single-dot format.
if (Regex.IsMatch(raw, @"^[+-]?\d+\.\d+$") &&
double.TryParse(raw, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleRes))
return doubleRes;
return raw;
}
return node.ToString();
}
public static void EnsureFieldsCollectionsInitialized(object instance)
{
var type = instance.GetType();
const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
// Fields
foreach (var field in type.GetFields(flags))
{
if (field.IsInitOnly)
continue;
try
{
var value = field.GetValue(instance);
if (value != null)
continue;
var ft = field.FieldType;
if (ft == typeof(string))
{
field.SetValue(instance, string.Empty);
}
else if ((typeof(IDictionary).IsAssignableFrom(ft) || typeof(IList).IsAssignableFrom(ft) || ft.IsGenericType && ft.GetGenericTypeDefinition() == typeof(List<>) || ft.IsArray) && ft is { IsAbstract: false, IsInterface: false })
{
object? created = null;
if (ft.IsArray)
{
var elemType = ft.GetElementType();
if (elemType != null)
created = Array.CreateInstance(elemType, 0);
}
else if (ft.GetConstructor(Type.EmptyTypes) != null)
{
created = Activator.CreateInstance(ft);
}
if (created != null)
field.SetValue(instance, created);
}
else if (ft.IsClass && ft != typeof(string) && !ft.IsAbstract)
{
var created = Activator.CreateInstance(ft, true);
if (created != null)
{
field.SetValue(instance, created);
EnsureFieldsCollectionsInitialized(created);
}
}
else if ((ft.IsAbstract || ft.IsInterface) && ft != typeof(string))
{
var concrete = FindConcreteAssignableType(ft);
if (concrete != null)
{
var created = Activator.CreateInstance(concrete);
if (created != null)
{
field.SetValue(instance, created);
EnsureFieldsCollectionsInitialized(created);
}
}
}
}
catch
{
// ignore
}
}
// Properties
foreach (var prop in type.GetProperties(flags))
{
if (!prop.CanWrite || prop.GetIndexParameters().Length != 0)
continue;
try
{
var value = prop.GetValue(instance);
if (value != null)
continue;
var pt = prop.PropertyType;
if ((typeof(IDictionary).IsAssignableFrom(pt) || typeof(IList).IsAssignableFrom(pt) || pt.IsGenericType && pt.GetGenericTypeDefinition() == typeof(List<>) || pt.IsArray) && pt is { IsAbstract: false, IsInterface: false })
{
object? created = null;
if (pt.IsArray)
{
var elemType = pt.GetElementType();
if (elemType != null)
created = Array.CreateInstance(elemType, 0);
}
else if (pt.GetConstructor(Type.EmptyTypes) != null)
{
created = Activator.CreateInstance(pt);
}
if (created != null)
prop.SetValue(instance, created);
}
else if (pt.IsClass && pt != typeof(string) && !pt.IsAbstract)
{
var created = Activator.CreateInstance(pt, true);
if (created != null)
{
prop.SetValue(instance, created);
EnsureFieldsCollectionsInitialized(created);
}
}
else if ((pt.IsAbstract || pt.IsInterface) && pt != typeof(string))
{
var concrete = FindConcreteAssignableType(pt);
if (concrete != null)
{
var created = Activator.CreateInstance(concrete);
if (created != null)
{
prop.SetValue(instance, created);
EnsureFieldsCollectionsInitialized(created);
}
}
}
}
catch
{
// ignore
}
}
}
private static Type? FindConcreteAssignableType(Type target)
{
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
var types = asm.GetTypes();
foreach (var t in types)
{
if (t.IsAbstract || t.IsInterface)
continue;
if (!target.IsAssignableFrom(t))
continue;
if (t.GetConstructor(Type.EmptyTypes) == null)
continue;
return t;
}
}
return null;
}
}

View File

@@ -0,0 +1,53 @@
using System.IO;
using System.Text.Encodings.Web;
using System.Text.Json;
namespace Content.Server.Corvax.GuideGenerator;
public static class MetaLicenseGenerator
{
public static void PublishJson(StreamWriter file)
{
var workingDir = Directory.GetCurrentDirectory();
var resourcesRoot = Path.Combine(workingDir, "Resources");
if (!Directory.Exists(resourcesRoot))
return;
var output = new Dictionary<string, Dictionary<string, string>>();
foreach (var metaPath in Directory.EnumerateFiles(resourcesRoot, "meta.json", SearchOption.AllDirectories))
{
var json = File.ReadAllText(metaPath);
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
var license = root.TryGetProperty("license", out var licEl) && licEl.ValueKind == JsonValueKind.String
? licEl.GetString() ?? string.Empty
: string.Empty;
var copyright = root.TryGetProperty("copyright", out var copyEl) && copyEl.ValueKind == JsonValueKind.String
? copyEl.GetString() ?? string.Empty
: string.Empty;
var resourceDir = Path.GetDirectoryName(metaPath) ?? metaPath;
var relativeResourcePath = Path.GetRelativePath(workingDir, resourceDir).Replace('\\', '/');
output[relativeResourcePath] = new Dictionary<string, string>
{
{ "license", license },
{ "copyright", copyright }
};
}
if (output.Count == 0)
return;
var serializeOptions = new JsonSerializerOptions
{
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
file.Write(JsonSerializer.Serialize(output, serializeOptions));
}
}

View File

@@ -0,0 +1,75 @@
using System.Linq;
using System.Text.Encodings.Web;
using System.Text.Json;
using Robust.Shared.ContentPack;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Utility;
namespace Content.Server.Corvax.GuideGenerator;
public static class PrototypeJsonGenerator
{
public static void PublishAll(IResourceManager res, ResPath destRoot)
{
var proto = IoCManager.Resolve<IPrototypeManager>();
var ser = IoCManager.Resolve<ISerializationManager>();
foreach (var kind in proto.EnumeratePrototypeKinds().OrderBy(t => t.Name))
{
// The entity prototype has its own generator due to its size <see cref="EntityJsonGenerator"/>.
if (kind == typeof(EntityPrototype))
continue;
// Map: entity id -> prototype fields
var map = new Dictionary<string, object?>();
foreach (var p in proto.EnumeratePrototypes(kind))
{
var node = ser.WriteValueAs<MappingDataNode>(kind, p);
node.Remove("id");
map[p.ID] = FieldEntry.DataNodeToObject(node);
}
if (map.Count == 0)
continue;
// Determine default field for this prototype.
object? defaultObj = null;
try
{
var instance = Activator.CreateInstance(kind);
if (instance != null)
{
FieldEntry.EnsureFieldsCollectionsInitialized(instance);
var defaultNode = ser.WriteValueAs<MappingDataNode>(kind, instance, true);
defaultNode.Remove("id");
defaultObj = FieldEntry.DataNodeToObject(defaultNode);
}
}
catch
{
defaultObj = new Dictionary<string, object?>();
}
var outObj = new Dictionary<string, object?>
{
["default"] = defaultObj,
["id"] = map
};
var serializeOptions = new JsonSerializerOptions
{
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
res.UserData.CreateDir(destRoot);
var fileName = PrototypeUtility.CalculatePrototypeName(kind.Name) + ".json";
var file = res.UserData.OpenWriteText(destRoot / fileName);
file.Write(JsonSerializer.Serialize(outObj, serializeOptions));
file.Flush();
}
}
}

View File

@@ -0,0 +1,196 @@
using System.IO;
using System.Reflection;
using System.Text.Encodings.Web;
using System.Text.Json;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Value;
namespace Content.Server.Corvax.GuideGenerator;
public static class PrototypeListGenerator
{
public static void PublishJson(StreamWriter file)
{
var proto = IoCManager.Resolve<IPrototypeManager>();
// Map: entity id -> (prototype kind name -> list of prototype ids that reference it).
var output = new Dictionary<string, Dictionary<string, List<string>>>();
foreach (var kindType in proto.EnumeratePrototypeKinds())
{
var kindName = PrototypeUtility.CalculatePrototypeName(kindType.Name);
foreach (var p in proto.EnumeratePrototypes(kindType))
{
if (!proto.TryGetMapping(kindType, p.ID, out var mapping))
continue;
var referencedEntityIds = new HashSet<string>();
InspectTypeForEntityRefs(kindType, mapping, referencedEntityIds);
if (referencedEntityIds.Count == 0)
continue;
foreach (var entId in referencedEntityIds)
{
if (!output.TryGetValue(entId, out var byKind))
{
byKind = new Dictionary<string, List<string>>();
output[entId] = byKind;
}
if (!byKind.TryGetValue(kindName, out var list))
{
list = new List<string>();
byKind[kindName] = list;
}
list.Add(p.ID);
}
}
}
if (output.Count == 0)
return;
var serializeOptions = new JsonSerializerOptions
{
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
file.Write(JsonSerializer.Serialize(output, serializeOptions));
}
private static void InspectTypeForEntityRefs(Type prototypeType, MappingDataNode mapping, HashSet<string> outIds)
{
// Check fields.
foreach (var field in prototypeType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
var attr = field.GetCustomAttribute<DataFieldAttribute>();
if (attr == null)
continue;
var tag = attr.Tag ?? LowerFirst(field.Name);
if (!mapping.TryGet(tag, out var node))
continue;
ExtractIdsFromNode(field.FieldType, node, outIds);
}
// Check properties.
foreach (var prop in prototypeType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
var attr = prop.GetCustomAttribute<DataFieldAttribute>();
if (attr == null)
continue;
var tag = attr.Tag ?? LowerFirst(prop.Name);
if (!mapping.TryGet(tag, out var node))
continue;
ExtractIdsFromNode(prop.PropertyType, node, outIds);
}
}
private static void ExtractIdsFromNode(Type memberType, DataNode node, HashSet<string> outIds)
{
var underlying = Nullable.GetUnderlyingType(memberType) ?? memberType;
if (IsEntProtoIdType(underlying))
{
if (node is ValueDataNode v)
{
if (!string.IsNullOrWhiteSpace(v.Value))
outIds.Add(v.Value);
}
else if (node is MappingDataNode m && m.TryGet("id", out var idNode) && idNode is ValueDataNode idVal)
{
if (!string.IsNullOrWhiteSpace(idVal.Value))
outIds.Add(idVal.Value);
}
return;
}
if (node is SequenceDataNode seq)
{
var elemType = GetElementType(underlying);
if (elemType == null)
return;
foreach (var child in seq.Sequence)
{
ExtractIdsFromNode(elemType, child, outIds);
}
return;
}
if (node is MappingDataNode map)
{
foreach (var field in underlying.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
var attr = field.GetCustomAttribute<DataFieldAttribute>();
if (attr == null)
continue;
var tag = attr.Tag ?? LowerFirst(field.Name);
if (!map.TryGet(tag, out var childNode))
continue;
ExtractIdsFromNode(field.FieldType, childNode, outIds);
}
foreach (var prop in underlying.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
var attr = prop.GetCustomAttribute<DataFieldAttribute>();
if (attr == null)
continue;
var tag = attr.Tag ?? LowerFirst(prop.Name);
if (!map.TryGet(tag, out var childNode))
continue;
ExtractIdsFromNode(prop.PropertyType, childNode, outIds);
}
}
}
private static bool IsEntProtoIdType(Type t)
{
if (t == typeof(EntProtoId))
return true;
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(EntProtoId<>))
return true;
return false;
}
private static Type? GetElementType(Type t)
{
if (t.IsArray)
return t.GetElementType();
if (t.IsGenericType)
{
var genDef = t.GetGenericTypeDefinition();
if (genDef == typeof(List<>) || genDef == typeof(IEnumerable<>) || genDef == typeof(IReadOnlyList<>) || genDef == typeof(ICollection<>))
return t.GetGenericArguments()[0];
}
return null;
}
private static string LowerFirst(string s)
{
if (string.IsNullOrEmpty(s))
return s;
if (s.Length == 1)
return s.ToLowerInvariant();
return char.ToLowerInvariant(s[0]) + s.Substring(1);
}
}

View File

@@ -165,6 +165,19 @@ namespace Content.Server.Entry
file = _res.UserData.OpenWriteText(resPath.WithName("loc.json"));
LocJsonGenerator.PublishJson(file);
file.Flush();
file = _res.UserData.OpenWriteText(resPath.WithName("meta_license.json"));
MetaLicenseGenerator.PublishJson(file);
file.Flush();
file = _res.UserData.OpenWriteText(resPath.WithName("prototype.json"));
PrototypeListGenerator.PublishJson(file);
file.Flush();
file = _res.UserData.OpenWriteText(resPath.WithName("component.json"));
ComponentListGenerator.PublishJson(file);
file.Flush();
PrototypeJsonGenerator.PublishAll(_res, new ResPath("prototype").ToRootedPath());
file.Flush();
ComponentJsonGenerator.PublishAll(_res, new ResPath("component").ToRootedPath());
file.Flush();
// Corvax-Wiki-End
Dependencies.Resolve<IBaseServer>().Shutdown("Data generation done");
return;