Пример #1
0
        /// <summary>
        /// Initializes the Entity with data loaded from a DataSet file.
        /// </summary>
        /// <param name="entityData">
        /// The data loaded from a DataSet file.
        /// </param>
        /// <param name="initFunctions">
        /// Helper functions to aid in initialization.
        /// </param>
        public void Initialize(Core.Entity entityData, EntityFactory.EntityInitializeFunctions initFunctions)
        {
            this.Address = entityData.Address;
            this.ReadStaticProperties(entityData.StaticProperties, initFunctions);

            foreach (var unused in entityData.DynamicProperties)
            {
                Debug.LogError($"Attempted to read dynamic property in an entity of type {entityData.ClassName} but dynamic properties are not yet supported. Report this.");
            }

            this.OnPropertiesLoaded();
        }
Пример #2
0
        private void ReadStaticProperties(Core.PropertyInfo[] properties, EntityFactory.EntityInitializeFunctions initFunctions)
        {
            var baseTypes = ReflectionUtils.GetParentTypes(this.GetType(), true);
            var fields    = (from type in baseTypes
                             from field in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic)
                             let attribute = field.GetCustomAttribute <PropertyInfoAttribute>()
                                             where attribute != null && !attribute.IsAutoProperty
                                             select new { Field = field, PropertyInfo = attribute }).ToList();

            foreach (var field in fields)
            {
                var loadedProperty = properties.FirstOrDefault(property => property.Name == field.Field.Name);

                if (loadedProperty == null)
                {
                    Debug.LogError("Property " + field.Field.Name + " is null.");
                    continue;
                }

                Assert.IsNotNull(loadedProperty);

                var propertyInfo = field.PropertyInfo;

                object value = null;
                switch (propertyInfo.Type)
                {
                case Core.PropertyInfoType.Int8:
                    value = ExtractPropertyValue <sbyte, sbyte>(
                        loadedProperty,
                        null,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.UInt8:
                    value = ExtractPropertyValue <byte, byte>(
                        loadedProperty,
                        null,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.Int16:
                    value = ExtractPropertyValue <short, short>(
                        loadedProperty,
                        null,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.UInt16:
                    value = ExtractPropertyValue <ushort, ushort>(
                        loadedProperty,
                        null,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.Int32:
                    value = ExtractPropertyValue <int, int>(
                        loadedProperty,
                        null,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.UInt32:
                    value = ExtractPropertyValue <uint, uint>(
                        loadedProperty,
                        null,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.Int64:
                    value = ExtractPropertyValue <long, long>(
                        loadedProperty,
                        null,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.UInt64:
                    value = ExtractPropertyValue <ulong, ulong>(
                        loadedProperty,
                        null,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.Float:
                    value = ExtractPropertyValue <float, float>(
                        loadedProperty,
                        null,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.Double:
                    value = ExtractPropertyValue <double, double>(
                        loadedProperty,
                        null,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.Bool:
                    value = ExtractPropertyValue <bool, bool>(
                        loadedProperty,
                        null,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.String:
                    value = ExtractPropertyValue <string, string>(
                        loadedProperty,
                        null,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.Path:
                    value = ExtractPropertyValue <string, string>(
                        loadedProperty,
                        FoxUtils.FoxPathToUnityPath,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.EntityPtr:
                    /* Abandon all hope ye who enter
                     * So what's going on here is that EntityPtr properties get Entities of varying types depending on their ptrType.
                     * However, we don't know that type at compile time, so we can't call ExtractPropertyValue.
                     * To do that, we must use reflection to dynamically invoke ExtractPropertyValue with the ptrType as a generic type argument.
                     * To make matters worse, it requires a delegate as a parameter, and we need to dynamically create that delegate too since
                     * its parameters are also unknown at compile time. We use the C# Expression API to create and compile a lambda expression at runtime.
                     *
                     * Last chance to turn back.
                     */
                    var method  = typeof(Entity).GetMethod(nameof(this.ExtractPropertyValue), BindingFlags.NonPublic | BindingFlags.Instance);
                    var generic = method.MakeGenericMethod(typeof(ulong), propertyInfo.PtrType);

                    var addressParameter      = Expression.Parameter(typeof(ulong), "address");
                    var initFunctionsInstance = Expression.Constant(initFunctions.GetEntityFromAddress.Target);
                    var getEntityFunction     = initFunctions.GetEntityFromAddress.Method;
                    var callGetEntityFunction = Expression.Call(
                        initFunctionsInstance,
                        getEntityFunction,
                        addressParameter);
                    var cast = Expression.Convert(callGetEntityFunction, propertyInfo.PtrType);
                    var del  = Expression.Lambda(cast, addressParameter).Compile();

                    value = generic.Invoke(
                        this,
                        new object[]
                    {
                        loadedProperty, del, propertyInfo.Container, propertyInfo.ArraySize
                    });
                    break;

                case Core.PropertyInfoType.Vector3:
                    value = ExtractPropertyValue <Core.Vector3, UnityEngine.Vector3>(
                        loadedProperty,
                        FoxUtils.FoxToUnity,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.Vector4:
                    value = ExtractPropertyValue <Core.Vector4, UnityEngine.Vector4>(
                        loadedProperty,
                        FoxUtils.FoxToUnity,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.Quat:
                    value = ExtractPropertyValue <Core.Quaternion, UnityEngine.Quaternion>(
                        loadedProperty,
                        FoxUtils.FoxToUnity,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.Matrix3:
                    value = ExtractPropertyValue <Core.Matrix3, Matrix3x3>(
                        loadedProperty,
                        FoxUtils.FoxToUnity,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.Matrix4:
                    value = ExtractPropertyValue <Core.Matrix4, UnityEngine.Matrix4x4>(
                        loadedProperty,
                        FoxUtils.FoxToUnity,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.Color:
                    value = ExtractPropertyValue <Core.ColorRGBA, UnityEngine.Color>(
                        loadedProperty,
                        FoxUtils.FoxColorRGBAToUnityColor,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.FilePtr:
                    value = ExtractPropertyValue <string, string>(
                        loadedProperty,
                        FoxUtils.FoxPathToUnityPath,
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.EntityHandle:
                    value = ExtractPropertyValue <ulong, Entity>(
                        loadedProperty,
                        address => initFunctions.GetEntityFromAddress(address),
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.EntityLink:
                    value = ExtractPropertyValue <Core.EntityLink, EntityLink>(
                        loadedProperty,
                        rawValue => initFunctions.MakeEntityLink(rawValue),
                        propertyInfo.Container,
                        propertyInfo.ArraySize);
                    break;

                case Core.PropertyInfoType.PropertyInfo:
                    Debug.LogError(
                        "Property type PropertyInfo is not supported. I don't think it even exists. Is the DataSet file well-formed?");
                    break;

                case Core.PropertyInfoType.WideVector3:
                    Debug.LogError("Property type WideVector3 is not supported. Is the DataSet file well-formed?");
                    break;
                }

                // If we're dealing with an enum, we need to cast to the enum type.
                if (field.PropertyInfo.Enum != null)
                {
                    if (field.PropertyInfo.Container == Core.ContainerType.StaticArray &&
                        field.PropertyInfo.ArraySize > 1)
                    {
                        var typeOfList = typeof(List <>).MakeGenericType(field.PropertyInfo.Enum);
                        var castedList = Activator.CreateInstance(typeOfList) as IList;
                        foreach (var item in (value as IList))
                        {
                            castedList.Add(item);
                        }

                        value = castedList;
                    }
                    else if (field.PropertyInfo.Container == Core.ContainerType.DynamicArray || field.PropertyInfo.Container == Core.ContainerType.List)
                    {
                        var typeOfList = typeof(List <>).MakeGenericType(field.PropertyInfo.Enum);
                        var castedList = Activator.CreateInstance(typeOfList) as IList;
                        foreach (var item in (value as IList))
                        {
                            castedList.Add(item);
                        }

                        value = castedList;
                    }
                    else if (field.PropertyInfo.Container == Core.ContainerType.StringMap)
                    {
                        var typeOfList       = typeof(Dictionary <,>).MakeGenericType(typeof(string), field.PropertyInfo.Enum);
                        var oldDictionary    = value as IDictionary;
                        var castedDictionary = Activator.CreateInstance(typeOfList) as IDictionary;

                        foreach (var item in oldDictionary.Keys)
                        {
                            castedDictionary.Add(item, oldDictionary[item]);
                        }

                        value = castedDictionary;
                    }
                }

                // FilePtr and Path properties are unique in that we don't actually get the value at this stage.
                if (field.PropertyInfo.Type != Core.PropertyInfoType.FilePtr &&
                    field.PropertyInfo.Type != Core.PropertyInfoType.Path)
                {
                    field.Field.SetValue(this, value);
                }
            }
        }