Exemple #1
0
    /// <summary>
    /// Gets the cached private constructor of the node. The node can potentially have null values in non-nullable properties and fields.
    /// </summary>
    /// <typeparam name="T">Type of the node to instantiate.</typeparam>
    /// <param name="classId">Class ID.</param>
    /// <returns>The instantiated node.</returns>
    /// <exception cref="NodeNotFoundException">Node has not been found in the cached list.</exception>
    internal static T GetNodeInstance <T>(uint classId) where T : CMwNod
    {
        if (AvailableClassConstructors.TryGetValue(classId, out Func <CMwNod>?constructor))
        {
            var node = (T)constructor();
            node.SetIDAndChunks();
            return(node);
        }

        throw new NodeNotFoundException(classId);
    }
Exemple #2
0
    private static void DefineTypes()
    {
        var watch = Stopwatch.StartNew();

        var assembly = Assembly.GetExecutingAssembly();

        IEnumerable <Type> types;

        try
        {
            types = assembly.GetTypes();
        }
        catch (ReflectionTypeLoadException e)
        {
            types = e.Types.Where(x => x is not null) !;
        }

        var engineRelatedTypes = types.Where(t =>
                                             t?.IsClass == true &&
                                             t.Namespace?.StartsWith("GBX.NET.Engines") == true);

        var availableClassesByType = new Dictionary <Type, uint>();

        foreach (var type in engineRelatedTypes)
        {
            if (!type.IsSubclassOf(typeof(CMwNod)) && type != typeof(CMwNod)) // Engine types
            {
                continue;
            }

            var id = type.GetCustomAttribute <NodeAttribute>()?.ID;

            if (!id.HasValue)
            {
                throw new Exception($"{type.Name} misses NodeAttribute.");
            }

            AvailableClasses.Add(id.Value, type);
            availableClassesByType.Add(type, id.Value);
        }

        foreach (var typePair in AvailableClasses)
        {
            var id   = typePair.Key;
            var type = typePair.Value;

            var classes = new List <uint>();

            Type currentType = type.BaseType !;

            while (currentType != typeof(object))
            {
                classes.Add(availableClassesByType[currentType]);

                currentType = currentType.BaseType !;
            }

            AvailableInheritanceClasses[type] = classes;

            var chunks = type.GetNestedTypes().Where(x => x.IsSubclassOf(typeof(Chunk)));

            var baseType = type.BaseType !;

            while (baseType !.IsSubclassOf(typeof(CMwNod)))
            {
                chunks = chunks.Concat(baseType.GetNestedTypes().Where(x => x.IsSubclassOf(typeof(Chunk))));

                baseType = baseType.BaseType;
            }

            var availableChunkClasses       = new Dictionary <uint, Type>();
            var availableHeaderChunkClasses = new Dictionary <uint, Type>();

            foreach (var chunk in chunks)
            {
                var chunkAttribute = chunk.GetCustomAttribute <ChunkAttribute>();

                if (chunkAttribute == null)
                {
                    throw new Exception($"Chunk {chunk.FullName} doesn't have ChunkAttribute.");
                }

                if (chunk.GetInterface(nameof(IHeaderChunk)) == null)
                {
                    availableChunkClasses.Add(chunkAttribute.ID, chunk);
                }
                else
                {
                    availableHeaderChunkClasses.Add(chunkAttribute.ID, chunk);
                }
            }

            AvailableChunkClasses.Add(type, availableChunkClasses);
            AvailableHeaderChunkClasses.Add(type, availableHeaderChunkClasses);
        }

        foreach (var idClassPair in AvailableClasses)
        {
            var id        = idClassPair.Key;
            var classType = idClassPair.Value;

            AvailableClassAttributes.Add(classType, classType.GetCustomAttributes());
        }

        foreach (var classChunksPair in AvailableHeaderChunkClasses.Concat(AvailableChunkClasses))
        {
            var attributeDictionary = new Dictionary <uint, IEnumerable <Attribute> >();

            foreach (var chunkClassIdTypePair in classChunksPair.Value)
            {
                var id         = chunkClassIdTypePair.Key;
                var chunkClass = chunkClassIdTypePair.Value;

                var attributes = chunkClass.GetCustomAttributes();

                attributeDictionary[id] = attributes;

                AvailableChunkAttributesByType[chunkClass] = attributes;
            }

            AvailableChunkAttributes[classChunksPair.Key] = attributeDictionary;
        }

        foreach (var idClassPair in AvailableClasses)
        {
            var id        = idClassPair.Key;
            var classType = idClassPair.Value;

            var privateConstructor = classType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Array.Empty <Type>(), null);

            if (privateConstructor is null)
            {
                throw new PrivateConstructorNotFoundException(classType);
            }

            var newExp   = Expression.New(privateConstructor);
            var lambda   = Expression.Lambda <Func <CMwNod> >(newExp);
            var compiled = lambda.Compile();

            AvailableClassConstructors.Add(id, compiled);
        }

        foreach (var classChunksPair in AvailableChunkClasses)
        {
            var constructors = GetChunkConstructors(classChunksPair);
            if (constructors != null)
            {
                AvailableChunkConstructors[classChunksPair.Key] = constructors;
            }
        }

        foreach (var classChunksPair in AvailableHeaderChunkClasses)
        {
            var constructors = GetChunkConstructors(classChunksPair);
            if (constructors != null)
            {
                AvailableHeaderChunkConstructors[classChunksPair.Key] = constructors;
            }
        }

        Debug.WriteLine("Types defined in " + watch.Elapsed.TotalMilliseconds + "ms");
    }