Example #1
0
        public void TestIntProperty()
        {
            var test = new TestClass();

            var updateMemberInfo = new List<UpdateMemberInfo>
            {
                new UpdateMemberInfo("IntProperty", 0),
            };

            var blittableData = new TestData[] { 123 };
            var objectData = new UpdateObjectData[0];

            RunUpdateEngine(test, updateMemberInfo, blittableData, objectData);

            Assert.That(test.IntProperty, Is.EqualTo(123));
        }
 public abstract void Evaluate(CompressedTimeSpan newTime, IntPtr data, UpdateObjectData[] objects);
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);
            }
        }
Example #4
0
        public void TestCastQualifiedName()
        {
            var test = new TestClass()
            {
                ObjectField = new TestClass(),
                ObjectProperty = new TestClass(),
            };

            var updateMemberInfo = new List<UpdateMemberInfo>
            {
                new UpdateMemberInfo("ObjectField.(SiliconStudio.Xenko.Engine.Tests.TestClass,SiliconStudio.Xenko.Engine.Tests).IntField", 0),
                new UpdateMemberInfo("ObjectProperty.(SiliconStudio.Xenko.Engine.Tests.TestClass,SiliconStudio.Xenko.Engine.Tests).IntField", 8),
            };

            var blittableData = new TestData[] { 123, 456 };
            var objectData = new UpdateObjectData[0];

            RunUpdateEngine(test, updateMemberInfo, blittableData, objectData);

            Assert.That(((TestClass)test.ObjectField).IntField, Is.EqualTo(123));
            Assert.That(((TestClass)test.ObjectProperty).IntField, Is.EqualTo(456));
        }
Example #5
0
        private static unsafe void RunUpdateEngine(TestClass test, List<UpdateMemberInfo> updateMemberInfo, TestData[] blittableData, UpdateObjectData[] objectData)
        {
            var compiledUpdate = UpdateEngine.Compile(test.GetType(), updateMemberInfo);

            fixed (TestData* dataPtr = blittableData)
            {
                UpdateEngine.Run(test, compiledUpdate, (IntPtr)dataPtr, objectData);
            }
        }
Example #6
0
        public void TestBlittableStruct()
        {
            var test = new TestClass();

            var updateMemberInfo = new List<UpdateMemberInfo>
            {
                new UpdateMemberInfo("BlittableStructField.IntField", 0),
                new UpdateMemberInfo("BlittableStructField.IntProperty", 8),
                new UpdateMemberInfo("BlittableStructProperty.IntField", 0),
                new UpdateMemberInfo("BlittableStructProperty.IntProperty", 8),
            };

            var blittableData = new TestData[] { 123, 456 };
            var objectData = new UpdateObjectData[0];

            RunUpdateEngine(test, updateMemberInfo, blittableData, objectData);

            Assert.That(test.BlittableStructField.IntField, Is.EqualTo(123));
            Assert.That(test.BlittableStructField.IntProperty, Is.EqualTo(456));
            Assert.That(test.BlittableStructProperty.IntField, Is.EqualTo(123));
            Assert.That(test.BlittableStructProperty.IntProperty, Is.EqualTo(456));
        }
Example #7
0
        public void TestIntList()
        {
            var test = new TestClass();

            var updateMemberInfo = new List<UpdateMemberInfo>
            {
                new UpdateMemberInfo("IntList[0]", 0),
                new UpdateMemberInfo("IntList[2]", 0),
                new UpdateMemberInfo("IntList[3]", 8),
            };

            var blittableData = new TestData[] { 123, 456 };
            var objectData = new UpdateObjectData[0];

            RunUpdateEngine(test, updateMemberInfo, blittableData, objectData);

            Assert.That(test.IntList[0], Is.EqualTo(123));
            Assert.That(test.IntList[1], Is.EqualTo(0));
            Assert.That(test.IntList[2], Is.EqualTo(123));
            Assert.That(test.IntList[3], Is.EqualTo(456));
        }