/// <summary>
        /// Register the given entity prototype class.
        /// </summary>
        /// <param name="entityComponentType">Entity class prototype.</param>
        internal static void TryRegister(Type entityComponentType)
        {
            if (!entityComponentType.IsAbstract && !entityComponentType.IsValueType && entityComponentType.GetConstructor(Type.EmptyTypes) == null)
            {
                string errorMessage = string.Format("Unable to register component of type {0}!{2}" +
                                                    "The component doesn't have a default parameterless constructor defined which is not supported on classes inheriting from {1}." +
                                                    "The {1} will overwrite the values of the constructor with the serialized values of the component." +
                                                    "Use {3} instead to initialize your component.",
                                                    entityComponentType.FullName, nameof(EntityComponent), Environment.NewLine, nameof(EntityComponent.OnInitialize));
                throw new NotSupportedException(errorMessage);
            }

            var typeInfo = new TypeInfo
            {
                type = entityComponentType
            };

            _componentTypes.Add(typeInfo);

            var  guidAttribute      = entityComponentType.GetCustomAttribute <GuidAttribute>(false);
            var  componentAttribute = entityComponentType.GetCustomAttribute <EntityComponentAttribute>(false);
            bool hasGuid            = false;

            if (guidAttribute != null)
            {
                Guid guid;
                if (ValidateGuid(entityComponentType.Name, guidAttribute.Value, out guid))
                {
                    var guidArray = guid.ToByteArray();
                    typeInfo.guid.hipart = BitConverter.ToUInt64(guidArray, 0);
                    typeInfo.guid.lopart = BitConverter.ToUInt64(guidArray, 8);
                    hasGuid = true;
                }
            }

            if (!hasGuid && componentAttribute != null)
            {
                if (!string.IsNullOrWhiteSpace(componentAttribute.Guid))
                {
                    Guid guid;
                    if (ValidateGuid(entityComponentType.Name, componentAttribute.Guid, out guid))
                    {
                        var guidArray = guid.ToByteArray();
                        typeInfo.guid.hipart = BitConverter.ToUInt64(guidArray, 0);
                        typeInfo.guid.lopart = BitConverter.ToUInt64(guidArray, 8);
                        hasGuid = true;
                    }
                }
            }

            if (!hasGuid)
            {
                // Fall back to generating GUID based on type
                var guidString = Engine.TypeToHash(entityComponentType);
                var half       = (int)(guidString.Length / 2.0f);
                if (!ulong.TryParse(guidString.Substring(0, half), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out typeInfo.guid.hipart))
                {
                    Log.Error("Failed to parse {0} to UInt64", guidString.Substring(0, half));
                }
                if (!ulong.TryParse(guidString.Substring(half, guidString.Length - half), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out typeInfo.guid.lopart))
                {
                    Log.Error("Failed to parse {0} to UInt64", guidString.Substring(half, guidString.Length - half));
                }
            }

            if (componentAttribute == null)
            {
                componentAttribute = new EntityComponentAttribute();
            }

            if (componentAttribute.Name.Length == 0)
            {
                componentAttribute.Name = entityComponentType.Name;
            }

            if (entityComponentType.IsAbstract || entityComponentType.IsInterface)
            {
                // By passing an empty string as the name the component will still be registered,
                // but the Sandbox will not show it in the AddComponent menu.
                componentAttribute.Name = string.Empty;
            }

            NativeInternals.Entity.RegisterComponent(entityComponentType,
                                                     typeInfo.guid.hipart,
                                                     typeInfo.guid.lopart,
                                                     componentAttribute.Name,
                                                     componentAttribute.Category,
                                                     componentAttribute.Description,
                                                     componentAttribute.Icon);

            // Register all bases, note that the base has to have been registered before the component we're registering right now!
            var baseType = entityComponentType.BaseType;

            while (baseType != typeof(object))
            {
                NativeInternals.Entity.AddComponentBase(entityComponentType, baseType);

                baseType = baseType.BaseType;
            }

            if (!entityComponentType.IsAbstract)
            {
                RegisterComponentProperties(typeInfo);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Register the given entity prototype class.
        /// </summary>
        /// <param name="entityComponentType">Entity class prototype.</param>
        internal static void TryRegister(Type entityComponentType)
        {
            var typeInfo = new TypeInfo
            {
                type = entityComponentType
            };

            _componentTypes.Add(typeInfo);

            var guidAttribute = (GuidAttribute)entityComponentType.GetCustomAttributes(typeof(GuidAttribute), false).FirstOrDefault();

            if (guidAttribute != null)
            {
                var guid = new Guid(guidAttribute.Value);

                var guidArray = guid.ToByteArray();
                typeInfo.guid.hipart = BitConverter.ToUInt64(guidArray, 0);
                typeInfo.guid.lopart = BitConverter.ToUInt64(guidArray, 8);
            }
            else
            {
                // Fall back to generating GUID based on type
                var guidString = Engine.TypeToHash(entityComponentType);
                var half       = (int)(guidString.Length / 2.0f);
                if (!ulong.TryParse(guidString.Substring(0, half), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out typeInfo.guid.hipart))
                {
                    Log.Error("Failed to parse {0} to UInt64", guidString.Substring(0, half));
                }
                if (!ulong.TryParse(guidString.Substring(half, guidString.Length - half), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out typeInfo.guid.lopart))
                {
                    Log.Error("Failed to parse {0} to UInt64", guidString.Substring(half, guidString.Length - half));
                }
            }

            var componentAttribute = (EntityComponentAttribute)entityComponentType.GetCustomAttributes(typeof(EntityComponentAttribute), false).FirstOrDefault();

            if (componentAttribute == null)
            {
                componentAttribute = new EntityComponentAttribute();
            }

            if (componentAttribute.Name.Length == 0)
            {
                componentAttribute.Name = entityComponentType.Name;
            }

            if (entityComponentType.IsAbstract || entityComponentType.IsInterface)
            {
                // By passing an empty string as the name the component will still be registered,
                // but the Sandbox will not show it in the AddComponent menu.
                componentAttribute.Name = string.Empty;
            }

            NativeInternals.Entity.RegisterComponent(entityComponentType,
                                                     typeInfo.guid.hipart,
                                                     typeInfo.guid.lopart,
                                                     componentAttribute.Name,
                                                     componentAttribute.Category,
                                                     componentAttribute.Description,
                                                     componentAttribute.Icon);

            // Register all bases, note that the base has to have been registered before the component we're registering right now!
            var baseType = entityComponentType.BaseType;

            while (baseType != typeof(object))
            {
                NativeInternals.Entity.AddComponentBase(entityComponentType, baseType);

                baseType = baseType.BaseType;
            }


            // Register all properties
            var properties = entityComponentType.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.SetProperty);

            foreach (PropertyInfo propertyInfo in properties)
            {
                var attribute = (EntityPropertyAttribute)propertyInfo.GetCustomAttributes(typeof(EntityPropertyAttribute), false).FirstOrDefault();
                if (attribute == null)
                {
                    continue;
                }

                NativeInternals.Entity.RegisterComponentProperty(entityComponentType, propertyInfo, propertyInfo.Name, propertyInfo.Name, attribute.Description, attribute.Type);
            }
        }