Example #1
0
        private void RegenerateUpdateChannels(List<AnimationBlender.Channel> channels)
        {
            var updateMemberInfos = new List<UpdateMemberInfo>();

            foreach (var channel in channels)
            {
                updateMemberInfos.Add(new UpdateMemberInfo { Name = channel.PropertyName, DataOffset = channel.Offset });
            }

            compiledUpdate = UpdateEngine.Compile(typeof(Entity), updateMemberInfos);
        }
Example #2
0
        /// <summary>
        /// Updates the specified <see cref="target"/> object with new data.
        /// </summary>
        /// <param name="target">The object to update.</param>
        /// <param name="compiledUpdate">The precompiled list of update operations, generated by <see cref="Compile"/>.</param>
        /// <param name="updateData">The data source for blittable struct.</param>
        /// <param name="updateObjects">The data source for objects and non-blittable struct</param>
        public static void Run(object target, CompiledUpdate compiledUpdate, IntPtr updateData, UpdateObjectData[] updateObjects)
        {
            var operations       = compiledUpdate.UpdateOperations;
            var temporaryObjects = compiledUpdate.TemporaryObjects;

            var stack = new Stack <UpdateStackEntry>();

            // Current object being processed
            object currentObj = target;
            object nextObject;

            // This object needs to be pinned since we will have a pointer to its memory
            // Note that the stack don't need to have each of its object pinned since we store entries as object + offset
            Interop.Pin(currentObj);

            // pinned test (this will need to be on a stack somehow)
            IntPtr currentPtr = UpdateEngineHelper.ObjectToPtr(currentObj);

            var operationCount = operations.Length;

            if (operationCount == 0)
            {
                return;
            }

            var operation = Interop.Pin(ref operations[0]);

            for (int index = 0; index < operationCount; index++)
            {
                // Adjust offset
                currentPtr += operation.AdjustOffset;

                switch (operation.Type)
                {
                case UpdateOperationType.EnterObjectProperty:
                {
                    nextObject = ((UpdatableProperty)operation.Member).GetObject(currentPtr);
                    if (nextObject == null && operation.SkipCountIfNull != -1)
                    {
                        index    += operation.SkipCountIfNull;
                        operation = Interop.AddPinned(operation, operation.SkipCountIfNull);
                        break;
                    }

                    // Compute offset and push to stack
                    stack.Push(new UpdateStackEntry(
                                   currentObj,
                                   (int)((byte *)currentPtr - (byte *)UpdateEngineHelper.ObjectToPtr(currentObj))
                                   ));

                    // Get object
                    currentObj = nextObject;
                    currentPtr = UpdateEngineHelper.ObjectToPtr(currentObj);

                    break;
                }

                case UpdateOperationType.EnterStructPropertyBase:
                {
                    // Compute offset and push to stack
                    stack.Push(new UpdateStackEntry(
                                   currentObj,
                                   (int)((byte *)currentPtr - (byte *)UpdateEngineHelper.ObjectToPtr(currentObj))
                                   ));

                    currentObj = temporaryObjects[operation.DataOffset];
                    currentPtr = ((UpdatablePropertyBase)operation.Member).GetStructAndUnbox(currentPtr, currentObj);

                    break;
                }

                case UpdateOperationType.EnterObjectField:
                {
                    nextObject = ((UpdatableField)operation.Member).GetObject(currentPtr);
                    if (nextObject == null && operation.SkipCountIfNull != -1)
                    {
                        index    += operation.SkipCountIfNull;
                        operation = Interop.AddPinned(operation, operation.SkipCountIfNull);
                        break;
                    }

                    // Compute offset and push to stack
                    stack.Push(new UpdateStackEntry(
                                   currentObj,
                                   (int)((byte *)currentPtr - (byte *)UpdateEngineHelper.ObjectToPtr(currentObj))
                                   ));

                    // Get object
                    currentObj = nextObject;
                    currentPtr = UpdateEngineHelper.ObjectToPtr(currentObj);
                    break;
                }

                case UpdateOperationType.EnterObjectCustom:
                {
                    nextObject = ((UpdatableCustomAccessor)operation.Member).GetObject(currentPtr);
                    if (nextObject == null && operation.SkipCountIfNull != -1)
                    {
                        index    += operation.SkipCountIfNull;
                        operation = Interop.AddPinned(operation, operation.SkipCountIfNull);
                        break;
                    }

                    // Compute offset and push to stack
                    stack.Push(new UpdateStackEntry(
                                   currentObj,
                                   (int)((byte *)currentPtr - (byte *)UpdateEngineHelper.ObjectToPtr(currentObj))
                                   ));

                    // Get object
                    currentObj = nextObject;
                    currentPtr = UpdateEngineHelper.ObjectToPtr(currentObj);
                    break;
                }

                case UpdateOperationType.LeaveAndCopyStructPropertyBase:
                {
                    // Save back struct pointer
                    var oldPtr = currentPtr;

                    // Restore currentObj and currentPtr from stack
                    var stackEntry = stack.Pop();
                    currentObj = stackEntry.Object;
                    currentPtr = UpdateEngineHelper.ObjectToPtr(currentObj) + stackEntry.Offset;

                    // Use setter to set back struct
                    ((UpdatablePropertyBase)operation.Member).SetBlittable(currentPtr, oldPtr);

                    break;
                }

                case UpdateOperationType.Leave:
                {
                    // Restore currentObj and currentPtr from stack
                    var stackEntry = stack.Pop();
                    currentObj = stackEntry.Object;
                    currentPtr = UpdateEngineHelper.ObjectToPtr(currentObj) + stackEntry.Offset;
                    break;
                }

                case UpdateOperationType.ConditionalSetObjectProperty:
                {
                    var updateObject = updateObjects[operation.DataOffset];
                    if (updateObject.Condition != 0)     // 0 is 0.0f in float
                    {
                        ((UpdatableProperty)operation.Member).SetObject(currentPtr, updateObject.Value);
                    }
                    break;
                }

                case UpdateOperationType.ConditionalSetBlittablePropertyBase:
                {
                    // TODO: This case can happen quite often (i.e. a float property) and require an extra indirection
                    // We could probably avoid it by having common types as non virtual methods (i.e. object, int, float, maybe even Vector3/4?)
                    var data = (int *)((byte *)updateData + operation.DataOffset);
                    if (*data++ != 0)     // 0 is 0.0f in float
                    {
                        ((UpdatablePropertyBase)operation.Member).SetBlittable(currentPtr, (IntPtr)data);
                    }
                    break;
                }

                case UpdateOperationType.ConditionalSetStructPropertyBase:
                {
                    // TODO: This case can happen quite often (i.e. a float property) and require an extra indirection
                    // We could probably avoid it by having common types as non virtual methods (i.e. object, int, float, maybe even Vector3/4?)
                    var updateObject = updateObjects[operation.DataOffset];
                    if (updateObject.Condition != 0)     // 0 is 0.0f in float
                    {
                        ((UpdatablePropertyBase)operation.Member).SetStruct(currentPtr, updateObject.Value);
                    }
                    break;
                }

                case UpdateOperationType.ConditionalSetObjectField:
                {
                    var updateObject = updateObjects[operation.DataOffset];
                    if (updateObject.Condition != 0)     // 0 is 0.0f in float
                    {
                        ((UpdatableField)operation.Member).SetObject(currentPtr, updateObject.Value);
                    }
                    break;
                }

                case UpdateOperationType.ConditionalSetBlittableField:
                {
                    var data = (int *)((byte *)updateData + operation.DataOffset);
                    if (*data++ != 0)     // 0 is 0.0f in float
                    {
                        ((UpdatableField)operation.Member).SetBlittable(currentPtr, (IntPtr)data);
                    }
                    break;
                }

                case UpdateOperationType.ConditionalSetBlittableField4:
                {
                    var data = (int *)((byte *)updateData + operation.DataOffset);
                    if (*data++ != 0)     // 0 is 0.0f in float
                    {
                        *(int *)currentPtr = *data;
                    }
                    break;
                }

                case UpdateOperationType.ConditionalSetBlittableField8:
                {
                    var data = (int *)((byte *)updateData + operation.DataOffset);
                    if (*data++ != 0)     // 0 is 0.0f in float
                    {
                        *(Blittable8 *)currentPtr = *(Blittable8 *)data;
                    }
                    break;
                }

                case UpdateOperationType.ConditionalSetBlittableField12:
                {
                    var data = (int *)((byte *)updateData + operation.DataOffset);
                    if (*data++ != 0)     // 0 is 0.0f in float
                    {
                        *(Blittable12 *)currentPtr = *(Blittable12 *)data;
                    }
                    break;
                }

                case UpdateOperationType.ConditionalSetBlittableField16:
                {
                    var data = (int *)((byte *)updateData + operation.DataOffset);
                    if (*data++ != 0)     // 0 is 0.0f in float
                    {
                        *(Blittable16 *)currentPtr = *(Blittable16 *)data;
                    }
                    break;
                }

                case UpdateOperationType.ConditionalSetStructField:
                {
                    // Use setter to set back struct
                    var updateObject = updateObjects[operation.DataOffset];
                    if (updateObject.Condition != 0)     // 0 is 0.0f in float
                    {
                        ((UpdatableField)operation.Member).SetStruct(currentPtr, updateObject.Value);
                    }
                    break;
                }

                case UpdateOperationType.ConditionalSetObjectCustom:
                {
                    var updateObject = updateObjects[operation.DataOffset];
                    if (updateObject.Condition != 0)     // 0 is 0.0f in float
                    {
                        ((UpdatableCustomAccessor)operation.Member).SetObject(currentPtr, updateObject.Value);
                    }
                    break;
                }

                default:
                    throw new ArgumentOutOfRangeException();
                }

                operation = Interop.IncrementPinned(operation);
            }
        }
Example #3
0
        /// <summary>
        /// Updates the specified <see cref="target"/> object with new data.
        /// </summary>
        /// <param name="target">The object to update.</param>
        /// <param name="compiledUpdate">The precompiled list of update operations, generated by <see cref="Compile"/>.</param>
        /// <param name="updateData">The data source for blittable struct.</param>
        /// <param name="updateObjects">The data source for objects and non-blittable struct</param>
        public static void Run(object target, CompiledUpdate compiledUpdate, IntPtr updateData, UpdateObjectData[] updateObjects)
        {
            var operations = compiledUpdate.UpdateOperations;
            var temporaryObjects = compiledUpdate.TemporaryObjects;

            var stack = new Stack<UpdateStackEntry>();

            // Current object being processed
            object currentObj = target;
            object nextObject;

            // This object needs to be pinned since we will have a pointer to its memory
            // Note that the stack don't need to have each of its object pinned since we store entries as object + offset
            Interop.Pin(currentObj);

            // pinned test (this will need to be on a stack somehow)
            IntPtr currentPtr = UpdateEngineHelper.ObjectToPtr(currentObj);

            var operationCount = operations.Length;
            if (operationCount == 0)
                return;

            var operation = Interop.Pin(ref operations[0]);
            for (int index = 0; index < operationCount; index++)
            {
                // Adjust offset
                currentPtr += operation.AdjustOffset;

                switch (operation.Type)
                {
                    case UpdateOperationType.EnterObjectProperty:
                    {
                        nextObject = ((UpdatableProperty)operation.Member).GetObject(currentPtr);
                        if (nextObject == null && operation.SkipCountIfNull != -1)
                        {
                            index += operation.SkipCountIfNull;
                            operation = Interop.AddPinned(operation, operation.SkipCountIfNull);
                            break;
                        }

                        // Compute offset and push to stack
                        stack.Push(new UpdateStackEntry(
                            currentObj,
                            (int) ((byte*) currentPtr - (byte*) UpdateEngineHelper.ObjectToPtr(currentObj))
                        ));

                        // Get object
                        currentObj = nextObject;
                        currentPtr = UpdateEngineHelper.ObjectToPtr(currentObj);

                        break;
                    }
                    case UpdateOperationType.EnterStructPropertyBase:
                    {
                        // Compute offset and push to stack
                        stack.Push(new UpdateStackEntry(
                            currentObj,
                            (int) ((byte*) currentPtr - (byte*) UpdateEngineHelper.ObjectToPtr(currentObj))
                        ));

                        currentObj = temporaryObjects[operation.DataOffset];
                        currentPtr = ((UpdatablePropertyBase)operation.Member).GetStructAndUnbox(currentPtr, currentObj);

                        break;
                    }
                    case UpdateOperationType.EnterObjectField:
                    {
                        nextObject = ((UpdatableField)operation.Member).GetObject(currentPtr);
                        if (nextObject == null && operation.SkipCountIfNull != -1)
                        {
                            index += operation.SkipCountIfNull;
                            operation = Interop.AddPinned(operation, operation.SkipCountIfNull);
                            break;
                        }

                        // Compute offset and push to stack
                        stack.Push(new UpdateStackEntry(
                            currentObj,
                            (int) ((byte*) currentPtr - (byte*) UpdateEngineHelper.ObjectToPtr(currentObj))
                        ));

                        // Get object
                        currentObj = nextObject;
                        currentPtr = UpdateEngineHelper.ObjectToPtr(currentObj);
                        break;
                    }
                    case UpdateOperationType.EnterObjectCustom:
                    {
                        nextObject = ((UpdatableCustomAccessor)operation.Member).GetObject(currentPtr);
                        if (nextObject == null && operation.SkipCountIfNull != -1)
                        {
                            index += operation.SkipCountIfNull;
                            operation = Interop.AddPinned(operation, operation.SkipCountIfNull);
                            break;
                        }

                        // Compute offset and push to stack
                        stack.Push(new UpdateStackEntry(
                            currentObj,
                            (int)((byte*)currentPtr - (byte*)UpdateEngineHelper.ObjectToPtr(currentObj))
                        ));

                        // Get object
                        currentObj = nextObject;
                        currentPtr = UpdateEngineHelper.ObjectToPtr(currentObj);
                        break;
                    }

                    case UpdateOperationType.LeaveAndCopyStructPropertyBase:
                    {
                        // Save back struct pointer
                        var oldPtr = currentPtr;

                        // Restore currentObj and currentPtr from stack
                        var stackEntry = stack.Pop();
                        currentObj = stackEntry.Object;
                        currentPtr = UpdateEngineHelper.ObjectToPtr(currentObj) + stackEntry.Offset;

                        // Use setter to set back struct
                        ((UpdatablePropertyBase)operation.Member).SetBlittable(currentPtr, oldPtr);

                        break;
                    }
                    case UpdateOperationType.Leave:
                    {
                        // Restore currentObj and currentPtr from stack
                        var stackEntry = stack.Pop();
                        currentObj = stackEntry.Object;
                        currentPtr = UpdateEngineHelper.ObjectToPtr(currentObj) + stackEntry.Offset;
                        break;
                    }
                    case UpdateOperationType.ConditionalSetObjectProperty:
                    {
                        var updateObject = updateObjects[operation.DataOffset];
                        if (updateObject.Condition != 0) // 0 is 0.0f in float
                            ((UpdatableProperty)operation.Member).SetObject(currentPtr, updateObject.Value);
                        break;
                    }
                    case UpdateOperationType.ConditionalSetBlittablePropertyBase:
                    {
                        // TODO: This case can happen quite often (i.e. a float property) and require an extra indirection
                        // We could probably avoid it by having common types as non virtual methods (i.e. object, int, float, maybe even Vector3/4?)
                        var data = (int*)((byte*)updateData + operation.DataOffset);
                        if (*data++ != 0) // 0 is 0.0f in float
                            ((UpdatablePropertyBase)operation.Member).SetBlittable(currentPtr, (IntPtr)data);
                        break;
                    }
                    case UpdateOperationType.ConditionalSetStructPropertyBase:
                    {
                        // TODO: This case can happen quite often (i.e. a float property) and require an extra indirection
                        // We could probably avoid it by having common types as non virtual methods (i.e. object, int, float, maybe even Vector3/4?)
                        var updateObject = updateObjects[operation.DataOffset];
                        if (updateObject.Condition != 0) // 0 is 0.0f in float
                            ((UpdatablePropertyBase)operation.Member).SetStruct(currentPtr, updateObject.Value);
                        break;
                    }
                    case UpdateOperationType.ConditionalSetObjectField:
                    {
                        var updateObject = updateObjects[operation.DataOffset];
                        if (updateObject.Condition != 0) // 0 is 0.0f in float
                            ((UpdatableField)operation.Member).SetObject(currentPtr, updateObject.Value);
                        break;
                    }
                    case UpdateOperationType.ConditionalSetBlittableField:
                    {
                        var data = (int*)((byte*)updateData + operation.DataOffset);
                        if (*data++ != 0) // 0 is 0.0f in float
                            ((UpdatableField)operation.Member).SetBlittable(currentPtr, (IntPtr)data);
                        break;
                    }
                    case UpdateOperationType.ConditionalSetBlittableField4:
                    {
                        var data = (int*)((byte*)updateData + operation.DataOffset);
                        if (*data++ != 0) // 0 is 0.0f in float
                        {
                            *(int*)currentPtr = *data;
                        }
                        break;
                    }
                    case UpdateOperationType.ConditionalSetBlittableField8:
                    {
                        var data = (int*)((byte*)updateData + operation.DataOffset);
                        if (*data++ != 0) // 0 is 0.0f in float
                        {
                            *(Blittable8*)currentPtr = *(Blittable8*)data;
                        }
                        break;
                    }
                    case UpdateOperationType.ConditionalSetBlittableField12:
                    {
                        var data = (int*)((byte*)updateData + operation.DataOffset);
                        if (*data++ != 0) // 0 is 0.0f in float
                        {
                            *(Blittable12*)currentPtr = *(Blittable12*)data;
                        }
                        break;
                    }
                    case UpdateOperationType.ConditionalSetBlittableField16:
                    {
                        var data = (int*)((byte*)updateData + operation.DataOffset);
                        if (*data++ != 0) // 0 is 0.0f in float
                        {
                            *(Blittable16*)currentPtr = *(Blittable16*)data;
                        }
                        break;
                    }
                    case UpdateOperationType.ConditionalSetStructField:
                    {
                        // Use setter to set back struct
                        var updateObject = updateObjects[operation.DataOffset];
                        if (updateObject.Condition != 0) // 0 is 0.0f in float
                            ((UpdatableField)operation.Member).SetStruct(currentPtr, updateObject.Value);
                        break;
                    }
                    case UpdateOperationType.ConditionalSetObjectCustom:
                    {
                        var updateObject = updateObjects[operation.DataOffset];
                        if (updateObject.Condition != 0) // 0 is 0.0f in float
                            ((UpdatableCustomAccessor)operation.Member).SetObject(currentPtr, updateObject.Value);
                        break;
                    }
                    default:
                        throw new ArgumentOutOfRangeException();
                }

                operation = Interop.IncrementPinned(operation);
            }
        }