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);
/// <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); } }
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)); }
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); } }
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)); }
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)); }