예제 #1
0
 internal static GameStateParameterLookupEntry Property(string name, string path, Type type) => new GameStateParameterLookupEntry
 {
     Name     = name,
     Path     = path,
     IsFolder = false,
     ClrType  = type,
     Type     = GSIPropertyTypeConverter.TypeToPropertyType(type)
 };
예제 #2
0
        /// <summary>
        /// Creates a new <see cref="GameStateParameterLookup"/> by inspecting all properties on the given type.
        /// </summary>
        public GameStateParameterLookup(Type type)
        {
            // Recursive function for visiting all types on the given type
            // Will add relevant entries to lookup
            void Visit(string path, string name, Type type)
            {
                // If this is a variable that can be handled (such as a number or bool), add it to the lookup
                if (GSIPropertyTypeConverter.TypeToPropertyType(type) != GSIPropertyType.None)
                {
                    lookup.Add(path, GameStateParameterLookupEntry.Property(name, path, type));
                }

                else if (recursiveWhiteList.Any(t => t.IsAssignableFrom(type)))
                {
                    // Else if this not a handlable property, check if it's a node or list of nodes and if so make a folder and visit it's children
                    if (path != "") // If it's the root folder, don't add it
                    {
                        lookup.Add(path, GameStateParameterLookupEntry.Folder(name, path));
                    }

                    var accessor = TypeAccessor.Create(type);
                    if (!accessor.GetMembersSupported)
                    {
                        return;
                    }
                    foreach (var member in accessor.GetMembers())
                    {
                        if (member.Type == type)
                        {
                            continue;                      // Ignore recursive types
                        }
                        if (member.GetAttribute(typeof(GameStateIgnoreAttribute), true) != null)
                        {
                            continue;                                                                      // Ignore properties with [GameStateIgnore]
                        }
                        var nextPath = (path + "/" + member.Name).TrimStart('/');

                        // If the type is an Enumerable with a range attribute, visit for each item in that range
                        if (member.Type.GetGenericInterfaceTypes(typeof(IEnumerable <>)) is { } ienumTypes&& typeof(Node).IsAssignableFrom(ienumTypes[0]) && member.GetAttribute(typeof(RangeAttribute), true) is RangeAttribute range)
                        {
                            for (var i = range.Start; i <= range.End; i++)
                            {
                                Visit(nextPath + "/" + i, i.ToString(), ienumTypes[0]);
                            }
                        }

                        // Recursively visit the next type (do this even if it is IEnumerable, as it might be a custom class that implements IEnumerable with extra properties)
                        Visit(nextPath, member.Name, member.Type);
                    }
                }
            }

            // Start the recursive function at the root.
            Visit("", "", type);
        }