public static TEntity MakeTrackable <TEntity>(TEntity entity) where TEntity : class { var trackableInterceptor = new DirtyPropertiesTrackerInterceptor(); var options = new ProxyGenerationOptions(_generationHook); options.AddMixinInstance(new DirtyPropertiesTracker()); var proxy = (TEntity)_generator.CreateClassProxy <TEntity>( options, trackableInterceptor); if (entity == null) { return(proxy); } var result = EntityPatcher <TEntity> .Patch(entity, proxy); if (result.IsSuccess) { return(result.Value); } else { return(proxy); } }
public void EntityPatcher_ApplyChanges_EntityPatchWithAmbiguousTargetDoesNotThrow() { using (var differ = new EntityManagerDiffer(SrcEntityManager, Allocator.TempJob)) { var entityGuid0 = CreateEntityGuid(); var entity0 = SrcEntityManager.CreateEntity(); SrcEntityManager.AddComponentData(entity0, entityGuid0); var entityGuid1 = CreateEntityGuid(); var entity1 = SrcEntityManager.CreateEntity(); SrcEntityManager.AddComponentData(entity1, entityGuid1); PushChanges(differ, DstEntityManager); // Create a patch SrcEntityManager.AddComponentData(entity1, new EcsTestDataEntity { value1 = entity0 }); using (var changes = differ.GetChanges(EntityManagerDifferOptions.IncludeForwardChangeSet, Allocator.TempJob)) { var forward = changes.ForwardChangeSet; Assert.That(forward.EntityReferenceChanges.Length, Is.EqualTo(1)); // Create a new entity in the dst world with the same ID the patch target. var dstEntity0 = DstEntityManager.CreateEntity(); DstEntityManager.AddComponentData(dstEntity0, entityGuid1); Assert.DoesNotThrow(() => { EntityPatcher.ApplyChangeSet(DstEntityManager, forward); }); } } }
public void EntityPatcher_ApplyChanges_EntityPatchWithMissingValueDoesNotThrow() { using (var differ = new EntityManagerDiffer(SrcEntityManager, Allocator.TempJob)) { var entityGuid0 = CreateEntityGuid(); var entity0 = SrcEntityManager.CreateEntity(); SrcEntityManager.AddComponentData(entity0, entityGuid0); var entityGuid1 = CreateEntityGuid(); var entity1 = SrcEntityManager.CreateEntity(); SrcEntityManager.AddComponentData(entity1, entityGuid1); PushChanges(differ, DstEntityManager); // Create a component with an entity reference SrcEntityManager.AddComponentData(entity1, new EcsTestDataEntity { value1 = entity0 }); using (var changes = differ.GetChanges(EntityManagerDifferOptions.IncludeForwardChangeSet, Allocator.TempJob)) { var forward = changes.ForwardChangeSet; Assert.That(forward.EntityReferenceChanges.Length, Is.EqualTo(1)); // Destroy the entity the patch references SrcEntityManager.DestroyEntity(entity0); Assert.DoesNotThrow(() => { EntityPatcher.ApplyChangeSet(DstEntityManager, forward); }); } } }
public void CanSerializeAndDeserializeManagedComponents() { using (var differ = new EntityManagerDiffer(SrcWorld.EntityManager, Allocator.TempJob)) { var entityGuid = CreateEntityGuid(); var entity = SrcEntityManager.CreateEntity(); var srcManagedComponent = new EcsTestManagedDataEntity { value0 = "Hello", value2 = 42, nullField = new ClassWithClassFields { ClassWithString = new ClassWithString { String = "World" } } }; SrcEntityManager.AddComponentData(entity, entityGuid); SrcEntityManager.AddComponentData(entity, srcManagedComponent); SrcEntityManager.AddComponentData(entity, (EcsTestManagedComponent2)null); var options = EntityManagerDifferOptions.IncludeForwardChangeSet | EntityManagerDifferOptions.FastForwardShadowWorld; using (var changes = differ.GetChanges(options, Allocator.TempJob)) { var srcChange = new LiveLinkChangeSet { Changes = changes.ForwardChangeSet, SceneName = "Boing", UnloadAllPreviousEntities = true, SceneGUID = new Unity.Entities.Hash128(), FramesToRetainBlobAssets = 1 }; var changeSet = SerializeAndDeserialize(srcChange); AssertChangeSetsAreEqual(srcChange, changeSet); EntityPatcher.ApplyChangeSet(DstEntityManager, changeSet.Changes); changeSet.Dispose(); } var dstManagedComponent = GetManagedComponentData <EcsTestManagedDataEntity>(DstEntityManager, entityGuid); Assert.That(dstManagedComponent, Is.Not.Null); Assert.That(dstManagedComponent, Is.Not.SameAs(srcManagedComponent)); Assert.That(dstManagedComponent.value0, Is.EqualTo(srcManagedComponent.value0)); Assert.That(dstManagedComponent.value1, Is.EqualTo(srcManagedComponent.value1)); Assert.That(dstManagedComponent.value2, Is.EqualTo(srcManagedComponent.value2)); Assert.That(dstManagedComponent.nullField, Is.Not.SameAs(srcManagedComponent.nullField)); Assert.That(dstManagedComponent.nullField.ClassWithString, Is.Not.SameAs(srcManagedComponent.nullField.ClassWithString)); Assert.That(dstManagedComponent.nullField.ClassWithString.String, Is.EqualTo(srcManagedComponent.nullField.ClassWithString.String)); Assert.That(GetManagedComponentData <EcsTestManagedComponent2>(DstEntityManager, entityGuid), Is.Null); } }
public void ApplyPatch(LiveLinkChangeSet changeSet) { var dstEntities = _DstWorld.EntityManager; var sceneSystem = _DstWorld.GetExistingSystem<SceneSystem>(); Entity sectionEntity; var sceneEntity = sceneSystem.GetSceneEntity(changeSet.SceneGUID); //@TODO: Check if the scene or section is requested to be loaded if (sceneEntity == Entity.Null) { Debug.LogWarning($"'{changeSet.SceneName}' ({{changeSet.sceneGUID}}) was ignored in live link since it is not loaded."); return; } // Unload scene if (changeSet.UnloadAllPreviousEntities) { //@Todo: Can we try to keep scene & section entities alive? (In case user put custom data on it) sceneSystem.UnloadScene(sceneEntity, SceneSystem.UnloadParameters.DestroySectionProxyEntities | SceneSystem.UnloadParameters.DontRemoveRequestSceneLoaded); // Create section sectionEntity = dstEntities.CreateEntity(); dstEntities.AddComponentData(sectionEntity, new SceneSectionStreamingSystem.StreamingState { Status = SceneSectionStreamingSystem.StreamingStatus.Loaded}); dstEntities.AddComponentData(sectionEntity, new DisableSceneResolveAndLoad( )); // Configure scene dstEntities.AddComponentData(sceneEntity, new DisableSceneResolveAndLoad( )); dstEntities.AddComponentData(sceneEntity, new LiveLinkedSceneState { Scene = changeSet.SceneGUID }); dstEntities.AddBuffer<ResolvedSectionEntity>(sceneEntity).Add(new ResolvedSectionEntity { SectionEntity = sectionEntity} ); #if UNITY_EDITOR dstEntities.SetName(sectionEntity, "SceneSection (LiveLink): " + changeSet.SceneName); dstEntities.SetName(sceneEntity, "Scene (LiveLink): " + changeSet.SceneName); #endif } else { sectionEntity = dstEntities.GetBuffer<ResolvedSectionEntity>(sceneEntity)[0].SectionEntity; } // SceneTag.SceneEntity == Entity.Null is reserved for new entities added via live link. if (_AddedScenesQuery.CalculateChunkCount() != 0) { Debug.LogWarning("SceneTag.SceneEntity must not reference Entity.Null. Destroying Entities."); dstEntities.DestroyEntity(_AddedScenesQuery); } EntityPatcher.ApplyChangeSet(_DstWorld.EntityManager, changeSet.Changes); //liveLink.ConvertedShadowWorld.EntityManager.Debug.CheckInternalConsistency(); dstEntities.SetSharedComponentData(_AddedScenesQuery, new SceneTag { SceneEntity = sectionEntity }); EditorUpdateUtility.EditModeQueuePlayerLoopUpdate(); }
/// <summary> /// Pushes forward changes from the tracker to the applier. /// </summary> protected static void PushChanges(EntityManagerDiffer differ, EntityManager target, bool fastForward = true) { var options = EntityManagerDifferOptions.IncludeForwardChangeSet; if (fastForward) { options |= EntityManagerDifferOptions.FastForwardShadowWorld; } using (var changes = differ.GetChanges(options, Allocator.TempJob)) { EntityPatcher.ApplyChangeSet(target, changes.ForwardChangeSet); } }
public void Validate() { var srcEm = SourceWorld.EntityManager; var dstEm = DestinationWorld.EntityManager; using (var changes = EntityDiffer.GetChanges(srcEm, dstEm, _differOptions, Query, _srcBlobAssets, Allocator.TempJob)) { EntityPatcher.ApplyChangeSet(dstEm, changes.ForwardChangeSet); } using (var changes = EntityDiffer.GetChanges(dstEm, srcEm, _differOptions, Query, _dstBlobAssets, Allocator.TempJob)) { if (!changes.ForwardChangeSet.HasChanges) { return; } // TODO: Format the entity changeset nicely and print it out throw new Exception("Diff is not zero!"); } }
public void PatchWithObjectReferenceResolving() { var material = AssetDatabase.LoadAssetAtPath <Material>("Packages/com.unity.entities/Unity.Scenes.Hybrid.Tests/Test.mat"); using (var differ = new EntityManagerDiffer(SrcWorld.EntityManager, Allocator.TempJob)) { var entityGuid = CreateEntityGuid(); var entity = SrcEntityManager.CreateEntity(); SrcEntityManager.AddComponentData(entity, entityGuid); SrcEntityManager.AddSharedComponentData(entity, new ComponentWithObjectRef { Material = material }); SrcEntityManager.AddComponentData(entity, new EcsTestData(5)); var options = EntityManagerDifferOptions.IncludeForwardChangeSet | EntityManagerDifferOptions.FastForwardShadowWorld; using (var changes = differ.GetChanges(options, Allocator.TempJob)) { var srcChange = new LiveLinkChangeSet { Changes = changes.ForwardChangeSet, SceneName = "Boing", UnloadAllPreviousEntities = true, SceneGUID = new Unity.Entities.Hash128(), FramesToRetainBlobAssets = 1 }; var changeSet = SerializeAndDeserialize(srcChange); AssertChangeSetsAreEqual(srcChange, changeSet); EntityPatcher.ApplyChangeSet(DstEntityManager, changeSet.Changes); changeSet.Dispose(); } var dstMaterial = GetSharedComponentData <ComponentWithObjectRef>(DstEntityManager, entityGuid).Material; Assert.AreEqual(material, dstMaterial); Assert.AreEqual(5, GetComponentData <EcsTestData>(DstEntityManager, entityGuid).value); } }
public async Task <ResponseContext <T> > UpdateAsync(T entity, params Expression <Func <T, bool> >[] keySelectors) { try { if (entity == null) { return(ResponseContext.Fail <T>(string.Format(ExceptionMessages.ArgumentException_ProvideValue, ResourceName), ErrorType.Argument)); } return((await this.Async(async r => (await ValidateUpdateEntity(entity)) .Then(() => OnUpdateSecurityClearance())) .ThenAsync(() => GetByIdBasicAsync(keySelectors)) .ThenAsync(result => EntityPatcher <T> .PatchAsync(entity, result.Value)) .ThenAsync(result => OnBeforeUpdate(result.Value)) .ThenAsync(result => OnUpdateAsync(result.Value)) .ThenAsync(result => IncludeInUpdateTransaction(result.Value)) .ThenIfAsync(CommitInmediately, async result => { Result <int> commitResult; if (_wrapUpdateInTrasaction) { commitResult = await AggregateParams.UOW.CommitWithinTransactionAsync(); } else { commitResult = await AggregateParams.UOW.CommitAsync(); } return commitResult.Ensure(r => r.Value > 0, ErrorType.CommitFailure, string.Format(ExceptionMessages.Exception_UpdateEntityError, ResourceName)) .Return(() => result); }) .ThenAsync(result => AfterUpdate(result))) .ToResponseContext() .withRecordCount(1) .ThenIf(AggregateParams.Context.IsHATEOASRequest, response => UpdateHATEOAS(response))); } catch (Exception e) { throw new Exception(string.Format(ExceptionMessages.Exception_UpdateEntityError, ResourceName), e); } }
public void UndoRedoPrefabInstancesWithRelationship() { const int instanceCount = 10; var srcPrefabRootGuid = CreateEntityGuid(); var srcPrefabLevel0Guid = CreateEntityGuid(); var prefabLevel1Guid = CreateEntityGuid(); const EntityManagerDifferOptions options = EntityManagerDifferOptions.IncludeForwardChangeSet | EntityManagerDifferOptions.FastForwardShadowWorld; using (var differ = new EntityManagerDiffer(SrcEntityManager, Allocator.TempJob)) { // Create Root Prefab entity with a Guid component var srcPrefabRoot = SrcEntityManager.CreateEntity(typeof(HierarchyComponent), typeof(Prefab), typeof(LinkedEntityGroup)); SrcEntityManager.AddComponentData(srcPrefabRoot, srcPrefabRootGuid); SrcEntityManager.GetBuffer <LinkedEntityGroup>(srcPrefabRoot).Add(srcPrefabRoot); PushChanges(differ, DstEntityManager); using (var changes = differ.GetChanges(options, Allocator.TempJob)) { EntityPatcher.ApplyChangeSet(DstEntityManager, changes.ForwardChangeSet); } // Instantiate root prefab in dst world 10 times var dstPrefabRoot = GetEntity(DstEntityManager, srcPrefabRootGuid); var dstInstanceRoots = new Entity[instanceCount]; for (var i = 0; i != dstInstanceRoots.Length; i++) { var dstInstanceRoot = DstEntityManager.Instantiate(dstPrefabRoot); dstInstanceRoots[i] = dstInstanceRoot; Assert.AreEqual(1, DstEntityManager.GetBuffer <LinkedEntityGroup>(dstInstanceRoot).Length); Assert.AreEqual(dstInstanceRoot, DstEntityManager.GetBuffer <LinkedEntityGroup>(dstInstanceRoot)[0].Value); } // Add level 0 entity to the prefab var srcLevel0Prefab = SrcEntityManager.CreateEntity(typeof(HierarchyComponent), typeof(Prefab)); SrcEntityManager.AddComponentData(srcLevel0Prefab, srcPrefabLevel0Guid); SrcEntityManager.GetBuffer <LinkedEntityGroup>(srcPrefabRoot).Add(srcLevel0Prefab); SrcEntityManager.SetComponentData(srcPrefabRoot, new HierarchyComponent { Parent = Entity.Null, Child = srcLevel0Prefab }); SrcEntityManager.SetComponentData(srcLevel0Prefab, new HierarchyComponent { Parent = srcPrefabRoot, Child = Entity.Null }); // Synchronize worlds, we now should have 10 instances in the world along with a level0 for each // and hierarchy matching the relationships create PushChanges(differ, DstEntityManager); for (var i = 0; i != dstInstanceRoots.Length; i++) { var dstInstanceRoot = dstInstanceRoots[i]; var dstInstanceGroup = DstEntityManager.GetBuffer <LinkedEntityGroup>(dstInstanceRoot); var dstInstanceLevel0 = dstInstanceGroup[1].Value; Assert.AreEqual(2, dstInstanceGroup.Length); Assert.AreEqual(dstInstanceRoot, dstInstanceGroup[0].Value); Assert.AreEqual(dstInstanceLevel0, dstInstanceGroup[1].Value); var hierarchyLevel0 = DstEntityManager.GetComponentData <HierarchyComponent>(dstInstanceLevel0); var hierarchyRoot = DstEntityManager.GetComponentData <HierarchyComponent>(dstInstanceRoot); Assert.AreEqual(dstInstanceRoot, hierarchyLevel0.Parent); Assert.AreEqual(dstInstanceLevel0, hierarchyRoot.Child); } // Add level 1 entity to the prefab var srcLevel1Prefab = SrcEntityManager.CreateEntity(typeof(HierarchyComponent), typeof(Prefab)); SrcEntityManager.AddComponentData(srcLevel1Prefab, prefabLevel1Guid); SrcEntityManager.GetBuffer <LinkedEntityGroup>(srcPrefabRoot).Add(srcLevel1Prefab); SrcEntityManager.SetComponentData(srcLevel0Prefab, new HierarchyComponent { Parent = srcPrefabRoot, Child = srcLevel1Prefab }); SrcEntityManager.SetComponentData(srcLevel1Prefab, new HierarchyComponent { Parent = srcLevel0Prefab, Child = Entity.Null }); // Synchronize worlds, we now should have 10 instances of level 1 linked to their matching level 0 PushChanges(differ, DstEntityManager); for (var i = 0; i != dstInstanceRoots.Length; i++) { var dstRootInstance = dstInstanceRoots[i]; var dstInstanceGroup = DstEntityManager.GetBuffer <LinkedEntityGroup>(dstRootInstance); Assert.AreEqual(3, dstInstanceGroup.Length); Assert.AreEqual(dstRootInstance, dstInstanceGroup[0].Value); var dstInstanceLevel0 = dstInstanceGroup[1].Value; var dstInstanceLevel1 = dstInstanceGroup[2].Value; Assert.AreEqual(dstInstanceLevel0, DstEntityManager.GetComponentData <HierarchyComponent>(dstRootInstance).Child); Assert.AreEqual(dstRootInstance, DstEntityManager.GetComponentData <HierarchyComponent>(dstInstanceLevel0).Parent); Assert.AreEqual(dstInstanceLevel1, DstEntityManager.GetComponentData <HierarchyComponent>(dstInstanceLevel0).Child); Assert.AreEqual(dstInstanceLevel0, DstEntityManager.GetComponentData <HierarchyComponent>(dstInstanceLevel1).Parent); } // Remove level 1 entity from the prefab SrcEntityManager.GetBuffer <LinkedEntityGroup>(srcPrefabRoot).RemoveAt(2); SrcEntityManager.DestroyEntity(srcLevel1Prefab); // Fix the hierarchy of level 0 to remove the link to level 1 SrcEntityManager.SetComponentData(srcLevel0Prefab, new HierarchyComponent { Parent = srcPrefabRoot, Child = Entity.Null }); // Synchronize worlds, destination world should no longer have instances of level 1 PushChanges(differ, DstEntityManager); for (var i = 0; i != dstInstanceRoots.Length; i++) { var dstRootInstance = dstInstanceRoots[i]; var dstInstanceGroup = DstEntityManager.GetBuffer <LinkedEntityGroup>(dstRootInstance); Assert.AreEqual(2, dstInstanceGroup.Length); Assert.AreEqual(dstRootInstance, dstInstanceGroup[0].Value); var dstInstanceLevel1 = dstInstanceGroup[1].Value; Assert.AreEqual(dstInstanceLevel1, DstEntityManager.GetComponentData <HierarchyComponent>(dstRootInstance).Child); Assert.AreEqual(dstRootInstance, DstEntityManager.GetComponentData <HierarchyComponent>(dstInstanceLevel1).Parent); Assert.AreEqual(Entity.Null, DstEntityManager.GetComponentData <HierarchyComponent>(dstInstanceLevel1).Child); } // Add again level 1 as a Child of level 0 srcLevel1Prefab = SrcEntityManager.CreateEntity(typeof(HierarchyComponent), typeof(Prefab)); SrcEntityManager.AddComponentData(srcLevel1Prefab, prefabLevel1Guid); SrcEntityManager.GetBuffer <LinkedEntityGroup>(srcPrefabRoot).Add(srcLevel1Prefab); SrcEntityManager.SetComponentData(srcLevel0Prefab, new HierarchyComponent { Parent = srcPrefabRoot, Child = srcLevel1Prefab }); SrcEntityManager.SetComponentData(srcLevel1Prefab, new HierarchyComponent { Parent = srcLevel0Prefab, Child = Entity.Null }); PushChanges(differ, DstEntityManager); for (var i = 0; i != dstInstanceRoots.Length; i++) { var dstRootInstance = dstInstanceRoots[i]; var dstInstanceGroup = DstEntityManager.GetBuffer <LinkedEntityGroup>(dstRootInstance); Assert.AreEqual(3, dstInstanceGroup.Length); Assert.AreEqual(dstRootInstance, dstInstanceGroup[0].Value); var dstInstanceLevel0 = dstInstanceGroup[1].Value; var dstInstanceLevel1 = dstInstanceGroup[2].Value; Assert.AreEqual(dstInstanceLevel0, DstEntityManager.GetComponentData <HierarchyComponent>(dstRootInstance).Child); Assert.AreEqual(dstRootInstance, DstEntityManager.GetComponentData <HierarchyComponent>(dstInstanceLevel0).Parent); Assert.AreEqual(dstInstanceLevel1, DstEntityManager.GetComponentData <HierarchyComponent>(dstInstanceLevel0).Child); Assert.AreEqual(dstInstanceLevel0, DstEntityManager.GetComponentData <HierarchyComponent>(dstInstanceLevel1).Parent); } } }