예제 #1
0
        /// <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 = (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;
            }

            if (!entityComponentType.IsAbstract)
            {
                RegisterComponentProperties(entityComponentType);
            }
        }