Defines a GameModeInfo record holding Path, Title, Description and provides static methods to enumerate GameMode components from a scene file. It walks SceneFile JSON, resolves prefab roots and prefab variable overrides for Title and Description, builds GameModeInfo instances and returns a list.
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace KOTH;
public record GameModeInfo(
[property: JsonIgnore] string Path,
string Title,
string Description);
partial class GameMode
{
/// <summary>
/// Gets all game modes referenced by a scene.
/// </summary>
public static IReadOnlyList<GameModeInfo> GetAll(SceneFile scene)
{
var list = new List<GameModeInfo>();
foreach (var go in scene?.GameObjects)
{
if (go == null)
continue;
GetAll(go, "", list);
}
return list;
}
private static void GetAll(JsonObject go, string path, List<GameModeInfo> infos)
{
if (!go.TryGetPropertyValue("Enabled", out var enabledNode) || enabledNode?.GetValue<bool>() is not true)
{
return;
}
if (!go.TryGetPropertyValue("Name", out var nameNode) || nameNode?.GetValue<string>() is not { } name)
{
return;
}
path = $"{path}/{name}";
// TODO: actually support prefab variables properly, instead of hard coding "Title" and "Description"
string titleOverride = null;
string descriptionOverride = null;
if (go.TryGetPropertyValue("__Prefab", out var prefabNode)
&& prefabNode?.GetValue<string>() is { } prefabPath
&& ResourceLibrary.TryGet<PrefabFile>(prefabPath, out var prefabFile))
{
if (go.TryGetPropertyValue("__PrefabVariables", out var variables))
{
titleOverride = variables?["Title"]?.GetValue<string>();
descriptionOverride = variables?["Description"]?.GetValue<string>();
}
go = prefabFile.RootObject;
}
if (go.TryGetPropertyValue("Components", out var componentsNode) && componentsNode is JsonArray components)
{
foreach (var component in components.Select(x => x.AsObject()))
{
if (!component.TryGetPropertyValue("__type", out var typeNode)
|| !string.Equals(typeNode?.GetValue<string>(), typeof(GameMode).FullName, StringComparison.OrdinalIgnoreCase))
{
continue;
}
var info = (GameModeInfo)Json.FromNode(component, typeof(GameModeInfo)) with { Path = path };
info = info with
{
Title = titleOverride ?? info.Title,
Description = descriptionOverride ?? info.Description
};
infos.Add(info);
}
}
if (!go.TryGetPropertyValue("Children", out var childrenNode) || childrenNode is not JsonArray children)
{
return;
}
foreach (var child in children)
{
GetAll(child.AsObject(), path, infos);
}
}
}