Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
## [1.3.5] - 2024-10-04

### Changed

* Local optimization in EntityManager.CopyEntitiesFrom
* Updated Mathematics dependency to version 1.3.2
* Updated Burst dependency to version 1.8.18

### Fixed

* Fixed misleading documentation for Baker.IsActiveAndEnabled
* Improved build determinism by sorting inputs to build methods.
* Exception thrown under certain circumstances when a system was destroyed could break various DOTS editor windows.
  • Loading branch information
Unity Technologies committed Oct 4, 2024
1 parent 55ca11e commit 18e63ee
Show file tree
Hide file tree
Showing 25 changed files with 1,756 additions and 145 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ uid: changelog

# Changelog

## [1.3.5] - 2024-10-04

### Changed

* Local optimization in EntityManager.CopyEntitiesFrom
* Updated Mathematics dependency to version 1.3.2
* Updated Burst dependency to version 1.8.18

### Fixed

* Fixed misleading documentation for Baker.IsActiveAndEnabled
* Improved build determinism by sorting inputs to build methods.
* Exception thrown under certain circumstances when a system was destroyed could break various DOTS editor windows.


## [1.3.2] - 2024-09-06

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,10 @@ public void PopulateWorldProxy()
if (sys == null) // will happen in subset world
continue;

var handle = CreateSystemProxy(m_WorldProxy, sys.World, sys.World == m_LocalWorld);
var systemProxy = CreateSystemProxy(m_WorldProxy, sys.World, sys.World == m_LocalWorld);
m_WorldProxy.m_SystemData.Add(new ScheduledSystemData(sys, -1));

workQueue.Enqueue(new GroupSystemInQueue { group = (ComponentSystemGroup) sys, index = handle.SystemIndex });
workQueue.Enqueue(new GroupSystemInQueue { group = (ComponentSystemGroup) sys, index = systemProxy.SystemIndex });
}

// Iterate through groups, making sure that all group children end up in sequential order in resulting list
Expand All @@ -113,7 +113,6 @@ public void PopulateWorldProxy()
var work = workQueue.Dequeue();
var group = work.group;
var groupIndex = work.index;

var firstChildIndex = m_WorldProxy.m_AllSystems.Count;

ref var updateSystemList = ref group.m_MasterUpdateList;
Expand All @@ -123,38 +122,54 @@ public void PopulateWorldProxy()
{
var updateIndex = updateSystemList[i];

ComponentSystemBase sys = null;
ScheduledSystemData sd;
ComponentSystemBase system = null;
ScheduledSystemData scheduledSystemData;
World creationWorld;

if (updateIndex.IsManaged)
{
sys = group.ManagedSystems[updateIndex.Index];
sd = new ScheduledSystemData(sys, groupIndex);
system = group.ManagedSystems[updateIndex.Index];
if (system == null)
{
removedSystemCount++;
continue;
}

scheduledSystemData = new ScheduledSystemData(system, groupIndex);
}
else
{
var unmanagedSystem = group.UnmanagedSystems[updateIndex.Index];
creationWorld = FindCreationWorld(unmanagedSystem.m_WorldSeqNo);
if (creationWorld != m_LocalWorld)
if (unmanagedSystem == SystemHandle.Null)
{
removedSystemCount++;
continue;
}

sd = new ScheduledSystemData(unmanagedSystem, creationWorld, groupIndex);
creationWorld = FindCreationWorld(unmanagedSystem.m_WorldSeqNo);
unsafe
{
if (creationWorld != m_LocalWorld ||
creationWorld.Unmanaged.ResolveSystemState(unmanagedSystem) == null)
{
removedSystemCount++;
continue;
}
}

scheduledSystemData = new ScheduledSystemData(unmanagedSystem, creationWorld, groupIndex);
}

var handle = CreateSystemProxy(m_WorldProxy, updateIndex.IsManaged? sys?.World : m_LocalWorld, !updateIndex.IsManaged || sys?.World == m_LocalWorld);
var systemProxy = CreateSystemProxy(m_WorldProxy, updateIndex.IsManaged? system?.World : m_LocalWorld, !updateIndex.IsManaged || system?.World == m_LocalWorld);

if (sd.Recorder != null)
sd.Recorder.enabled = true;
if (scheduledSystemData.Recorder != null)
scheduledSystemData.Recorder.enabled = true;

m_WorldProxy.m_SystemData.Add(sd);
m_WorldProxy.m_SystemData.Add(scheduledSystemData);

if (sys is ComponentSystemGroup childGroup)
if (system is ComponentSystemGroup childGroup)
{
workQueue.Enqueue(new GroupSystemInQueue { group = childGroup, index = handle.SystemIndex });
workQueue.Enqueue(new GroupSystemInQueue { group = childGroup, index = systemProxy.SystemIndex });
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,17 @@ struct ScheduledSystemData
public Recorder Recorder;
public ComponentSystemBase Managed;

public ScheduledSystemData(ComponentSystemBase m, int parentIndex) // managed systems
public ScheduledSystemData(ComponentSystemBase system, int parentIndex) // managed systems
{
Managed = m;
WorldSystemHandle = m.SystemHandle;
if (system == null)
throw new ArgumentNullException(nameof(system));

Category = SystemUtils.GetSystemCategory(m);
Managed = system;
WorldSystemHandle = system.SystemHandle;

var systemType = m.GetType();
Category = SystemUtils.GetSystemCategory(system);

var systemType = system.GetType();
NicifiedDisplayName = ContentUtilities.NicifySystemTypeName(systemType);
TypeName = TypeUtility.GetTypeDisplayName(systemType);
FullName = systemType.FullName;
Expand All @@ -42,17 +45,30 @@ public ScheduledSystemData(ComponentSystemBase m, int parentIndex) // managed sy

UpdateAfterIndices = Array.Empty<int>();
UpdateBeforeIndices = Array.Empty<int>();
Recorder = Recorder.Get($"{m.World?.Name ?? "none"} {FullName}");
Recorder = Recorder.Get($"{system.World?.Name ?? "none"} {FullName}");
}

public unsafe ScheduledSystemData(SystemHandle u, World w, int parentIndex) // unmanaged systems
public unsafe ScheduledSystemData(SystemHandle system, World world, int parentIndex) // unmanaged systems
{
if (system == SystemHandle.Null)
throw new ArgumentNullException(nameof(system));
if (world == null || !world.IsCreated)
throw new ArgumentNullException(nameof(world));

var unmanagedWorld = world.Unmanaged;
if (!unmanagedWorld.IsCreated)
throw new InvalidOperationException("WorldUnmanaged is not created");

var systemState = unmanagedWorld.ResolveSystemStateChecked(system);
if (systemState == null)
throw new NullReferenceException("SystemState is null");

Managed = null;
WorldSystemHandle = u;
WorldSystemHandle = system;

Category = SystemCategory.Unmanaged;

var systemType = SystemBaseRegistry.GetStructType(w.Unmanaged.ResolveSystemState(u)->UnmanagedMetaIndex);
var systemType = SystemBaseRegistry.GetStructType(systemState->UnmanagedMetaIndex);
NicifiedDisplayName = ContentUtilities.NicifySystemTypeName(systemType);
TypeName = TypeUtility.GetTypeDisplayName(systemType);
FullName = systemType.FullName;
Expand All @@ -64,7 +80,7 @@ public unsafe ScheduledSystemData(SystemHandle u, World w, int parentIndex) // u

UpdateAfterIndices = Array.Empty<int>();
UpdateBeforeIndices = Array.Empty<int>();
Recorder = Recorder.Get($"{w.Name ?? "none"} {FullName}");
Recorder = Recorder.Get($"{world.Name ?? "none"} {FullName}");
}
}
}
8 changes: 4 additions & 4 deletions Unity.Entities.Hybrid/Baking/Baker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1051,9 +1051,9 @@ public bool IsActive(GameObject gameObject)
}

/// <summary>
/// Checks if the GameObject is active and enabled.
/// Checks if the GameObject is active the component active and enabled.
/// </summary>
/// <returns>Returns true if the GameObject is active and enabled.</returns>
/// <returns>Returns true if the GameObject is active the component active and enabled.</returns>
/// <remarks>This takes a dependency on the active and enable state</remarks>
public bool IsActiveAndEnabled()
{
Expand All @@ -1065,10 +1065,10 @@ public bool IsActiveAndEnabled()
}

/// <summary>
/// Checks if the GameObject is active and enabled for a given component.
/// Checks if the GameObject is active the component active and enabled.
/// </summary>
/// <param name="component">The Object to check.</param>
/// <returns>Returns true if the GameObject is active and enabled.</returns>
/// <returns>Returns true if the GameObject is active the component active and enabled.</returns>
/// <remarks>This takes a dependency on the active and enable state.</remarks>
public bool IsActiveAndEnabled(Component component)
{
Expand Down
50 changes: 50 additions & 0 deletions Unity.Entities.PerformanceTests/CopyFromPerformanceTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using NUnit.Framework;
using Unity.Collections;
using Unity.Entities.Tests;
using Unity.PerformanceTesting;
using Assert = Unity.Assertions.Assert;

namespace Unity.Entities.PerformanceTests
{
[Category("Performance")]
public class CopyFromPerformanceTests : EntityDifferTestFixture
{
[Test, Performance]
public void CopyEntitiesToOtherWorld([Values] bool collectDstEntities)
{
var srcEntities = CollectionHelper.CreateNativeArray<Entity>(5000, SrcWorld.UpdateAllocator.ToAllocator);
var dstEntities = CollectionHelper.CreateNativeArray<Entity>(srcEntities.Length, DstWorld.UpdateAllocator.ToAllocator);

var archetype = SrcEntityManager.CreateArchetype(ComponentType.ReadWrite<EcsTestData>());

for (int ei = 0, ec = srcEntities.Length; ei < ec; ei++)
{
srcEntities[ei] = SrcEntityManager.CreateEntity(archetype);
SrcEntityManager.CreateEntity(archetype, 99);
}

Measure.Method(() =>
{
if (collectDstEntities)
{
DstEntityManager.CopyEntitiesFrom(SrcEntityManager, srcEntities, dstEntities);
}
else
{
DstEntityManager.CopyEntitiesFrom(SrcEntityManager, srcEntities);
}
})
.CleanUp(() =>
{
Assert.AreEqual(srcEntities.Length * 100, SrcEntityManager.Debug.EntityCount);
Assert.AreEqual(srcEntities.Length, DstEntityManager.Debug.EntityCount);
DstEntityManager.DestroyEntity(DstEntityManager.UniversalQuery);
})
.MeasurementCount(10)
.IterationsPerMeasurement(1)
.WarmupCount(2)
.Run();
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 19 additions & 14 deletions Unity.Entities/EntityManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3777,24 +3777,26 @@ public void CopyEntitiesFrom(EntityManager srcEntityManager, NativeArray<Entity>
srcEntityManager.CopyEntitiesInternal(srcEntities, srcManagerInstances);
srcEntityManager.AddComponent(srcManagerInstances, ComponentType.ReadWrite<IsolateCopiedEntities>());

var instantiated = new EntityQueryBuilder(Allocator.Temp)
var queryBuilder = new EntityQueryBuilder(Allocator.Temp)
.WithAll<IsolateCopiedEntities>()
.WithOptions(EntityQueryOptions.IncludeDisabledEntities | EntityQueryOptions.IncludePrefab)
.Build(srcEntityManager);
.WithOptions(EntityQueryOptions.IncludeDisabledEntities | EntityQueryOptions.IncludePrefab);

var instantiatedInSrcWorld = queryBuilder.Build(srcEntityManager);
var instantiatedInDstWorld = queryBuilder.Build(this);

using (var entityRemapping = srcEntityManager.CreateEntityRemapArray(Allocator.TempJob))
{
MoveEntitiesFromInternalQuery(srcEntityManager, instantiated, entityRemapping);

EntityRemapUtility.GetTargets(out var output, entityRemapping);
RemoveComponent(output, ComponentType.ReadWrite<IsolateCopiedEntities>());
output.Dispose();
MoveEntitiesFromInternalQuery(srcEntityManager, instantiatedInSrcWorld, entityRemapping);

if (outputEntities.IsCreated)
{
for (int i = 0; i != outputEntities.Length; i++)
outputEntities[i] = entityRemapping[srcManagerInstances[i].Index].Target;
for (int ei = 0, ec = srcManagerInstances.Length; ei != ec; ei++)
{
outputEntities[ei] = entityRemapping[srcManagerInstances[ei].Index].Target;
}
}

RemoveComponent(instantiatedInDstWorld, ComponentType.ReadWrite<IsolateCopiedEntities>());
}
}
}
Expand Down Expand Up @@ -4159,17 +4161,20 @@ public int GetComponentOrderVersion<T>()
var ecs = access->EntityComponentStore;
return ecs->GetComponentTypeOrderVersion(TypeManager.GetTypeIndex<T>());
}

/// <summary>
/// Gets the version number of the specified component type.
/// </summary>
/// <remarks>This version number is incremented each time there is a structural change involving the specified
/// <remarks>
/// <para>
/// This version number is incremented each time there is a structural change involving the specified
/// type of component. Such changes include creating or destroying entities that have this component and adding
/// or removing the component type from an entity. Shared components are not covered by this version;
/// see <see cref="GetSharedComponentOrderVersion{T}(T)"/>.
/// or removing the component type from an entity. Shared components are not covered by this version.
/// <see cref="GetSharedComponentOrderVersion{T}(T)"/>.
///
/// Version numbers can overflow. To compare if one version is more recent than another, directly checking if
/// VersionB is greater than VersionA is not sufficient. Instead, use the helper function:
///
/// </para>
/// <code>
/// bool VersionBisNewer = ChangeVersionUtility.DidChange(VersionB, VersionA);
/// </code>
Expand Down
4 changes: 4 additions & 0 deletions Unity.Entities/EntityRemapUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,11 @@ public struct BufferEntityPatchInfo
/// <param name="hasEntityRefs">True if the type has any fields of type <see cref="Entity"/>, otherwise false.</param>
/// <param name="hasBlobRefs">True if the type has any fields of type <see cref="BlobAssetReferenceData"/>, otherwise false.</param>
/// <param name="hasWeakAssetRefs">True if the type has fields of type <see cref="UntypedWeakReferenceId"/>, otherwise false.</param>
/// <param name="hasUnityObjectRefs">True if the type has fields of type <see cref="UnityObjectRef{T}"/>, otherwise false.</param>
/// <param name="entityOffsets">The offsets of the fields of type <see cref="Entity"/>.</param>
/// <param name="blobOffsets">The offsets of the fields of type <see cref="BlobAssetReferenceData"/>.</param>
/// <param name="weakAssetRefOffsets">The offsets of the fields of type <see cref="UntypedWeakReferenceId"/>.</param>
/// <param name="unityObjectRefOffsets">The offsets of the fields of type <see cref="UnityObjectRef{T}"/>.</param>
/// <param name="cache">Cache to accelerate type inspection codepaths when calling this function multiple times.</param>
public static void CalculateFieldOffsetsUnmanaged(Type type,
out bool hasEntityRefs,
Expand Down Expand Up @@ -269,6 +271,7 @@ public struct EntityBlobRefResult
/// </summary>
/// <param name="hasEntityRef">Specifies if there are any <see cref="Entity"/> references.</param>
/// <param name="hasBlobRef">Specifies if there are any <see cref="BlobAssetReferenceData"/> references.</param>
/// <param name="hasUnityObjectRef">Specifies if there are any <see cref="UnityObjectRef{T}"/> references.</param>
public EntityBlobRefResult(HasRefResult hasEntityRef, HasRefResult hasBlobRef, HasRefResult hasUnityObjectRef)
{
this.HasEntityRef = hasEntityRef;
Expand All @@ -283,6 +286,7 @@ public EntityBlobRefResult(HasRefResult hasEntityRef, HasRefResult hasBlobRef, H
/// <param name="type">The type to inspect.</param>
/// <param name="hasEntityReferences">Specifies if the type has any <see cref="Entity"/> references.</param>
/// <param name="hasBlobReferences">Specifies if the type has any <see cref="BlobAssetReferenceData"/> references.</param>
/// <param name="hasUnityObjectReferences">Specifies if the type has any <see cref="UnityObjectRef{T}"/> references.</param>
/// <param name="cache">Map of type to <see cref="EntityBlobRefResult"/> used to accelerate the type recursion.</param>
/// <param name="maxDepth">The maximum depth for the recursion.</param>
public static void HasEntityReferencesManaged(Type type, out HasRefResult hasEntityReferences, out HasRefResult hasBlobReferences, out HasRefResult hasUnityObjectReferences, Dictionary<Type,EntityBlobRefResult> cache = null, int maxDepth = 128)
Expand Down
5 changes: 2 additions & 3 deletions Unity.Entities/Iterators/ArchetypeChunkArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -855,9 +855,8 @@ public readonly EnabledMask GetEnabledMask<T>(ref BufferTypeHandle<T> typeHandle
/// <summary>
/// Provides a <see cref="EnabledMask"/> to the component enabled bits in this chunk.
/// </summary>
/// <typeparam name="T">The component type</typeparam>
/// <param name="typeHandle">Type handle for the component type <typeparamref name="T"/>.</param>
/// <returns>An <see cref="EnabledMask"/> instance for component <typeparamref name="T"/> in this chunk.</returns>
/// <param name="typeHandle">Type handle for the dynamic component/>.</param>
/// <returns>An <see cref="EnabledMask"/> instance for component in this chunk.</returns>
public readonly EnabledMask GetEnabledMask(ref DynamicComponentTypeHandle typeHandle)
{
#if ENABLE_UNITY_COLLECTIONS_CHECKS
Expand Down
Loading

0 comments on commit 18e63ee

Please sign in to comment.