diff --git a/package/Documentation~/TableOfContents.md b/package/Documentation~/TableOfContents.md new file mode 100755 index 000000000..6fae25dda --- /dev/null +++ b/package/Documentation~/TableOfContents.md @@ -0,0 +1,27 @@ + +* [Overview](index.md) +* Core ECS +** [Entities](ecs_entities.md) +*** [Worlds](world.md) +** [Components](ecs_components.md) +*** [General Purpose Components](component_data.md) +*** [Shared Components](shared_component_data.md) +*** [System State Components](system_state_components.md) +*** [Dynamic Buffer Components](dynamic_buffers.md) +** [System](ecs_systems.md) +*** [Component Systems](component_system.md) +*** [Job Component Systems](job_component_system.md) +*** [Entity Command Buffers](entity_command_buffer.md) +*** [System Update Order](system_update_order.md) +** [Accessing Entity Data](chunk_iteration.md) +*** [Using IJobProcessComponentData](entity_iteration_job.md) +*** [Using IJobChunk](chunk_iteration_job.md) +*** [Using ComponentSystem and ForEach](entity_iteration_foreach.md) +*** [Manual iteration](manual_iteration.md) +*** [Component Groups](component_group.md) +** [Versions and Generations](version_numbers.md) +** [Jobs in ECS](ecs_job_overview.md) +*** [ECS Job System extensions](ecs_job_extensions.md) +* Creating Gameplay +** [Transforms](transform_system.md) +** [Rendering](gp_rendering.md) diff --git a/package/Documentation~/chunk_iteration.md b/package/Documentation~/chunk_iteration.md new file mode 100755 index 000000000..b43e186ed --- /dev/null +++ b/package/Documentation~/chunk_iteration.md @@ -0,0 +1,22 @@ +--- +uid: ecs-iteration +--- +# Accessing entity data + +Iterating over your data is one of the most common tasks you will perform when implementing an ECS system. ECS systems typically process a set of entities, reading data from one or more components, performing a calculation, and then writing the result to another component. + +In general, the most efficient way to iterate over your entities and components is in a parallelizable Job that processes the components in order. This takes advantage of processing power from all available cores and data locality to avoid CPU cache misses. + +The ECS API provides a number of ways to accomplish iteration, each with its own performance implications and restrictions. You can iterate over ECS data in the following ways: + +* [IJobProcessComponentData](entity_iteration_job.md) — the simplest efficient way to process component data entity by entity. + +* [IJobProcessComponentDataWithEntity](entity_iteration_job.md#with-entity) — slightly more complex than IJobProcessComponentData, giving you access to the entity handle and array index of the entity you are processing. + +* [IJobChunk](chunk_iteration_job.md) — iterates over the eligible blocks of memory (called a *Chunk*) containing matching entities. Your Job Execute() function can iterate over the Elements inside each chunk using a for loop. You can use IJobChunk for more complex situations than supported by IJobProcessComponentData, while maintaining maximum efficiency. + +* [ComponentSystem](entity_iteration_foreach.md) — the ComponentSystem offers the Entities.ForEach delegate functions to help iterate over your entities. However, ForEach runs on the main thread, so typically, you should only use ComponentSystem implementations for tasks that must be carried out on the main thread anyway. + +* [Manual iteration](manual_iteration.md) — if the previous methods are insufficient, you can manually iterate over entities or chunks. For example, you can get a NativeArray containing entities or the chunks of the entities that you want to process and iterate over them using a Job, such as IJobParallelFor. + +The [ComponentGroup](component_group.md) class provides a way to construct a view of your data that contains only the specific data you need for a given algorithm or process. Many of the iteration methods in the list above use a ComponentGroup, either explicitly or internally. \ No newline at end of file diff --git a/package/Documentation~/chunk_iteration_job.md b/package/Documentation~/chunk_iteration_job.md new file mode 100755 index 000000000..08d7e4171 --- /dev/null +++ b/package/Documentation~/chunk_iteration_job.md @@ -0,0 +1,219 @@ +# Using IJobChunk + +You can implement IJobChunk inside a JobComponentSystem to iterate through your data by chunk. The JobComponentSystem calls your Execute() function once for each chunk that contains the entities that you want the system to process. You can then process the data inside each chunk, entity by entity. + +Iterating with IJobChunk requires more code setup than does IJobProcessComponentData, but is also more explicit and represents the most direct access to the data, as it is actually stored. + +Another benefit of using iterating by chunks is that you can check whether an optional component is present in each chunk (with Archetype.Has) and process all the entities in the chunk accordingly. + +The steps involved in implementing an IJobChunk Job include: + +1. Identify the entities that you want to process by creating a ComponentGroup. +2. Defining the Job struct, including fields for ArchetypeChunkComponentType objects to identifying the types of components the Job directly accesses, specifying whether the Job reads or writes to those components. +3. Instantiating the Job struct and scheduling the Job in the system OnUpdate() function. +4. In the Execute() function, getting the NativeArray instances for the components the Job reads or writes and, finally, iterating over the current chunk to perform the desired work. + +The [ECS samples repository](https://github.com/Unity-Technologies/EntityComponentSystemSamples) contains a simple example, HelloCube_03_IJobChunk, that uses IJobChunk. + +## Query for data with a ComponentGroup + +A ComponentGroup defines the set of component types that an archetype must contain for the system to process its associated chunks and entities. An archetype can have additional components as well, but it must have at least those defined by the ComponentGroup. You can also exclude archetypes that contain specific types of components. + +For simple queries, you can use the JobComponentSystem.GetComponentGroup() function, passing in the component types: + +``` c# +public class RotationSpeedSystem : JobComponentSystem +{ + private ComponentGroup m_Group; + protected override void OnCreateManager() + { + m_Group = GetComponentGroup(typeof(RotationQuaternion), ComponentType.ReadOnly()); + } + //… +} +```` + +For more complex situations, you can use an EntityArchetypeQuery. An EntityArchetypeQuery provides a flexible query mechanism to specify the component types: + +* `All` = All component types in this array must exist in the archetype +* `Any` = At least one of the component types in this array must exist in the archetype +* `None` = None of the component types in this array can exist in the archetype + +For example, the following query includes archetypes containing the RotationQuaternion and RotationSpeed components, but excludes any archetypes containing the Frozen component: + +``` c# +protected override void OnCreateManager() +{ + var query = new EntityArchetypeQuery + { + None = new ComponentType[]{ typeof(Frozen) }, + All = new ComponentType[]{ typeof(RotationQuaternion), ComponentType.ReadOnly() } +} + }; + m_Group = GetComponentGroup(query); +} +``` + +The query uses `ComponentType.ReadOnly` instead of the simpler `typeof` expression to designate that the system does not write to RotationSpeed. + +You can also combine multiple queries by passing an array of EntityArchetypeQuery objects rather than a single instance. Each query is combined using a logical OR operation. The following example selects an archetypes that contain a RotationQuaternion component or a RotationSpeed component (or both): + +``` c# +protected override void OnCreateManager() +{ + var query0 = new EntityArchetypeQuery + { + All = new ComponentType[] {typeof(RotationQuaternion)} + }; + + var query1 = new EntityArchetypeQuery + { + All = new ComponentType[] {typeof(RotationSpeed)} + }; + + m_Group = GetComponentGroup(new EntityArchetypeQuery[] {query0, query1}); +} +``` + +**Note:** Do not include completely optional components in the EntityArchetypeQuery. To handle optional components, use the `chunk.Has()` method inside `IJobChunk.Execute()` to determine whether the current ArchetypeChunk has the optional component or not. Since all entities within the same chunk have the same components, you only need to check whether an optional component exists once per chunk -- not once per entity. + +For efficiency and to avoid needless creation of garbage-collected reference types, you should create the ComponentGroups for a system in the system’s OnCreateManager() function and store the result in an instance variable. (In the above examples, the `m_Group` variable is used for this purpose.) + +### ## Define the IJobChunk struct + +The IJobChunk struct defines fields for the data the Job needs when it runs, as well as the Job’s Execute() method. + +In order to access the component arrays inside the chunks that the system passes to your Execute() method, you must create an ArchetypeChunkComponentType object for each type of component that the Job reads or writes. These objects allow you to get instances of the NativeArrays providing access to the components of an entity. Include all the components referenced in the Job’s ComponentGroup that the Execute method reads or writes. You can also provide ArchetypeChunkComponentType variables for optional component types that you do not include in the ComponentGroup. (You must check to make sure that the current chunk has an optional component before trying to access it.) + +For example, the HelloCube_03_IJobChunk example declares a Job struct that defines ArchetypeChunkComponentType variables for two components, RotationQuaternion and RotationSpeed: + +``` c# +[BurstCompile] +struct RotationSpeedJob : IJobChunk +{ + public float DeltaTime; + public ArchetypeChunkComponentType RotationType; + [ReadOnly] public ArchetypeChunkComponentType RotationSpeedType; + + public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) + { + //... + } +} +``` + +The system assigns values to these variables in the OnUpdate() function. The variables are used inside the Execute() method when the ECS framework runs the Job. + +The Job also uses the Unity delta time to animate the rotation of a 3D object. The example also passes this value to the Execute method using a struct field. + +### ## Writing the Execute method + +The signature of the IJobChunk Execute method is: + +``` c# + public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) +``` + +The `chunk` parameter is a handle to the block of memory containing the entities and components to be processed in this iteration of the Job. Since a chunk can only contain a single archetype, all the entities in a chunk have the same set of components. + +Use the `chunk` parameter to get the NativeArray instances for your components: + +``` c# +var chunkRotations = chunk.GetNativeArray(RotationType); +var chunkRotationSpeeds = chunk.GetNativeArray(RotationSpeedType); +``` + +These arrays are aligned such that an entity has the same index in all of them. You can then iterate through the component arrays with a normal for loop. Use `chunk.Count` to get the number of entities stored in the current chunk: + +``` c# +for (var i = 0; i < chunk.Count; i++) +{ + var rotation = chunkRotations[i]; + var rotationSpeed = chunkRotationSpeeds[i]; + + // Rotate something about its up vector at the speed given by RotationSpeed. + chunkRotations[i] = new RotationQuaternion + { + Value = math.mul(math.normalize(rotation.Value), + quaternion.AxisAngle(math.up(), rotationSpeed.RadiansPerSecond * DeltaTime)) + }; +} +``` + +If you the `Any` filter in your EntityArchetypeQuery or have completely optional components that don’t appear in the query at all, you can use the `ArchetypeChunk.Has` function to test whether the current chunk contains the one of those components before using it: + + if (chunk.Has(OptionalCompType)) + {//...} + +__Note:__ If you use a concurrent entity command buffer, pass the chunkIndex argument as the `jobIndex` parameter to the command buffer functions. + +## Skipping chunks with unchanged entities + +If you only need to update entities when a component value has changed, you can add that component type to the change filter of the ComponentGroup used to select the entities and chunks for the job. For example, if you have a system that reads two components and only needs to update a third when one of the first two has changed, you could use a ComponentGroup as follows: + +``` c# +ComponentGroup m_Group; +protected override void OnCreateManager() +{ + m_Group = GetComponentGroup(typeof(Output), + ComponentType.ReadOnly(), + ComponentType.ReadOnly()); + m_Group.SetFilterChanged(new ComponentType{ typeof(InputA), typeof(InputB)}); +} +``` + +The ComponentGroup change filter supports up to two components. If you want to check more or aren't using a ComponentGroup, you can make the check manually. To make this check, compare the chunk’s change version for the component to the system’s LastSystemVersion using the `ArchetypeChunk.DidChange()` function. If this function returns false, you can skip the current chunk altogether since none of the components of that type have changed since the last time the system ran. + +The LastSystemVersion from the system must be passed into the Job using a struct field: + + [BurstCompile] + struct UpdateJob : IJobChunk + { + public ArchetypeChunkComponentType InputAType; + public ArchetypeChunkComponentType InputBType; + [ReadOnly] public ArchetypeChunkComponentType OutputType; + public uint LastSystemVersion; + + public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) + { + var inputAChanged = chunk.DidChange(InputAType, LastSystemVersion); + var inputBChanged = chunk.DidChange(InputBType, LastSystemVersion); + if (!(inputAChanged || inputBChanged)) + return; + //... + } + +As with all the Job struct fields, you must assign its value before scheduling the Job: + +``` c# + var job = new UpdateJob() + { + LastSystemVersion = this.LastSystemVersion, + //… initialize other fields + } +``` + +Note that for efficiency, the change version applies to whole chunks not individual entities. If a chunk has been accessed by another Job which had the ability to write to that type of component, then the change version for that component is incremented and the `DidChange()` function returns true. + +## Instantiate and schedule the Job + +To run an IJobChunk Job, you must create an instance of your Job struct, setting the struct fields, and then schedule the Job. When you do this in the OnUpdate() function of a JobComponentSystem, the system schedules the Job to run every frame. + +``` c# +// OnUpdate runs on the main thread. +protected override JobHandle OnUpdate(JobHandle inputDependencies) +{ + var job = new RotationSpeedJob() + { + RotationType = GetArchetypeChunkComponentType(false), + RotationSpeedType = GetArchetypeChunkComponentType(true), + DeltaTime = Time.deltaTime + }; + + return job.Schedule(m_Group, inputDependencies); +} +``` + +When you call the GetArchetypeChunkComponentType function to set your component type variables, make sure that you set the isReadOnly to true for components that the Job reads, but doesn’t write. Setting these parameters correctly can have a significant impact on how efficiently the ECS framework can schedule your Jobs. These access mode settings must match their equivalents in both the struct definition, and the ComponentGroup. + +Do not cache the return value of GetArchetypeChunkComponentType in a system class variable. The function must be called every time the system runs and the updated value passed to the Job. diff --git a/package/Documentation~/component_data.md b/package/Documentation~/component_data.md new file mode 100755 index 000000000..430b2ad64 --- /dev/null +++ b/package/Documentation~/component_data.md @@ -0,0 +1,26 @@ +--- +uid: ecs-component-data +--- +# ComponentData + +ComponentData in Unity (also known as acomponentin standard ECS terms) is a struct that contains only the instance data for an [entity](entity.md). ComponentData cannot contain methods. To put this in terms of the old Unity system, this is somewhat similar to an old Component class, but one that **only contains variables**. + +Unity ECS provides an interface called `IComponentData` that you can implement in your code. + +## IComponentData + +Traditional Unity components (including `MonoBehaviour`) are [object-oriented](https://en.wikipedia.org/wiki/Object-oriented_programming) classes which contain data and methods for behavior. `IComponentData` is a pure ECS-style component, meaning that it defines no behavior, only data. `IComponentData` is a struct rather than a class, meaning that it is copied [by value instead of by reference](https://stackoverflow.com/questions/373419/whats-the-difference-between-passing-by-reference-vs-passing-by-value?answertab=votes#tab-top) by default. You will usually need to use the following pattern to modify data: + +```c# +var transform = group.transform[index]; // Read + +transform.heading = playerInput.move; // Modify +transform.position += deltaTime * playerInput.move * settings.playerMoveSpeed; + +group.transform[index] = transform; // Write +``` + +`IComponentData` structs may not contain references to managed objects. Since the all `ComponentData` lives in simple non-garbage-collected tracked [chunk memory](chunk_iteration.md). + +See file: _/Packages/com.unity.entities/Unity.Entities/IComponentData.cs_. + diff --git a/package/Documentation~/component_group.md b/package/Documentation~/component_group.md new file mode 100755 index 000000000..53bc3088c --- /dev/null +++ b/package/Documentation~/component_group.md @@ -0,0 +1,223 @@ +--- +uid: ecs-component-group +--- +# Querying for data using a ComponentGroup + +The first step to reading or writing data is finding that data. Data in the ECS framework is stored in components, which are grouped together in memory according to the archetype of the entity to which they belong. To define a view into your ECS data that contains only the specific data you need for a given algorithm or process, you can construct a ComponentGroup. + +After creating a ComponentGroup, you can + +* Run a Job to process the entities and components selected for the view +* Get a NativeArray containing all the selected entities +* Get NativeArrays of the selected components (by component type) + +The entity and component arrays returned by a ComponentGroup are guaranteed to be "parallel", that is, the same index value always applies to the same entity in any array. + +**Note:** that the `ComponentSystem.Entites.ForEach` delegates and IJobProcessComponentData create internal ComponentGroups based on the component types and attributes you specify for these APIs. + + + +## Defining a query + +A ComponentGroup query defines the set of component types that an archetype must contain in order for its chunks and entities to be included in the view. You can also exclude archetypes that contain specific types of components. + +For simple queries, you can create a ComponentGroup based on an array of component types. The following example defines a ComponentGroup that finds all entities with both RotationQuaternion and RotationSpeed components. + +``` c# +ComponentGroup m_Group = GetComponentGroup(typeof(RotationQuaternion), ComponentType.ReadOnly()); +```` + +The query uses `ComponentType.ReadOnly` instead of the simpler `typeof` expression to designate that the system does not write to RotationSpeed. Always specify read only when possible, since there are fewer constraints on read access to data, which can help the Job scheduler execute your Jobs more efficiently. + +### EntityArchetypeQuery + +For more complex queries, you can use an EntityArchetypeQuery to create the ComponentGroup. An EntityArchetypeQuery provides a flexible query mechanism to specify which archetypes to select based on the following sets of components: + +* `All` = All component types in this array must exist in the archetype +* `Any` = At least one of the component types in this array must exist in the archetype +* `None` = None of the component types in this array can exist in the archetype + +For example, the following query includes archetypes containing the RotationQuaternion and RotationSpeed components, but excludes any archetypes containing the Frozen component: + +``` c# +var query = new EntityArchetypeQuery +{ + None = new ComponentType[]{ typeof(Frozen) }, + All = new ComponentType[]{ typeof(RotationQuaternion), ComponentType.ReadOnly() } +} +ComponentGroup m_Group = GetComponentGroup(query); +``` + +**Note:** Do not include completely optional components in the EntityArchetypeQuery. To handle optional components, use the `ArchetypeChunk.Has()` method to determine whether a chunk contains the optional component or not. Since all entities within the same chunk have the same components, you only need to check whether an optional component exists once per chunk -- not once per entity. + +### Query options + +When you create an EntityArchetypeQuery, you can set its `Options` variable. The options allow for specialized queries (normally you do not need to set them): + +* Default — no options set; the query behaves normally. +* IncludePrefab — includes archetypes containing the special Prefab tag component. +* IncludeDisabled — includes archetypes containing the special Disabled tag component. +* FilterWriteGroup — considers the WriteGroup of any components in the query. + +When you set the FilterWriteGroup option, only entities with those components in a Write Group that are explicitly included in the query will be included in the view. Entities that have any additional components from the same WriteGroup are excluded. + +For example, suppose C2 and C3 are components in the same Write Group based on C1, and you created a query using the FilterWriteGroup option that requires C1 and C3: + +``` c# +public struct C1: IComponentData{} + +[WriteGroup(C1)] +public struct C2: IComponentData{} + +[WriteGroup(C1)] +public struct C3: IComponentData{} + +// ... In a system: +var query = new EntityArchetypeQuery{ + All = new ComponentType{typeof(C1), ComponentType.ReadOnly()}, + Options = EntityArchetypeQueryOptions.FilterWriteGroup +}; +var m_group = GetComponentGroup(query); +``` + +This query excludes any entities with both C2 and C3 because C2 is not explicitly included in the query. While you could design this into the query using `None`, doing it through a Write Group provides an important benefit: you don't need to alter the queries used by other systems (as long as these systems also use Write Groups). + +Write Groups are a mechanism that allow you to extend existing systems. For example, if C1 and C2 are defined in another system (perhaps part of a library that you don't control), you could put C3 into the same Write Group as C2 in order to change how C1 is updated. For any entities to which you add your C3 component, your system will update C1 and the original system will not. For other entities without C3, the original system will update C1 as before. + +See [Write Groups](ecs_write_groups.md) for more information. + +### Combining queries + +You can combine multiple queries by passing an array of EntityArchetypeQuery objects rather than a single instance. Each query is combined using a logical OR operation. The following example selects an archetypes that contain a RotationQuaternion component or a RotationSpeed component (or both): + +``` c# +var query0 = new EntityArchetypeQuery +{ + All = new ComponentType[] {typeof(RotationQuaternion)} +}; + +var query1 = new EntityArchetypeQuery +{ + All = new ComponentType[] {typeof(RotationSpeed)} +}; + +ComponentGroup m_Group = GetComponentGroup(new EntityArchetypeQuery[] {query0, query1}); + ``` + +## Creating a ComponentGroup + +Outside a system class, you can create a ComponentGroup with the `EntityManager.CreateComponentGroup()` function: + +``` c# +ComponentGroup m_Group = CreateComponentGroup(typeof(RotationQuaternion), ComponentType.ReadOnly()); +``` + +However, in a system class, you must use the `GetComponentGroup()` function: + +``` c# +public class RotationSpeedSystem : JobComponentSystem +{ + private ComponentGroup m_Group; + protected override void OnCreateManager() + { + m_Group = GetComponentGroup(typeof(RotationQuaternion), ComponentType.ReadOnly()); + } + //… +} +``` + +When you plan to reuse the same view, you should cache the ComponentGroup instance, if possible, instead of creating a new one for each use. For example, in a system, you can create the ComponentGroup in the system’s `OnCreateManager()` function and store the result in an instance variable. The `m_Group` variable in the above example is used for this purpose. + +## Defining filters + +In addition to defining which components must be included or excluded from the query, you can also filter the view. You can specify the following types of filters: + +* Shared component values —filter the set of entities based on specific values of a shared component. +* Change filter — Filter the set of entities based on whether the value of a specific component type has potentially changed + +### Shared component filters + +To use a shared component filter, first include the shared component in the ComponentGroup (along with other needed components), and then call the `SetFilter()` function, passing in a struct of the same ISharedComponent type that contains the values to select. All values must match. You can add up to two different shared components to the filter. + +You can change the filter at any time, but changing the filter does not change any existing arrays of entities or components that you received from the group `ToComponentDataArray()` or `ToEntityArray()` functions. You must recreate these arrays. + +The following example defines a shared component named SharedGrouping and a system that only processes entities that have the Group field set to 1. + +```cs +struct SharedGrouping : ISharedComponentData +{ + public int Group; +} + +class ImpulseSystem : ComponentSystem +{ + ComponentGroup m_Group; + + protected override void OnCreateManager(int capacity) + { + m_Group = GetComponentGroup(typeof(Position), typeof(Displacement), typeof(SharedGrouping)); + } + + protected override void OnUpdate() + { + // Only iterate over entities that have the SharedGrouping data set to 1 + m_Group.SetFilter(new SharedGrouping { Group = 1 }); + + var positions = m_Group.ToComponentDataArray(Allocator.Temp); + var displacememnts = m_Group.ToComponentDataArray(Allocator.Temp); + + for (int i = 0; i != positions.Length; i++) + positions[i].Value = positions[i].Value + displacememnts[i].Value; + } +} +``` + +### Change filters + +If you only need to update entities when a component value has changed, you can add that component to the ComponentGroup filter using the `SetFilterChanged()` function. For example, the following ComponentGroup only includes entities from chunks in which another system has already written to the Translation component: + +``` c# +protected override void OnCreateManager(int capacity) +{ + m_Group = GetComponentGroup(typeof(LocalToWorld), ComponentType.ReadOnly()); + m_Group.SetFilterChanged(typeof(Translation)); +} + +``` + +Note that for efficiency, the change filter applies to whole chunks not individual entities. The change filter also only checks whether a system has run that declared write access to the component, not whether it actually changed any data. In other words, if a chunk has been accessed by another Job which had the ability to write to that type of component, then the change filter includes all entities in that chunk. (This is another reason to always declare read only access to components that you do not need to modify.) + +## Executing the query + +A ComponentGroup executes its query when you use the ComponentGroup in a Job or you call one of the ComponentGroup methods that returns arrays of entities, components, or chunks in the view: + +* `ToEntityArray()` returns an array of the selected entities. +* `ToComponentDataArray` returns an array of the components of type T for the selected entities. +* `CreateArchetypeChunkArray()` returns all the chunks containing the selected entities. (Since a query operates on archetypes, shared component values, and change filters, which are all identical for all the entities in a chunk, the set of entities stored within the returned set of chunks is exactly the same as the set of entities returned by `ToEntityArray()`.) + + + +### In Jobs + +In a JobComponentSystem, pass the ComponentGroup object to the system's `Schedule()` method. In the following example, from the HelloCube_03_IJobChunk sample, the `m_Group` argument is the ComponentGroup object + +``` c# +// OnUpdate runs on the main thread. +protected override JobHandle OnUpdate(JobHandle inputDependencies) +{ + var rotationType = GetArchetypeChunkComponentType(false); + var rotationSpeedType = GetArchetypeChunkComponentType(true); + + var job = new RotationSpeedJob() + { + RotationType = rotationType, + RotationSpeedType = rotationSpeedType, + DeltaTime = Time.deltaTime + }; + + return job.Schedule(m_Group, inputDependencies); +} +``` + +A ComponentGroup uses Jobs internally to create the required arrays. When you pass the group to the `Schedule()` method, the ComponentGroup Jobs are scheduled along with the system's own Jobs and can take advantage of parallel processing. + diff --git a/package/Documentation~/component_system.md b/package/Documentation~/component_system.md new file mode 100755 index 000000000..3201680eb --- /dev/null +++ b/package/Documentation~/component_system.md @@ -0,0 +1,15 @@ +--- +uid: ecs-component-system +--- +# ComponentSystem + +A `ComponentSystem` in Unity (also known as a system in standard ECS terms) performs operations on [entities](entity.md). A `ComponentSystem` cannot contain instance data. To put this in terms of the old Unity system, this is somewhat similar to an old [Component](https://docs.unity3d.com/Manual/Components.html) class, but one that **only contains methods**. One `ComponentSystem` is responsible for updating all entities with a matching set of components (that is defined within a struct called a [ComponentGroup](component_group.md)). + +Unity ECS provides an abstract class called `ComponentSystem` that you can extend in your code. + +See file: _/Packages/com.unity.entities/Unity.Entities/ComponentSystem.cs_. + +See also: [System update order](system_update_order.md). + + + diff --git a/package/Documentation~/custom_job_types.md b/package/Documentation~/custom_job_types.md new file mode 100755 index 000000000..7d4f401ba --- /dev/null +++ b/package/Documentation~/custom_job_types.md @@ -0,0 +1,382 @@ +--- +uid: ecs-custom-job-types +--- +# Custom job types + +On the lowest level of the job system, jobs are scheduled by calling one of the `Schedule` functions in [JobsUtility](https://docs.unity3d.com/ScriptReference/Unity.Jobs.LowLevel.Unsafe.JobsUtility.html). The currently existing [job types](https://docs.unity3d.com/ScriptReference/Unity.Jobs.LowLevel.Unsafe.JobType.html) all use these functions, but it is also possible to create specialized job types using the same APIs. + +These APIs use unsafe code and have to be crafted carefully, since they can easily introduce unwanted race conditions. If you add your own job types, we strongly recommend to aim for full test coverage. + +As an example we have a custom job type `IJobParallelForBatch` (see file: _/Packages/com.unity.jobs/Unity.Jobs/IJobParallelForBatch.cs_). + +It works like __IJobParallelFor__, but instead of calling a single execute function per index it calls one execute function per batch being executed. This is useful if you need to do something on more than one item at a time, but still want to do it in parallel. A common scenario for this job type is if you need to create a temporary array and you want to avoid creating each item in the array one at a time. By using IJobParallelFor you can instead create one temporary array per batch. + +In the IJobParallelForBatch example, the entry point where the job is actually scheduled looks like this: + +```c# +unsafe static public JobHandle ScheduleBatch(this T jobData, int arrayLength, int minIndicesPerJobCount, JobHandle dependsOn = new JobHandle()) where T : struct, IJobParallelForBatch +{ + var scheduleParams = new JobsUtility.JobScheduleParameters(UnsafeUtility.AddressOf(ref jobData), ParallelForBatchJobStruct.Initialize(), dependsOn, ScheduleMode.Batched); + return JobsUtility.ScheduleParallelFor(ref scheduleParams, arrayLength, minIndicesPerJobCount); +} +``` + +The first line creates a struct containing the scheduling parameters. When creating it you need to set a pointer to the data which will be copied to the jobs. The reason this is a pointer is that the native code which uses it does not know about the type. +You also need to pass it a pointer to the __JobReflectionData__ created by calling: + +```c# +JobsUtility.CreateJobReflectionData(typeof(T), JobType.ParallelFor, (ExecuteJobFunction)Execute); +``` + +JobReflection stores information about the struct with the data for the job, such as which __NativeContainers__ it has and how they need to be patched when scheduling a job. It lives on the native side of the engine and the managed code only has access to it though pointers without any information about what the type is. When creating JobReflectionData you need to specify the type of the struct implementing the job, the __JobType__ and the method which will be called to execute the job. The JobReflectionData does not depend on the data in the struct you schedule, only its type, so it should only be created once for all jobs implementing the same interface. There are currently only two job types, __Single__ and __ParallelFor__. Single means the job will only get a single call, ParallelFor means there will be multiple calls to process it; where each call is restricted to a subset of the range of indices to process. Which job type you choose affects which schedule function you are allowed to call. + +The third parameter of __JobsUtility.JobScheduleParameters__ is the __JobHandle__ that the scheduled job should depend on. + +The final parameter is the schedule mode. There are two scheduling modes to choose from, __Run__ and __Batched__. Batched means one or more jobs will be scheduled to do the processing, while Run means the processing will be done on the main thread before Schedule returns. + +Once the schedule parameters are created we actually schedule the job. There are three ways to schedule jobs depending on their type: + +```c# +JobHandle Schedule(ref JobScheduleParameters parameters); +JobHandle ScheduleParallelFor(ref JobScheduleParameters parameters, int arrayLength, int innerLoopBatchCount); +JobHandle ScheduleParallelForTransform(ref JobScheduleParameters parameters, IntPtr transfromAccessArray); + +``` + +Schedule can only be used if the __ScheduleParameters__ are created with __JobType.Single__, the other two schedule functions require __JobType.ParallelFor__. +The __arrayLength__ and __innerLoopBatchCount__ parameter passed to __ScheduleParallelFor__ are used to determine how many indices the jobs should process and how many indices it should handle in the inner loop (see the section on [Execution and JobRanges](#execution-and-jobranges) for more information on the inner loop count). +__ScheduleParallelForTransform__ is similar to ScheduleParallelFor, but it also has access to a __TransformAccessArray__ that allows you to modify __Transform__ components on __GameObjects__. The number of indices and batch size is inferred from the TransformAccessArray. + +## Execution and JobRanges + +After scheduling the job, Unity will call the entry point you specified directly from the native side. It works in a similar way to how __Update__ is called on MonoBehaviours, but from inside a job instead. You only get one call per job and there is either one job, or one job per worker thread; in the case of ParallelFor. + +The signature used for Execute is + +```c# +public delegate void ExecuteJobFunction(ref T data, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex); +``` +For Single jobs, only the data is needed and you can just do your processing right away, but for ParallelFor jobs it requires some more work before you can start processing indices. We need to split up the indices into a number of sequential sub-sets that each job will process in parallel. This way we do not process the same thing twice and we are sure that everything gets covered. The memory layout will determine the order of indices. + +The JobRanges contain the batches and indices a ParallelFor job is supposed to process. The indices are split into batches based on the batch size, the batches are evenly distributed between the jobs doing the execution in such a way that each job can iterate over a continuous section of memory. The ParallelFor job should call: + +```c# +JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out begin, out end) +``` + +This continues until it returns `false`, and after calling it process all items with index between __begin__ and __end__. +The reason you get batches of items, rather than the full set of items the job should process, is that Unity will apply [work stealing](https://en.wikipedia.org/wiki/Work_stealing) if one job completes before the others. Work stealing in this context means that when one job is done it will look at the other jobs running and see if any of them still have a lot of work left. If it finds a job which is not complete it will steal some of the batches that it has not yet started; to dynamically redistribute the work. + +Before a ParallelFor job starts processing items it also needs to limit the write access to NativeContainers on the range of items which the job is processing. If it does not do this several jobs can potentially write to the same index which leads to race conditions. The NativeContainers that need to be limited is passed to the job and there is a function to patch them; so they cannot access items outside the correct range. The code to do it looks like this: + +```c# +#if ENABLE_UNITY_COLLECTIONS_CHECKS +JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), begin, end - begin); +#endif +``` + +# Custom NativeContainers + +When writing jobs, the data communication between jobs is one of the hardest parts to get right. Just using __NativeArray__ is very limiting. Using __NativeQueue__, __NativeHashMap__ and __NativeMultiHashMap__ and their __Concurrent__ versions solves most scenarios. + +For the remaining scenarios it is possible to write your own custom NativeContainers. +When writing custom containers for [thread synchronization](https://en.wikipedia.org/wiki/Synchronization_(computer_science)#Thread_or_process_synchronization) it is very important to write correct code. We strongly recommend full test coverage for any new containers you add. + +As a very simple example of this we will create a __NativeCounter__ that can be incremented in a ParallelFor job through __NativeCounter.Concurrent__ and read in a later job or on the main thread. + +Let's start with the basic container type: + +```c# +// Mark this struct as a NativeContainer, usually this would be a generic struct for containers, but a counter does not need to be generic +// TODO - why does a counter not need to be generic? - explain the argument for this reasoning please. +[StructLayout(LayoutKind.Sequential)] +[NativeContainer] +unsafe public struct NativeCounter +{ + // The actual pointer to the allocated count needs to have restrictions relaxed so jobs can be schedled with this container + [NativeDisableUnsafePtrRestriction] + int* m_Counter; + +#if ENABLE_UNITY_COLLECTIONS_CHECKS + AtomicSafetyHandle m_Safety; + // The dispose sentinel tracks memory leaks. It is a managed type so it is cleared to null when scheduling a job + // The job cannot dispose the container, and no one else can dispose it until the job has run, so it is ok to not pass it along + // This attribute is required, without it this NativeContainer cannot be passed to a job; since that would give the job access to a managed object + [NativeSetClassTypeToNullOnSchedule] + DisposeSentinel m_DisposeSentinel; +#endif + + // Keep track of where the memory for this was allocated + Allocator m_AllocatorLabel; + + public NativeCounter(Allocator label) + { + // This check is redundant since we always use an int that is blittable. + // It is here as an example of how to check for type correctness for generic types. +#if ENABLE_UNITY_COLLECTIONS_CHECKS + if (!UnsafeUtility.IsBlittable()) + throw new ArgumentException(string.Format("{0} used in NativeQueue<{0}> must be blittable", typeof(int))); +#endif + m_AllocatorLabel = label; + + // Allocate native memory for a single integer + m_Counter = (int*)UnsafeUtility.Malloc(UnsafeUtility.SizeOf(), 4, label); + + // Create a dispose sentinel to track memory leaks. This also creates the AtomicSafetyHandle +#if ENABLE_UNITY_COLLECTIONS_CHECKS + DisposeSentinel.Create(out m_Safety, out m_DisposeSentinel, 0); +#endif + // Initialize the count to 0 to avoid uninitialized data + Count = 0; + } + + public void Increment() + { + // Verify that the caller has write permission on this data. + // This is the race condition protection, without these checks the AtomicSafetyHandle is useless +#if ENABLE_UNITY_COLLECTIONS_CHECKS + AtomicSafetyHandle.CheckWriteAndThrow(m_Safety); +#endif + (*m_Counter)++; + } + + public int Count + { + get + { + // Verify that the caller has read permission on this data. + // This is the race condition protection, without these checks the AtomicSafetyHandle is useless +#if ENABLE_UNITY_COLLECTIONS_CHECKS + AtomicSafetyHandle.CheckReadAndThrow(m_Safety); +#endif + return *m_Counter; + } + set + { + // Verify that the caller has write permission on this data. This is the race condition protection, without these checks the AtomicSafetyHandle is useless +#if ENABLE_UNITY_COLLECTIONS_CHECKS + AtomicSafetyHandle.CheckWriteAndThrow(m_Safety); +#endif + *m_Counter = value; + } + } + + public bool IsCreated + { + get { return m_Counter != null; } + } + + public void Dispose() + { + // Let the dispose sentinel know that the data has been freed so it does not report any memory leaks +#if ENABLE_UNITY_COLLECTIONS_CHECKS + DisposeSentinel.Dispose(m_Safety, ref m_DisposeSentinel); +#endif + + UnsafeUtility.Free(m_Counter, m_AllocatorLabel); + m_Counter = null; + } +} +``` + +With this we have a simple NativeContainer where we can get, set, and increment the count. This container can be passed to a job, but it has the same restrictions as NativeArray, which means it cannot be passed to a ParallelFor job with write access. + +The next step is to make it usable in ParallelFor. In order to avoid race conditions we want to make sure no-one else is reading it while the ParallelFor is writing to it. To achieve this we create a separate inner struct called Concurrent that can handle multiple writers, but no readers. We make sure NativeCounter.Concurrent can be assigned to from within a normal NativeCounter, since it is not possible for it to live separately outside a NativeCounter. TODO - why is that? + +```c# +[NativeContainer] +// This attribute is what makes it possible to use NativeCounter.Concurrent in a ParallelFor job +[NativeContainerIsAtomicWriteOnly] +unsafe public struct Concurrent +{ + // Copy of the pointer from the full NativeCounter + [NativeDisableUnsafePtrRestriction] + int* m_Counter; + + // Copy of the AtomicSafetyHandle from the full NativeCounter. The dispose sentinel is not copied since this inner struct does not own the memory and is not responsible for freeing it. +#if ENABLE_UNITY_COLLECTIONS_CHECKS + AtomicSafetyHandle m_Safety; +#endif + + // This is what makes it possible to assign to NativeCounter.Concurrent from NativeCounter + public static implicit operator NativeCounter.Concurrent (NativeCounter cnt) + { + NativeCounter.Concurrent concurrent; +#if ENABLE_UNITY_COLLECTIONS_CHECKS + AtomicSafetyHandle.CheckWriteAndThrow(cnt.m_Safety); + concurrent.m_Safety = cnt.m_Safety; + AtomicSafetyHandle.UseSecondaryVersion(ref concurrent.m_Safety); +#endif + + concurrent.m_Counter = cnt.m_Counter; + return concurrent; + } + + public void Increment() + { + // Increment still needs to check for write permissions +#if ENABLE_UNITY_COLLECTIONS_CHECKS + AtomicSafetyHandle.CheckWriteAndThrow(m_Safety); +#endif + // The actual increment is implemented with an atomic, since it can be incremented by multiple threads at the same time + Interlocked.Increment(ref *m_Counter); + } +} +``` + +With this setup we can schedule ParallelFor with write access to a NativeCounter through the inner Concurrent struct, like this: + +```c# +struct CountZeros : IJobParallelFor +{ + [ReadOnly] + public NativeArray input; + public NativeCounter.Concurrent counter; + public void Execute(int i) + { + if (input[i] == 0) + { + counter.Increment(); + } + } +} +``` + +```c# +var counter = new NativeCounter(Allocator.Temp); +var jobData = new CountZeros(); +jobData.input = input; +jobData.counter = counter; +counter.Count = 0; + +var handle = jobData.Schedule(input.Length, 8); +handle.Complete(); + +Debug.Log("The array countains " + counter.Count + " zeros"); +counter.Dispose(); +``` + +## Better cache usage + +The NativeCounter from the previous section is a working implementation of a counter, but all jobs in the ParallelFor will access the same atomic to increment the value. This is not optimal as it means the same cache line is used by all threads. +The way this is generally solved in NativeContainers is to have a local cache per worker thread, which is stored on its own cache line. + +The __[NativeSetThreadIndex]__ attribute can inject a worker thread index, the index is guaranteed to be unique while accessing the NativeContainer from the ParallelFor jobs. + +In order to make such an optimization here we need to change a few things. The first thing we need to change is the data layout. For performance reasons we need one full cache line per worker thread, rather than a single int to avoid [false sharing](https://en.wikipedia.org/wiki/False_sharing). + +We start by adding a constant for the number of ints on a cache line. + +```c# +public const int IntsPerCacheLine = JobsUtility.CacheLineSize / sizeof(int); +``` + +Next we change the amount of memory allocated. + +```c# +// One full cache line (integers per cacheline * size of integer) for each potential worker index, JobsUtility.MaxJobThreadCount +m_Counter = (int*)UnsafeUtility.Malloc(UnsafeUtility.SizeOf()*IntsPerCacheLine*JobsUtility.MaxJobThreadCount, 4, label); +``` + +TODO: I'm not sure which example you are referring to when you say: main, non-concurrent, version below (is this an example you used on this page or what you would do if you were not using jobified code/ECS etc. It has potential for confusion.) + +When accessing the counter from the main, non-concurrent, version there can only be one writer so the increment function is fine with the new memory layout. +For `get` and `set` of the `count` we need to loop over all potential worker indices. + +```c# +public int Count +{ + get + { + // Verify that the caller has read permission on this data. + // This is the race condition protection, without these checks the AtomicSafetyHandle is useless +#if ENABLE_UNITY_COLLECTIONS_CHECKS + AtomicSafetyHandle.CheckReadAndThrow(m_Safety); +#endif + int count = 0; + for (int i = 0; i < JobsUtility.MaxJobThreadCount; ++i) + count += m_Counter[IntsPerCacheLine * i]; + return count; + } + set + { + // Verify that the caller has write permission on this data. + // This is the race condition protection, without these checks the AtomicSafetyHandle is useless +#if ENABLE_UNITY_COLLECTIONS_CHECKS + AtomicSafetyHandle.CheckWriteAndThrow(m_Safety); +#endif + // Clear all locally cached counts, + // set the first one to the required value + for (int i = 1; i < JobsUtility.MaxJobThreadCount; ++i) + m_Counter[IntsPerCacheLine * i] = 0; + *m_Counter = value; + } +} +``` + +The final change is the inner Concurrent struct that needs to get the worker index injected into it. Since each worker only runs one job at a time, there is no longer any need to use atomics when only accessing the local count. + +```c# +[NativeContainer] +[NativeContainerIsAtomicWriteOnly] +// Let the job system know that it should inject the current worker index into this container +unsafe public struct Concurrent +{ + [NativeDisableUnsafePtrRestriction] + int* m_Counter; + +#if ENABLE_UNITY_COLLECTIONS_CHECKS + AtomicSafetyHandle m_Safety; +#endif + + // The current worker thread index; it must use this exact name since it is injected + [NativeSetThreadIndex] + int m_ThreadIndex; + + public static implicit operator NativeCacheCounter.Concurrent (NativeCacheCounter cnt) + { + NativeCacheCounter.Concurrent concurrent; +#if ENABLE_UNITY_COLLECTIONS_CHECKS + AtomicSafetyHandle.CheckWriteAndThrow(cnt.m_Safety); + concurrent.m_Safety = cnt.m_Safety; + AtomicSafetyHandle.UseSecondaryVersion(ref concurrent.m_Safety); +#endif + + concurrent.m_Counter = cnt.m_Counter; + concurrent.m_ThreadIndex = 0; + return concurrent; + } + + public void Increment() + { +#if ENABLE_UNITY_COLLECTIONS_CHECKS + AtomicSafetyHandle.CheckWriteAndThrow(m_Safety); +#endif + // No need for atomics any more since we are just incrementing the local count + ++m_Counter[IntsPerCacheLine*m_ThreadIndex]; + } +} +``` + +Writing the NativeCounter this way significantly reduces the overhead of having multiple threads writing to it. It does, however, come at a price. The cost of getting the count on the main thread has increased significantly since it now needs to check all local caches and sum them up. If you are aware of this and make sure to cache the return values it is usually worth it, but you need to know the limitations of your data structures. So we strongly recommend documenting the performance characteristics. + +## Tests + +The NativeCounter is not complete, the only thing left is to add tests for it to make sure it is correct and that it does not break in the future. When writing tests you should try to cover as many unusual scenarios as possible. It is also a good idea to add some kind of stress test using jobs to detect race conditions, even if it is unlikely to find all of them. The NativeCounter API is very small so the number of tests required is not huge. + +* Both versions of the counter examples above are available at: _/Assets/NativeCounterDemo_. +* The tests for them can be found at: _/Assets/NativeCounterDemo/Editor/NativeCounterTests.cs_. + +## Available attributes + +The NativeCounter uses many attributes, but there are a few more available for other types of containers. Here is a list of the available attributes you can use on the NativeContainer struct. +* [NativeContainer](https://docs.unity3d.com/2018.1/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.NativeContainerAttribute.html) - marks a struct as a NativeContainer.Required for all native containers. +* [NativeContainerSupportsMinMaxWriteRestriction](https://docs.unity3d.com/2018.1/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.NativeContainerSupportsMinMaxWriteRestrictionAttribute.html) - signals that the NativeContainer can restrict its writable ranges to be between a min and max index. This is used when passing the container to an IJobParallelFor to make sure that the job does not write to indices it is not supposed to process. In order to use this the NativeContainer must have the members int __m_Length__, int __m_MinIndex__ and int __m_MaxIndex__ in that order with no other members between them. The container must also throw an exception for writes outside the min/max range. +* [NativeContainerIsAtomicWriteOnly](https://docs.unity3d.com/2018.1/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.NativeContainerIsAtomicWriteOnlyAttribute.html) - signals that the NativeContainer uses atomic writes and no reads. By adding this is is possible to pass the NativeContainer to an IJobParallelFor as writable without restrictions on which indices can be written to. +* [NativeContainerSupportsDeallocateOnJobCompletion](https://docs.unity3d.com/2018.1/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.NativeContainerSupportsDeallocateOnJobCompletionAttribute.html) - makes the NativeContainer usable with [DeallocateOnJobCompletion](https://docs.unity3d.com/2018.1/Documentation/ScriptReference/Unity.Collections.DeallocateOnJobCompletionAttribute.html). In order to use this the NativeContainer must have a single allocation in __m_Buffer__, an allocator label in __m_AllocatorLabel__ and a dispose sentinel in __m_DisposeSentinel__. +* [NativeSetThreadIndex](https://docs.unity3d.com/2018.1/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.NativeSetThreadIndexAttribute.html) - Patches an int with the thread index of the job. + +In addition to these attributes on the native container struct itself there are a few attributes which can be used on members of the native container. +* [NativeDisableUnsafePtrRestriction](https://docs.unity3d.com/2018.1/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.NativeDisableUnsafePtrRestrictionAttribute.html) - allows the NativeContainer to be passed to a job even though it contains a pointer, which is usually not allowed. +* [NativeSetClassTypeToNullOnSchedule](https://docs.unity3d.com/2018.1/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.NativeSetClassTypeToNullOnScheduleAttribute.html) - allows the NativeContainer to be passed to a job even though it contains a managed object. The managed object will be set to `null` on the copy passed to the job. + diff --git a/package/Documentation~/doo_design.md b/package/Documentation~/doo_design.md new file mode 100755 index 000000000..2279c17cf --- /dev/null +++ b/package/Documentation~/doo_design.md @@ -0,0 +1,7 @@ +--- +uid: ecs-data-oriented-design +--- +# Data-oriented design in Unity + +> Synopsis: Discuss how to design optimal data structures and algorithms to transform them. Provide case studies for different types of data commonly found in games: transform data, hierarchical skinned meshes, audio, strings, etc... + diff --git a/package/Documentation~/dynamic_buffers.md b/package/Documentation~/dynamic_buffers.md new file mode 100755 index 000000000..a9f9931e3 --- /dev/null +++ b/package/Documentation~/dynamic_buffers.md @@ -0,0 +1,94 @@ +--- +uid: ecs-dynamic-buffers +--- +# Dynamic Buffers + +A `DynamicBuffer` is a type of component data that allows a variable-sized, "stretchy" +buffer to be associated with an entity. It behaves as a component type that +carries an internal capacity of a certain number of elements, but can allocate +a heap memory block if the internal capacity is exhausted. + +Memory management is fully automatic when using this approach. Memory associated with +`DynamicBuffers` is managed by the `EntityManager` so that when a `DynamicBuffer` +component is removed, any associated heap memory is automatically freed as well. + +`DynamicBuffers` supersede fixed array support which has been removed. + +## Declaring Buffer Element Types + +To declare a `Buffer`, you declare it with the type of element that you will be +putting into the `Buffer`: + + // This describes the number of buffer elements that should be reserved + // in chunk data for each instance of a buffer. In this case, 8 integers + // will be reserved (32 bytes) along with the size of the buffer header + // (currently 16 bytes on 64-bit targets) + [InternalBufferCapacity(8)] + public struct MyBufferElement : IBufferElementData + { + // These implicit conversions are optional, but can help reduce typing. + public static implicit operator int(MyBufferElement e) { return e.Value; } + public static implicit operator MyBufferElement(int e) { return new MyBufferElement { Value = e }; } + + // Actual value each buffer element will store. + public int Value; + } + +While it seem strange to describe the element type and not the `Buffer` itself, +this design enables two key benefits in the ECS: + +1. It supports having more than one `DynamicBuffer` of type `float3`, or any + other common value type. You can add any number of `Buffers` that leverage the + same value types, as long as the elements are uniquely wrapped in a top-level + struct. + +2. We can include `Buffer` element types in `EntityArchetypes`, and it generally + will behave like having a component. + +## Adding Buffer Types To Entities + +To add a buffer to an entity, you can use the normal methods of adding a +component type onto an entity: + +### Using AddBuffer() + + entityManager.AddBuffer(entity); + +### Using an archetype + + Entity e = entityManager.CreateEntity(typeof(MyBufferElement)); + +## Accessing Buffers + +There are several ways to access `DynamicBuffers`, which parallel access methods +to regular component data. + +### Direct, main-thread only access + + DynamicBuffer buffer = entityManager.GetBuffer(entity); + +## Entity based access + +You can also look up `Buffers` on a per-entity basis from a JobComponentSystem: + + var lookup = GetBufferFromEntity(); + var buffer = lookup[myEntity]; + buffer.Append(17); + buffer.RemoveAt(0); + +## Reinterpreting Buffers (experimental) + +`Buffers` can be reinterpreted as a type of the same size. The intention is to +allow controlled type-punning and to get rid of the wrapper element types when +they get in the way. To reinterpret, simply call `Reinterpret`: + + var intBuffer = entityManager.GetBuffer().Reinterpret(); + +The reinterpreted `Buffer` carries with it the safety handle of the original +`Buffer`, and is safe to use. They use the same underlying `BufferHeader`, so +modifications to one reinterpreted `Buffer` will be immediately reflected in +others. + +Note that there are no type checks involved, so it is entirely possible to +alias a `uint` and `float` buffer. + diff --git a/package/Documentation~/ecs_anatomy.md b/package/Documentation~/ecs_anatomy.md new file mode 100755 index 000000000..51354ee67 --- /dev/null +++ b/package/Documentation~/ecs_anatomy.md @@ -0,0 +1,7 @@ +--- +uid: ecs-anatomy +--- +# Anatomy of an ECS scene + +> Synopsis: Essential elements of an ECS scene in the Unity Editor. Also cover how to load and unload ECS scenes (assuming there are differences from normal -- which is certainly true with Tiny). + diff --git a/package/Documentation~/ecs_building_projects.md b/package/Documentation~/ecs_building_projects.md new file mode 100755 index 000000000..9801a4388 --- /dev/null +++ b/package/Documentation~/ecs_building_projects.md @@ -0,0 +1,7 @@ +--- +uid: ecs-building +--- +# Building your project + +> Synopsis: Cover any unique aspects for building ECS projects, including any cross-platform details. + diff --git a/package/Documentation~/ecs_burst.md b/package/Documentation~/ecs_burst.md new file mode 100755 index 000000000..26495fee5 --- /dev/null +++ b/package/Documentation~/ecs_burst.md @@ -0,0 +1,7 @@ +--- +uid: ecs-burst +--- +# Using Burst + +> Synopsis: Cover how, when, and why to use the Burst compiler with ECS. Everything burst -elated within ECS should go here. + diff --git a/package/Documentation~/ecs_components.md b/package/Documentation~/ecs_components.md new file mode 100755 index 000000000..17f375569 --- /dev/null +++ b/package/Documentation~/ecs_components.md @@ -0,0 +1,37 @@ +--- +uid: ecs-components +--- +# Components + + + +Components are one of the three principle elements of an Entity Component System architecture. They represent the data of your game or program. [Entities](ecs_entities.md) are essentially identifiers that index your collections of components [Systems](ecs_systems.md) provide the behavior. + +Concretely, a component in ECS is a struct with one of the following "marker interfaces": + +* IComponentData +* ISharedComponentData +* ISystemStateComponentData +* ISharedSystemStateComponentData + +The EntityManager organizes unique combinations of components appearing on your entities into **Archetypes**. It stores the components of all entities with the same archetype together in blocks of memory called **Chunks**. The entities in a given Chunk all have the same component archetype. + +Shared components are a special kind of data component that you can use to subdivide entities based on the specific values in the shared component (in addition to their archetype). When you add a shared component to an entity, the EntityManager places all entities with the same shared data values into the same Chunk. Shared components allow your systems to process like entities together. For example, the shared component [Rendering.RenderMesh](link), which is part of the Hybrid.rendering package, defines several fields, including **mesh**, **material**, **receiveShadows**, etc. When rendering, it is most efficient to process all the 3D objects that all have the same value for those fields together. Because these properties are specified in a shared component the EntityManager places the matching entities together in memory so the rendering system can efficiently iterate over them. + +**Note:** Over using shared components can lead to poor Chunk utilization since it involves a combinatorial expansion of the number of memory Chunks required based on archetype and every unique value of each shared component field. Avoid adding unnecessary fields to a shared component Use the [Entity Debugger](ecs_debugging.md) to view the current Chunk utilization. + +If you add or remove a component from an entity, or change the value of a SharedComponent, The EntityManager moves the entity to a different Chunk, creating a new Chunk if necessary. + +System state components behave like normal components or shared components with the exception that when you destroy entities, the EntityManager does not remove any system state components and does not recycle the entity ID until they are removed. This difference in behavior allows a system to cleanup its internal state or free resources when an entity is destroyed. + diff --git a/package/Documentation~/ecs_core.md b/package/Documentation~/ecs_core.md new file mode 100755 index 000000000..7b93fc542 --- /dev/null +++ b/package/Documentation~/ecs_core.md @@ -0,0 +1,117 @@ +--- +uid: ecs-concepts +--- +# ECS concepts + +If you are familiar with [Entity-component-system](https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system) (ECS) concepts, you might see the potential for naming conflicts with Unity's existing __GameObject__/__Component__ setup. + +The purpose of this page is: +1. Clarify and disambiguate the concepts as used in the ECS. +2. Provide a brief introduction to each concept as an entry point to a new user. + +### EntityManager +Manages memory and structural changes. + +### ComponentData +Parallel streams of concrete, [blittable](https://docs.microsoft.com/en-us/dotnet/framework/interop/blittable-and-non-blittable-types) data. + +e.g. + +| Position | HitPoints | +| ---------- | -----------| +| 64,30 | 69 | +| 58,55 | 70 | +| 95,81 | 81 | + +See: [General purpose components](component_data.md) + + +### Entity +An ID which can be used for indirect component lookups for the purposes of graph traversal. + +e.g. + +| Entity | Position | HitPoints | +|--- | ---------- | -----------| +|0 | 64,30 | 69 | +|1 | 58,55 | 70 | +|2 | 95,81 | 81 | + +See: [Entities](ecs_entities.md) + +### SharedComponentData +Type of ComponentData where each unique value is only stored once. ComponentData streams are divided into subsets by each value of all SharedComponentData. + +e.g. (Mesh SharedComponentData) + +__Mesh = RocketShip__ + +| Position | HitPoints | +| ---------- | -----------| +| 64,30 | 69 | +| 58,55 | 70 | +| 95,81 | 81 | + +__Mesh = Bullet__ + +| Position | HitPoints | +| ---------- | -----------| +| 10,50 | 19 | +| 36,24 | 38 | +| 67,33 | 40 | + +See: [Shared components](shared_component_data.md) + +### Dynamic Buffers + +This is a type of component data that allows a variable-sized, "stretchy" +buffer to be associated with an entity. Behaves as a component type that +carries an internal capacity of a certain number of elements, but can allocate +a heap memory block if the internal capacity is exhausted. + +See: [Dynamic Buffers](dynamic_buffers.md) + +### EntityArchetype +Specific set of ComponentData types and SharedComponentData values which define the subsets of ComponentData streams stored in the EntityManager. + +e.g. In the above, there are two EntityArchetypes: +1. Position, HitPoints, Mesh = RocketShip +2. Position, HitPoints, Mesh = Bullet + +See: [EntityArchetype in detail](../api/Unity.Entities.EntityArchetype.html) + +### ComponentSystem +Where gameplay/system logic/behavior occurs. + +See: [ComponentSystem in detail](ecs_in_detail.md#componentsystem) + +### World +A unique EntityManager with specific instances of defined ComponentSystems. Multiple Worlds may exist and work on independent data sets. + +See: [World in detail](ecs_in_detail.md#world) + +### SystemStateComponentData +A specific type of ComponentData which is not serialized or removed by default when an entity ID is deleted. Used for internal state and resource management inside a system. Allows you to manage construction and destruction of resources. + +See: [SystemStateComponentData in detail](ecs_in_detail.md#systemstatecomponentdata) + +### JobComponentSystem +A type of ComponentSystem where jobs are queued independently of the JobComponentSystem's update, in the background. Those jobs are guaranteed to be completed in the same order as the systems. + +See: [JobComponentSystem in detail](ecs_in_detail.md#jobcomponentsystem) + +### EntityCommandBuffer +A list of structural changes to the data in an EntityManager for later completion. Structural changes are: +1. Adding Component +2. Removing Component +3. Changing SharedComponent value + +See: [EntityCommandBuffer in detail](ecs_in_detail.md#entitycommandbuffer) + +### EntityCommandBufferSystem +A type of ComponentSystem, which provides an EntityCommandBuffer. i.e. A specific (synchronization) point in the frame where that EntityCommandBuffer will be resolved. + + + + + diff --git a/package/Documentation~/ecs_data_structures.md b/package/Documentation~/ecs_data_structures.md new file mode 100755 index 000000000..a02c4c839 --- /dev/null +++ b/package/Documentation~/ecs_data_structures.md @@ -0,0 +1,8 @@ +--- +uid: ecs-data-structures +--- +# Data structures + +> Synopsis: About the Native data structures in the core module and in the extension module in detail (that isn't already covered in the script reference). +> How to create your own native data structures. + diff --git a/package/Documentation~/ecs_debugging.md b/package/Documentation~/ecs_debugging.md new file mode 100755 index 000000000..4f91cb4b1 --- /dev/null +++ b/package/Documentation~/ecs_debugging.md @@ -0,0 +1,56 @@ +--- +uid: ecs-debugging +--- +# Debugging ECS + +> Synopsis: All about debugging ECS +> Outline: +> Entity Debugger +> Inspecting an Entity +> Live-link + + +## Entity Debugger + +The Entity Debugger allows you to visualize your entities, systems, and components + +Open the entity Debugger window using the menu: Window > Analysis > Entity Debugger. + + +### Systems list + +The Systems list shows the systems in your project and how much time a system takes to run each frame. You can turn systems on and off from the list using the checkbox provided for each system. + +Use the System Display control drop down at the top of the list to control what to display in the System list. The System Display control contains: + +* Worlds — Choose the World containing the entities and ComponentSystems to display. By default, an **Editor World** exists when not in play mode and a **Default World** exists in play mode. +* **Show Full Player Loop** option — Choose to display the systems of all Worlds and show all of the Unity execution phases (not just those containing systems). +* **Show Inactive Systems** option — Choose to show systems that are not currently running in addition to the running systems. + +Select a system to view its details. + +**Note:** If you select the EntityManager entry in the System list, then you have different options on the System details section. + + +### System details + +The System details section shows the groups of components that a System operates on and the list of entities associated with those component groups. + + Each component group shows the components in the group along with the number of entities associated with it. Select a component group to view information about the Chunks containing the data for the components in the group. + + When you select the EntityManager entry in the system list, the details section shows all of the entities in the displayed World. When you display a World (rather than the full player loop), you can also filter the list of entities by component + + To filter the Entity list: + 1. Select a World in the System Display control. + 2. Select the EntityManager for that World. + 3. At the top of the System details section, click **Edit**. + 4. In the **Choose Component** window, check the components whose entities you want to view. + + +### Chunk information + +The Chunk information section shows the Chunks containing data for the components and entities selected in the details section. + +## Inspecting an Entity + +Select an entity in the Entity Debugger to view its data in the Unity Inspector window. diff --git a/package/Documentation~/ecs_entities.md b/package/Documentation~/ecs_entities.md new file mode 100755 index 000000000..95cb94b94 --- /dev/null +++ b/package/Documentation~/ecs_entities.md @@ -0,0 +1,66 @@ +--- +uid: ecs-entities +--- +# Entities + + +Entities are one of the three principle elements of an Entity Component System architecture. They represent the individual "things" in you game or program. An entity has neither behavior nor data; instead, it identifies which pieces of data belong together. [Systems](ecs_systems.md) provide the behavior. [Components](ecs_components.md) store the data. + +An entity is essentially an ID. You can think of it as a super lightweight [GameObject](https://docs.unity3d.com/Manual/class-GameObject.html) that does not even have a name by default. entity ID's are stable. They are the only stable way to store a reference to another component or entity. + +An [EntityManager](../api/Unity.Entities.EntityManager.html) manages all of the entities in a [World](../api/Unity.Entities.World.html). An EntityManager maintains the list of entities and organizes the data associated with an entity for optimal performance. + +Although an entity does not have a type, groups of entities can be categorized by the types of the data components associated with them. As you create entities and add components to them, the EntityManager keeps track of the unique combinations of components on the existing entities. Such a unique combination is called an _Archetype_. The EntityManager creates an [EntityArchetype](../api/Unity.Entities.EntityArchetype.html) struct as you add components to an entity. You can use existing EntityArchetypes to create new entities conforming to that archetype. You can also create an EntityArchetype in advance and use that to create entities. + +## Creating Entities + +The easiest way to create an entity is in the Unity Editor. You can set up both GameObjects placed in a scene and Prefabs to be converted into entities at runtime. For more dynamic parts of your game or program, you can create spawning systems that create multiple entities in a job. Finally, you can create entities one at a time using one of the [EntityManager.CreateEntity](../api/Unity.Entities.EntityManager.html#Unity_Entities_EntityManager_CreateEntity) functions. + + + +### Creating Entities with an EntityManager + +Use one of the [EntityManager.CreateEntity](../api/Unity.Entities.EntityManager.html#Unity_Entities_EntityManager_CreateEntity) functions to create an entity. The entity is created in the same World as the EntityManager. + +You can create entities one-by-one in the following ways: + +* Create an entity with components using an array of [ComponentType](../api/Unity.Entities.ComponentType.html) objects. +* Create an entity with components using an [EntityArchetype](../api/Unity.Entities.EntityArchetype.html). +* Copy an existing entity, including its current data, with [Instantiate](../api/Unity.Entities.EntityManager.html#Unity_Entities_EntityManager_Instantiate_Unity_Entities_Entity_) +* Create an entity with no components and then add components to it. (You can add components immediately or as additional components are needed.) + +You can create multiple entities at a time also: + +* Fill a NativeArray with new entities with the same archetype using [CreateEntity](../api/Unity.Entities.EntityManager.html#Unity_Entities_EntityManager_CreateEntity_Unity_Entities_EntityArchetype_NativeArray_Unity_Entities_Entity__). +* Fill a NativeArray with copies of an existing entity, including its current data, using [Instantiate](../api/Unity.Entities.EntityManager.html#Unity_Entities_EntityManager_Instantiate_Unity_Entities_Entity_NativeArray_Unity_Entities_Entity__). +* Explicitly create Chunks populated with a specified number of entities with a given archetype with [CreateChunk](../api/Unity.Entities.EntityManager.html#Unity_Entities_EntityManager_CreateChunk_Unity_Entities_EntityArchetype_NativeArray_Unity_Entities_ArchetypeChunk__System_Int32_). + +## Adding and Removing Components + +After an entity has been created, you can add or remove components When you do this, the archetype of the affected entities change and the EntityManager must move altered data to a new Chunk of memory, as well as condense the component arrays in the original Chunks. + +Changes to an entity that cause structural changes — that is, adding or removing components changing the values of SharedComponentData, and destroying the entity — cannot be done inside a Job since these could invalidate the data that the Job is working on. Instead, you add the commands to make these types of changes to an [EntityCommandBuffer](../api/Unity.Entities.EntityCommandBuffer.html) and execute this command buffer after the Job is complete. + + +The EntityManager provides functions for removing a component from a single entity as well as all of the entities in a NativeArray. See [Components](ecs_components.md) for more information. + +## Iterating entities + +Iterating over all entities that have a matching set of components, is at the center of the ECS architecture. See [Accessing entity Data](chunk_iteration.md). + + diff --git a/package/Documentation~/ecs_gameplay.md b/package/Documentation~/ecs_gameplay.md new file mode 100755 index 000000000..a34372001 --- /dev/null +++ b/package/Documentation~/ecs_gameplay.md @@ -0,0 +1,8 @@ +--- +uid: ecs-gameplay +--- +# Creating Gameplay with ECS + + + +Also when scheduling multiple jobs in a single system, dependencies must be passed to all jobs even though different jobs may need less dependencies. If that proves to be a performance issue the best solution is to split a system into two. + +The dependency management approach is conservative. It allows for deterministic and correct behaviour while providing a very simple API. + +## Sync points + +All structural changes have hard sync points. `CreateEntity`, `Instantiate`, `Destroy`, `AddComponent`, `RemoveComponent`, `SetSharedComponentData` all have a hard sync point. Meaning all jobs scheduled through `JobComponentSystem` will be completed before creating the entity, for example. This happens automatically. So for instance: calling `EntityManager.CreateEntity` in the middle of the frame might result in a large stall waiting for all previously scheduled jobs in the `World` to complete. + +See [EntityCommandBuffer](entity_command_buffer.md) for more on avoiding sync points when creating entities during game play. + +## Multiple Worlds + +Every `World` has its own `EntityManager` and thus a separate set of `JobHandle` dependency management. A hard sync point in one world will not affect the other `World`. As a result, for streaming and procedural generation scenarios, it is useful to create entities in one `World` and then move them to another `World` in one transaction at the beginning of the frame. + +See [ExclusiveEntityTransaction](exclusive_entity_transaction.md) for more on avoiding sync points for procedural generation & streaming scenarios and [System update order](system_update_order.md). + + + diff --git a/package/Documentation~/manual_iteration.md b/package/Documentation~/manual_iteration.md new file mode 100755 index 000000000..a2f06f5b3 --- /dev/null +++ b/package/Documentation~/manual_iteration.md @@ -0,0 +1,89 @@ +# Manual iteration + +You can also request all the chunks explicitly in a NativeArray and process them with a Job such as `IJobParallelFor`. This method is recommended if you need to manage chunks in some way that is not appropriate for the simplified model of simply iterating over all the Chunks in a ComponentGroup. As in: + +```c# +public class RotationSpeedSystem : JobComponentSystem +{ + [BurstCompile] + struct RotationSpeedJob : IJobParallelFor + { + [DeallocateOnJobCompletion] public NativeArray Chunks; + public ArchetypeChunkComponentType RotationType; + [ReadOnly] public ArchetypeChunkComponentType RotationSpeedType; + public float DeltaTime; + + public void Execute(int chunkIndex) + { + var chunk = Chunks[chunkIndex]; + var chunkRotation = chunk.GetNativeArray(RotationType); + var chunkSpeed = chunk.GetNativeArray(RotationSpeedType); + var __instanceCount __= chunk.Count; + + for (int i = 0; i < instanceCount; i++) + { + var rotation = chunkRotation[i]; + var speed = chunkSpeed[i]; + rotation.Value = math.mul(math.normalize(rotation.Value), quaternion.AxisAngle(math.up(), speed.RadiansPerSecond * DeltaTime)); + chunkRotation[i] = rotation; + } + } + } + + ComponentGroup m_group; + + protected override void OnCreateManager() + { + var query = new EntityArchetypeQuery + { + All = new ComponentType[]{ typeof(RotationQuaternion), ComponentType.ReadOnly() } + }; + + m_group = GetComponentGroup(query); + } + + protected override JobHandle OnUpdate(JobHandle inputDeps) + { + var rotationType = GetArchetypeChunkComponentType(); + var rotationSpeedType = GetArchetypeChunkComponentType(true); + var chunks = m_group.CreateArchetypeChunkArray(Allocator.__TempJob__); + + var rotationsSpeedJob = new RotationSpeedJob + { + Chunks = chunks, + RotationType = rotationType, + RotationSpeedType = rotationSpeedType, + DeltaTime = Time.deltaTime + }; + return rotationsSpeedJob.Schedule(chunks.Length,32,inputDeps); + } +} +``` + +## Iterating manually in a ComponentSystem + +Although not a generally recommended practice, you can use the EntityManager class to manually iterate through the entities or chunks. These iteration methods should only be used in test or debugging code (or when you are just experimenting) or in an isolated World in which you have a perfectly controlled set of entities. + +For example, the following snippet iterates through all of the entities in the active World: + +``` c# +var entityManager = World.Active.EntityManager; +var allEntities = entityManager.GetAllEntities(); +foreach (var entity in allEntities) +{ + //... +} +allEntities.Dispose(); +``` + + While this snippet iterates through all of the chunks in the active World: + +``` c# +var entityManager = World.Active.EntityManager; +var allChunks = entityManager.GetAllChunks(); +foreach (var chunk in allChunks) +{ + //... +} +allChunks.Dispose(); +``` diff --git a/package/Documentation~/shared_component_data.md b/package/Documentation~/shared_component_data.md new file mode 100755 index 000000000..d80a250cb --- /dev/null +++ b/package/Documentation~/shared_component_data.md @@ -0,0 +1,34 @@ +--- +uid: ecs-shared-component-data +--- +# Shared ComponentData + +`IComponentData` is appropriate for data that varies between entities, such as storing a `World` position. `ISharedComponentData` is useful when many entities have something in common, for example in the `Boid` demo we instantiate many entities from the same [Prefab](https://docs.unity3d.com/Manual/Prefabs.html) and thus the `RenderMesh` between many `Boid` entities is exactly the same. + +```cs +[System.Serializable] +public struct RenderMesh : ISharedComponentData +{ + public Mesh mesh; + public Material material; + + public ShadowCastingMode castShadows; + public bool receiveShadows; +} +``` + +The great thing about `ISharedComponentData` is that there is literally zero memory cost on a per entity basis. + +We use `ISharedComponentData` to group all entities using the same `InstanceRenderer` data together and then efficiently extract all matrices for rendering. The resulting code is simple & efficient because the data is laid out exactly as it is accessed. + +- `RenderMeshSystemV2` (see file: _Packages/com.unity.entities/Unity.Rendering.Hybrid/RenderMeshSystemV2.cs_) + +## Some important notes about SharedComponentData: + +- Entities with the same `SharedComponentData` are grouped together in the same [Chunks](chunk_iteration.md). The index to the `SharedComponentData` is stored once per `Chunk`, not per entity. As a result `SharedComponentData` have zero memory overhead on a per entity basis. +- Using `ComponentGroup` we can iterate over all entities with the same type. +- Additionally we can use `ComponentGroup.SetFilter()` to iterate specifically over entities that have a specific `SharedComponentData` value. Due to the data layout this iteration has low overhead. +- Using `EntityManager.GetAllUniqueSharedComponents` we can retrieve all unique `SharedComponentData` that is added to any alive entities. +- `SharedComponentData` are automatically [reference counted](https://en.wikipedia.org/wiki/Reference_counting). +- `SharedComponentData` should change rarely. Changing a `SharedComponentData` involves using [memcpy](https://msdn.microsoft.com/en-us/library/aa246468(v=vs.60).aspx) to copy all `ComponentData` for that entity into a different `Chunk`. + diff --git a/package/Documentation~/system_state_components.md b/package/Documentation~/system_state_components.md new file mode 100755 index 000000000..b61dbbc4c --- /dev/null +++ b/package/Documentation~/system_state_components.md @@ -0,0 +1,74 @@ +--- +uid: ecs-system-state-components +--- +# SystemStateComponents + +The purpose of `SystemStateComponentData` is to allow you to track resources internal to a system and have the opportunity to appropriately create and destroy those resources as needed without relying on individual callbacks. + +`SystemStateComponentData` and `SystemStateSharedComponentData` are exactly like `ComponentData` and `SharedComponentData`, respectively, except in one important respect: + +1. `SystemStateComponentData` is not deleted when an entity is destroyed. + +`DestroyEntity` is shorthand for + +1. Find all components which reference this particular entity ID. +2. Delete those components. +3. Recycle the entity id for reuse. + +However, if `SystemStateComponentData` is present, it is not removed. This gives a system the opportunity to cleanup any resources or state associated with an entity ID. The entity ID will only be reused once all `SystemStateComponentData` has been removed. + +## Motivation + +- Systems may need to keep an internal state based on `ComponentData`. For instance, resources may be allocated. +- Systems need to be able to manage that state as values and state changes are made by other systems. For example, when values in components change, or when relevant components are added or deleted. +- "No callbacks" is an important element of the ECS design rules. + +## Concept + +The general use of `SystemStateComponentData` is expected to mirror a user component, providing the internal state. + +For instance, given: +- FooComponent (`ComponentData`, user assigned) +- FooStateComponent (`SystemComponentData`, system assigned) + +### Detecting Component Add + +When user adds FooComponent, FooStateComponent does not exist. The FooSystem update queries for FooComponent without FooStateComponent and can infer that they have been added. At that point, the FooSystem will add the FooStateComponent and any needed internal state. + +### Detecting Component Remove + +When user removes FooComponent, FooStateComponent still exists. The FooSystem update queries for FooStateComponent without FooComponent and can infer that they have been removed. At that point, the FooSystem will remove the FooStateComponent and fix up any needed internal state. + +### Detecting Destroy Entity + +`DestroyEntity` is actually a shorthand utility for: + +- Find components which reference given entity ID. +- Delete components found. +- Recycle entity ID. + +However, `SystemStateComponentData` are not removed on `DestroyEntity` and the entity ID is not recycled until the last component is deleted. This gives the system the opportunity to clean up the internal state in the exact same way as with component removal. + +## SystemStateComponent + +A `SystemStateComponentData` is analogous to a `ComponentData` and used similarly. + +``` +struct FooStateComponent : ISystemStateComponentData +{ +} +``` + +Visibility of a `SystemStateComponentData` is also controlled in the same way as a component (using `private`, `public`, `internal`) However, it's expected, as a general rule, that a `SystemStateComponentData` will be `ReadOnly` outside the system that creates it. + +## SystemStateSharedComponent + +A `SystemStateSharedComponentData` is analogous to a `SharedComponentData` and used similarly. + +``` +struct FooStateSharedComponent : ISystemStateSharedComponentData +{ + public int Value; +} +``` + diff --git a/package/Documentation~/system_update_order.md b/package/Documentation~/system_update_order.md new file mode 100755 index 000000000..580d7b5cf --- /dev/null +++ b/package/Documentation~/system_update_order.md @@ -0,0 +1,94 @@ +# System Update Order + +Use Component System Groups to specify the update order of your systems. You can place a systems in a group using the [UpdateInGroup] attribute on the system’s class declaration. You can then use [UpdateBefore] and [UpdateAfter] attributes to specify the update order within the group. + +The ECS framework creates a set of [default system groups](#default-system-groups) that you can use to update your systems in the correct phase of a frame. You can nest one group inside another so that all systems in your group update in the correct phase and, then, also update according to the order within their group. + +## Component System Groups + +The ComponentSystemGroup class represents a list of related component systems that should be updated together in a specific order. ComponentSystemGroup is derived from ComponentSystemBase, so it acts like a component system in all the important ways -- it can be ordered relative to other systems, has an OnUpdate() method, etc. Most relevantly, this means component system groups can be nested in other component system groups, forming a hierarchy. + +By default, when a ComponentSystemGroup’s `Update()` method is called, it calls Update() on each system in its sorted list of member systems. If any member systems are themselves system groups, they will recursively update their own members. The resulting system ordering follows a depth-first traversal of a tree. + +## System Ordering Attributes + +The existing system ordering attributes are maintained, with slightly different semantics and restrictions. + +* [UpdateInGroup] — specifies a ComponentSystemGroup that this system should be a member of. If this attribute is omitted, the system is automatically added to the default World’s SimulationSystemGroup (see below). +* [UpdateBefore] and [UpdateAfter] — order systems relative to other systems. The system type specified for these attributes must be a member of the same group. Ordering across group boundaries is handled at the appropriate deepest group containing both systems: + * __Example:__ if SystemA is in GroupA and SystemB is in GroupB, and GroupA and GroupB are both members of GroupC, then the ordering of GroupA and GroupB implicitly determines the relative ordering of SystemA and SystemB; no explicit ordering of the systems is necessary. +* [DisableAutoCreation] — prevents the system from being created during default world initialization. You must explicitly create and update the system. However, you can add a system with this tag to a ComponentSystemGroup’s update list, and it will then be automatically updated just like the other systems in that list. + + +## Default System Groups + +The default World contains a hierarchy of ComponentSystemGroup instances. Only three root-level system groups are added to the Unity player loop (the following list also shows the pre-defined member systems in each group): + +* InitializationSystemGroup (updated at the end of the `Initialization` phase of the player loop) + * BeginInitializationEntityCommandBufferSystem + * CopyInitialTransformFromGameObjectSystem + * SubSceneLiveLinkSystem + * SubSceneStreamingSystem + * EndInitializationEntityCommandBufferSystem +* SimulationSystemGroup (updated at the end of the `Update` phase of the player loop) + * BeginSimulationEntityCommandBufferSystem + * TransformSystemGroup + * EndFrameParentSystem + * CopyTransformFromGameObjectSystem + * EndFrameTRSToLocalToWorldSystem + * EndFrameTRSToLocalToParentSystem + * EndFrameLocalToParentSystem + * CopyTransformToGameObjectSystem + * LateSimulationSystemGroup + * EndSimulationEntityCommandBufferSystem +* PresentationSystemGroup (updated at the end of the `PreLateUpdate` phase of the player loop) + * BeginPresentationEntityCommandBufferSystem + * CreateMissingRenderBoundsFromMeshRenderer + * RenderingSystemBootstrap + * RenderBoundsUpdateSystem + * RenderMeshSystem + * LODGroupSystemV1 + * LodRequirementsUpdateSystem + * EndPresentationEntityCommandBufferSystem + +Note that the specific contents of this list is subject to change. + +## Multiple Worlds + +You can create multiple Worlds, in addition to (or instead of) the default World described above. The same component system class can be instantiated in more than one World, and each instance can be updated at different rates from different points in the update order. + +There is currently no way to manually update every system in a given World; instead, you can control which systems are created in which World, and which of the existing system groups they should be added to. Thus, a custom WorldB could instantiate SystemX and SystemY, adding SystemX to the default World’s SimulationSystemGroup, and adding SystemY to the default World’s PresentationSystemGroup. These systems can order themselves relative to their group siblings as usual, and will be updated along with the corresponding group. + +To support this use case, a new ICustomBootstrap interface is now available: + +``` c# +public interface ICustomBootstrap +{ + // Returns the systems which should be handled by the default bootstrap process. + // If null is returned the default world will not be created at all. + // Empty list creates default world and entrypoints + List Initialize(List systems); +} +``` + +When you implement this interface, the full list of component system types will be passed to the classes `Initialize()` method, prior to default world initialization. A custom bootstrapper can iterate through this list and create systems in whatever World it wants. You can return a list of systems from the Initialize() method and they will be created as part of the normal, default world initialization. + +For example, here’s the typical procedure of a custom `MyCustomBootstrap.Initialize()` implementation: + +1. Create any additional Worlds and their top-level ComponentSystemGroups. +2. For each Type in the system Type list: + 1. Traverse upward through the ComponentSystemGroup hierarchy to find this system Type’s top-level group. + 2. If it’s one of the groups created in step 1, create the system in that World and add it to the hierarchy with `group.AddSystemToUpdateList()`. + 3. If not, append this Type to the List to return to DefaultWorldInitialization. +3. Call group.SortSystemUpdateList() on new top-level groups. + 4. Optionally add them to one of the default world groups +4. Return list of unhandled systems to DefaultWorldInitialization. + +**Note:** the ECS framework finds your ICustomBootstrap implementation by reflection. + +## Tips and Best Practices + +* __Use [UpdateInGroup] to specify the system group for each system you write.__ If not specified, the implicit default group is SimulationSystemGroup. +* __Use manually-ticked ComponentSystemGroups to update systems elsewhere in the Unity player loop.__ Adding the [DisableAutoCreation] attribute to a component system (or system group) prevents it from being created or added to the default system groups. You can still manually create the system with World.GetOrCreateManager() and update it by calling manually calling MySystem.Update() from the main thread. This is an easy way to insert systems elsewhere in the Unity player loop (for example, if you have a system that should run later or earlier in the frame). +* __Use the existing `EntityCommandBufferSystem`s instead of adding new ones, if possible.__ An `EntityCommandBufferSystem` represents a sync point where the main thread waits for worker threads to complete before processing any outstanding `EntityCommandBuffer`s. Reusing one of the predefined Begin/End systems in each root-level system group is less likely to introduce a new "bubble" into the frame pipeline than creating a new one. +* __Avoid putting custom logic in `ComponentSystemGroup.OnUpdate()`__. Since `ComponentSystemGroup` is functionally a component system itself, it may be tempting to add custom processing to its OnUpdate() method, to perform some work, spawn some jobs, etc. We advise against this in general, as it’s not immediately clear from the outside whether the custom logic is executed before or after the group’s members are updated. It’s preferable to keep system groups limited to a grouping mechanism, and to implement the desired logic in a separate component system, explicitly ordered relative to the group. diff --git a/package/Documentation~/toc.yml b/package/Documentation~/toc.yml new file mode 100755 index 000000000..5f5d675b8 --- /dev/null +++ b/package/Documentation~/toc.yml @@ -0,0 +1,103 @@ +# Unity Entity Component TOC +#- name: Data-oriented design in Unity +# href: doo_design.md +#- name: Execution order of events +# href: execution_order.md +#- name: Anatomy of an ECS scene +# href: ecs_anatomy.md +#- name: ECS project status +# href: ecs_project_status.md +- name: Overview + href: index.md +- name: Core ECS + items: + - name: Entities + href: ecs_entities.md + items: + - name: Worlds + href: world.md + - name: Components + href: ecs_components.md + items: + - name: General Purpose Components + href: component_data.md + - name: Shared Components + href: shared_component_data.md + - name: System State Components + href: system_state_components.md + - name: Dynamic Buffer Components + href: dynamic_buffers.md + - name: System + href: ecs_systems.md + items: + - name: Component Systems + href: component_system.md + - name: Job Component Systems + href: job_component_system.md + - name: Entity Command Buffers + href: entity_command_buffer.md + - name: System Update Order + href: system_update_order.md + - name: Accessing Entity Data + href: chunk_iteration.md + items: + - name: Using IJobProcessComponentData + href: entity_iteration_job.md + - name: Using IJobChunk + href: chunk_iteration_job.md + - name: Using ComponentSystem and ForEach + href: entity_iteration_foreach.md + - name: Manual iteration + href: manual_iteration.md + - name: Component Groups + href: component_group.md + - name: Versions and Generations + href: version_numbers.md +# - name: Using Burst +# href: ecs_burst.md +# - name: Data Structures +# href: ecs_data_structures.md + - name: Jobs in ECS + href: ecs_job_overview.md + items: + - name: ECS Job System extensions + href: ecs_job_extensions.md +- name: Creating Gameplay +# href: ecs_gameplay.md + items: +# - name: Scenes +# href: gp_scenes.md + - name: Transforms + href: transform_system.md + - name: Rendering + href: gp_rendering.md +# - name: Sharing data between MonoBehaviours and systems +# href: gp_ecs_interop.md +# - name: Physics +# href: gp_physics.md +# - name: Player input +# href: gp_input.md +# - name: Animation +# href: gp_animation.md +# - name: Networking and Multiplayer +# href: gp_multiplayer.md +# - name: Pathfinding and AI +# href: gp_ai.md +# - name: Audio +# href: gp_audio.md +# - name: User interface +# href: gp_ui.md +# - name: Handling text +# href: gp_text_handling.md +# - name: Prefabs +# href: gp_prefabs.md +# - name: Assets and resources +# href: gp_assets.md +# - name: Debugging +# href: ecs_debugging.md +# - name: Profiling +# href: ecs_profiling.md +# - name: Unit Tests +# href: ecs_testing.md +# - name: Building a project +# href: ecs_building_projects.md diff --git a/package/Documentation~/transform_system.md b/package/Documentation~/transform_system.md new file mode 100755 index 000000000..8258b4830 --- /dev/null +++ b/package/Documentation~/transform_system.md @@ -0,0 +1,1458 @@ +--- +uid: gameplay-transform-system +--- +# TransformSystem + +---------------------------------------------- +Section 1: Non-hierarchical Transforms (Basic) +---------------------------------------------- + +LocalToWorld (float4x4) represents the transform from local space to world space. It is the canonical representation and is the only component and can be relied upon to communicate local space among systems. + +- Some DOTS features may rely on the existence of LocalToWorld in order to function. +- For example, the RenderMesh component relies on the LocalToWorld component to exist for rendering an instance. +- If only the LocalToWorld transform component exists, no transform system will write or affect the LocalToWorld data. +- User code may write directly to LocalToWorld to define the transform for an instance, if no other transform components are associated with the same entity. + +The purpose of all transform systems and all other transform components is to provide interfaces to write to LocalToWorld. + +LocalToWorld = Translation * Rotation * Scale + +If any combination of Translation (float3), Rotation (quaternion), or Scale (float) components are present along with a LocalToWorld component, a transform system will combine those components and write to LocalToWorld. + +Concretely, each of these component combinations will write to LocalToWorld as: + +- [TRSToLocalToWorldSystem] LocalToWorld <= Translation +- [TRSToLocalToWorldSystem] LocalToWorld <= Translation * Rotation +- [TRSToLocalToWorldSystem] LocalToWorld <= Translation * Rotation * Scale +- [TRSToLocalToWorldSystem] LocalToWorld <= Rotation +- [TRSToLocalToWorldSystem] LocalToWorld <= Rotation * Scale +- [TRSToLocalToWorldSystem] LocalToWorld <= Scale + +e.g. If the following components are present... + +| (Entity) | +| --------------| +| LocalToWorld | +| Translation | +| Rotation | + +...then the transform system will: + +- [TRSToLocalToWorldSystem] Write LocalToWorld <= Translation * Rotation + +``` +┌─────────────┐ ┌──────────────┐ ┌──────────┐ +│ Translation │ ──> │ LocalToWorld │ <── │ Rotation │ +└─────────────┘ └──────────────┘ └──────────┘ +``` +Or, if the following components are present... + +| (Entity) | +| --------------| +| LocalToWorld | +| Translation | +| Rotation | +| Scale | + +...then the transform system will: + +- [TRSToLocalToWorldSystem] Write LocalToWorld <= Translation * Rotation * Scale + +``` + ┌──────────────┐ + │ Scale │ + └──────────────┘ + │ + │ + ∨ +┌─────────────┐ ┌──────────────┐ ┌──────────┐ +│ Translation │ ──> │ LocalToWorld │ <── │ Rotation │ +└─────────────┘ └──────────────┘ └──────────┘ +``` +------------------------------------------ +Section 2: Hierarchical Transforms (Basic) +------------------------------------------ + +LocalToParent and Parent components are required for the transform system to write a LocalToWorld based on a hierarchical transform. + +- LocalToParent (float4x4) represents the transform from local space to parent local space. +- Parent (Entity) references the parent's LocalToWorld. +- User code may write directly to LocalToParent, if no other transform system is defined as writing to it. + +e.g. If the following components are present... + +| Parent (Entity) | Child (Entity) | +| --------------- | -------------- | +| LocalToWorld | LocalToWorld | +| Translation | LocalToParent | +| Rotation | Parent | +| Scale | | + +...then the transform system will: + +1. [TRSToLocalToWorldSystem] Parent: Write LocalToWorld as defined above in "Non-hierarchical Transforms (Basic)" +2. [LocalToParentSystem] Child: Write LocalToWorld <= LocalToWorld[Parent] * LocalToParent + +``` +------ Parent: ------ + + ┌──────────────┐ + │ Scale │ + └──────────────┘ + │ + │ + ∨ +┌─────────────┐ ┌──────────────┐ ┌──────────┐ +│ Translation │ ──> │ LocalToWorld │ <── │ Rotation │ +└─────────────┘ └──────────────┘ └──────────┘ + +------ Child: ------ + +┌──────────────────────┐ ┌──────────────┐ ┌───────────────┐ +│ LocalToWorld[Parent] │ ──> │ LocalToWorld │ <── │ LocalToParent │ +└──────────────────────┘ └──────────────┘ └───────────────┘ +``` + +LocalToWorld components associated with Parent Entity IDs are guaranteed to be computed before multiplies with LocalToParent associated with Child Entity ID. + +Note: Cyclical graph relationships are invalid. Results are undefined. + +When the hierarchy (topology) is changed (i.e. Any Parent component is added, removed or changed) internal state is added as SystemStateComponentData as: + +- Child component (ISystemStateBufferElementData of Entity) associated with the Parent Entity ID +- PreviousParent component (ISystemStateComponentData of Entity) associated with the Child Entity ID + +| Parent (Entity) | Child (Entity) | +| --------------- | --------------- | +| LocalToWorld | LocalToWorld | +| Translation | LocalToParent | +| Rotation | Parent | +| Scale | PreviousParent* | +| Child* | | + +Adding, removing, and updating of these components is handled by the [ParentSystem]. It is not expected that systems external to transform systems will read or write to these components. + +LocalToParent = Translation * Rotation * Scale + +If any combination of Translation (float3), Rotation (quaternion), or Scale (float) components are present along with a LocalToParent component, a transform system will combine those components and write to LocalToParent. + +Concretely, each of these component combinations will write to LocalToParent as: + +- [TRSToLocalToParentSystem] LocalToParent <= Translation +- [TRSToLocalToParentSystem] LocalToParent <= Translation * Rotation +- [TRSToLocalToParentSystem] LocalToParent <= Translation * Rotation * Scale +- [TRSToLocalToParentSystem] LocalToParent <= Rotation +- [TRSToLocalToParentSystem] LocalToParent <= Rotation * Scale +- [TRSToLocalToParentSystem] LocalToParent <= Scale + +e.g. If the following components are present... + +| Parent (Entity) | Child (Entity) | +| --------------- | --------------- | +| LocalToWorld | LocalToWorld | +| Translation | LocalToParent | +| Rotation | Parent | +| Scale | PreviousParent* | +| Child* | Translation | +| | Rotation | +| | Scale | + +...then the transform system will: + +1. [TRSToLocalToWorldSystem] Parent: Write LocalToWorld as defined above in "Non-hierarchical Transforms (Basic)" +2. [TRSToLocalToParentSystem] Child: Write LocalToParent <= Translation * Rotation * Scale +3. [LocalToParentSystem] Child: Write LocalToWorld <= LocalToWorld[Parent] * LocalToParent + +``` +------ Parent: ------ + + ┌──────────────┐ + │ Scale │ + └──────────────┘ + │ + │ + ∨ +┌─────────────┐ ┌──────────────┐ ┌──────────┐ +│ Translation │ ──> │ LocalToWorld │ <── │ Rotation │ +└─────────────┘ └──────────────┘ └──────────┘ + +------ Child: ------ + + ┌───────────────┐ ┌──────────────────────┐ + │ LocalToWorld │ <── │ LocalToWorld[Parent] │ + └───────────────┘ └──────────────────────┘ + ∧ + │ + │ +┌──────────┐ ┌───────────────┐ ┌──────────────────────┐ +│ Rotation │ ──> │ LocalToParent │ <── │ Translation │ +└──────────┘ └───────────────┘ └──────────────────────┘ + ∧ + │ + │ + ┌───────────────┐ + │ Scale │ + └───────────────┘ +``` + +Parents may of course themselves be children of other LocalToWorld components. + +e.g. If the following components are present... + +| Parent (Entity) | Child (Entity) | +| --------------- | --------------- | +| LocalToWorld | LocalToWorld | +| LocalToParent | LocalToParent | +| Parent | Parent | +| PreviousParent* | PreviousParent* | +| Child* | Translation | +| Translation | Rotation | +| Rotation | Scale | +| Scale | | + +...then the transform system will: + +1. [TRSToLocalToParentSystem] Parent: Write LocalToParent <= Translation * Rotation * Scale +2. [TRSToLocalToParentSystem] Child: Write LocalToParent <= Translation * Rotation * Scale +3. [LocalToParentSystem] Parent: Write LocalToWorld <= LocalToWorld[Parent] * LocalToParent +4. [LocalToParentSystem] Child: Write LocalToWorld <= LocalToWorld[Parent] * LocalToParent + +``` +------ Parent: ------ + + ┌───────────────┐ ┌──────────────────────┐ + │ LocalToWorld │ <── │ LocalToWorld[Parent] │ + └───────────────┘ └──────────────────────┘ + ∧ + │ + │ +┌──────────┐ ┌───────────────┐ ┌──────────────────────┐ +│ Rotation │ ──> │ LocalToParent │ <── │ Translation │ +└──────────┘ └───────────────┘ └──────────────────────┘ + ∧ + │ + │ + ┌───────────────┐ + │ Scale │ + └───────────────┘ + +------ Child: ------ + + ┌───────────────┐ ┌──────────────────────┐ + │ LocalToWorld │ <── │ LocalToWorld[Parent] │ + └───────────────┘ └──────────────────────┘ + ∧ + │ + │ +┌──────────┐ ┌───────────────┐ ┌──────────────────────┐ +│ Rotation │ ──> │ LocalToParent │ <── │ Translation │ +└──────────┘ └───────────────┘ └──────────────────────┘ + ∧ + │ + │ + ┌───────────────┐ + │ Scale │ + └───────────────┘ +``` + +------------------------------------- +Section 3: Default Conversion (Basic) +------------------------------------- + +Hybrid Conversion: + +UnityEngine.Transform MonoBehaviours which are part of GameObjects and are included in Sub Scenes or are on GameObjects with "Convert To Entity" Monobehaviours attached, have a default conversion to Transform system components. That conversion can be found in TransformConversion system in the Unity.Transforms.Hybrid assembly. + +1. Entities associated with the GameObject being transformed which have a Static component, only have LocalToWorld added to the resulting entity. So in the case of static instances, no transform system update will happen at runtime. +2. For non-Static entities, + a. Translation component will be added with the Transform.position value. + b. Rotation component will be added with the Transform.rotation value. + c. Transform.parent == null + - For non-unit Transform.localScale, NonUniformScale component will be added with the Transform.localScale value. + d. If Transform.parent != null, but at the start of the (partial) hierarchy being converted: + - For non-unit Transform.lossyScale, NonUniformScale component will be added with the Transform.lossyScale value. + e. For other cases where Transform.parent != null, + - Parent component will be added with the Entity referring to the converted Transform.parent GameObject. + - LocalToParent component will be added. + +------------------------------------------------- +Section 4: Non-hierarchical Transforms (Advanced) +------------------------------------------------- + +NonUniformScale (float3) as an alternative to Scale to specify scale per-axis. Note that not all DOTS features fully support non-uniform scale. Be sure to check those features’ documentation to understand their limitations. + +- [TRSToLocalToWorldSystem] LocalToWorld <= Translation +- [TRSToLocalToWorldSystem] LocalToWorld <= Translation * Rotation +- [TRSToLocalToWorldSystem] LocalToWorld <= Translation * Rotation * NonUniformScale +- [TRSToLocalToWorldSystem] LocalToWorld <= Rotation +- [TRSToLocalToWorldSystem] LocalToWorld <= Rotation * NonUniformScale +- [TRSToLocalToWorldSystem] LocalToWorld <= NonUniformScale + +The presence of both Scale and NonUniform scale is not a valid case, but the result is defined. Scale will be used, NonUniformScale will be ignored. + +e.g. If the following components are present... + +| (Entity) | +| ---------------- | +| LocalToWorld | +| Translation | +| Rotation | +| NonUniformScale | + +...then the transform system will: + +- [TRSToLocalToWorldSystem] Write LocalToWorld <= Translation * Rotation * NonUniformScale + +``` + ┌──────────────┐ + │ Rotation │ + └──────────────┘ + │ + │ + ∨ +┌─────────────┐ ┌──────────────┐ ┌─────────────────┐ +│ Translation │ ──> │ LocalToWorld │ <── │ NonUniformScale │ +└─────────────┘ └──────────────┘ └─────────────────┘ +``` + +The Rotation component may be written to directly as a quaternion by user code. However, if an Euler interface is preferred, components are available for each rotation order which will cause a write to the Rotation component if present. + +- [RotationEulerSystem] Rotation <= RotationEulerXYZ +- [RotationEulerSystem] Rotation <= RotationEulerXZY +- [RotationEulerSystem] Rotation <= RotationEulerYXZ +- [RotationEulerSystem] Rotation <= RotationEulerYZX +- [RotationEulerSystem] Rotation <= RotationEulerZXY +- [RotationEulerSystem] Rotation <= RotationEulerZYX + +e.g. If the following components are present... + +| (Entity) | +| ---------------- | +| LocalToWorld | +| Translation | +| Rotation | +| RotationEulerXYZ | + +...then the transform system will: + +1. [RotationEulerSystem] Write Rotation <= RotationEulerXYZ +2. [TRSToLocalToWorldSystem] Write LocalToWorld <= Translation * Rotation * Scale + +``` + ┌──────────────┐ + │ Scale │ + └──────────────┘ + │ + │ + ∨ +┌─────────────┐ ┌──────────────┐ ┌──────────┐ ┌──────────────────┐ +│ Translation │ ──> │ LocalToWorld │ <── │ Rotation │ <── │ RotationEulerXYZ │ +└─────────────┘ └──────────────┘ └──────────┘ └──────────────────┘ +``` + +It is a setup error to have more than one RotationEuler*** component is associated with the same Entity, however the result is defined. The first to be found in the order of precedence will be applied. That order is: + +1. RotationEulerXYZ +2. RotationEulerXZY +3. RotationEulerYXZ +4. RotationEulerYZX +5. RotationEulerZXY +6. RotationEulerZYX + +For more complex Rotation requirements, a CompositeRotation (float4x4) component may be used as an alternative to Rotation. + +All of the combinations which are valid for Rotation are also valid for CompositeRotation. i.e. + +- [TRSToLocalToWorldSystem] LocalToWorld <= Translation * CompositeRotation +- [TRSToLocalToWorldSystem] LocalToWorld <= Translation * CompositeRotation * Scale +- [TRSToLocalToWorldSystem] LocalToWorld <= CompositeRotation +- [TRSToLocalToWorldSystem] LocalToWorld <= CompositeRotation * Scale +- [TRSToLocalToWorldSystem] LocalToWorld <= Translation * CompositeRotation +- [TRSToLocalToWorldSystem] LocalToWorld <= Translation * CompositeRotation * NonUniformScale +- [TRSToLocalToWorldSystem] LocalToWorld <= CompositeRotation +- [TRSToLocalToWorldSystem] LocalToWorld <= CompositeRotation * NonUniformScale + +The CompositeRotation component may be written to directly as a float4x4 by user code. However, if a Maya/FBX-style interface is preferred, components are available which will write to the CompositeRotation component if present. + +CompositeRotation = RotationPivotTranslation * RotationPivot * Rotation * PostRotation * RotationPivot^-1 + +If any combination of RotationPivotTranslation (float3), RotationPivot (float3), Rotation (quaternion), or PostRotation (quaternion) components are present along with a CompositeRotation component, a transform system will combine those components and write to CompositeRotation. + +Concretely, each of these component combinations will write to CompositeRotation as: + +- [CompositeRotationSystem] CompositeRotation <= RotationPivotTranslation +- [CompositeRotationSystem] CompositeRotation <= RotationPivotTranslation * RotationPivot * Rotation * RotationPivot^-1 +- [CompositeRotationSystem] CompositeRotation <= RotationPivotTranslation * RotationPivot * Rotation * PostRotation * RotationPivot^-1 +- [CompositeRotationSystem] CompositeRotation <= RotationPivotTranslation * RotationPivot * PostRotation * RotationPivot^-1 +- [CompositeRotationSystem] CompositeRotation <= RotationPivotTranslation * Rotation +- [CompositeRotationSystem] CompositeRotation <= RotationPivotTranslation * Rotation * PostRotation +- [CompositeRotationSystem] CompositeRotation <= RotationPivotTranslation * PostRotation +- [CompositeRotationSystem] CompositeRotation <= RotationPivot * Rotation * RotationPivot^-1 +- [CompositeRotationSystem] CompositeRotation <= RotationPivot * Rotation * PostRotation * RotationPivot^-1 +- [CompositeRotationSystem] CompositeRotation <= PostRotation +- [CompositeRotationSystem] CompositeRotation <= Rotation +- [CompositeRotationSystem] CompositeRotation <= Rotation * PostRotation + +Cases where RotationPivot is specified without either of Rotation, PostRotation have no additional affect on CompositeRotation. + +Note that since Rotation is re-used as a source for CompositeRotation, the alternative data interfaces to Rotation are still available. + +e.g. If the following components are present... + +| (Entity) | +| ------------------------ | +| LocalToWorld | +| Translation | +| CompositeRotation | +| Rotation | +| RotationPivotTranslation | +| RotationPivot | +| PostRotation | +| RotationEulerXYZ | +| Scale | + +...then the transform system will: + +1. [CompositeRotationSystem] Write CompositeRotation <= RotationPivotTranslation * RotationPivot * Rotation * PostRotation * RotationPivot^-1 +2. [TRSToLocalToWorldSystem] Write LocalToWorld <= Translation * CompositeRotation * Scale + +``` + ┌──────────────────────────┐ ┌───────────────────┐ + │ Scale │ │ RotationPivot │ + └──────────────────────────┘ └───────────────────┘ + │ │ + │ │ + ∨ ∨ +┌─────────────┐ ┌──────────────────────────┐ ┌───────────────────┐ ┌──────────────────┐ +│ Translation │ ──> │ LocalToWorld │ <── │ │ <── │ PostRotation │ +└─────────────┘ └──────────────────────────┘ │ CompositeRotation │ └──────────────────┘ + ┌──────────────────────────┐ │ │ ┌──────────────────┐ + │ RotationPivotTranslation │ ──> │ │ │ RotationEulerXYZ │ + └──────────────────────────┘ └───────────────────┘ └──────────────────┘ + ∧ │ + │ │ + │ ∨ + │ ┌──────────────────┐ + └────────────────────── │ Rotation │ + └──────────────────┘ +``` + +The PostRotation component may be written to directly as a quaternion by user code. However, if an Euler interface is preferred, components are available for each rotation order which will cause a write to the PostRotation component if present. + +- [PostRotationEulerSystem] PostRotation <= PostRotationEulerXYZ +- [PostRotationEulerSystem] PostRotation <= PostRotationEulerXZY +- [PostRotationEulerSystem] PostRotation <= PostRotationEulerYXZ +- [PostRotationEulerSystem] PostRotation <= PostRotationEulerYZX +- [PostRotationEulerSystem] PostRotation <= PostRotationEulerZXY +- [PostRotationEulerSystem] PostRotation <= PostRotationEulerZYX + +e.g. If the following components are present... + +| (Entity) | +| ------------------------ | +| LocalToWorld | +| Translation | +| CompositeRotation | +| Rotation | +| RotationPivotTranslation | +| RotationPivot | +| RotationEulerXYZ | +| PostRotation | +| PostRotationEulerXYZ | +| Scale | + +...then the transform system will: + +1. [RotationEulerSystem] Write Rotation <= RotationEulerXYZ +2. [PostRotationEulerSystem] Write PostRotation <= PostRotationEulerXYZ +3. [CompositeRotationSystem] Write CompositeRotation <= RotationPivotTranslation * RotationPivot * Rotation * PostRotation * RotationPivot^-1 +4. [TRSToLocalToWorldSystem] Write LocalToWorld <= Translation * CompositeRotation * Scale + +``` + ┌──────────────────────────┐ ┌───────────────────┐ + │ Scale │ │ RotationPivot │ + └──────────────────────────┘ └───────────────────┘ + │ │ + │ │ + ∨ ∨ +┌─────────────┐ ┌──────────────────────────┐ ┌───────────────────┐ ┌──────────────┐ ┌──────────────────────┐ +│ Translation │ ──> │ LocalToWorld │ <── │ │ <── │ PostRotation │ <── │ PostRotationEulerXYZ │ +└─────────────┘ └──────────────────────────┘ │ CompositeRotation │ └──────────────┘ └──────────────────────┘ + ┌──────────────────────────┐ │ │ ┌──────────────┐ ┌──────────────────────┐ + │ RotationPivotTranslation │ ──> │ │ <── │ Rotation │ <── │ RotationEulerXYZ │ + └──────────────────────────┘ └───────────────────┘ └──────────────┘ └──────────────────────┘ +``` + +For more complex Scale requirements, a CompositeScale (float4x4) component may be used as an alternative to Scale (or NonUniformScale). + +All of the combinations which are valid for Scale or NonUniformScale are also valid for CompositeScale. i.e. + +- [TRSToLocalToWorldSystem] LocalToWorld <= Translation * Rotation * CompositeScale +- [TRSToLocalToWorldSystem] LocalToWorld <= Rotation * CompositeScale +- [TRSToLocalToWorldSystem] LocalToWorld <= CompositeScale +- [TRSToLocalToWorldSystem] LocalToWorld <= Translation * CompositeRotation * CompositeScale +- [TRSToLocalToWorldSystem] LocalToWorld <= CompositeRotation * CompositeScale + +The CompositeScale component may be written to directly as a float4x4 by user code. However, if a Maya/FBX-style interface is preferred, components are available which will write to the CompositeScale component if present. + +CompositeScale = ScalePivotTranslation * ScalePivot * Scale * ScalePivot^-1 +CompositeScale = ScalePivotTranslation * ScalePivot * NonUniformScale * ScalePivot^-1 + +If any combination of ScalePivotTranslation (float3), ScalePivot (float3), Scale (float) components are present along with a CompositeScale component, a transform system will combine those components and write to CompositeScale. + +Alternatively, if any combination of ScalePivotTranslation (float3), ScalePivot (float3), NonUniformScale (float3) components are present along with a CompositeScale component, a transform system will combine those components and write to CompositeScale. + +Concretely, each of these component combinations will write to CompositeRotation as: + +- [CompositeScaleSystem] CompositeScale <= ScalePivotTranslation +- [CompositeScaleSystem] CompositeScale <= ScalePivotTranslation * ScalePivot * Scale * ScalePivot^-1 +- [CompositeScaleSystem] CompositeScale <= ScalePivotTranslation * Scale +- [CompositeScaleSystem] CompositeScale <= ScalePivot * Scale * ScalePivot^-1 +- [CompositeScaleSystem] CompositeScale <= Scale +- [CompositeScaleSystem] CompositeScale <= ScalePivotTranslation * ScalePivot * NonUniformScale * ScalePivot^-1 +- [CompositeScaleSystem] CompositeScale <= ScalePivotTranslation * Scale +- [CompositeScaleSystem] CompositeScale <= ScalePivot * NonUniformScale * ScalePivot^-1 +- [CompositeScaleSystem] CompositeScale <= NonUniformScale + +Cases where ScalePivot is specified without either of Scale, NonUniformScale have no additional effect have no additional affect on CompositeScale. + +e.g. If the following components are present... + +| (Entity) | +| ------------------------ | +| LocalToWorld | +| Translation | +| CompositeRotation | +| Rotation | +| RotationPivotTranslation | +| RotationPivot | +| RotationEulerXYZ | +| PostRotation | +| PostRotationEulerXYZ | +| CompositeScale | +| Scale | +| ScalePivotTranslation | +| ScalePivot | + +...then the transform system will: + +1. [RotationEulerSystem] Write Rotation <= RotationEulerXYZ +2. [PostRotationEulerSystem] Write PostRotation <= PostRotationEulerXYZ +3. [CompositeScaleSystem] Write CompositeScale <= ScalePivotTranslation * ScalePivot * Scale * ScalePivot^-1 +4. [CompositeRotationSystem] Write CompositeRotation <= RotationPivotTranslation * RotationPivot * Rotation * PostRotation * RotationPivot^-1 +5. [TRSToLocalToWorldSystem] Write LocalToWorld <= Translation * CompositeRotation * CompositeScale + +``` + ┌───────────────────┐ + │ RotationPivot │ + └───────────────────┘ + │ + │ + ∨ +┌─────────────┐ ┌──────────────────────────┐ ┌───────────────────┐ ┌───────────────────────┐ ┌──────────────────────┐ +│ Translation │ ──> │ LocalToWorld │ <── │ │ <── │ PostRotation │ <── │ PostRotationEulerXYZ │ +└─────────────┘ └──────────────────────────┘ │ │ └───────────────────────┘ └──────────────────────┘ + ∧ │ │ + ┌────┘ │ CompositeRotation │ + │ │ │ + │ ┌──────────────────────────┐ │ │ ┌───────────────────────┐ ┌──────────────────────┐ + │ │ RotationPivotTranslation │ ──> │ │ <── │ Rotation │ <── │ RotationEulerXYZ │ + │ └──────────────────────────┘ └───────────────────┘ └───────────────────────┘ └──────────────────────┘ + │ + │ ┌─────────────────────────────────────────────────────┐ + │ ∨ │ + │ ┌───────────────────────┐ ┌──────────────────────┐ │ + └──────────────────────────────────────────────────────────── │ CompositeScale │ <── │ Scale │ │ + └───────────────────────┘ └──────────────────────┘ │ + ∧ │ + │ │ + │ │ + ┌───────────────────────┐ │ + │ ScalePivotTranslation │ │ + └───────────────────────┘ │ + ┌───────────────────────┐ │ + │ ScalePivot │ ──────────────────────────────┘ + └───────────────────────┘ +``` + +--------------------------------------------- +Section 5: Hierarchical Transforms (Advanced) +--------------------------------------------- + +Note: Advanced Hierarchical transform component rules largely mirror the use of the non-hierarchical components, except that they are writing to LocalToParent (instead of LocalToWorld.) The main additional component unique to hierarchical transforms is ParentScaleInverse. + +----- + +NonUniformScale (float3) as an alternative to Scale to specify scale per-axis. Note that not all DOTS features fully support non-uniform scale. Be sure to check those features’ documentation to understand their limitations. + +- [TRSToLocalToParentSystem] LocalToParent <= Translation +- [TRSToLocalToParentSystem] LocalToParent <= Translation * Rotation +- [TRSToLocalToParentSystem] LocalToParent <= Translation * Rotation * NonUniformScale +- [TRSToLocalToParentSystem] LocalToParent <= Rotation +- [TRSToLocalToParentSystem] LocalToParent <= Rotation * NonUniformScale +- [TRSToLocalToParentSystem] LocalToParent <= NonUniformScale + +The presence of both Scale and NonUniform scale is not a valid case, but the result is defined. Scale will be used, NonUniformScale will be ignored. + +e.g. If the following components are present... + +| Parent (Entity) | Child (Entity) | +| --------------- | ---------------- | +| LocalToWorld | LocalToWorld | +| Translation | LocalToParent | +| Rotation | Parent | +| Scale | PreviousParent* | +| Child* | Translation | +| | Rotation | +| | NonUniformScale | + +...then the transform system will: + +1. [TRSToLocalToWorldSystem] Parent: Write LocalToWorld as defined above in "Non-hierarchical Transforms (Basic)" +2. [TRSToLocalToParentSystem] Child: Write LocalToParent <= Translation * Rotation * NonUniformScale +3. [LocalToParentSystem] Child: Write LocalToWorld <= LocalToWorld[Parent] * LocalToParent + +``` +------ Parent: ------ + + ┌──────────────┐ + │ Scale │ + └──────────────┘ + │ + │ + ∨ +┌─────────────┐ ┌──────────────┐ ┌──────────┐ +│ Translation │ ──> │ LocalToWorld │ <── │ Rotation │ +└─────────────┘ └──────────────┘ └──────────┘ + +------ Child: ------ + + ┌───────────────┐ ┌──────────────────────┐ + │ LocalToWorld │ <── │ LocalToWorld[Parent] │ + └───────────────┘ └──────────────────────┘ + ∧ + │ + │ +┌─────────────────┐ ┌───────────────┐ ┌──────────────────────┐ +│ NonUniformScale │ ──> │ LocalToParent │ <── │ Translation │ +└─────────────────┘ └───────────────┘ └──────────────────────┘ + ∧ + │ + │ + ┌───────────────┐ + │ Rotation │ + └───────────────┘ +``` + +Parent LocalToWorld is multiplied with the Child LocalToWorld, which includes any scaling. However, if removing Parent scale is preferred (AKA Scale Compensate), ParentScaleInverse is available for that purpose. + +- [TRSToLocalToParentSystem] LocalToParent <= ParentScaleInverse +- [TRSToLocalToParentSystem] LocalToParent <= Translation * ParentScaleInverse +- [TRSToLocalToParentSystem] LocalToParent <= Translation * ParentScaleInverse * Rotation +- [TRSToLocalToParentSystem] LocalToParent <= Translation * ParentScaleInverse * Rotation * NonUniformScale +- [TRSToLocalToParentSystem] LocalToParent <= Translation * ParentScaleInverse * CompositeRotation +- [TRSToLocalToParentSystem] LocalToParent <= Translation * ParentScaleInverse * CompositeRotation * NonUniformScale +- [TRSToLocalToParentSystem] LocalToParent <= Translation * ParentScaleInverse * Rotation * Scale +- [TRSToLocalToParentSystem] LocalToParent <= Translation * ParentScaleInverse * CompositeRotation * Scale +- [TRSToLocalToParentSystem] LocalToParent <= Translation * ParentScaleInverse * Rotation * CompositeScale +- [TRSToLocalToParentSystem] LocalToParent <= Translation * ParentScaleInverse * CompositeRotation * CompositeScale +- [TRSToLocalToParentSystem] LocalToParent <= ParentScaleInverse * Rotation +- [TRSToLocalToParentSystem] LocalToParent <= ParentScaleInverse * Rotation * NonUniformScale +- [TRSToLocalToParentSystem] LocalToParent <= ParentScaleInverse * CompositeRotation * NonUniformScale +- [TRSToLocalToParentSystem] LocalToParent <= ParentScaleInverse * Rotation * Scale +- [TRSToLocalToParentSystem] LocalToParent <= ParentScaleInverse * CompositeRotation +- [TRSToLocalToParentSystem] LocalToParent <= ParentScaleInverse * CompositeRotation * Scale +- [TRSToLocalToParentSystem] LocalToParent <= ParentScaleInverse * Rotation * CompositeScale +- [TRSToLocalToParentSystem] LocalToParent <= ParentScaleInverse * CompositeRotation * CompositeScale + +Inverse of any explicitly assigned parent scale values if present are written to ParentScaleInverse, as: + +- [ParentScaleInverseSystem] ParentScaleInverse <= CompositeScale[Parent]^-1 +- [ParentScaleInverseSystem] ParentScaleInverse <= Scale[Parent]^-1 +- [ParentScaleInverseSystem] ParentScaleInverse <= NonUniformScale[Parent]^-1 + +If LocalToWorld[Parent] is written directly by the user, or scaling is otherwise applied in a way that is not explicitly using the scale components, then nothing is written to the ParentScaleInverse. It is the responsibility of the system applying that scaling to write inverse to ParentScaleInverse. The results of a system not updating ParentScaleInverse in this case are undefined. + +e.g. If the following components are present... + +| Parent (Entity) | Child (Entity) | +| --------------- | ------------------ | +| LocalToWorld | LocalToWorld | +| Translation | LocalToParent | +| Rotation | Parent | +| Scale | PreviousParent* | +| Child* | Translation | +| | Rotation | +| | ParentScaleInverse | + +...then the transform system will: + +1. [TRSToLocalToWorldSystem] Parent: Write LocalToWorld as defined above in "Non-hierarchical Transforms (Basic)" +2. [ParentScaleInverseSystem] Child: ParentScaleInverse <= Scale[Parent]^-1 +3. [TRSToLocalToParentSystem] Child: Write LocalToParent <= Translation * ParentScaleInverse * Rotation +4. [LocalToParentSystem] Child: Write LocalToWorld <= LocalToWorld[Parent] * LocalToParent + +``` +------ Parent: ------ + + ┌──────────────┐ + │ Scale │ + └──────────────┘ + │ + │ + ∨ +┌─────────────┐ ┌──────────────┐ ┌──────────┐ +│ Translation │ ──> │ LocalToWorld │ <── │ Rotation │ +└─────────────┘ └──────────────┘ └──────────┘ + +------ Child: ------ + + ┌────────────────────┐ ┌──────────────────────┐ + │ LocalToWorld │ <── │ LocalToWorld[Parent] │ + └────────────────────┘ └──────────────────────┘ + ∧ + │ + │ +┌──────────┐ ┌────────────────────┐ ┌──────────────────────┐ +│ Rotation │ ──> │ LocalToParent │ <── │ Translation │ +└──────────┘ └────────────────────┘ └──────────────────────┘ + ∧ + │ + │ + ┌────────────────────┐ ┌──────────────────────┐ + │ ParentScaleInverse │ <── │ Scale[Parent] │ + └────────────────────┘ └──────────────────────┘ +``` + +The Rotation component may be written to directly as a quaternion by user code. However, if an Euler interface is preferred, components are available for each rotation order which will cause a write to the Rotation component if present. + +- [RotationEulerSystem] Rotation <= RotationEulerXYZ +- [RotationEulerSystem] Rotation <= RotationEulerXZY +- [RotationEulerSystem] Rotation <= RotationEulerYXZ +- [RotationEulerSystem] Rotation <= RotationEulerYZX +- [RotationEulerSystem] Rotation <= RotationEulerZXY +- [RotationEulerSystem] Rotation <= RotationEulerZYX + +e.g. If the following components are present... + +| Parent (Entity) | Child (Entity) | +| --------------- | ---------------- | +| LocalToWorld | LocalToWorld | +| Translation | LocalToParent | +| Rotation | Parent | +| Scale | PreviousParent* | +| Child* | Translation | +| | Rotation | +| | RotationEulerXYZ | + +...then the transform system will: + +1. [TRSToLocalToWorldSystem] Parent: Write LocalToWorld as defined above in "Non-hierarchical Transforms (Basic)" +2. [RotationEulerSystem] Child: Write Rotation <= RotationEulerXYZ +3. [TRSToLocalToParentSystem] Child: Write LocalToParent <= Translation * Rotation +4. [LocalToParentSystem] Child: Write LocalToWorld <= LocalToWorld[Parent] * LocalToParent + +``` +------ Parent: ------ + + ┌──────────────┐ + │ Scale │ + └──────────────┘ + │ + │ + ∨ +┌─────────────┐ ┌──────────────┐ ┌──────────┐ +│ Translation │ ──> │ LocalToWorld │ <── │ Rotation │ +└─────────────┘ └──────────────┘ └──────────┘ + +------ Child: ------ + +┌───────────────┐ ┌──────────────────────┐ +│ LocalToWorld │ <── │ LocalToWorld[Parent] │ +└───────────────┘ └──────────────────────┘ + ∧ + │ + │ +┌───────────────┐ ┌──────────────────────┐ +│ LocalToParent │ <── │ Translation │ +└───────────────┘ └──────────────────────┘ + ∧ + │ + │ +┌───────────────┐ ┌──────────────────────┐ +│ Rotation │ <── │ RotationEulerXYZ │ +└───────────────┘ └──────────────────────┘ +``` + +For more complex Rotation requirements, a CompositeRotation (float4x4) component may be used as an alternative to Rotation. + +All of the combinations which are valid for Rotation are also valid for CompositeRotation. i.e. + +- [TRSToLocalToParentSystem] LocalToParent <= Translation * CompositeRotation +- [TRSToLocalToParentSystem] LocalToParent <= Translation * CompositeRotation * Scale +- [TRSToLocalToParentSystem] LocalToParent <= Translation * CompositeRotation * NonUniformScale +- [TRSToLocalToParentSystem] LocalToParent <= Translation * CompositeRotation * CompositeScale +- [TRSToLocalToParentSystem] LocalToParent <= Translation * ParentScaleInverse * CompositeRotation +- [TRSToLocalToParentSystem] LocalToParent <= Translation * ParentScaleInverse * CompositeRotation * Scale +- [TRSToLocalToParentSystem] LocalToParent <= Translation * ParentScaleInverse * CompositeRotation * NonUniformScale +- [TRSToLocalToParentSystem] LocalToParent <= Translation * ParentScaleInverse * CompositeRotation * CompositeScale +- [TRSToLocalToParentSystem] LocalToParent <= ParentScaleInverse * CompositeRotation +- [TRSToLocalToParentSystem] LocalToParent <= ParentScaleInverse * CompositeRotation * Scale +- [TRSToLocalToParentSystem] LocalToParent <= ParentScaleInverse * CompositeRotation * NonUniformScale +- [TRSToLocalToParentSystem] LocalToParent <= ParentScaleInverse * CompositeRotation * CompositeScale +- [TRSToLocalToParentSystem] LocalToParent <= CompositeRotation +- [TRSToLocalToParentSystem] LocalToParent <= CompositeRotation * Scale +- [TRSToLocalToParentSystem] LocalToParent <= CompositeRotation * NonUniformScale +- [TRSToLocalToParentSystem] LocalToParent <= CompositeRotation * CompositeScale + +The CompositeRotation component may be written to directly as a float4x4 by user code. However, if a Maya/FBX-style interface is preferred, components are available which will write to the CompositeRotation component if present. + +CompositeRotation = RotationPivotTranslation * RotationPivot * Rotation * PostRotation * RotationPivot^-1 + +If any combination of RotationPivotTranslation (float3), RotationPivot (float3), Rotation (quaternion), or PostRotation (quaternion) components are present along with a CompositeRotation component, a transform system will combine those components and write to CompositeRotation. + +Concretely, each of these component combinations will write to CompositeRotation as: + +- [CompositeRotationSystem] CompositeRotation <= RotationPivotTranslation +- [CompositeRotationSystem] CompositeRotation <= RotationPivotTranslation * RotationPivot * Rotation * RotationPivot^-1 +- [CompositeRotationSystem] CompositeRotation <= RotationPivotTranslation * RotationPivot * Rotation * PostRotation * RotationPivot^-1 +- [CompositeRotationSystem] CompositeRotation <= RotationPivotTranslation * RotationPivot * PostRotation * RotationPivot^-1 +- [CompositeRotationSystem] CompositeRotation <= RotationPivotTranslation * Rotation +- [CompositeRotationSystem] CompositeRotation <= RotationPivotTranslation * Rotation * PostRotation +- [CompositeRotationSystem] CompositeRotation <= RotationPivotTranslation * PostRotation +- [CompositeRotationSystem] CompositeRotation <= RotationPivot * Rotation * RotationPivot^-1 +- [CompositeRotationSystem] CompositeRotation <= RotationPivot * Rotation * PostRotation * RotationPivot^-1 +- [CompositeRotationSystem] CompositeRotation <= PostRotation +- [CompositeRotationSystem] CompositeRotation <= Rotation +- [CompositeRotationSystem] CompositeRotation <= Rotation * PostRotation + +Cases where RotationPivot is specified without either of Rotation, PostRotation have no additional affect on CompositeRotation. + +Note that since Rotation is re-used as a source for CompositeRotation, the alternative data interfaces to Rotation are still available. + +e.g. If the following components are present... + +| Parent (Entity) | Child (Entity) | +| --------------- | ------------------------ | +| LocalToWorld | LocalToWorld | +| Translation | LocalToParent | +| Rotation | Parent | +| Scale | PreviousParent* | +| Child* | Translation | +| | CompositeRotation | +| | Rotation | +| | RotationPivotTranslation | +| | RotationPivot | +| | PostRotation | +| | RotationEulerXYZ | +| | Scale | + +...then the transform system will: + +1. [TRSToLocalToWorldSystem] Parent: Write LocalToWorld as defined above in "Non-hierarchical Transforms (Basic)" +2. [RotationEulerSystem] Child: Write Rotation <= RotationEulerXYZ +3. [CompositeRotationSystem] Child: Wirte CompositeRotation <= RotationPivotTranslation * RotationPivot * Rotation * PostRotation * RotationPivot^-1 +4. [TRSToLocalToParentSystem] Child: Write LocalToParent <= Translation * CompositeRotation * Scale +5. [LocalToParentSystem] Child: Write LocalToWorld <= LocalToWorld[Parent] * LocalToParent + +``` +------ Parent: ------ + + ┌──────────────┐ + │ Scale │ + └──────────────┘ + │ + │ + ∨ +┌─────────────┐ ┌──────────────┐ ┌──────────┐ +│ Translation │ ──> │ LocalToWorld │ <── │ Rotation │ +└─────────────┘ └──────────────┘ └──────────┘ + +------ Child: ------ + ┌───────────────────┐ ┌──────────────────────┐ + │ LocalToWorld │ <── │ LocalToWorld[Parent] │ + └───────────────────┘ └──────────────────────┘ + ∧ + │ + │ +┌──────────────────────────┐ ┌───────────────────┐ ┌──────────────────────┐ +│ Scale │ ──> │ │ <── │ Translation │ +└──────────────────────────┘ │ │ └──────────────────────┘ + │ │ + │ LocalToParent │ <─────────────────────────────┐ + │ │ │ + │ │ ┌──────────────────────┐ │ + │ │ │ RotationEulerXYZ │ │ + └───────────────────┘ └──────────────────────┘ │ + ∧ │ │ + │ │ │ + │ ∨ │ +┌──────────────────────────┐ ┌───────────────────┐ ┌──────────────────────┐ │ +│ RotationPivotTranslation │ ──> │ │ <── │ Rotation │ │ +└──────────────────────────┘ │ CompositeRotation │ └──────────────────────┘ │ +┌──────────────────────────┐ │ │ ┌──────────────────────┐ │ +│ PostRotation │ ──> │ │ │ Scale[Parent] │ │ +└──────────────────────────┘ └───────────────────┘ └──────────────────────┘ │ + ∧ │ │ + │ │ │ + │ ∨ │ + ┌───────────────────┐ ┌──────────────────────┐ │ + │ RotationPivot │ │ ParentScaleInverse │ ─┘ + └───────────────────┘ └──────────────────────┘ +``` + +The PostRotation component may be written to directly as a quaternion by user code. However, if an Euler interface is preferred, components are available for each rotation order which will cause a write to the PostRotation component if present. + +- [PostRotationEulerSystem] PostRotation <= PostRotationEulerXYZ +- [PostRotationEulerSystem] PostRotation <= PostRotationEulerXZY +- [PostRotationEulerSystem] PostRotation <= PostRotationEulerYXZ +- [PostRotationEulerSystem] PostRotation <= PostRotationEulerYZX +- [PostRotationEulerSystem] PostRotation <= PostRotationEulerZXY +- [PostRotationEulerSystem] PostRotation <= PostRotationEulerZYX + +e.g. If the following components are present... + +| Parent (Entity) | Child (Entity) | +| --------------- | ------------------------ | +| LocalToWorld | LocalToWorld | +| Translation | LocalToParent | +| Rotation | Parent | +| Scale | PreviousParent* | +| Child* | Translation | +| | CompositeRotation | +| | Rotation | +| | RotationPivotTranslation | +| | RotationPivot | +| | PostRotation | +| | RotationEulerXYZ | +| | Scale | +| | PostRotationEulerXYZ | + +...then the transform system will: + +1. [TRSToLocalToWorldSystem] Parent: Write LocalToWorld as defined above in "Non-hierarchical Transforms (Basic)" +2. [PostRotationEulerSystem] Child: Write PostRotation <= PostRotationEulerXYZ +3. [RotationEulerSystem] Child: Write Rotation <= RotationEulerXYZ +4. [CompositeRotationSystem] Child: Wirte CompositeRotation <= RotationPivotTranslation * RotationPivot * Rotation * PostRotation * RotationPivot^-1 +5. [TRSToLocalToParentSystem] Child: Write LocalToParent <= Translation * CompositeRotation * Scale +6. [LocalToParentSystem] Child: Write LocalToWorld <= LocalToWorld[Parent] * LocalToParent + +``` +------ Parent: ------ + + ┌──────────────┐ + │ Scale │ + └──────────────┘ + │ + │ + ∨ +┌─────────────┐ ┌──────────────┐ ┌──────────┐ +│ Translation │ ──> │ LocalToWorld │ <── │ Rotation │ +└─────────────┘ └──────────────┘ └──────────┘ + +------ Child: ------ + + ┌────────────────────┐ ┌──────────────────────┐ + │ LocalToWorld │ <── │ LocalToWorld[Parent] │ + └────────────────────┘ └──────────────────────┘ + ∧ + │ + │ +┌──────────────────────────┐ ┌────────────────────┐ ┌──────────────────────┐ +│ Scale │ ──> │ │ <── │ Translation │ +└──────────────────────────┘ │ │ └──────────────────────┘ + │ │ + │ LocalToParent │ <─────────────────────────────┐ + │ │ │ + │ │ ┌──────────────────────┐ │ + │ │ │ PostRotationEulerXYZ │ │ + └────────────────────┘ └──────────────────────┘ │ + ∧ │ │ + │ │ │ + │ ∨ │ +┌──────────────────────────┐ ┌────────────────────┐ ┌──────────────────────┐ │ +│ RotationPivotTranslation │ ──> │ │ <── │ PostRotation │ │ +└──────────────────────────┘ │ CompositeRotation │ └──────────────────────┘ │ +┌──────────────────────────┐ │ │ ┌──────────────────────┐ │ +│ RotationPivot │ ──> │ │ │ RotationEulerXYZ │ │ +└──────────────────────────┘ └────────────────────┘ └──────────────────────┘ │ + ∧ │ │ + │ │ │ + │ ∨ │ + │ ┌──────────────────────┐ │ + └─────────────────────── │ Rotation │ │ + └──────────────────────┘ │ + │ + ┌──────────────────────────────────────────────────┘ + │ + ┌────────────────────┐ ┌──────────────────────┐ + │ ParentScaleInverse │ <── │ Scale[Parent] │ + └────────────────────┘ └──────────────────────┘ +``` + +It is a setup error to have more than one PostRotationEuler*** component is associated with the same Entity, however the result is defined. The first to be found in the order of precedence will be applied. That order is: + +1. PostRotationEulerXYZ +2. PostRotationEulerXZY +3. PostRotationEulerYXZ +4. PostRotationEulerYZX +5. PostRotationEulerZXY +6. PostRotationEulerZYX + +For more complex Scale requirements, a CompositeScale (float4x4) component may be used as an alternative to Scale (or NonUniformScale). + +All of the combinations which are valid for Scale or NonUniformScale are also valid for CompositeScale. i.e. + +- [TRSToLocalToParentSystem] LocalToParent <= Translation * Rotation * CompositeScale +- [TRSToLocalToParentSystem] LocalToParent <= Rotation * CompositeScale +- [TRSToLocalToParentSystem] LocalToParent <= CompositeScale +- [TRSToLocalToParentSystem] LocalToParent <= Translation * CompositeRotation * CompositeScale +- [TRSToLocalToParentSystem] LocalToParent <= CompositeRotation * CompositeScale +- [TRSToLocalToParentSystem] LocalToParent <= Translation * ParentScaleInverse * Rotation * CompositeScale +- [TRSToLocalToParentSystem] LocalToParent <= Translation * ParentScaleInverse * CompositeRotation * CompositeScale +- [TRSToLocalToParentSystem] LocalToParent <= ParentScaleInverse * Rotation * CompositeScale +- [TRSToLocalToParentSystem] LocalToParent <= ParentScaleInverse * CompositeRotation * CompositeScale +- [TRSToLocalToParentSystem] LocalToParent <= ParentScaleInverse * CompositeScale + +The CompositeScale component may be written to directly as a float4x4 by user code. However, if a Maya/FBX-style interface is preferred, components are available which will write to the CompositeScale component if present. + +CompositeScale = ScalePivotTranslation * ScalePivot * Scale * ScalePivot^-1 +CompositeScale = ScalePivotTranslation * ScalePivot * NonUniformScale * ScalePivot^-1 + +If any combination of ScalePivotTranslation (float3), ScalePivot (float3), Scale (float) components are present along with a CompositeScale component, a transform system will combine those components and write to CompositeScale. + +Alternatively, if any combination of ScalePivotTranslation (float3), ScalePivot (float3), NonUniformScale (float3) components are present along with a CompositeScale component, a transform system will combine those components and write to CompositeScale. + +Concretely, each of these component combinations will write to CompositeRotation as: + +- [CompositeScaleSystem] CompositeScale <= ScalePivotTranslation +- [CompositeScaleSystem] CompositeScale <= ScalePivotTranslation * ScalePivot * Scale * ScalePivot^-1 +- [CompositeScaleSystem] CompositeScale <= ScalePivotTranslation * Scale +- [CompositeScaleSystem] CompositeScale <= ScalePivot * Scale * ScalePivot^-1 +- [CompositeScaleSystem] CompositeScale <= Scale +- [CompositeScaleSystem] CompositeScale <= ScalePivotTranslation * ScalePivot * NonUniformScale * ScalePivot^-1 +- [CompositeScaleSystem] CompositeScale <= ScalePivotTranslation * Scale +- [CompositeScaleSystem] CompositeScale <= ScalePivot * NonUniformScale * ScalePivot^-1 +- [CompositeScaleSystem] CompositeScale <= NonUniformScale + +Cases where ScalePivot is specified without either of Scale, NonUniformScale have no additional effect have no additional affect on CompositeScale. + +e.g. If the following components are present... + +| Parent (Entity) | Child (Entity) | +| --------------- | ------------------------ | +| LocalToWorld | LocalToWorld | +| Translation | LocalToParent | +| Rotation | Parent | +| Scale | PreviousParent* | +| Child* | Translation | +| | CompositeRotation | +| | Rotation | +| | RotationPivotTranslation | +| | RotationPivot | +| | PostRotation | +| | RotationEulerXYZ | +| | Scale | +| | PostRotationEulerXYZ | +| | CompositeScale | +| | ScalePivotTranslation | +| | ScalePivot | + +...then the transform system will: + +1. [TRSToLocalToWorldSystem] Parent: Write LocalToWorld as defined above in "Non-hierarchical Transforms (Basic)" +2. [PostRotationEulerSystem] Child: Write PostRotation <= PostRotationEulerXYZ +2. [RotationEulerSystem] Child: Write Rotation <= RotationEulerXYZ +3. [CompositeRotationSystem] Child: Wirte CompositeRotation <= RotationPivotTranslation * RotationPivot * Rotation * PostRotation * RotationPivot^-1 +4. [TRSToLocalToParentSystem] Child: Write LocalToParent <= Translation * CompositeRotation * Scale +5. [LocalToParentSystem] Child: Write LocalToWorld <= LocalToWorld[Parent] * LocalToParent + +``` +------ Parent: ------ + + ┌──────────────┐ + │ Scale │ + └──────────────┘ + │ + │ + ∨ +┌─────────────┐ ┌──────────────┐ ┌──────────┐ +│ Translation │ ──> │ LocalToWorld │ <── │ Rotation │ +└─────────────┘ └──────────────┘ └──────────┘ +``` +...then the transform system will: + +1. [TRSToLocalToWorldSystem] Parent: Write LocalToWorld as defined above in "Non-hierarchical Transforms (Basic)" +2. [PostRotationEulerSystem] Child: Write PostRotation <= PostRotationEulerXYZ +3. [RotationEulerSystem] Child: Write Rotation <= RotationEulerXYZ +4. [CompositeScaleSystem] Child: Write CompositeScale <= ScalePivotTranslation * ScalePivot * Scale * ScalePivot^-1 +5. [CompositeRotationSystem] Child: Wirte CompositeRotation <= RotationPivotTranslation * RotationPivot * Rotation * PostRotation * RotationPivot^-1 +6. [TRSToLocalToParentSystem] Child: Write LocalToParent <= Translation * CompositeRotation * Scale +7. [LocalToParentSystem] Child: Write LocalToWorld <= LocalToWorld[Parent] * LocalToParent + +``` + ┌───────────────────┐ ┌──────────────────────┐ + │ LocalToWorld │ <── │ LocalToWorld[Parent] │ + └───────────────────┘ └──────────────────────┘ + ∧ + │ + │ + ┌───────────────────┐ ┌──────────────────────┐ + │ │ <── │ Translation │ + │ │ └──────────────────────┘ + │ │ + │ LocalToParent │ <─────────────────────────────┐ + │ │ │ + │ │ ┌──────────────────────┐ │ + ┌─────────────────────────────────> │ │ │ PostRotationEulerXYZ │ │ + │ └───────────────────┘ └──────────────────────┘ │ + │ ∧ │ │ + │ │ │ │ + │ │ ∨ │ + │ ┌──────────────────────────┐ ┌───────────────────┐ ┌──────────────────────┐ │ + │ │ RotationPivotTranslation │ ──> │ │ <── │ PostRotation │ │ + │ └──────────────────────────┘ │ CompositeRotation │ └──────────────────────┘ │ + │ ┌──────────────────────────┐ │ │ ┌──────────────────────┐ │ + │ │ RotationPivot │ ──> │ │ │ RotationEulerXYZ │ │ + │ └──────────────────────────┘ └───────────────────┘ └──────────────────────┘ │ + │ ∧ │ │ + │ │ │ │ + │ │ ∨ │ + │ │ ┌──────────────────────┐ │ + │ └────────────────────── │ Rotation │ │ + │ └──────────────────────┘ │ + │ │ + │ ┌─────────────────────────────────────────────────┘ + │ │ + │ ┌──────────────────────────┐ ┌───────────────────┐ ┌──────────────────────┐ + │ │ ScalePivotTranslation │ ──> │ CompositeScale │ <── │ Scale │ + │ └──────────────────────────┘ └───────────────────┘ └──────────────────────┘ + │ ∧ + │ │ + │ │ + │ ┌───────────────────┐ ┌──────────────────────┐ + │ │ ScalePivot │ │ Scale[Parent] │ + │ └───────────────────┘ └──────────────────────┘ + │ │ + │ │ + │ ∨ + │ ┌──────────────────────┐ + └──────────────────────────────────────────────────────────── │ ParentScaleInverse │ + └──────────────────────┘ +``` + +--------------------------------------- +Section 6: Custom Transforms (Advanced) +--------------------------------------- + +There are two methods for writing user-defined transforms that are fully compatible with the transform system. + +1. Overriding transform components +2. Extending transform components + +Overriding transform components +------------------------------- + +A user component (UserComponent) is defined and added to the LocalToWorld WriteGroup, as in: + +[Serializable] +[WriteGroup(typeof(LocalToWorld))] +struct UserComponent : IComponentData +{ +} + +Overriding transform components means that no additional extensions are possible. The user defined transform is the only transform that can occur with the specified user component. + +In the UserTransformSystem, use the default query method to request write access to LocalToWorld. + +e.g. + + public class UserTransformSystem : JobComponentSystem + { + [BurstCompile] + struct UserTransform : IJobProcessComponentData + { + public void Execute(ref LocalToWorld localToWorld, [ReadOnly] ref UserComponent userComponent) + { + localToWorld.Value = ... // Assign localToWorld as needed for UserTransform + } + } + + protected override JobHandle OnUpdate(JobHandle inputDependencies) + { + var job = new UserTransform() + { + }; + return job.Schedule(this, inputDependencies); + } + } + +All other transform components which write to LocalToWorld will be ignored by the transform system where UserComponent is included. + +e.g. +If the following components are present... + +| (Entity) | +| --------------| +| LocalToWorld | +| Translation | +| Rotation | +| Scale | +| UserComponent | + +...then: + +- [TRSToLocalToWorldSystem] Will not run on this Entity +- [UserTransformSystem] Will run on this Entity + +However, unexpected behavior may result if two different systems both override LocalToWorld and both components are present. e.g. + +e.g. If there is an additional: + + [Serializable] + [WriteGroup(typeof(LocalToWorld))] + struct UserComponent2 : IComponentData + { + } + +And the equivalent system: + + public class UserTransformSystem2 : JobComponentSystem + { + [BurstCompile] + struct UserTransform2 : IJobProcessComponentData + { + public void Execute(ref LocalToWorld localToWorld, [ReadOnly] ref UserComponent2 userComponent2) + { + localToWorld.Value = ... // Assign localToWorld as needed for UserTransform + } + } + + protected override JobHandle OnUpdate(JobHandle inputDependencies) + { + var job = new UserTransform() + { + }; + return job.Schedule(this, inputDependencies); + } + } + +Then if the following components are present... + +| (Entity) | +| -------------- | +| LocalToWorld | +| Translation | +| Rotation | +| Scale | +| UserComponent | +| UserComponent2 | + +Both systems will attempt to write to LocalToWorld, likely resulting in unexpected behavior. This may not be an issue in context. + + +Extending transform components +------------------------------ + +In order to ensure that multiple overridden transform components can interact in a way which is well-defined, a WriteGroup query can be used to only explicitly match the requested components. + +e.g. If there is a: + + [Serializable] + [WriteGroup(typeof(LocalToWorld))] + struct UserComponent : IComponentData + { + } + +And a system which filters based on the WriteGroup of LocalToWorld: + + public class UserTransformSystem : JobComponentSystem + { + private ComponentGroup m_Group; + + protected override void OnCreateManager() + { + m_Group = GetComponentGroup(new EntityArchetypeQuery() + { + All = new ComponentType[] + { + ComponentType.ReadWrite(), + ComponentType.ReadOnly(), + }, + Options = EntityArchetypeQueryOptions.FilterWriteGroup + }); + } + + [BurstCompile] + struct UserTransform : IJobProcessComponentData + { + public void Execute(ref LocalToWorld localToWorld, [ReadOnly] ref UserComponent userComponent) + { + localToWorld.Value = ... // Assign localToWorld as needed for UserTransform + } + } + + protected override JobHandle OnUpdate(JobHandle inputDependencies) + { + var job = new UserTransform() + { + }; + return job.ScheduleGroup(m_Group, inputDependencies); + } + } + +m_Group in UserTransformSystem will only match the explicitly mentioned components. + +For instance, the following with match and be included in the ComponentGroup: + +| (Entity) | +| -------------- | +| LocalToWorld | +| UserComponent | + +But this will not: + +| (Entity) | +| -------------- | +| LocalToWorld | +| Translation | +| Rotation | +| Scale | +| UserComponent | + +The implicit expectation is that UserComponent is a completely orthogonal set of requirements to write to LocalToWorld, so no other (unstated) components which are in the same WriteGroup should be present. + +However, they may be explicitly supported by UserComponent systems by adding to the queries, as: + + public class UserTransformExtensionSystem : JobComponentSystem + { + private ComponentGroup m_Group; + + protected override void OnCreateManager() + { + m_Group = GetComponentGroup(new EntityArchetypeQuery() + { + All = new ComponentType[] + { + ComponentType.ReadWrite(), + ComponentType.ReadOnly(), + ComponentType.ReadOnly(), + ComponentType.ReadOnly(), + ComponentType.ReadOnly(), + }, + Options = EntityArchetypeQueryOptions.FilterWriteGroup + }); + } + + [BurstCompile] + struct UserTransform : IJobProcessComponentData + { + public void Execute(ref LocalToWorld localToWorld, [ReadOnly] ref UserComponent userComponent, + [ReadOnly] ref Translation translation, + [ReadOnly] ref Rotation rotation, + [ReadOnly] ref Scale scale) + { + localToWorld.Value = ... // Assign localToWorld as needed for UserTransform + } + } + + protected override JobHandle OnUpdate(JobHandle inputDependencies) + { + var job = new UserTransform() + { + }; + return job.ScheduleGroup(m_Group, inputDependencies); + } + } + +In the same way, if there is an additional: + + [Serializable] + [WriteGroup(typeof(LocalToWorld))] + struct UserComponent2 : IComponentData + { + } + +And there is: + +| (Entity) | +| -------------- | +| LocalToWorld | +| UserComponent | +| UserComponent2 | + +The UserTransformSystem defined above would not match, since UserComponent2 is not explicitly mentioned and it is in the LocalToWorld WriteGroup. + +However, an explicit query can be created which can resolve the case and ensure the behavior is well defined. As in: + + public class UserTransformComboSystem : JobComponentSystem + { + private ComponentGroup m_Group; + + protected override void OnCreateManager() + { + m_Group = GetComponentGroup(new EntityArchetypeQuery() + { + All = new ComponentType[] + { + ComponentType.ReadWrite(), + ComponentType.ReadOnly(), + ComponentType.ReadOnly(), + }, + Options = EntityArchetypeQueryOptions.FilterWriteGroup + }); + } + + [BurstCompile] + struct UserTransform : IJobProcessComponentData + { + public void Execute(ref LocalToWorld localToWorld, + [ReadOnly] ref UserComponent userComponent, + [ReadOnly] ref UserComponent2 userComponent2 + { + localToWorld.Value = ... // Assign localToWorld as needed for UserTransform + } + } + + protected override JobHandle OnUpdate(JobHandle inputDependencies) + { + var job = new UserTransform() + { + }; + return job.ScheduleGroup(m_Group, inputDependencies); + } + } + +Then the following systems (or equivalents): + - UserTransformSystem (LocalToWorld FilterWriteGroup:UserComponent) + - UserTransformSystem2 (LocalToWorld FilterWriteGroup:UserComponent2) + - UserTransformComboSystem (LocalToWorld FilterWriteGroup:UserComponent, UserComponent2) + +Will all run side-by-side, query and run on their respective component archetypes, and have well-defined behavior. + +----------------------------------------------- +Section 7: Relationship to Maya transform nodes +----------------------------------------------- + +For reference on Maya transform nodes, see: https://download.autodesk.com/us/maya/2010help/Nodes/transform.html + +Maya Transformation Matrix is defined as: +> matrix = SP^-1 * S * SH * SP * ST * RP^-1 * RA * R * RP * RT * T + +These can be mapped to transform components as follows: + +| Maya | Unity | +| -------------------------- | ------------------------- | +| T | Translation | +| (RT * RP * R * RA * RP^-1) | CompositeRotation | +| RT | RotationPivotTranslation | +| RP | RotationPivot | +| R | Rotation | +| RA | PostRotation | +| (ST * SP * S * SP^-1) | CompositeScale | +| ST | ScalePivotTranslation | +| SP | ScalePivot | +| SH | --- Unused --- | +| S | NonUniformScale | + diff --git a/package/Documentation~/version_numbers.md b/package/Documentation~/version_numbers.md new file mode 100755 index 000000000..927981c98 --- /dev/null +++ b/package/Documentation~/version_numbers.md @@ -0,0 +1,65 @@ +--- +uid: ecs-version-numbers +--- +# Version Numbers + +## Scope + +The purpose of version numbers (aka. generations) is the detection of potential changes. Amongst other things, they can be used to implement cheap and efficient optimization strategies, e.g. some processing might be skipped when the data it operates on is guaranteed not to have changed since last frame. + +It often happens that by performing a very quick conservative version check for a bunch of entities at once, significant performance gains can be easily obtained. + +This page lists and documents all the different version numbers used by ECS, in particular conditions that will cause them to change. + +## Preliminary Remarks + +All version numbers are 32 bits signed integers, they always increase unless they wrap around, signed integer overflow is defined behavior in C#. This means that comparing version numbers should be done using the (in)equality operator, not relational operators. + +The right way to check if VersionB is more recent than VersionA is: +`bool VersionBIsMoreRecent = (VersionB - VersionA) > 0;` + +There is usually no guarantee by how much a version number will increase. + +## EntityId.Version + +An `EntityId` is made of an index and a version number. Since indices are recycled, the version number is increased in `EntityManager` every time the entity is destroyed. If there is a mismatch in the version numbers when an `EntityId` is looked up in `EntityManager`, it means the entity referred to doesn’t exist anymore. + +> Before fetching the position of the enemy some unit is tracking via an EntityId, you can call `ComponentDataFromEntity.Exists` that uses the version number to check if the entity still exists. + +## World.Version + +The version number of a world is increased every time a manager (i.e. system) is created or destroyed. + +## EntityDataManager.GlobalVersion + +Is increased before every single (job) component system update. + +> The purpose of this version number is to be used in conjunction with `System.LastSystemVersion`. + +## System.LastSystemVersion + +Takes the value of `EntityDataManager.GlobalVersion` after every single (job) component system update. + +> The purpose of this version number is to be used in conjunction with `Chunk.ChangeVersion[]`. + +## Chunk.ChangeVersion[] (ArchetypeChunk.GetComponentVersion) + +For each component type in the archetype, this array contains the value of `EntityDataManager.GlobalVersion` at the time the component array was last accessed as writeable within this chunk. This in no way guarantees that anything has effectively changed, only that it could have potentially changed. + +Shared components can never be accessed as writeable, even if there is technically a version number stored for those too, it serves no purpose. + +When using the `[ChangedFilter]` attribute in an `IJobProcessComponentData`, the `Chunk.ChangeVersion` for that specific component is compared to `System.LastSystemVersion`, so only chunks whose component arrays have been accessed as writeable since after the system last started running will be processed. + +> If the amount of health points of a group of units is guaranteed not to have changed since the previous frame, checking if those units should update their damage model can be skipped altogether. + +## EntityManager.m_ComponentTypeOrderVersion[] + +For each non-shared component type, the version number is increased every time an iterator involving that type should become invalid. In other words, anything that might modify arrays of that type (not instances). + +> If we have static objects identified by a particular component, and a per-chunk bounding box, we know we only need to update those bounding boxes if the type order version changes for that component. + +## SharedComponentDataManager.m_SharedComponentVersion[] + +These version numbers increase when any structural change happens to the entities stored in a chunk referencing that shared component. + +> Imagine we keep a count of entities per shared component, we can rely on that version number to only redo each count if the corresponding version number changes. diff --git a/package/Documentation~/world.md b/package/Documentation~/world.md new file mode 100755 index 000000000..76e4624fa --- /dev/null +++ b/package/Documentation~/world.md @@ -0,0 +1,12 @@ +--- +uid: ecs-world +--- +# World + +A `World` owns both an [EntityManager](../api/Unity.Entities.EntityManager.html) and a set of [ComponentSystems](component_system.md). You can create as many `World` objects as you like. Commonly you would create a simulation `World` and rendering or presentation `World`. + +By default we create a single `World` when entering __Play Mode__ and populate it with all available `ComponentSystem` objects in the project, but you can disable the default `World` creation and replace it with your own code via a global define. + +- **Default World creation code** (see file: _Packages/com.unity.entities/Unity.Entities.Hybrid/Injection/DefaultWorldInitialization.cs_) +- **Automatic bootstrap entry point** (see file: _Packages/com.unity.entities/Unity.Entities.Hybrid/Injection/AutomaticWorldBootstrap.cs_) + diff --git a/package/Unity.Entities.BuildUtils/TypeUtils.cs b/package/Unity.Entities.BuildUtils/TypeUtils.cs index b7ceaebd9..7825d14d2 100755 --- a/package/Unity.Entities.BuildUtils/TypeUtils.cs +++ b/package/Unity.Entities.BuildUtils/TypeUtils.cs @@ -112,6 +112,18 @@ public static AlignAndSize AlignAndSizeOfType(TypeReference typeRef, int bits) return AlignAndSizeOfType(fixedSpecialType.MetadataType, bits); } + // Handle the case where we have a fixed buffer. Cecil will name it: "e_FixedBuffer" + if(type.ClassSize != -1 && type.Name.Contains(">e__FixedBuffer")) + { + // Fixed buffers can only be of primitive types so inspect the fields if the buffer (there should only be one) + // and determine the packing requirement for the type + if (type.Fields.Count() != 1) + throw new ArgumentException("A FixedBuffer type contains more than one field, this should not happen"); + + var fieldAlignAndSize = AlignAndSizeOfType(type.Fields[0].FieldType.MetadataType, bits); + return new AlignAndSize(fieldAlignAndSize.align, type.ClassSize); + } + if (ValueTypeAlignment[bits].ContainsKey(type)) { var sz = ValueTypeAlignment[bits][type]; diff --git a/package/Unity.Entities.Editor/EntityInspector/EntityIMGUIVisitor.cs b/package/Unity.Entities.Editor/EntityInspector/EntityIMGUIVisitor.cs index 53fd5ed11..29aa878f7 100755 --- a/package/Unity.Entities.Editor/EntityInspector/EntityIMGUIVisitor.cs +++ b/package/Unity.Entities.Editor/EntityInspector/EntityIMGUIVisitor.cs @@ -531,7 +531,7 @@ void ICustomVisit.CustomVisit(string f) DoField(Property, f, (label, val) => { - return EditorGUILayout.TextField(label, val.ToString()); + return EditorGUILayout.TextField(label, val); }); } #endregion diff --git a/package/Unity.Entities.Editor/IJobProcessComponentDataGenerator.cs b/package/Unity.Entities.Editor/IJobProcessComponentDataGenerator.cs index ca11a72b7..82d27b69d 100755 --- a/package/Unity.Entities.Editor/IJobProcessComponentDataGenerator.cs +++ b/package/Unity.Entities.Editor/IJobProcessComponentDataGenerator.cs @@ -155,6 +155,7 @@ static string GenerateFile(List combinations) //------------------------------------------------------------------------------ #if !UNITY_ZEROPLAYER +using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Jobs; using Unity.Jobs.LowLevel.Unsafe; @@ -192,6 +193,7 @@ static string Generate(bool withEntity, Combination[] combination, StringBuilder var executeParams = new StringBuilder(); var executeCallParams = new StringBuilder(); var ptrs = new StringBuilder(); + var typeLookupCache = new StringBuilder(); var interfaceName = withEntity ? "IJobProcessComponentDataWithEntity" : "IJobProcessComponentData"; @@ -201,7 +203,7 @@ static string Generate(bool withEntity, Combination[] combination, StringBuilder executeParams.Append("Entity entity, int index, "); ptrs.AppendLine ( -$" var ptrE = (Entity*)UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(false, 0));" +$" var ptrE = (Entity*)UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, false, 0, jobData.Iterator.GlobalSystemVersion));" ); } @@ -209,7 +211,15 @@ static string Generate(bool withEntity, Combination[] combination, StringBuilder { ptrs.AppendLine ( -$" var ptr{i} = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly{i} == 0, jobData.Iterator.IndexInGroup{i}));" + +$@" ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex{i}, ref typeLookupCache{i}); + var ptr{i} = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly{i} == 0, typeLookupCache{i}, jobData.Iterator.GlobalSystemVersion));" + ); + + typeLookupCache.AppendLine + ( + +$@" var typeLookupCache{i} = 0; " ); genericConstraints.Append($" where U{i} : struct, IComponentData"); @@ -255,9 +265,14 @@ public interface {interfaceName}<{genericParams}> : JobProcessComponentDataExten var isParallelFor = innerloopBatchCount != -1; Initialize(system, componentGroup, typeof(T), typeof(JobStruct_Process_{comboString}<{untypedGenericParams}>), isParallelFor, ref JobStruct_ProcessInfer_{comboString}.Cache, out fullData.Iterator); - return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, ref JobStruct_ProcessInfer_{comboString}.Cache, dependsOn, mode); - }} + + var unfilteredChunkCount = fullData.Iterator.m_Length; + var iterator = JobStruct_ProcessInfer_{comboString}.Cache.ComponentGroup.GetComponentChunkIterator(); + var prefilterHandle = ComponentChunkIterator.PreparePrefilteredChunkLists(unfilteredChunkCount, iterator.m_MatchingArchetypeList, iterator.m_Filter, dependsOn, mode, out fullData.PrefilterData, out var deferredCountData); + + return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.PrefilterData, fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, iterator.RequiresFilter(), ref JobStruct_ProcessInfer_{comboString}.Cache, deferredCountData, prefilterHandle, mode); + }} [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public interface IBaseJobProcessComponentData_{comboString} : IBaseJobProcessComponentData {{ }} @@ -269,6 +284,10 @@ private struct JobStruct_ProcessInfer_{comboString} where T : struct public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; }} [StructLayout(LayoutKind.Sequential)] @@ -278,6 +297,10 @@ internal struct JobStruct_Process_{comboString} {{ public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; [Preserve] public static IntPtr Initialize(JobType jobType) @@ -289,41 +312,35 @@ public static IntPtr Initialize(JobType jobType) public static unsafe void Execute(ref JobStruct_Process_{comboString} jobData, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex) {{ + var chunks = (ArchetypeChunk*)NativeArrayUnsafeUtility.GetUnsafePtr(jobData.PrefilterData); + var entityIndices = (int*) (chunks + jobData.Iterator.m_Length); + var chunkCount = *(entityIndices + jobData.Iterator.m_Length); + if (jobData.Iterator.m_IsParallelFor) {{ int begin, end; while (JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out begin, out end)) - ExecuteChunk(ref jobData, bufferRangePatchData, begin, end); + ExecuteChunk(ref jobData, bufferRangePatchData, begin, end, chunks, entityIndices); }} else {{ - ExecuteChunk(ref jobData, bufferRangePatchData, 0, jobData.Iterator.m_Length); + ExecuteChunk(ref jobData, bufferRangePatchData, 0, chunkCount, chunks, entityIndices); }} }} - static unsafe void ExecuteChunk(ref JobStruct_Process_{comboString} jobData, IntPtr bufferRangePatchData, int begin, int end) + static unsafe void ExecuteChunk(ref JobStruct_Process_{comboString} jobData, IntPtr bufferRangePatchData, int begin, int end, ArchetypeChunk* chunks, int* entityIndices) {{ - ref ComponentChunkIterator chunkIterator = ref jobData.Iterator.Iterator; - +{typeLookupCache} for (var blockIndex = begin; blockIndex != end; ++blockIndex) - {{ - jobData.Iterator.Iterator.MoveToChunkWithoutFiltering(blockIndex); - - var processBlock = jobData.Iterator.Iterator.MatchesFilter(); - - if (!processBlock) - continue; - - int beginIndex, endIndex; - chunkIterator.GetCurrentChunkRange(out beginIndex, out endIndex); + {{ + var chunk = chunks[blockIndex]; + int beginIndex = entityIndices[blockIndex]; + var count = chunk.Count; #if ENABLE_UNITY_COLLECTIONS_CHECKS - JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, endIndex - beginIndex); - #endif - - var count = chunkIterator.GetCurrentChunkCount(); - -{ptrs} - + JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, beginIndex + count); + #endif +{ptrs} + for (var i = 0; i != count; i++) {{ jobData.Data.Execute({executeCallParams}); diff --git a/package/Unity.Entities.Hybrid.Tests/ComponentGroupTransformAccessArrayTests.cs b/package/Unity.Entities.Hybrid.Tests/ComponentGroupTransformAccessArrayTests.cs index 70aa5a52e..fec5c1dab 100755 --- a/package/Unity.Entities.Hybrid.Tests/ComponentGroupTransformAccessArrayTests.cs +++ b/package/Unity.Entities.Hybrid.Tests/ComponentGroupTransformAccessArrayTests.cs @@ -34,6 +34,7 @@ public struct TransformAccessArrayTestTag : IComponentData { } [DisallowMultipleComponent] + [UnityEngine.AddComponentMenu("Hidden/DontUse")] public class TransformAccessArrayTestTagProxy : ComponentDataProxy { } [Test] diff --git a/package/Unity.Entities.Hybrid.Tests/Runtime/EntityManagerTests.cs b/package/Unity.Entities.Hybrid.Tests/Runtime/EntityManagerTests.cs index 7b8ba68a7..1f088248b 100755 --- a/package/Unity.Entities.Hybrid.Tests/Runtime/EntityManagerTests.cs +++ b/package/Unity.Entities.Hybrid.Tests/Runtime/EntityManagerTests.cs @@ -4,8 +4,10 @@ namespace Unity.Entities.Tests { [DisallowMultipleComponent] + [UnityEngine.AddComponentMenu("Hidden/DontUse")] public class EcsFooTestProxy : ComponentDataProxy { } [DisallowMultipleComponent] + [UnityEngine.AddComponentMenu("Hidden/DontUse")] public class EcsTestProxy : ComponentDataProxy { } class EntityManagerTests : ECSTestsFixture diff --git a/package/Unity.Entities.Hybrid.Tests/TypeUtility_UnitTests.cs b/package/Unity.Entities.Hybrid.Tests/TypeUtility_UnitTests.cs index 6bfbd7ef8..6c494227b 100755 --- a/package/Unity.Entities.Hybrid.Tests/TypeUtility_UnitTests.cs +++ b/package/Unity.Entities.Hybrid.Tests/TypeUtility_UnitTests.cs @@ -7,10 +7,14 @@ namespace Unity.Entities.Tests public class TypeUtility_UnitTests { struct Data : IComponentData {} + [DisallowMultipleComponent] + [UnityEngine.AddComponentMenu("Hidden/DontUse")] class DataProxy : ComponentDataProxy {} struct SharedData : ISharedComponentData {} + + [UnityEngine.AddComponentMenu("Hidden/DontUse")] class SharedDataProxy : SharedComponentDataProxy {} struct BufferElement : IBufferElementData {} diff --git a/package/Unity.Entities.Hybrid/ConvertToEntity.cs b/package/Unity.Entities.Hybrid/ConvertToEntity.cs index d3ac1c679..04887fdcf 100755 --- a/package/Unity.Entities.Hybrid/ConvertToEntity.cs +++ b/package/Unity.Entities.Hybrid/ConvertToEntity.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Reflection; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using UnityEditor; @@ -7,37 +8,6 @@ namespace Unity.Entities { - -#if false - //@TODO: * SubScene conversion error if it has ConvertAndInjectGameObject - // * Error when ComponentDataWrapper without any converter or game object entity on top - // * Should there be a hierarchical injection mode? - [CustomEditor(typeof(ConvertToEntity))] - public class ConvertToEntityEditor : Editor - { - public override void OnInspectorGUI() - { - base.OnInspectorGUI(); - - ConvertToEntity convertToEntity = (ConvertToEntity)target; - - if (convertToEntity.gameObject.scene.isSubScene) - { - if (convertToEntity.ConversionMode == ConvertToEntity.Mode.ConvertAndInjectGameObject) - EditorGUILayout.HelpBox($"The SubScene will be fully converted, so this mode has no effect", MessageType.Warning, true); - else - EditorGUILayout.HelpBox($"The SubScene will be fully converted, so this mode has no effect", MessageType.Info, true); - return; - } - - if (convertToEntity.ConversionMode == ConvertToEntity.Mode.ConvertAndInjectGameObject) - { - EditorGUILayout.HelpBox($"ConvertToEntity.ConvertAndDestroy is enabled on a parent.\nThe parent game objects will be destroyed and this game object will be attached to the entity.", MessageType.Info, true); - } - } - } -#endif - public class ConvertToEntity : MonoBehaviour { public enum Mode diff --git a/package/Unity.Entities.Hybrid/GameObjectConversion/ComponentDataProxyToEntitySystem.cs b/package/Unity.Entities.Hybrid/GameObjectConversion/ComponentDataProxyToEntitySystem.cs index ee08df765..f8bd8bb17 100755 --- a/package/Unity.Entities.Hybrid/GameObjectConversion/ComponentDataProxyToEntitySystem.cs +++ b/package/Unity.Entities.Hybrid/GameObjectConversion/ComponentDataProxyToEntitySystem.cs @@ -6,9 +6,9 @@ class ComponentDataProxyToEntitySystem : GameObjectConversionSystem { protected override void OnUpdate() { - ForEach((Transform transform) => + Entities.ForEach((Transform transform) => { GameObjectEntity.CopyAllComponentsToEntity(transform.gameObject, DstEntityManager, GetPrimaryEntity(transform)); }); } -} \ No newline at end of file +} diff --git a/package/Unity.Entities.Hybrid/GameObjectConversion/ConvertGameObjectToEntitySystem.cs b/package/Unity.Entities.Hybrid/GameObjectConversion/ConvertGameObjectToEntitySystem.cs index 5fe2c3fe4..42750611d 100755 --- a/package/Unity.Entities.Hybrid/GameObjectConversion/ConvertGameObjectToEntitySystem.cs +++ b/package/Unity.Entities.Hybrid/GameObjectConversion/ConvertGameObjectToEntitySystem.cs @@ -2,55 +2,61 @@ using Unity.Entities; using UnityEngine; - -public interface IConvertGameObjectToEntity +namespace Unity.Entities { - void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem); -} - -public interface IDeclareReferencedPrefabs -{ - void DeclareReferencedPrefabs(List gameObjects); -} + public interface IConvertGameObjectToEntity + { + void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem); + } + public interface IDeclareReferencedPrefabs + { + void DeclareReferencedPrefabs(List referencedPrefabs); + } -class ConvertGameObjectToEntitySystem : GameObjectConversionSystem -{ - protected override void OnUpdate() + public class RequiresEntityConversionAttribute : System.Attribute { - var convertibles = new List(); + + } - ForEach((Transform transform) => + class ConvertGameObjectToEntitySystem : GameObjectConversionSystem + { + protected override void OnUpdate() { - transform.GetComponents(convertibles); + var convertibles = new List(); - foreach (var c in convertibles) + Entities.ForEach((Transform transform) => { - var entity = GetPrimaryEntity((Component) c); - c.Convert(entity, DstEntityManager, this); - } - }); + transform.GetComponents(convertibles); + + foreach (var c in convertibles) + { + var entity = GetPrimaryEntity((Component) c); + c.Convert(entity, DstEntityManager, this); + } + }); + } } -} -[DisableAutoCreation] -class ConvertGameObjectToEntitySystemDeclarePrefabs : GameObjectConversionSystem -{ - protected override void OnUpdate() - { - //@TODO: Support prefab to prefab referencing recursion... - var declares = new List(); - var prefabs = new List(); + [DisableAutoCreation] + class ConvertGameObjectToEntitySystemDeclarePrefabs : GameObjectConversionSystem + { + protected override void OnUpdate() + { + //@TODO: Support prefab to prefab referencing recursion... + var declares = new List(); + var prefabs = new List(); - ForEach((Transform transform) => - { - transform.GetComponents(declares); + Entities.ForEach((Transform transform) => + { + transform.GetComponents(declares); - foreach (var c in declares) - c.DeclareReferencedPrefabs(prefabs); - }); + foreach (var c in declares) + c.DeclareReferencedPrefabs(prefabs); + }); - foreach (var p in prefabs) - AddReferencedPrefab(p); + foreach (var p in prefabs) + AddReferencedPrefab(p); + } } } diff --git a/package/Unity.Entities.Hybrid/PlayerLoopDisableManager.cs b/package/Unity.Entities.Hybrid/PlayerLoopDisableManager.cs index 4ad64d007..f8a86a31d 100755 --- a/package/Unity.Entities.Hybrid/PlayerLoopDisableManager.cs +++ b/package/Unity.Entities.Hybrid/PlayerLoopDisableManager.cs @@ -1,8 +1,10 @@ -using UnityEngine; +using UnityEditor; +using UnityEngine; namespace Unity.Entities { [ExecuteAlways] + [AddComponentMenu("Hidden/Disabled")] class PlayerLoopDisableManager : MonoBehaviour { public bool IsActive; diff --git a/package/Unity.Entities.Hybrid/SceneSectionComponent.cs b/package/Unity.Entities.Hybrid/SceneSectionComponent.cs index 530091c82..1d1f0e5ae 100755 --- a/package/Unity.Entities.Hybrid/SceneSectionComponent.cs +++ b/package/Unity.Entities.Hybrid/SceneSectionComponent.cs @@ -1,7 +1,9 @@ -using UnityEngine; +using Unity.Entities; +using UnityEngine; using UnityEngine.Serialization; using Hash128 = Unity.Entities.Hash128; +[RequiresEntityConversion] public class SceneSectionComponent : MonoBehaviour { [FormerlySerializedAs("SectionId")] diff --git a/package/Unity.Entities.Hybrid/SceneSectionProxy.cs b/package/Unity.Entities.Hybrid/SceneSectionProxy.cs index 6d739e777..2aaf897ad 100755 --- a/package/Unity.Entities.Hybrid/SceneSectionProxy.cs +++ b/package/Unity.Entities.Hybrid/SceneSectionProxy.cs @@ -3,6 +3,7 @@ using UnityEngine.Serialization; using Hash128 = Unity.Entities.Hash128; +[UnityEngine.AddComponentMenu("Hidden/DontUse")] public class SceneSectionProxy : SharedComponentDataProxy { } diff --git a/package/Unity.Entities.Hybrid/StaticOptimizeEntity.cs b/package/Unity.Entities.Hybrid/StaticOptimizeEntity.cs index 1e30d51f3..c94e5789c 100755 --- a/package/Unity.Entities.Hybrid/StaticOptimizeEntity.cs +++ b/package/Unity.Entities.Hybrid/StaticOptimizeEntity.cs @@ -9,6 +9,7 @@ namespace Unity.Entities { [DisallowMultipleComponent] + [RequiresEntityConversion] public class StaticOptimizeEntity : MonoBehaviour { } diff --git a/package/Unity.Entities.PerformanceTests/Unity.Entities.PerformanceTests.asmdef b/package/Unity.Entities.PerformanceTests/Unity.Entities.PerformanceTests.asmdef index d139c22e4..a7db2d6fe 100755 --- a/package/Unity.Entities.PerformanceTests/Unity.Entities.PerformanceTests.asmdef +++ b/package/Unity.Entities.PerformanceTests/Unity.Entities.PerformanceTests.asmdef @@ -23,5 +23,6 @@ "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, - "defineConstraints": [] + "defineConstraints": [], + "versionDefines": [] } \ No newline at end of file diff --git a/package/Unity.Entities.Tests/ArchetypeChunkArrayTests.cs b/package/Unity.Entities.Tests/ArchetypeChunkArrayTests.cs index 593a031aa..476c8c69d 100755 --- a/package/Unity.Entities.Tests/ArchetypeChunkArrayTests.cs +++ b/package/Unity.Entities.Tests/ArchetypeChunkArrayTests.cs @@ -80,7 +80,7 @@ public void Execute(int chunkIndex) } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void ACS_WriteMixed() { CreateMixedEntities(64); @@ -178,7 +178,7 @@ public void Execute(int chunkIndex) } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void ACS_WriteMixedFilterShared() { CreateMixedEntities(64); @@ -282,7 +282,7 @@ public void ACS_WriteMixedFilterShared() } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void ACS_Buffers() { CreateEntities(128); @@ -360,7 +360,7 @@ protected override void OnUpdate() } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void ACS_BufferHas() { CreateEntities(128); @@ -387,7 +387,7 @@ public void ACS_BufferHas() } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void ACS_BufferVersions() { CreateEntities(128); @@ -430,7 +430,7 @@ public void ACS_BufferVersions() } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void ACS_BuffersRO() { CreateEntities(128); @@ -450,7 +450,7 @@ public void ACS_BuffersRO() } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void ACS_ChunkArchetypeTypesMatch() { var entityTypes = new ComponentType[] {typeof(EcsTestData), typeof(EcsTestSharedComp), typeof(EcsIntElement)}; @@ -481,7 +481,7 @@ public void ACS_ChunkArchetypeTypesMatch() struct Max3Capacity : IComponentData { } [Test] - [TinyFixme] // MaximumChunkCapacityAttribute not supported in Tiny? + [StandaloneFixme] // MaximumChunkCapacityAttribute not supported in Tiny? public void MaximumChunkCapacityIsRespected() { for (int i = 0; i != 4; i++) diff --git a/package/Unity.Entities.Tests/BlobificationTests.cs b/package/Unity.Entities.Tests/BlobificationTests.cs index 811d39b03..b681d77b5 100755 --- a/package/Unity.Entities.Tests/BlobificationTests.cs +++ b/package/Unity.Entities.Tests/BlobificationTests.cs @@ -7,7 +7,7 @@ using Unity.Entities; using Unity.Entities.Tests; -[TinyFixme] // Should this work for Tiny? +[StandaloneFixme] // Should this work for Tiny? public class BlobTests : ECSTestsFixture { //@TODO: Test Prevent NativeArray and other containers inside of Blob data @@ -140,6 +140,7 @@ public unsafe void Execute(ref ComponentWithBlobData component) } } + [DisableAutoCreation] class DummySystem : JobComponentSystem { protected override JobHandle OnUpdate(JobHandle inHandle) @@ -180,6 +181,21 @@ public void DestroyedBlobAccessFromEntityJobThrows() jobHandle.Complete (); } + [Test] + public void BlobAssetReferenceIsComparable() + { + var blob1 = ConstructBlobData(); + var blob2 = ConstructBlobData(); + var blobNull = new BlobAssetReference(); + + var temp1 = blob1; + + Assert.IsTrue(blob1 != blob2); + Assert.IsTrue(blob1 != BlobAssetReference.Null); + Assert.IsTrue(blobNull == BlobAssetReference.Null); + Assert.IsTrue(blob1 == temp1); + Assert.IsTrue(blob2 != temp1); + } BlobAssetReference CreateBlobEntities() { diff --git a/package/Unity.Entities.Tests/BufferElementDataSystemStateInstantiateTests.cs b/package/Unity.Entities.Tests/BufferElementDataSystemStateInstantiateTests.cs index b4d6b12d2..9dc84222c 100755 --- a/package/Unity.Entities.Tests/BufferElementDataSystemStateInstantiateTests.cs +++ b/package/Unity.Entities.Tests/BufferElementDataSystemStateInstantiateTests.cs @@ -5,7 +5,7 @@ namespace Unity.Entities.Tests public class BufferElementDataSystemStateInstantiateTests : ECSTestsFixture { [Test] - [TinyFixme] // Real issue + [StandaloneFixme] // Real issue public unsafe void InstantiateDoesNotCreatesCopy() { var original = m_Manager.CreateEntity(typeof(EcsIntStateElement)); diff --git a/package/Unity.Entities.Tests/BufferElementDataSystemStateTests.cs b/package/Unity.Entities.Tests/BufferElementDataSystemStateTests.cs index 6969a7bba..4a683be91 100755 --- a/package/Unity.Entities.Tests/BufferElementDataSystemStateTests.cs +++ b/package/Unity.Entities.Tests/BufferElementDataSystemStateTests.cs @@ -49,26 +49,14 @@ public void BufferComponentTypeCreationWorks() [Test] public void CreateEntityWithIntThrows() { - Assert.Throws< -#if UNITY_CSHARP_TINY - System.InvalidOperationException -#else - System.ArgumentException -#endif - >(() => { m_Manager.CreateEntity(typeof(int));}); + Assert.Throws(() => { m_Manager.CreateEntity(typeof(int));}); } [Test] public void AddComponentWithIntThrows() { var entity = m_Manager.CreateEntity(); - Assert.Throws< -#if UNITY_CSHARP_TINY - System.InvalidOperationException -#else - System.ArgumentException -#endif - >(() => { m_Manager.AddComponent(entity, ComponentType.ReadWrite()); }); + Assert.Throws(() => { m_Manager.AddComponent(entity, ComponentType.ReadWrite()); }); } [Test] @@ -367,7 +355,7 @@ public void BufferFromEntityWorks() } [Test] - [TinyFixme] // Real issue - Safety & Sentinel should be invalid after Destroy + [StandaloneFixme] // Real issue - Safety & Sentinel should be invalid after Destroy public void OutOfBoundsAccessThrows() { var entityInt = m_Manager.CreateEntity(typeof(EcsIntStateElement)); @@ -382,7 +370,7 @@ public void OutOfBoundsAccessThrows() } [Test] - [TinyFixme] // Real issue - Safety & Sentinel should be invalid after Destroy + [StandaloneFixme] // Real issue - Safety & Sentinel should be invalid after Destroy public void UseAfterStructuralChangeThrows() { var entityInt = m_Manager.CreateEntity(typeof(EcsIntStateElement)); @@ -396,7 +384,7 @@ public void UseAfterStructuralChangeThrows() } [Test] - [TinyFixme] // Real issue - Safety & Sentinel should be invalid after Destroy + [StandaloneFixme] // Real issue - Safety & Sentinel should be invalid after Destroy public void UseAfterStructuralChangeThrows2() { var entityInt = m_Manager.CreateEntity(typeof(EcsIntStateElement)); @@ -411,7 +399,7 @@ public void UseAfterStructuralChangeThrows2() } [Test] - [TinyFixme] // Real issue - Safety & Sentinel should be invalid after Add on structural change + [StandaloneFixme] // Real issue - Safety & Sentinel should be invalid after Add on structural change public void UseAfterStructuralChangeThrows3() { var entityInt = m_Manager.CreateEntity(typeof(EcsIntStateElement)); @@ -423,7 +411,7 @@ public void UseAfterStructuralChangeThrows3() [Test] - [TinyFixme] // Real issue - Safety & Sentinel should be invalid after Add on structural change + [StandaloneFixme] // Real issue - Safety & Sentinel should be invalid after Add on structural change public void WritingReadOnlyThrows() { var entityInt = m_Manager.CreateEntity(typeof(EcsIntStateElement)); @@ -495,7 +483,7 @@ protected override JobHandle OnUpdate(JobHandle inputDeps) } [Test] - [TinyFixme] // IJob - InjectionTestSystem : JobComponentSystem + [StandaloneFixme] // IJob - InjectionTestSystem : JobComponentSystem public void Injection() { var system = World.Active.GetOrCreateManager(); @@ -578,7 +566,7 @@ public void NoCapacitySpecifiedWorks() } [Test] - [TinyFixme] // Real issue : buffer.AsNativeArray should invalidate the Safety + [StandaloneFixme] // Real issue : buffer.AsNativeArray should invalidate the Safety public void ArrayInvalidationWorks() { var original = m_Manager.CreateEntity(typeof(EcsIntStateElement)); @@ -599,7 +587,7 @@ public void ArrayInvalidationWorks() } [Test] - [TinyFixme] // Real issue : buffer.AsNativeArray should invalidate the Safety + [StandaloneFixme] // Real issue : buffer.AsNativeArray should invalidate the Safety public void ArrayInvalidationHappensForAllInstances() { var e0 = m_Manager.CreateEntity(typeof(EcsIntStateElement)); @@ -650,7 +638,7 @@ public void Execute() } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void BufferInvalidationNotPossibleWhenArraysAreGivenToJobs() { var original = m_Manager.CreateEntity(typeof(EcsIntStateElement)); @@ -685,7 +673,7 @@ public void Execute(ArchetypeChunk chunk, int chunkIndex, int entityOffset) } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void ReadWriteDynamicBuffer() { var original = m_Manager.CreateEntity(typeof(EcsIntStateElement)); @@ -742,7 +730,7 @@ public void ReadOnlyDynamicBufferImpl(bool readOnlyType) } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void ReadOnlyDynamicBufferReadOnly() { ReadOnlyDynamicBufferImpl(true); @@ -765,7 +753,7 @@ public void Execute() } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void BufferInvalidationNotPossibleWhenBuffersAreGivenToJobs() { var original = m_Manager.CreateEntity(typeof(EcsIntStateElement)); @@ -797,7 +785,7 @@ public void Execute() } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void NativeArrayInJobReadOnly() { var original = m_Manager.CreateEntity(typeof(EcsIntStateElement)); diff --git a/package/Unity.Entities.Tests/BufferElementDataTests.cs b/package/Unity.Entities.Tests/BufferElementDataTests.cs index f2b9aa568..7f5ecd9b4 100755 --- a/package/Unity.Entities.Tests/BufferElementDataTests.cs +++ b/package/Unity.Entities.Tests/BufferElementDataTests.cs @@ -49,26 +49,14 @@ public void BufferComponentTypeCreationWorks() [Test] public void CreateEntityWithIntThrows() { - Assert.Throws< -#if !UNITY_CSHARP_TINY - System.ArgumentException -#else - System.InvalidOperationException -#endif - >(() => { m_Manager.CreateEntity(typeof(int));}); + Assert.Throws(() => { m_Manager.CreateEntity(typeof(int));}); } [Test] public void AddComponentWithIntThrows() { var entity = m_Manager.CreateEntity(); - Assert.Throws< -#if !UNITY_CSHARP_TINY - System.ArgumentException -#else - System.InvalidOperationException -#endif - >(() => { m_Manager.AddComponent(entity, ComponentType.ReadWrite()); }); + Assert.Throws(() => { m_Manager.AddComponent(entity, ComponentType.ReadWrite()); }); } [Test] @@ -367,7 +355,7 @@ public void BufferFromEntityWorks() } [Test] - [TinyFixme] // Real problem DestroyEntity should invalidate the buffers. Not sure about array bounds checking in this test + [StandaloneFixme] // Real problem DestroyEntity should invalidate the buffers. Not sure about array bounds checking in this test public void OutOfBoundsAccessThrows() { var entityInt = m_Manager.CreateEntity(typeof(EcsIntElement)); @@ -382,7 +370,7 @@ public void OutOfBoundsAccessThrows() } [Test] - [TinyFixme] // Real problem DestroyEntity should invalidate the buffers + [StandaloneFixme] // Real problem DestroyEntity should invalidate the buffers public void UseAfterStructuralChangeThrows() { var entityInt = m_Manager.CreateEntity(typeof(EcsIntElement)); @@ -396,7 +384,7 @@ public void UseAfterStructuralChangeThrows() } [Test] - [TinyFixme] // Real problem DestroyEntity should invalidate the buffers + [StandaloneFixme] // Real problem DestroyEntity should invalidate the buffers public void UseAfterStructuralChangeThrows2() { var entityInt = m_Manager.CreateEntity(typeof(EcsIntElement)); @@ -411,7 +399,7 @@ public void UseAfterStructuralChangeThrows2() } [Test] - [TinyFixme] // Real problem structural change should invalidate the buffers + [StandaloneFixme] // Real problem structural change should invalidate the buffers public void UseAfterStructuralChangeThrows3() { var entityInt = m_Manager.CreateEntity(typeof(EcsIntElement)); @@ -423,7 +411,7 @@ public void UseAfterStructuralChangeThrows3() [Test] - [TinyFixme] // Real problem structural change should invalidate the buffers + [StandaloneFixme] // Real problem structural change should invalidate the buffers public void WritingReadOnlyThrows() { var entityInt = m_Manager.CreateEntity(typeof(EcsIntElement)); @@ -495,7 +483,7 @@ protected override JobHandle OnUpdate(JobHandle inputDeps) } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void Injection() { var system = World.Active.GetOrCreateManager(); @@ -578,7 +566,7 @@ public void NoCapacitySpecifiedWorks() } [Test] - [TinyFixme] // Real problem structural change should invalidate the buffers + [StandaloneFixme] // Real problem structural change should invalidate the buffers public void ArrayInvalidationWorks() { var original = m_Manager.CreateEntity(typeof(EcsIntElement)); @@ -600,7 +588,7 @@ public void ArrayInvalidationWorks() } [Test] - [TinyFixme] // Real problem structural change should invalidate the buffers + [StandaloneFixme] // Real problem structural change should invalidate the buffers public void ArrayInvalidationHappensForAllInstances() { var e0 = m_Manager.CreateEntity(typeof(EcsIntElement)); @@ -651,7 +639,7 @@ public void Execute() } [Test] - [TinyFixme] // Real problem structural change should invalidate the buffers && IJob + [StandaloneFixme] // Real problem structural change should invalidate the buffers && IJob public void BufferInvalidationNotPossibleWhenArraysAreGivenToJobs() { var original = m_Manager.CreateEntity(typeof(EcsIntElement)); @@ -686,7 +674,7 @@ public void Execute(ArchetypeChunk chunk, int chunkIndex, int entityOffset) } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void ReadWriteDynamicBuffer() { var original = m_Manager.CreateEntity(typeof(EcsIntElement)); @@ -743,7 +731,7 @@ public void ReadOnlyDynamicBufferImpl(bool readOnlyType) } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void ReadOnlyDynamicBufferReadOnly() { ReadOnlyDynamicBufferImpl(true); @@ -766,7 +754,7 @@ public void Execute() } [Test] - [TinyFixme] // IJob + Safety Handles + [StandaloneFixme] // IJob + Safety Handles public void BufferInvalidationNotPossibleWhenBuffersAreGivenToJobs() { var original = m_Manager.CreateEntity(typeof(EcsIntElement)); @@ -798,7 +786,7 @@ public void Execute() } [Test] - [TinyFixme] // IJob + Safety Handles + [StandaloneFixme] // IJob + Safety Handles public void NativeArrayInJobReadOnly() { var original = m_Manager.CreateEntity(typeof(EcsIntElement)); diff --git a/package/Unity.Entities.Tests/ChangeVersionTests.cs b/package/Unity.Entities.Tests/ChangeVersionTests.cs index b9a522618..108f8319f 100755 --- a/package/Unity.Entities.Tests/ChangeVersionTests.cs +++ b/package/Unity.Entities.Tests/ChangeVersionTests.cs @@ -136,7 +136,7 @@ public bool AllEcsTestDataChunksChanged() } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void CHG_IncrementedOnInjectionInJob() { var entity0 = m_Manager.CreateEntity(typeof(EcsTestData), typeof(EcsTestData2)); @@ -160,7 +160,7 @@ public void CHG_IncrementedOnInjectionInJob() } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void CHG_IncrementedOnInjection() { var entity0 = m_Manager.CreateEntity(typeof(EcsTestData), typeof(EcsTestData2)); diff --git a/package/Unity.Entities.Tests/ChunkChangeVersionTests.cs b/package/Unity.Entities.Tests/ChunkChangeVersionTests.cs index 23e565b26..f91e88ef3 100755 --- a/package/Unity.Entities.Tests/ChunkChangeVersionTests.cs +++ b/package/Unity.Entities.Tests/ChunkChangeVersionTests.cs @@ -143,6 +143,7 @@ public void ModifyingBufferComponentMarksOnlySetTypeAsChanged() } [Test] + [StandaloneFixme] // ISharedComponentData public void AddSharedComponentMarksSrcAndDestChunkAsChanged() { var e0 = m_Manager.CreateEntity(typeof(EcsTestData), typeof(EcsTestData2)); @@ -157,6 +158,7 @@ public void AddSharedComponentMarksSrcAndDestChunkAsChanged() } [Test] + [StandaloneFixme] // ISharedComponentData public void SetSharedComponentMarksSrcAndDestChunkAsChanged() { var e0 = m_Manager.CreateEntity(typeof(EcsTestData), typeof(EcsTestSharedComp)); @@ -170,6 +172,7 @@ public void SetSharedComponentMarksSrcAndDestChunkAsChanged() } [Test] + [StandaloneFixme] // ISharedComponentData public void SwapComponentsMarksSrcAndDestChunkAsChanged() { var e0 = m_Manager.CreateEntity(typeof(EcsTestData), typeof(EcsTestSharedComp)); diff --git a/package/Unity.Entities.Tests/ChunkComponentTests.cs b/package/Unity.Entities.Tests/ChunkComponentTests.cs index 71c8a8c40..f35f67a50 100755 --- a/package/Unity.Entities.Tests/ChunkComponentTests.cs +++ b/package/Unity.Entities.Tests/ChunkComponentTests.cs @@ -166,7 +166,7 @@ public void ProcessMetaChunkComponent() #if !UNITY_ZEROPLAYER [DisableAutoCreation] [UpdateInGroup(typeof(PresentationSystemGroup))] - [TinyFixme] + [StandaloneFixme] private class ChunkBoundsUpdateSystem : JobComponentSystem { struct UpdateChunkBoundsJob : IJobProcessComponentData @@ -194,7 +194,7 @@ protected override JobHandle OnUpdate(JobHandle inputDeps) } [Test] - [TinyFixme] + [StandaloneFixme] public void SystemProcessMetaChunkComponent() { var chunkBoundsUpdateSystem = World.GetOrCreateManager (); diff --git a/package/Unity.Entities.Tests/ComponentGroupArrayTests.cs b/package/Unity.Entities.Tests/ComponentGroupArrayTests.cs index 0f711a89b..2caa057ac 100755 --- a/package/Unity.Entities.Tests/ComponentGroupArrayTests.cs +++ b/package/Unity.Entities.Tests/ComponentGroupArrayTests.cs @@ -59,7 +59,7 @@ unsafe struct TestEntityReadOnly #pragma warning restore 649 [Test] - [TinyFixme] + [StandaloneFixme] public void ComponentAccessAfterScheduledJobThrowsEntityArray() { m_Manager.CreateEntity(typeof(EcsTestData), typeof(EcsTestData2)); @@ -76,7 +76,7 @@ public void ComponentAccessAfterScheduledJobThrowsEntityArray() } [Test] - [TinyFixme] + [StandaloneFixme] public void ComponentGroupArrayJobScheduleDetectsWriteDependency() { var entity = m_Manager.CreateEntity(typeof(EcsTestData), typeof(EcsTestData2)); @@ -92,7 +92,7 @@ public void ComponentGroupArrayJobScheduleDetectsWriteDependency() } [Test] - [TinyFixme] + [StandaloneFixme] public void ComponentGroupArrayJobScheduleReadOnlyParallelIsAllowed() { var entity = m_Manager.CreateEntity(typeof(EcsTestData), typeof(EcsTestData2)); @@ -116,7 +116,7 @@ unsafe struct TestEntitySub2 } [Test] - [TinyFixme] + [StandaloneFixme] public void ComponentGroupArrayExclude() { m_Manager.CreateEntity(typeof(EcsTestData), typeof(EcsTestData2)); diff --git a/package/Unity.Entities.Tests/ComponentGroupDelta.cs b/package/Unity.Entities.Tests/ComponentGroupDelta.cs index f4eff7a62..e523c57db 100755 --- a/package/Unity.Entities.Tests/ComponentGroupDelta.cs +++ b/package/Unity.Entities.Tests/ComponentGroupDelta.cs @@ -47,7 +47,7 @@ public void UpdateExpectedResults(Entity[] expected) [Test] - [TinyFixme] + [StandaloneFixme] public void CreateEntityTriggersChange() { Entity[] entity = new Entity[] { m_Manager.CreateEntity(typeof(EcsTestData)) }; @@ -136,7 +136,7 @@ void GetValue(ChangeMode mode) } [Test] - [TinyFixme] + [StandaloneFixme] public void ChangeEntity([Values]ChangeMode mode) { var entity0 = m_Manager.CreateEntity(typeof(EcsTestData)); @@ -172,7 +172,7 @@ public void ChangeEntity([Values]ChangeMode mode) } [Test] - [TinyFixme] + [StandaloneFixme] public void GetEntityDataDoesNotChange([Values]ChangeMode mode) { var entity0 = m_Manager.CreateEntity(typeof(EcsTestData)); @@ -191,7 +191,7 @@ public void GetEntityDataDoesNotChange([Values]ChangeMode mode) } [Test] - [TinyFixme] + [StandaloneFixme] public void ChangeEntityWrap() { m_Manager.Debug.SetGlobalSystemVersion(uint.MaxValue-3); @@ -210,7 +210,7 @@ public void ChangeEntityWrap() } [Test] - [TinyFixme] + [StandaloneFixme] public void NoChangeEntityWrap() { m_Manager.Debug.SetGlobalSystemVersion(uint.MaxValue - 3); @@ -244,7 +244,7 @@ protected override JobHandle OnUpdate(JobHandle deps) [Test] - [TinyFixme] + [StandaloneFixme] public void IJobProcessComponentDeltaWorks() { var entity0 = m_Manager.CreateEntity(typeof(EcsTestData), typeof(EcsTestData2), typeof(EcsTestData3)); @@ -291,7 +291,7 @@ protected override void OnUpdate() } [Test] - [TinyFixme] + [StandaloneFixme] public void IJobProcessComponentDeltaWorksWhenUsingRun() { var entity0 = m_Manager.CreateEntity(typeof(EcsTestData), typeof(EcsTestData2), typeof(EcsTestData3)); @@ -320,7 +320,7 @@ public void IJobProcessComponentDeltaWorksWhenUsingRun() #if false [Test] - [TinyFixme] + [StandaloneFixme] public void IJobProcessComponentDeltaWorksWhenSetSharedComponent() { var entity0 = m_Manager.CreateEntity(typeof(EcsTestData), typeof(EcsTestData2), typeof(EcsTestData3), typeof(EcsTestSharedComp)); @@ -394,7 +394,7 @@ protected override JobHandle OnUpdate(JobHandle deps) } [Test] - [TinyFixme] + [StandaloneFixme] public void ChangedFilterJobAfterAnotherJob1Comp() { var archetype = m_Manager.CreateArchetype(typeof(EcsTestData), typeof(EcsTestSharedComp)); @@ -517,7 +517,7 @@ protected override JobHandle OnUpdate(JobHandle deps) } [Test] - [TinyFixme] + [StandaloneFixme] public void ChangedFilterJobAfterAnotherJob2Comp([Values]DeltaModifyComponentSystem2Comp.Variant variant) { var archetype = m_Manager.CreateArchetype(typeof(EcsTestData), typeof(EcsTestData2), typeof(EcsTestSharedComp)); diff --git a/package/Unity.Entities.Tests/ComponentGroupTests.cs b/package/Unity.Entities.Tests/ComponentGroupTests.cs index b4ecb076f..fde05527b 100755 --- a/package/Unity.Entities.Tests/ComponentGroupTests.cs +++ b/package/Unity.Entities.Tests/ComponentGroupTests.cs @@ -2,6 +2,8 @@ using System.Linq; using NUnit.Framework; using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; +using Unity.Jobs; namespace Unity.Entities.Tests { @@ -65,7 +67,7 @@ void SetShared(Entity e, int i) } [Test] - [TinyFixme] // ISharedComponent + [StandaloneFixme] // ISharedComponentData public void CreateArchetypeChunkArray_FiltersSharedComponents() { var archetype1 = m_Manager.CreateArchetype(typeof(EcsTestData), typeof(EcsTestSharedComp)); @@ -101,7 +103,7 @@ void SetShared(Entity e, int i, int j) } [Test] - [TinyFixme] // ISharedComponent + [StandaloneFixme] // ISharedComponentData public void CreateArchetypeChunkArray_FiltersTwoSharedComponents() { var archetype1 = m_Manager.CreateArchetype(typeof(EcsTestData), typeof(EcsTestSharedComp), typeof(EcsTestSharedComp2)); @@ -267,5 +269,89 @@ public void TestIssue1098() // NB: EcsTestData != EcsTestData2 Assert.Throws(() => group.ToComponentDataArray(Allocator.TempJob)); } + +#if !UNITY_ZEROPLAYER + + [DisableAutoCreation] + [AlwaysUpdateSystem] + public class WriteEcsTestDataSystem : JobComponentSystem + { + private struct WriteJob : IJobProcessComponentData + { + public void Execute(ref EcsTestData c0) {} + } + + protected override JobHandle OnUpdate(JobHandle input) + { + var job = new WriteJob() {}; + return job.Schedule(this, input); + } + } + + [Test] + public void CreateArchetypeChunkArray_SyncsChangeFilterTypes() + { + var group = m_Manager.CreateComponentGroup(typeof(EcsTestData)); + group.SetFilterChanged(typeof(EcsTestData)); + var ws1 = World.GetOrCreateManager(); + ws1.Update(); + var safetyHandle = m_Manager.ComponentJobSafetyManager.GetSafetyHandle(TypeManager.GetTypeIndex(), false); + + Assert.Throws(() => AtomicSafetyHandle.CheckWriteAndThrow(safetyHandle)); + var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob); + AtomicSafetyHandle.CheckWriteAndThrow(safetyHandle); + + chunks.Dispose(); + group.Dispose(); + } + + [Test] + public void CalculateLength_SyncsChangeFilterTypes() + { + var group = m_Manager.CreateComponentGroup(typeof(EcsTestData)); + group.SetFilterChanged(typeof(EcsTestData)); + var ws1 = World.GetOrCreateManager(); + ws1.Update(); + var safetyHandle = m_Manager.ComponentJobSafetyManager.GetSafetyHandle(TypeManager.GetTypeIndex(), false); + + Assert.Throws(() => AtomicSafetyHandle.CheckWriteAndThrow(safetyHandle)); + group.CalculateLength(); + AtomicSafetyHandle.CheckWriteAndThrow(safetyHandle); + + group.Dispose(); + } +#endif + + [Test] + [StandaloneFixme] // ISharedComponentData + public void ToEntityArrayOnFilteredGroup() + { + // Note - test is setup so that each entity is in its own chunk, this checks that entity indices are correct + var a = m_Manager.CreateEntity(typeof(EcsTestSharedComp), typeof(EcsTestData)); + var b = m_Manager.CreateEntity(typeof(EcsTestSharedComp), typeof(EcsTestData2)); + var c = m_Manager.CreateEntity(typeof(EcsTestSharedComp), typeof(EcsTestData3)); + + m_Manager.SetSharedComponentData(a, new EcsTestSharedComp {value = 123}); + m_Manager.SetSharedComponentData(b, new EcsTestSharedComp {value = 456}); + m_Manager.SetSharedComponentData(c, new EcsTestSharedComp {value = 123}); + + using (var group = m_Manager.CreateComponentGroup(typeof(EcsTestSharedComp))) + { + group.SetFilter(new EcsTestSharedComp {value = 123}); + using (var entities = group.ToEntityArray(Allocator.TempJob)) + { + CollectionAssert.AreEquivalent(new[] {a, c}, entities); + } + } + + using (var group = m_Manager.CreateComponentGroup(typeof(EcsTestSharedComp))) + { + group.SetFilter(new EcsTestSharedComp {value = 456}); + using (var entities = group.ToEntityArray(Allocator.TempJob)) + { + CollectionAssert.AreEquivalent(new[] {b}, entities); + } + } + } } } diff --git a/package/Unity.Entities.Tests/ComponentOrderVersionTests.cs b/package/Unity.Entities.Tests/ComponentOrderVersionTests.cs index 615fca080..1918ccda1 100755 --- a/package/Unity.Entities.Tests/ComponentOrderVersionTests.cs +++ b/package/Unity.Entities.Tests/ComponentOrderVersionTests.cs @@ -61,7 +61,7 @@ void ActionEvenOdd(Action even, Action } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void SharedComponentNoChangeVersionUnchanged() { AddEvenOddTestData(); @@ -98,7 +98,7 @@ void TestSourceOddValues(int version, ComponentGroup group) } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void SharedComponentNoChangeValuesUnchanged() { AddEvenOddTestData(); @@ -123,7 +123,7 @@ void ChangeGroupOrder(int version, ComponentGroup group) } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void SharedComponentChangeOddGroupOrderOnlyOddVersionChanged() { AddEvenOddTestData(); @@ -134,7 +134,7 @@ public void SharedComponentChangeOddGroupOrderOnlyOddVersionChanged() } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void SharedComponentChangeOddGroupOrderEvenValuesUnchanged() { AddEvenOddTestData(); @@ -157,7 +157,7 @@ void DestroyAllButOneEntityInGroup(int version, ComponentGroup group) } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void SharedComponentDestroyAllButOneEntityInOddGroupOnlyOddVersionChanged() { AddEvenOddTestData(); @@ -168,7 +168,7 @@ public void SharedComponentDestroyAllButOneEntityInOddGroupOnlyOddVersionChanged } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void SharedComponentDestroyAllButOneEntityInOddGroupEvenValuesUnchanged() { AddEvenOddTestData(); @@ -228,7 +228,7 @@ public void ChangedOnlyAffectedArchetype() } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void SetSharedComponent() { var entity = m_Manager.CreateEntity(typeof(SharedData1), typeof(SharedData2)); @@ -241,7 +241,7 @@ public void SetSharedComponent() } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void DestroySharedComponentEntity() { var sharedData = new SharedData1(1); @@ -258,7 +258,7 @@ public void DestroySharedComponentEntity() } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void DestroySharedComponentDataSetsOrderVersionToZero() { var sharedData = new SharedData1(1); diff --git a/package/Unity.Entities.Tests/ComponentSystemGroupTests.cs b/package/Unity.Entities.Tests/ComponentSystemGroupTests.cs index e62fa1a03..b34b2a1f2 100755 --- a/package/Unity.Entities.Tests/ComponentSystemGroupTests.cs +++ b/package/Unity.Entities.Tests/ComponentSystemGroupTests.cs @@ -1,7 +1,11 @@ +using System; using System.Collections; using System.Linq; +using System.Text.RegularExpressions; using NUnit.Framework; using Unity.Jobs; +using UnityEngine; +using UnityEngine.TestTools; namespace Unity.Entities.Tests { @@ -31,7 +35,7 @@ private class TestSystemBase : JobComponentSystem public void SortEmptyParentSystem() { var parent = new TestGroup(); - parent.SortSystemUpdateList(); + Assert.DoesNotThrow(() => { parent.SortSystemUpdateList(); }); } [DisableAutoCreation] @@ -42,8 +46,8 @@ class TestSystem : TestSystemBase [Test] public void SortOneChildSystem() { - var parent = new TestGroup(); - var child = new TestSystem(); + var parent = World.CreateManager(); + var child = World.CreateManager(); parent.AddSystemToUpdateList(child); parent.SortSystemUpdateList(); CollectionAssert.AreEqual(new[] {child}, parent.Systems); @@ -62,9 +66,9 @@ class Sibling2System : TestSystemBase [Test] public void SortTwoChildSystems_CorrectOrder() { - var parent = new TestGroup(); - var child1 = new Sibling1System(); - var child2 = new Sibling2System(); + var parent = World.CreateManager(); + var child1 = World.CreateManager(); + var child2 = World.CreateManager(); parent.AddSystemToUpdateList(child1); parent.AddSystemToUpdateList(child2); parent.SortSystemUpdateList(); @@ -115,13 +119,13 @@ class Circle6System : TestSystemBase #endif public void DetectCircularDependency_Throws() { - var parent = new TestGroup(); - var child1 = new Circle1System(); - var child2 = new Circle2System(); - var child3 = new Circle3System(); - var child4 = new Circle4System(); - var child5 = new Circle5System(); - var child6 = new Circle6System(); + var parent = World.CreateManager(); + var child1 = World.CreateManager(); + var child2 = World.CreateManager(); + var child3 = World.CreateManager(); + var child4 = World.CreateManager(); + var child5 = World.CreateManager(); + var child6 = World.CreateManager(); parent.AddSystemToUpdateList(child3); parent.AddSystemToUpdateList(child6); parent.AddSystemToUpdateList(child2); @@ -150,5 +154,88 @@ public void DetectCircularDependency_Throws() } Assert.IsTrue(foundCycleMatch); } + + + [DisableAutoCreation] + class Unconstrained1System : TestSystemBase + { + } + [DisableAutoCreation] + class Unconstrained2System : TestSystemBase + { + } + [DisableAutoCreation] + class Unconstrained3System : TestSystemBase + { + } + [DisableAutoCreation] + class Unconstrained4System : TestSystemBase + { + } + [Test] + public void SortUnconstrainedSystems_IsDeterministic() + { + var parent = World.CreateManager(); + var child1 = World.CreateManager(); + var child2 = World.CreateManager(); + var child3 = World.CreateManager(); + var child4 = World.CreateManager(); + parent.AddSystemToUpdateList(child2); + parent.AddSystemToUpdateList(child4); + parent.AddSystemToUpdateList(child3); + parent.AddSystemToUpdateList(child1); + parent.SortSystemUpdateList(); + CollectionAssert.AreEqual(parent.Systems, new TestSystemBase[] {child1, child2, child3, child4}); + } + + [DisableAutoCreation] + private class UpdateCountingSystemBase : ComponentSystem + { + public int CompleteUpdateCount = 0; + protected override void OnUpdate() + { + ++CompleteUpdateCount; + } + } + [DisableAutoCreation] + class NonThrowing1System : UpdateCountingSystemBase + { + } + [DisableAutoCreation] + class NonThrowing2System : UpdateCountingSystemBase + { + } + [DisableAutoCreation] + class ThrowingSystem : UpdateCountingSystemBase + { + public string ExceptionMessage = "I should always throw!"; + protected override void OnUpdate() + { + if (CompleteUpdateCount == 0) + { + throw new InvalidOperationException(ExceptionMessage); + } + base.OnUpdate(); + } + } + +#if !UNITY_CSHARP_TINY // Tiny precompiles systems, and lacks a Regex overload for LogAssert.Expect() + [Test] + public void SystemInGroupThrows_LaterSystemsRun() + { + var parent = World.CreateManager(); + var child1 = World.CreateManager(); + var child2 = World.CreateManager(); + var child3 = World.CreateManager(); + parent.AddSystemToUpdateList(child1); + parent.AddSystemToUpdateList(child2); + parent.AddSystemToUpdateList(child3); + parent.Update(); + LogAssert.Expect(LogType.Exception, new Regex(child2.ExceptionMessage)); + Assert.AreEqual(1, child1.CompleteUpdateCount); + Assert.AreEqual(0, child2.CompleteUpdateCount); + Assert.AreEqual(1, child3.CompleteUpdateCount); + } +#endif } } diff --git a/package/Unity.Entities.Tests/ComponentSystemStartStopRunningTests.cs b/package/Unity.Entities.Tests/ComponentSystemStartStopRunningTests.cs index 7ae7d52f1..532396667 100755 --- a/package/Unity.Entities.Tests/ComponentSystemStartStopRunningTests.cs +++ b/package/Unity.Entities.Tests/ComponentSystemStartStopRunningTests.cs @@ -105,7 +105,7 @@ public void TempAllocation_DisposedInOnStopRunning_IsDisposed() [Test] - [TinyFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs + [StandaloneFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs public void OnStartRunning_FirstUpdate_CalledOnce() { LogAssert.Expect(LogType.Log, TestSystem.OnStartRunningString); @@ -115,7 +115,7 @@ public void OnStartRunning_FirstUpdate_CalledOnce() } [Test] - [TinyFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs + [StandaloneFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs public void OnStartRunning_WhenReEnabled_CalledOnce() { system.Enabled = false; @@ -131,7 +131,7 @@ public void OnStartRunning_WhenReEnabled_CalledOnce() } [Test] - [TinyFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs + [StandaloneFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs public void OnStartRunning_WithEnabledAndShouldRun_CalledOnce() { LogAssert.Expect(LogType.Log, TestSystem.OnStartRunningString); @@ -153,7 +153,7 @@ public void OnStartRunning_WithDisabledAndShouldRun_NotCalled() } [Test] - [TinyFixme] // Not obvious reasons + [StandaloneFixme] // Not obvious reasons public void OnStartRunning_WithEnabledAndShouldNotRun_NotCalled() { system.Enabled = true; @@ -174,7 +174,7 @@ public void OnStartRunning_WithDisabledAndShouldNotRun_NotCalled() } [Test] - [TinyFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs + [StandaloneFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs public void OnStartRunning_EnablingWhenShouldRunSystemIsTrue_CalledOnce() { LogAssert.Expect(LogType.Log, TestSystem.OnStartRunningString); @@ -190,7 +190,7 @@ public void OnStartRunning_EnablingWhenShouldRunSystemIsTrue_CalledOnce() } [Test] - [TinyFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs + [StandaloneFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs public void OnStartRunning_WhenShouldRunSystemBecomesTrue_CalledOnce() { LogAssert.Expect(LogType.Log, TestSystem.OnStartRunningString); @@ -210,7 +210,7 @@ public void OnStartRunning_WhenShouldRunSystemBecomesTrue_CalledOnce() } [Test] - [TinyFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs + [StandaloneFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs public void OnStopRunning_WithEnabledAndShouldRun_NotCalled() { LogAssert.Expect(LogType.Log, TestSystem.OnStartRunningString); @@ -224,7 +224,7 @@ public void OnStopRunning_WithEnabledAndShouldRun_NotCalled() } [Test] - [TinyFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs + [StandaloneFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs public void OnStopRunning_WithDisabledAndShouldRun_CalledOnce() { LogAssert.Expect(LogType.Log, TestSystem.OnStartRunningString); @@ -238,7 +238,7 @@ public void OnStopRunning_WithDisabledAndShouldRun_CalledOnce() } [Test] - [TinyFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs + [StandaloneFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs public void OnStopRunning_WithEnabledAndShouldNotRun_CalledOnce() { LogAssert.Expect(LogType.Log, TestSystem.OnStartRunningString); @@ -252,7 +252,7 @@ public void OnStopRunning_WithEnabledAndShouldNotRun_CalledOnce() } [Test] - [TinyFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs + [StandaloneFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs public void OnStopRunning_WithDisabledAndShouldNotRun_CalledOnce() { LogAssert.Expect(LogType.Log, TestSystem.OnStartRunningString); @@ -275,7 +275,7 @@ public void OnStopRunning_WhenDisabledBeforeFirstUpdate_NotCalled() } [Test] - [TinyFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs + [StandaloneFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs public void OnStopRunning_WhenDestroyingActiveManager_CalledOnce() { LogAssert.Expect(LogType.Log, TestSystem.OnStartRunningString); @@ -301,7 +301,7 @@ public void OnStopRunning_WhenDestroyingInactiveManager_NotCalled() } [Test] - [TinyFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs + [StandaloneFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs public void OnStopRunning_WhenShouldRunSystemBecomesFalse_CalledOnce() { LogAssert.Expect(LogType.Log, TestSystem.OnStartRunningString); @@ -315,7 +315,7 @@ public void OnStopRunning_WhenShouldRunSystemBecomesFalse_CalledOnce() } [Test] - [TinyFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs + [StandaloneFixme] // UnityEngine.Debug.Log is at a very basic level in ZeroJobs public void OnStopRunning_DisablingWhenShouldRunSystemIsFalse_NotCalled() { LogAssert.Expect(LogType.Log, TestSystem.OnStartRunningString); diff --git a/package/Unity.Entities.Tests/ComponentSystemTests.cs b/package/Unity.Entities.Tests/ComponentSystemTests.cs index 5ed603c82..cdd80ec45 100755 --- a/package/Unity.Entities.Tests/ComponentSystemTests.cs +++ b/package/Unity.Entities.Tests/ComponentSystemTests.cs @@ -134,7 +134,7 @@ public void OnCreateThrowRemovesSystem() } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void DestroySystemWhileJobUsingArrayIsRunningWorks() { var system = World.CreateManager(); diff --git a/package/Unity.Entities.Tests/CreateAndDestroyTests.cs b/package/Unity.Entities.Tests/CreateAndDestroyTests.cs index 2c46ed602..426daf0de 100755 --- a/package/Unity.Entities.Tests/CreateAndDestroyTests.cs +++ b/package/Unity.Entities.Tests/CreateAndDestroyTests.cs @@ -12,7 +12,7 @@ unsafe public void CreateAndDestroyOne() m_Manager.DestroyEntity(entity); AssertDoesNotExist(entity); } - + [Test] unsafe public void DestroyNullIsIgnored() { @@ -345,6 +345,7 @@ public void AddComponentsWithTypeIndicesWorks() } [Test] + [StandaloneFixme] // ISharedComponentData public void AddComponentsWithSharedComponentsWorks() { var archetype = m_Manager.CreateArchetype(typeof(EcsTestData), typeof(EcsTestSharedComp)); @@ -414,7 +415,7 @@ public EcsSharedStateForcedOrder(int value) } [Test] - [TinyFixme] // ISharedComponent + [StandaloneFixme] // ISharedComponentData public void InstantiateWithSharedSystemStateComponent() { var srcEntity = m_Manager.CreateEntity(); diff --git a/package/Unity.Entities.Tests/EntityCommandBufferTests.cs b/package/Unity.Entities.Tests/EntityCommandBufferTests.cs index 3a5ffbf18..ea5cbcec9 100755 --- a/package/Unity.Entities.Tests/EntityCommandBufferTests.cs +++ b/package/Unity.Entities.Tests/EntityCommandBufferTests.cs @@ -28,7 +28,7 @@ public void Execute() } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void SingleWriterEnforced() { var cmds = new EntityCommandBuffer(Allocator.TempJob); @@ -57,7 +57,7 @@ public void SingleWriterEnforced() } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void DisposeWhileJobRunningThrows() { var cmds = new EntityCommandBuffer(Allocator.TempJob); @@ -73,7 +73,7 @@ public void DisposeWhileJobRunningThrows() } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void ModifiesWhileJobRunningThrows() { var cmds = new EntityCommandBuffer(Allocator.TempJob); @@ -89,7 +89,7 @@ public void ModifiesWhileJobRunningThrows() } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void PlaybackWhileJobRunningThrows() { var cmds = new EntityCommandBuffer(Allocator.TempJob); @@ -116,7 +116,7 @@ public void Execute(int index) } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void EntityCommandBufferConcurrent_PlaybackDuringWrite_ThrowsInvalidOperation() { EntityCommandBuffer cmds = new EntityCommandBuffer(Allocator.TempJob); @@ -130,7 +130,7 @@ public void EntityCommandBufferConcurrent_PlaybackDuringWrite_ThrowsInvalidOpera cmds.Dispose(); } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void EntityCommandBufferConcurrent_DisposeDuringWrite_ThrowsInvalidOperation() { EntityCommandBuffer cmds = new EntityCommandBuffer(Allocator.TempJob); @@ -246,7 +246,7 @@ public void TestMultiChunks() } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void AddSharedComponent() { var cmds = new EntityCommandBuffer(Allocator.TempJob); @@ -264,7 +264,7 @@ public void AddSharedComponent() } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void AddSharedComponentDefault() { var cmds = new EntityCommandBuffer(Allocator.TempJob); @@ -292,7 +292,7 @@ public void AddSharedComponentDefault() } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void SetSharedComponent() { var cmds = new EntityCommandBuffer(Allocator.TempJob); @@ -313,6 +313,7 @@ public void SetSharedComponent() } [Test] + [StandaloneFixme] // ISharedComponentData public void SetSharedComponentDefault() { var cmds = new EntityCommandBuffer(Allocator.TempJob); @@ -333,7 +334,7 @@ public void SetSharedComponentDefault() } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void RemoveSharedComponent() { var cmds = new EntityCommandBuffer(Allocator.TempJob); @@ -364,7 +365,7 @@ public void Execute() } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void JobWithSharedComponentData() { var cmds = new EntityCommandBuffer(Allocator.TempJob); @@ -551,7 +552,7 @@ public void DestroyEntityTwiceWorks() cmds.Playback(m_Manager); cmds.Dispose(); - + Assert.IsFalse(m_Manager.Exists(e)); } @@ -583,7 +584,7 @@ public void Execute() } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void ConcurrentRecord() { var cmds = new EntityCommandBuffer(Allocator.TempJob); @@ -611,7 +612,7 @@ public void Execute(int index) } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void ConcurrentRecordParallelFor() { const int kCreateCount = 10000; @@ -659,7 +660,7 @@ public void Execute(int index) } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void ConcurrentRecordInstantiate() { const int kInstantiateCount = 10000; @@ -699,7 +700,7 @@ public void ConcurrentRecordInstantiate() } [Test] - [TinyFixme] // // Real problem: Atomic Safety + [StandaloneFixme] // // Real problem: Atomic Safety public void PlaybackInvalidatesBuffers() { var cmds = new EntityCommandBuffer(Allocator.TempJob); @@ -717,7 +718,7 @@ public void PlaybackInvalidatesBuffers() } [Test] - [TinyFixme] // Real problem: Atomic Safety + [StandaloneFixme] // Real problem: Atomic Safety public void ArrayAliasesOfPendingBuffersAreInvalidateOnResize() { var cmds = new EntityCommandBuffer(Allocator.TempJob); @@ -817,7 +818,7 @@ public void Execute(int index) } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void DeterminismTest() { const int kRepeat = 10000; @@ -896,7 +897,7 @@ public void Execute(int index) } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void BufferCopyFromDoesNotThrowInJob() { var archetype = m_Manager.CreateArchetype(ComponentType.ReadWrite()); @@ -924,7 +925,7 @@ public void BufferCopyFromDoesNotThrowInJob() #if ENABLE_UNITY_COLLECTIONS_CHECKS [Test] - [TinyFixme] + [StandaloneFixme] public void EntityCommandBufferSystemPlaybackExceptionIsolation() { var entityCommandBufferSystem = World.GetOrCreateManager(); @@ -955,7 +956,7 @@ public void EntityCommandBufferSystemPlaybackExceptionIsolation() #if ENABLE_UNITY_COLLECTIONS_CHECKS [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void EntityCommandBufferSystem_OmitAddJobHandleForProducer_ThrowArgumentException() { var barrier = World.GetOrCreateManager(); @@ -973,7 +974,7 @@ public void EntityCommandBufferSystem_OmitAddJobHandleForProducer_ThrowArgumentE #endif [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void AddSharedComponent_WhenComponentHasEntityField_ThrowsArgumentException() { var cmds = new EntityCommandBuffer(Allocator.TempJob); diff --git a/package/Unity.Entities.Tests/EntityManagerComponentGroupOperationsTests.cs b/package/Unity.Entities.Tests/EntityManagerComponentGroupOperationsTests.cs index f52d9d063..004a2bed0 100755 --- a/package/Unity.Entities.Tests/EntityManagerComponentGroupOperationsTests.cs +++ b/package/Unity.Entities.Tests/EntityManagerComponentGroupOperationsTests.cs @@ -42,6 +42,7 @@ public void AddRemoveChunkComponentWithGroupWorks() } [Test] + [StandaloneFixme] public void AddRemoveSharedComponentWithGroupWorks() { var entity1 = m_Manager.CreateEntity(typeof(EcsTestData)); @@ -78,7 +79,7 @@ public static ComponentType[] GetTestTypes() } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void AddRemoveAnyComponentWithGroupWorksWith([ValueSource(nameof(GetTestTypes))] ComponentType type) { var metaChunkGroup = m_Manager.CreateComponentGroup(typeof(ChunkHeader)); @@ -117,7 +118,7 @@ public void AddRemoveAnyComponentWithGroupWorksWith([ValueSource(nameof(GetTestT } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void RemoveAnyComponentWithGroupIgnoresChunksThatDontHaveTheComponent([ValueSource(nameof(GetTestTypes))] ComponentType type) { var metaChunkGroup = m_Manager.CreateComponentGroup(typeof(ChunkHeader)); @@ -161,7 +162,7 @@ uint GetSharedComponentDataVersion(Entity e) where T : struct, ISharedCompone } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void AddRemoveComponentWithGroupPreservesChangeVersions() { m_ManagerDebug.SetGlobalSystemVersion(10); diff --git a/package/Unity.Entities.Tests/EntityQueryBuilderTests.cs b/package/Unity.Entities.Tests/EntityQueryBuilderTests.cs new file mode 100755 index 000000000..97f9f68d9 --- /dev/null +++ b/package/Unity.Entities.Tests/EntityQueryBuilderTests.cs @@ -0,0 +1,212 @@ +using System; +// TEMPORARY HACK +//using JetBrains.Annotations; +using NUnit.Framework; + +namespace Unity.Entities.Tests +{ + class EntityQueryBuilderTestFixture : ECSTestsFixture + { + [DisableAutoCreation]//, UsedImplicitly] + protected class TestComponentSystem : ComponentSystem + { protected override void OnUpdate() { } } + + protected static TestComponentSystem TestSystem => World.Active.GetOrCreateManager(); + } + + class EntityQueryBuilderTests : EntityQueryBuilderTestFixture + { + [DisableAutoCreation]//, UsedImplicitly] + class TestComponentSystem2 : ComponentSystem + { protected override void OnUpdate() { } } + + static TestComponentSystem2 TestSystem2 => World.Active.GetOrCreateManager(); + + [Test] + public void WithGroup_WithNullGroup_Throws() => + Assert.Throws(() => TestSystem.Entities.With(null)); + + [Test] + public void WithGroup_WithExistingGroup_Throws() + { + var group0 = TestSystem.GetComponentGroup(ComponentType.ReadWrite()); + var group1 = TestSystem.GetComponentGroup(ComponentType.ReadOnly()); + + var query = TestSystem.Entities.With(group0); + + Assert.Throws(() => query.With(group1)); + } + + [Test] + public void WithGroup_WithExistingSpec_Throws() + { + var group = TestSystem.GetComponentGroup(ComponentType.ReadWrite()); + + Assert.Throws(() => TestSystem.Entities.WithAny().With(group)); + Assert.Throws(() => TestSystem.Entities.WithNone().With(group)); + Assert.Throws(() => TestSystem.Entities.WithAll().With(group)); + } + + [Test] + public void WithSpec_WithExistingGroup_Throws() + { + var group = TestSystem.GetComponentGroup(ComponentType.ReadWrite()); + + Assert.Throws(() => TestSystem.Entities.With(group).WithAny()); + Assert.Throws(() => TestSystem.Entities.With(group).WithNone()); + Assert.Throws(() => TestSystem.Entities.With(group).WithAll()); + } + + [Test] + public void Equals_WithMatchedButDifferentlyConstructedBuilders_ReturnsTrue() + { + var builder0 = TestSystem.Entities + .WithAll() + .WithAny() + .WithNone(); + var builder1 = new EntityQueryBuilder(TestSystem) + .WithNone() + .WithAll() + .WithAny() + .WithNone() + .WithAny(); + + Assert.IsTrue(builder0.ShallowEquals(ref builder1)); + } + + [Test] + public void Equals_WithSlightlyDifferentlyConstructedBuilders_ReturnsFalse() + { + var builder0 = TestSystem.Entities + .WithAll() + .WithAny() + .WithNone(); + var builder1 = new EntityQueryBuilder(TestSystem) + .WithAll() + .WithAny(); + + Assert.IsFalse(builder0.ShallowEquals(ref builder1)); + } + + [Test] + public void Equals_WithDifferentGroups_ReturnsFalse() + { + var group0 = TestSystem.GetComponentGroup(ComponentType.ReadWrite()); + var group1 = TestSystem.GetComponentGroup(ComponentType.ReadOnly()); + + var builder0 = TestSystem.Entities.With(group0); + var builder1 = TestSystem.Entities.With(group1); + + Assert.IsFalse(builder0.ShallowEquals(ref builder1)); + } + + [Test] + public void ObjectGetHashCode_Throws() + { + // ReSharper disable once ReturnValueOfPureMethodIsNotUsed + Assert.Throws(() => TestSystem.Entities.GetHashCode()); + } + + [Test] + public void ObjectEquals_Throws() + { + // ReSharper disable once ReturnValueOfPureMethodIsNotUsed + Assert.Throws(() => TestSystem.Entities.Equals(null)); + } + + [Test] + public void Equals_WithMismatchedSystems_Throws() + { + var builder0 = TestSystem.Entities; + var builder1 = TestSystem2.Entities; + + Assert.Throws(() => builder0.ShallowEquals(ref builder1)); + } + + [Test] + public void Equals_WithMismatchedBuilders_ReturnsFalse() + { + { + var builder0 = TestSystem.Entities.WithAll(); + var builder1 = TestSystem.Entities.WithAll(); + Assert.IsFalse(builder0.ShallowEquals(ref builder1)); + } + + { + var builder0 = TestSystem.Entities.WithAny(); + var builder1 = TestSystem.Entities.WithAny(); + Assert.IsFalse(builder0.ShallowEquals(ref builder1)); + } + + { + var builder0 = TestSystem.Entities.WithNone(); + var builder1 = TestSystem.Entities.WithAll(); + Assert.IsFalse(builder0.ShallowEquals(ref builder1)); + } + + { + var group = TestSystem.GetComponentGroup(ComponentType.ReadWrite()); + var builder0 = TestSystem.Entities.With(group); + var builder1 = TestSystem.Entities; + Assert.IsFalse(builder0.ShallowEquals(ref builder1)); + } + } + + [Test] + public void ToEntityArchetypeQuery_WithFluentSpec_ReturnsQueryAsSpecified() + { + var eaq = TestSystem.Entities + .WithAll() + .WithAny() + .WithNone() + .ToEntityArchetypeQuery(); + + CollectionAssert.AreEqual( + new[] { ComponentType.ReadWrite() }, + eaq.All); + CollectionAssert.AreEqual( + new[] { ComponentType.ReadWrite(), ComponentType.ReadWrite() }, + eaq.Any); + CollectionAssert.AreEqual( + new[] { ComponentType.ReadWrite(), ComponentType.ReadWrite(), ComponentType.ReadWrite() }, + eaq.None); + } + + [Test] + public void ToComponentGroup_OnceCached_StaysCached() + { + // this will cause the group to get cached in the query + var query = TestSystem.Entities.WithAll(); + query.ToComponentGroup(); + + // this will throw because we're trying to modify the spec, yet we already have a group cached + Assert.Throws(() => query.WithNone()); + } + + [Test] + public void ForEach_WithReusedQueryButDifferentDelegateParams_Throws() + { + var entity = m_Manager.CreateEntity(); + m_Manager.AddComponentData(entity, new EcsTestData(0)); + m_Manager.AddComponentData(entity, new EcsTestData2(1)); + m_Manager.AddComponentData(entity, new EcsTestData3(2)); + + var query = TestSystem.Entities.WithAll(); + var oldQuery = query; + + // validate that each runs with a different componentgroup (if the second shared the first, we'd get a null ref) + + query.ForEach((ref EcsTestData3 three) => { Assert.NotNull(three); }); + query.ForEach((ref EcsTestData4 four) => { Assert.NotNull(four); }); + + // also validate that the query has not been altered by either ForEach + + Assert.IsTrue(oldQuery.ShallowEquals(ref query)); + + var eaq = query.ToEntityArchetypeQuery(); + CollectionAssert.AreEqual( + new[] { ComponentType.ReadWrite(), ComponentType.ReadWrite() }, + eaq.All); + } + } +} diff --git a/package/Unity.Entities.Tests/EntityQueryBuilderTests.cs.meta b/package/Unity.Entities.Tests/EntityQueryBuilderTests.cs.meta new file mode 100755 index 000000000..5cf95b36d --- /dev/null +++ b/package/Unity.Entities.Tests/EntityQueryBuilderTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 75a6ae34192b92844bc9d2a3f2c48c2f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package/Unity.Entities.Tests/EntityQueryCacheTests.cs b/package/Unity.Entities.Tests/EntityQueryCacheTests.cs new file mode 100755 index 000000000..aad117cb2 --- /dev/null +++ b/package/Unity.Entities.Tests/EntityQueryCacheTests.cs @@ -0,0 +1,195 @@ +using System; +using System.Text.RegularExpressions; +using NUnit.Framework; +using UnityEngine; +using UnityEngine.TestTools; + +namespace Unity.Entities.Tests +{ + unsafe class EntityQueryCacheTests + { + [Test] + public void Ctor_WithCacheSize0_Throws() + { + // ReSharper disable ObjectCreationAsStatement + Assert.Throws(() => new EntityQueryCache(0)); + Assert.Throws(() => new EntityQueryCache(-1)); + // ReSharper restore ObjectCreationAsStatement + } + + static void SimpleWrapCreateCachedQuery(EntityQueryCache cache, uint hash, ComponentGroup group) + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + var builder = new EntityQueryBuilder(); + cache.CreateCachedQuery(hash, group, ref builder, null, 0); + #else + cache.CreateCachedQuery(hash, group); + #endif + } + + [Test] + public void FindQueryInCache_WithEmptyCache_ReturnsErrorIndex() + { + var cache = new EntityQueryCache(1); + + var found = cache.FindQueryInCache(0); + + Assert.Less(found, 0); + } + + [Test] + public void FindQueryInCache_WithHashNotFound_ReturnsErrorIndex() + { + var cache = new EntityQueryCache(1); + SimpleWrapCreateCachedQuery(cache, 0, k_DummyGroup); + + var found = cache.FindQueryInCache(1); + + Assert.Less(found, 0); + } + + [Test] + public void FindQueryInCache_WithHashFound_ReturnsFoundIndex() + { + var cache = new EntityQueryCache(2); + SimpleWrapCreateCachedQuery(cache, 0, k_DummyGroup); + SimpleWrapCreateCachedQuery(cache, 1, k_DummyGroup); + + var found = cache.FindQueryInCache(1); + + Assert.AreEqual(1, found); + } + + readonly Regex k_ResizeError = new Regex(".*is too small to hold the current number of queries.*"); + readonly ComponentGroup k_DummyGroup = new ComponentGroup(null, null, null, null); + + [Test] + public void CreateCachedQuery_WithNullGroup_Throws() + { + var cache = new EntityQueryCache(1); + + Assert.Throws(() => SimpleWrapCreateCachedQuery(cache, 2, null)); + } + +// TEMPORARY HACK +#if !UNITY_ZEROPLAYER + [Test] + public void CreateCachedQuery_OverflowWithCacheSize1_ResizesAndWarns() + { + var cache = new EntityQueryCache(1); + SimpleWrapCreateCachedQuery(cache, 0, k_DummyGroup); + + LogAssert.Expect(LogType.Error, k_ResizeError); + SimpleWrapCreateCachedQuery(cache, 1, k_DummyGroup); + } + + [Test] + public void CreateCachedQuery_OverflowWithCacheSize4_ResizesByAtLeastHalf() + { + var cache = new EntityQueryCache(4); + SimpleWrapCreateCachedQuery(cache, 0, k_DummyGroup); + SimpleWrapCreateCachedQuery(cache, 1, k_DummyGroup); + SimpleWrapCreateCachedQuery(cache, 2, k_DummyGroup); + SimpleWrapCreateCachedQuery(cache, 3, k_DummyGroup); + + LogAssert.Expect(LogType.Error, k_ResizeError); + SimpleWrapCreateCachedQuery(cache, 4, k_DummyGroup); + + // this should not error + SimpleWrapCreateCachedQuery(cache, 5, k_DummyGroup); + } +#endif // !UNITY_ZEROPLAYER + + [Test] + public void CreateCachedQuery_WithExistingHash_Throws() + { + var cache = new EntityQueryCache(1); + SimpleWrapCreateCachedQuery(cache, 0, k_DummyGroup); + + Assert.Throws(() => SimpleWrapCreateCachedQuery(cache, 0, k_DummyGroup)); + } + + [Test] + public void GetCachedQuery_WithValidIndex_ReturnsGroup() + { + var cache = new EntityQueryCache(1); + SimpleWrapCreateCachedQuery(cache, 0, k_DummyGroup); + + var group = cache.GetCachedQuery(0); + + Assert.AreEqual(k_DummyGroup, group); + } + + [Test] + public void GetCachedQuery_WithInvalidIndex_Throws() + { + var cache = new EntityQueryCache(1); + + Assert.Throws(() => cache.GetCachedQuery(1)); + } + + [Test] + public void ValidateMatchesCache_WithValidMatch_DoesNotThrow() + { + var cache = new EntityQueryCache(1); + int index; + fixed (int* delegateTypes = new[] { 1 }) + { + var builder = new EntityQueryBuilder().WithAll(); + index = cache.CreateCachedQuery(0, k_DummyGroup, ref builder, delegateTypes, 1); + } + + Assert.AreEqual(0, index); + + var testBuilder = new EntityQueryBuilder().WithAll(); + + fixed (int* testDelegateTypes = new[] { 1 }) + cache.ValidateMatchesCache(index, ref testBuilder, testDelegateTypes, 1); + } + + [Test] + public void ValidateMatchesCache_WithMismatchedBuilder_Throws() + { + var cache = new EntityQueryCache(1); + var builder = new EntityQueryBuilder().WithAll(); + var index = cache.CreateCachedQuery(0, k_DummyGroup, ref builder, null, 0); + + var anotherBuilder = new EntityQueryBuilder(); + Assert.IsFalse(builder.ShallowEquals(ref anotherBuilder)); + + Assert.Throws(() => cache.ValidateMatchesCache(index, ref anotherBuilder, null, 0)); + } + + [Test] + public void ValidateMatchesCache_WithMismatchedDelegateTypeIndices_Throws() + { + var cache = new EntityQueryCache(1); + var builder = new EntityQueryBuilder().WithAll(); + int index; + fixed (int* delegateTypes = new[] { 1 }) + index = cache.CreateCachedQuery(0, k_DummyGroup, ref builder, delegateTypes, 1); + + Assert.Throws(() => cache.ValidateMatchesCache(index, ref builder, null, 0)); + + // note: can't use a `fixed` var inside a closure, so below we implement a manual Assert.Throws + + InvalidOperationException testException0 = null; + try + { + fixed (int* anotherDelegateTypes0 = new[] { 2 }) + cache.ValidateMatchesCache(index, ref builder, anotherDelegateTypes0, 1); + } + catch (InvalidOperationException x) { testException0 = x; } + Assert.NotNull(testException0); + + InvalidOperationException testException1 = null; + try + { + fixed (int* anotherDelegateTypes1 = new[] { 1, 2 }) + cache.ValidateMatchesCache(index, ref builder, anotherDelegateTypes1, 2); + } + catch (InvalidOperationException x) { testException1 = x; } + Assert.NotNull(testException1); + } + } +} diff --git a/package/Unity.Entities.Tests/EntityQueryCacheTests.cs.meta b/package/Unity.Entities.Tests/EntityQueryCacheTests.cs.meta new file mode 100755 index 000000000..2f7c2d05a --- /dev/null +++ b/package/Unity.Entities.Tests/EntityQueryCacheTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f2abab967e17ea64f83361bdd9cc6a9f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package/Unity.Entities.Tests/EntityRemapUtilityTests.cs b/package/Unity.Entities.Tests/EntityRemapUtilityTests.cs index 4e918c1f5..0376bb279 100755 --- a/package/Unity.Entities.Tests/EntityRemapUtilityTests.cs +++ b/package/Unity.Entities.Tests/EntityRemapUtilityTests.cs @@ -60,7 +60,7 @@ public void RemapEntityMapsNullSourceToNull() Assert.AreEqual(Entity.Null, EntityRemapUtility.RemapEntity(ref m_Remapping, Entity.Null)); } - struct EmptyStruct + struct EmptyStruct : IComponentData { } @@ -71,16 +71,18 @@ static TypeManager.EntityOffsetInfo[] GetEntityOffsets(System.Type type) #else unsafe { var info = TypeManager.GetTypeInfo(TypeManager.GetTypeIndex(type)); - TypeManager.EntityOffsetInfo[] ei = new TypeManager.EntityOffsetInfo[info.EntityOffsetCount]; - for (var i = 0; i < info.EntityOffsetCount; ++i) - ei[i] = info.EntityOffsets[i]; - return ei; + if (info.EntityOffsetCount > 0) { + TypeManager.EntityOffsetInfo[] ei = new TypeManager.EntityOffsetInfo[info.EntityOffsetCount]; + for (var i = 0; i < info.EntityOffsetCount; ++i) + ei[i] = info.EntityOffsets[i]; + return ei; + } + return null; } #endif } [Test] - [TinyFixme] // No Reflection public void CalculateEntityOffsetsReturnsNullIfNoEntities() { var offsets = GetEntityOffsets(typeof(EmptyStruct)); @@ -96,7 +98,7 @@ public void CalculateEntityOffsetsReturns0IfEntity() } - struct TwoEntityStruct + struct TwoEntityStruct : IComponentData { // The offsets of these fields are accessed through reflection #pragma warning disable CS0169 // field never used warning. @@ -108,7 +110,6 @@ struct TwoEntityStruct } [Test] - [TinyFixme] // No Reflection public void CalculateEntityOffsetsReturnsOffsetsOfEntities() { var offsets = GetEntityOffsets(typeof(TwoEntityStruct)); @@ -118,6 +119,9 @@ public void CalculateEntityOffsetsReturnsOffsetsOfEntities() } struct EmbeddedEntityStruct +#if UNITY_ZEROPLAYER + : IComponentData +#endif { // The offsets of these fields are accessed through reflection #pragma warning disable CS0169 // field never used warning. @@ -127,7 +131,6 @@ struct EmbeddedEntityStruct } [Test] - [TinyFixme] // No Reflection public void CalculateEntityOffsetsReturnsOffsetsOfEmbeddedEntities() { var offsets = GetEntityOffsets(typeof(EmbeddedEntityStruct)); diff --git a/package/Unity.Entities.Tests/EntityTransactionTests.cs b/package/Unity.Entities.Tests/EntityTransactionTests.cs index 30fe64e40..a661d6ed3 100755 --- a/package/Unity.Entities.Tests/EntityTransactionTests.cs +++ b/package/Unity.Entities.Tests/EntityTransactionTests.cs @@ -10,7 +10,7 @@ namespace Unity.Entities.Tests { - [TinyFixme] // Asserts on JobDebugger in constructor + [StandaloneFixme] // Asserts on JobDebugger in constructor class EntityTransactionTests : ECSTestsFixture { ComponentGroup m_Group; @@ -84,7 +84,7 @@ public void CreateEntitiesChainedJob() [Test] - [TinyFixme] + [StandaloneFixme] public void CommitAfterNotRegisteredTransactionJobLogsError() { var job = new CreateEntityJob(); diff --git a/package/Unity.Entities.Tests/ForEachTests.cs b/package/Unity.Entities.Tests/ForEachTests.cs index c8f5965af..0156601e2 100755 --- a/package/Unity.Entities.Tests/ForEachTests.cs +++ b/package/Unity.Entities.Tests/ForEachTests.cs @@ -3,7 +3,7 @@ namespace Unity.Entities.Tests { - class ForEachBasicTests : ComponentQueryBuilderTestFixture + class ForEachBasicTests : EntityQueryBuilderTestFixture { [SetUp] public void CreateTestEntities() @@ -80,7 +80,7 @@ public void DynamicBuffer() } } - class ForEachTests : ComponentQueryBuilderTestFixture + class ForEachTests : EntityQueryBuilderTestFixture { [Test] public void Many() diff --git a/package/Unity.Entities.Tests/IJobChunkTests.cs b/package/Unity.Entities.Tests/IJobChunkTests.cs index ad8e5a707..37987ee23 100755 --- a/package/Unity.Entities.Tests/IJobChunkTests.cs +++ b/package/Unity.Entities.Tests/IJobChunkTests.cs @@ -43,7 +43,7 @@ public void IJobChunkProcess() } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void IJobChunkProcessFiltered() { var archetype = m_Manager.CreateArchetype(typeof(EcsTestData), typeof(EcsTestData2), typeof(SharedData1)); @@ -123,7 +123,7 @@ public void Execute(ArchetypeChunk chunk, int chunkIndex, int entityOffset) } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void IJobChunkProcessChunkIndex() { var archetype = m_Manager.CreateArchetype(typeof(EcsTestData), typeof(EcsTestData2), typeof(SharedData1)); @@ -156,7 +156,7 @@ public void IJobChunkProcessChunkIndex() } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void IJobChunkProcessEntityOffset() { var archetype = m_Manager.CreateArchetype(typeof(EcsTestData), typeof(EcsTestData2), typeof(SharedData1)); @@ -189,7 +189,7 @@ public void IJobChunkProcessEntityOffset() } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void IJobChunkProcessChunkMultiArchetype() { var archetypeA = m_Manager.CreateArchetype(typeof(EcsTestData)); diff --git a/package/Unity.Entities.Tests/InjectComponentGroupTests.cs b/package/Unity.Entities.Tests/InjectComponentGroupTests.cs index 91818a53b..5182d26ee 100755 --- a/package/Unity.Entities.Tests/InjectComponentGroupTests.cs +++ b/package/Unity.Entities.Tests/InjectComponentGroupTests.cs @@ -109,7 +109,7 @@ protected override void OnUpdate() } [Test] - [TinyFixme] // ISharedComponent + [StandaloneFixme] // ISharedComponentData public void ComponentGroupFromInjectedGroup() { var system = World.GetOrCreateManager(); @@ -133,7 +133,7 @@ public void ComponentGroupFromInjectedGroup() } [Test] - [TinyFixme] // AtomicSafety + [StandaloneFixme] // AtomicSafety public void ReadOnlyComponentDataArray() { var readOnlySystem = World.GetOrCreateManager (); @@ -149,7 +149,7 @@ public void ReadOnlyComponentDataArray() [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void SharedComponentDataArray() { var sharedComponentSystem = World.GetOrCreateManager (); @@ -166,7 +166,7 @@ public void SharedComponentDataArray() [Test] - [TinyFixme] // Real problem - Test failure + [StandaloneFixme] // Real problem - Test failure public void RemoveComponentGroupTracking() { var pureSystem = World.GetOrCreateManager (); @@ -194,7 +194,7 @@ public void RemoveComponentGroupTracking() } [Test] - [TinyFixme] // Real problem - Test failure + [StandaloneFixme] // Real problem - Test failure public void EntityGroupTracking() { var pureSystem = World.GetOrCreateManager (); @@ -254,7 +254,7 @@ protected override JobHandle OnUpdate(JobHandle inputDeps) } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void FromEntitySystemIncrementInJobWorks() { var system = World.GetOrCreateManager(); @@ -295,7 +295,7 @@ protected override JobHandle OnUpdate(JobHandle inputDeps) } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void OnCreateManagerComponentGroupInjectionWorks() { var entity = m_Manager.CreateEntity (typeof(EcsTestData)); @@ -327,7 +327,7 @@ protected override JobHandle OnUpdate(JobHandle inputDeps) } [Test] - [TinyFixme] // IJob + [StandaloneFixme] // IJob public void OnDestroyManagerComponentGroupInjectionWorks() { var system = World.GetOrCreateManager(); diff --git a/package/Unity.Entities.Tests/IterationTests.cs b/package/Unity.Entities.Tests/IterationTests.cs index f377ce920..20dff2bf4 100755 --- a/package/Unity.Entities.Tests/IterationTests.cs +++ b/package/Unity.Entities.Tests/IterationTests.cs @@ -291,7 +291,7 @@ public void GroupCopyFromNativeArray() } [Test] - [TinyFixme] + [StandaloneFixme] public void ComponentGroupFilteredEntityIndexWithMultipleArchetypes() { var archetypeA = m_Manager.CreateArchetype(typeof(EcsTestData), typeof(EcsTestData2), typeof(EcsTestSharedComp)); @@ -320,7 +320,7 @@ public void ComponentGroupFilteredEntityIndexWithMultipleArchetypes() } [Test] - [TinyFixme] + [StandaloneFixme] public void ComponentGroupFilteredChunkCount() { var archetypeA = m_Manager.CreateArchetype(typeof(EcsTestData), typeof(EcsTestData2), typeof(EcsTestSharedComp)); diff --git a/package/Unity.Entities.Tests/JobComponentSystemDependencyTests.cs b/package/Unity.Entities.Tests/JobComponentSystemDependencyTests.cs index 11992555a..99bd0d8da 100755 --- a/package/Unity.Entities.Tests/JobComponentSystemDependencyTests.cs +++ b/package/Unity.Entities.Tests/JobComponentSystemDependencyTests.cs @@ -113,7 +113,7 @@ protected override JobHandle OnUpdate(JobHandle input) return input; } } - + protected override void OnCreateManager() { m_WriteGroup = GetComponentGroup(ComponentType.ReadWrite()); @@ -171,8 +171,19 @@ public void NotUsingDataIsHarmless() rs1.Update(); rs3.Update(); } - - + + [Test] + public void ReadAfterWrite_JobProcessComponentDataGroup_Works() + { + var entity = m_Manager.CreateEntity (typeof(EcsTestData)); + m_Manager.SetComponentData(entity, new EcsTestData(42)); + var ws = World.GetOrCreateManager(); + var rs = World.GetOrCreateManager(); + + ws.Update(); + rs.Update(); + } + [DisableAutoCreation] class UseEcsTestDataFromEntity: JobComponentSystem { @@ -182,7 +193,7 @@ public struct MutateEcsTestDataJob : IJob public void Execute() { - + } } @@ -192,8 +203,8 @@ protected override JobHandle OnUpdate(JobHandle dep) return job.Schedule(dep); } } - - // The writer dependency on EcsTestData is not predeclared during + + // The writer dependency on EcsTestData is not predeclared during // OnCreateManager, but we still expect the code to work correctly. // This should result in a sync point when adding the dependency for the first time. [Test] @@ -201,7 +212,7 @@ public void AddingDependencyTypeDuringOnUpdateSyncsDependency() { var systemA = World.CreateManager(); var systemB = World.CreateManager(); - + systemA.Update(); systemB.Update(); } @@ -248,4 +259,4 @@ public void EmptySystemAfterNonEmptySystemDoesntThrow() } } } -#endif \ No newline at end of file +#endif diff --git a/package/Unity.Entities.Tests/JobSafetyTests.cs b/package/Unity.Entities.Tests/JobSafetyTests.cs index 465c88525..202057ec3 100755 --- a/package/Unity.Entities.Tests/JobSafetyTests.cs +++ b/package/Unity.Entities.Tests/JobSafetyTests.cs @@ -7,7 +7,7 @@ namespace Unity.Entities.Tests { - [TinyFixme] // Tiny ignores because of the assert in the constructor. + [StandaloneFixme] // Tiny ignores because of the assert in the constructor. class JobSafetyTests : ECSTestsFixture { public JobSafetyTests() diff --git a/package/Unity.Entities.Tests/MoveEntitiesFromTests.cs b/package/Unity.Entities.Tests/MoveEntitiesFromTests.cs index 995273b37..2ea4f8332 100755 --- a/package/Unity.Entities.Tests/MoveEntitiesFromTests.cs +++ b/package/Unity.Entities.Tests/MoveEntitiesFromTests.cs @@ -6,7 +6,7 @@ namespace Unity.Entities.Tests { - [TinyFixme] // MultiWorlds + [StandaloneFixme] // MultiWorlds class MoveEntitiesFromTests : ECSTestsFixture { [Test] @@ -54,7 +54,7 @@ public void MoveEntities() } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void MoveEntitiesWithSharedComponentData() { var creationWorld = new World("CreationWorld"); @@ -206,7 +206,7 @@ public void MoveEntitiesWithComponentGroup() } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData public void MoveEntitiesWithComponentGroupMovesChunkComponents() { var creationWorld = new World("CreationWorld"); @@ -409,7 +409,7 @@ public void MoveEntitiesPatchesEntityReferences() } [Test] - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData [Ignore("This behaviour is currently not intended. It prevents streaming efficiently.")] public void MoveEntitiesPatchesEntityReferencesInSharedComponentData() { @@ -545,5 +545,26 @@ public unsafe void MoveEntitiesArchetypeChunkCountMatches() creationWorld.Dispose(); } + [Test] + public void MoveEntitiesFromChunksAreConsideredChangedOnlyOnce() + { + var creationWorld = new World("CreationWorld"); + var creationManager = creationWorld.GetOrCreateManager(); + var entity = creationManager.CreateEntity(); + creationManager.AddComponentData(entity, new EcsTestData(42)); + + var system = World.GetOrCreateManager(); + + system.Update(); + Assert.AreEqual(0, system.NumChanged); + + m_Manager.MoveEntitiesFrom(creationManager); + + system.Update(); + Assert.AreEqual(1, system.NumChanged); + + system.Update(); + Assert.AreEqual(0, system.NumChanged); + } } } diff --git a/package/Unity.Entities.Tests/SafetyTests.cs b/package/Unity.Entities.Tests/SafetyTests.cs index 336fd2e85..c49ba7ad2 100755 --- a/package/Unity.Entities.Tests/SafetyTests.cs +++ b/package/Unity.Entities.Tests/SafetyTests.cs @@ -40,7 +40,7 @@ public void ComponentArrayChunkSliceOutOfBoundsThrowsException() [Test] - [TinyFixme] // Real problem : Atomic Safety + [StandaloneFixme] // Real problem : Atomic Safety public void ReadOnlyComponentDataArray() { var group = m_Manager.CreateComponentGroup(typeof(EcsTestData2), ComponentType.ReadOnly(typeof(EcsTestData))); @@ -62,7 +62,7 @@ public void ReadOnlyComponentDataArray() } [Test] - [TinyFixme] // Real problem : Atomic Safety + [StandaloneFixme] // Real problem : Atomic Safety public void AccessComponentArrayAfterCreationThrowsException() { CreateEntityWithDefaultData(0); @@ -76,7 +76,7 @@ public void AccessComponentArrayAfterCreationThrowsException() } [Test] - [TinyFixme] // Real problem : Atomic Safety + [StandaloneFixme] // Real problem : Atomic Safety public void CreateEntityInvalidatesArray() { CreateEntityWithDefaultData(0); @@ -106,7 +106,7 @@ public void GetSetComponentThrowsIfNotExist() } [Test] - [TinyFixme] // Real problem : Atomic Safety + [StandaloneFixme] // Real problem : Atomic Safety public void ComponentDataArrayFromEntityThrowsIfNotExist() { var entity = m_Manager.CreateEntity(typeof(EcsTestData)); @@ -210,7 +210,7 @@ unsafe struct BigComponentData2 : IComponentData } [Test] - [TinyFixme] // Real problem - sizeof(BigComponentData1) = 4 vs 40000 expected + [StandaloneFixme] // Real problem - sizeof(BigComponentData1) = 4 vs 40000 expected public void CreateTooBigArchetypeThrows() { Assert.Throws(() => diff --git a/package/Unity.Entities.Tests/SerializeTests.cs b/package/Unity.Entities.Tests/SerializeTests.cs index 78ec94eb2..5ccd14974 100755 --- a/package/Unity.Entities.Tests/SerializeTests.cs +++ b/package/Unity.Entities.Tests/SerializeTests.cs @@ -454,9 +454,42 @@ public void SerializeDoesntRemapOriginalHeapBuffers() writer.Dispose(); } + struct ExternalSharedComponentValue + { + public object obj; + public int hashcode; + public int typeIndex; + } + + ExternalSharedComponentValue[] ExtractSharedComponentValues(int[] indices, EntityManager manager) + { + var values = new ExternalSharedComponentValue[indices.Length]; + for (int i = 0; i < indices.Length; ++i) + { + object value = manager.m_SharedComponentManager.GetSharedComponentDataNonDefaultBoxed(indices[i]); + int typeIndex = TypeManager.GetTypeIndex(value.GetType()); + int hash = SharedComponentDataManager.GetHashCodeFast(value, typeIndex); + values[i] = new ExternalSharedComponentValue {obj = value, hashcode = hash, typeIndex = typeIndex}; + } + return values; + } + + void InsertSharedComponentValues(ExternalSharedComponentValue[] values, EntityManager manager) + { + for (int i = 0; i < values.Length; ++i) + { + ExternalSharedComponentValue value = values[i]; + int index = manager.m_SharedComponentManager.InsertSharedComponentAssumeNonDefault(value.typeIndex, + value.hashcode, value.obj); + Assert.AreEqual(i+1, index); + } + } + [Test] public unsafe void SerializeEntitiesWorksWithBlobAssetReferences() { + var archetype1 = m_Manager.CreateArchetype(typeof(EcsTestSharedComp), typeof(EcsTestData)); + var archetype2 = m_Manager.CreateArchetype(typeof(EcsTestSharedComp2), typeof(EcsTestData2)); var dummyEntity = CreateEntityWithDefaultData(0); //To ensure entity indices are offset var allocator = new BlobAllocator(-1); @@ -471,44 +504,65 @@ public unsafe void SerializeEntitiesWorksWithBlobAssetReferences() var arrayComponent = new EcsTestDataBlobAssetArray {array = allocator.CreateBlobAssetReference>(Allocator.Temp)}; allocator.Dispose(); - var e1 = m_Manager.CreateEntity(); - m_Manager.AddComponentData(e1, arrayComponent); - var e2 = m_Manager.CreateEntity(); - m_Manager.AddComponentData(e2, arrayComponent); + const int entityCount = 1000; + var entities = new NativeArray(entityCount, Allocator.Temp); - var e3 = m_Manager.CreateEntity(); + m_Manager.CreateEntity(archetype1, entities); + for (int i = 0; i < entityCount; ++i) + { + m_Manager.AddComponentData(entities[i], arrayComponent); + m_Manager.SetSharedComponentData(entities[i], new EcsTestSharedComp(i%4)); + } - var intComponent = new EcsTestDataBlobAssetRef {value = BlobAssetReference.Create(42)}; - m_Manager.AddComponentData(e3, intComponent); + var intComponents = new NativeArray(entityCount/5, Allocator.Temp); + for(int i=0; i.Create(i)}; + m_Manager.CreateEntity(archetype2, entities); + for (int i = 0; i < entityCount; ++i) + { + var intComponent = intComponents[i % intComponents.Length]; + m_Manager.AddComponentData(entities[i], intComponent); + m_Manager.SetComponentData(entities[i], new EcsTestData2(intComponent.value.Value)); + m_Manager.SetSharedComponentData(entities[i], new EcsTestSharedComp2(i%3)); + } + m_Manager.DestroyEntity(dummyEntity); var writer = new TestBinaryWriter(); int[] sharedData; SerializeUtility.SerializeWorld(m_Manager, writer, out sharedData); - m_Manager.DestroyEntity(e1); - m_Manager.DestroyEntity(e2); - m_Manager.DestroyEntity(e3); + var sharedComponents = ExtractSharedComponentValues(sharedData, m_Manager); + + m_Manager.DestroyEntity(m_Manager.UniversalGroup); arrayComponent.array.Release(); - intComponent.value.Release(); + for(int i=0; i(); - SerializeUtility.DeserializeWorld(entityManager.BeginExclusiveEntityTransaction(), reader, 0); + InsertSharedComponentValues(sharedComponents, entityManager); + + SerializeUtility.DeserializeWorld(entityManager.BeginExclusiveEntityTransaction(), reader, sharedData.Length); entityManager.EndExclusiveEntityTransaction(); + for (int i = 0; i < sharedData.Length; ++i) + entityManager.m_SharedComponentManager.RemoveReference(i+1); + + Assert.IsTrue(entityManager.m_SharedComponentManager.AllSharedComponentReferencesAreFromChunks(entityManager.ArchetypeManager)); try { - var group = entityManager.CreateComponentGroup(typeof(EcsTestDataBlobAssetArray)); + var group1 = entityManager.CreateComponentGroup(typeof(EcsTestDataBlobAssetArray)); + var group2 = entityManager.CreateComponentGroup(typeof(EcsTestDataBlobAssetRef)); - Assert.AreEqual(2, group.CalculateLength()); - var entities1 = group.ToEntityArray(Allocator.TempJob); + var entities1 = group1.ToEntityArray(Allocator.TempJob); + Assert.AreEqual(entityCount, entities1.Length); var new_e1 = entities1[0]; arrayComponent = entityManager.GetComponentData(new_e1); var a = arrayComponent.array; @@ -517,8 +571,16 @@ public unsafe void SerializeEntitiesWorksWithBlobAssetReferences() Assert.AreEqual(3.5f, a.Value[2]); Assert.AreEqual(4.4f, a.Value[3]); Assert.AreEqual(5.3f, a.Value[4]); - entities1.Dispose(); + + var entities2 = group2.ToEntityArray(Allocator.TempJob); + Assert.AreEqual(entityCount, entities2.Length); + for (int i = 0; i < entityCount; ++i) + { + var val = entityManager.GetComponentData(entities2[i]).value0; + Assert.AreEqual(val, entityManager.GetComponentData(entities2[i]).value.Value); + } + entities2.Dispose(); } finally { @@ -529,6 +591,43 @@ public unsafe void SerializeEntitiesWorksWithBlobAssetReferences() float f = 1.0f; Assert.Throws(() => f = arrayComponent.array.Value[0]); } + + [Test] + public void DeserializedChunksAreConsideredChangedOnlyOnce() + { + TestBinaryReader CreateSerializedData() + { + var world = new World("DeserializedChunksAreConsideredChangedOnlyOnce World"); + var manager = world.GetOrCreateManager(); + var entity = manager.CreateEntity(); + manager.AddComponentData(entity, new EcsTestData(42)); + var writer = new TestBinaryWriter(); + SerializeUtility.SerializeWorld(manager, writer, out var sharedData); + world.Dispose(); + return new TestBinaryReader(writer); + } + + var reader = CreateSerializedData(); + + var deserializedWorld = new World("DeserializedChunksAreConsideredChangedOnlyOnce World 2"); + var deserializedManager = deserializedWorld.GetOrCreateManager(); + var system = deserializedWorld.GetOrCreateManager(); + + system.Update(); + Assert.AreEqual(0, system.NumChanged); + + SerializeUtility.DeserializeWorld(deserializedManager.BeginExclusiveEntityTransaction(), reader, 0); + deserializedManager.EndExclusiveEntityTransaction(); + reader.Dispose(); + + system.Update(); + Assert.AreEqual(1, system.NumChanged); + + system.Update(); + Assert.AreEqual(0, system.NumChanged); + + deserializedWorld.Dispose(); + } } } -#endif \ No newline at end of file +#endif diff --git a/package/Unity.Entities.Tests/SharedComponentDataTests.cs b/package/Unity.Entities.Tests/SharedComponentDataTests.cs index 521d9dbd3..47f5be081 100755 --- a/package/Unity.Entities.Tests/SharedComponentDataTests.cs +++ b/package/Unity.Entities.Tests/SharedComponentDataTests.cs @@ -20,7 +20,7 @@ struct SharedData2 : ISharedComponentData public SharedData2(int val) { value = val; } } - [TinyFixme] // ISharedComponentData + [StandaloneFixme] // ISharedComponentData class SharedComponentDataTests : ECSTestsFixture { //@TODO: No tests for invalid shared components / destroyed shared component data diff --git a/package/Unity.Entities.Tests/SingletonTests.cs b/package/Unity.Entities.Tests/SingletonTests.cs index 964039d9d..a919687f9 100755 --- a/package/Unity.Entities.Tests/SingletonTests.cs +++ b/package/Unity.Entities.Tests/SingletonTests.cs @@ -6,7 +6,7 @@ namespace Unity.Entities.Tests class SingletonTests : ECSTestsFixture { [Test] - [TinyFixme] + [StandaloneFixme] public void GetSetSingleton() { var entity = m_Manager.CreateEntity(typeof(EcsTestData)); @@ -16,7 +16,7 @@ public void GetSetSingleton() } [Test] - [TinyFixme] + [StandaloneFixme] public void GetSetSingletonZeroThrows() { Assert.Throws(() => EmptySystem.SetSingleton(new EcsTestData())); @@ -24,7 +24,7 @@ public void GetSetSingletonZeroThrows() } [Test] - [TinyFixme] + [StandaloneFixme] public void GetSetSingletonMultipleThrows() { m_Manager.CreateEntity(typeof(EcsTestData)); @@ -35,7 +35,7 @@ public void GetSetSingletonMultipleThrows() } [Test] - [TinyFixme] + [StandaloneFixme] public void RequireSingletonWorks() { EmptySystem.RequireSingletonForUpdate(); @@ -48,7 +48,7 @@ public void RequireSingletonWorks() } [Test] - [TinyFixme] + [StandaloneFixme] public void HasSingletonWorks() { Assert.IsFalse(EmptySystem.HasSingleton()); diff --git a/package/Unity.Entities.Tests/StandaloneFixme.cs b/package/Unity.Entities.Tests/StandaloneFixme.cs new file mode 100755 index 000000000..6be963597 --- /dev/null +++ b/package/Unity.Entities.Tests/StandaloneFixme.cs @@ -0,0 +1,18 @@ +using System; +using NUnit.Framework; + +namespace Unity.Entities.Tests +{ +#if UNITY_CSHARP_TINY + public class StandaloneFixmeAttribute : IgnoreAttribute + { + public StandaloneFixmeAttribute() : base("Need to fix for Tiny.") + { + } + } +#else + public class StandaloneFixmeAttribute : Attribute + { + } +#endif +} diff --git a/package/Unity.Entities.Tests/StandaloneFixme.cs.meta b/package/Unity.Entities.Tests/StandaloneFixme.cs.meta new file mode 100755 index 000000000..48251a9ba --- /dev/null +++ b/package/Unity.Entities.Tests/StandaloneFixme.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 19db81d35de66dc4eb7378bf9191d080 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package/Unity.Entities.Tests/SystemStateBufferElementTests.cs b/package/Unity.Entities.Tests/SystemStateBufferElementTests.cs index b99bf9569..34eed5347 100755 --- a/package/Unity.Entities.Tests/SystemStateBufferElementTests.cs +++ b/package/Unity.Entities.Tests/SystemStateBufferElementTests.cs @@ -51,7 +51,7 @@ void VerifyQueryCount(ComponentGroup group, int expectedCount) } [Test] - [TinyFixme] + [StandaloneFixme] public void DeleteWhenEmpty() { var entity = m_Manager.CreateEntity( @@ -80,7 +80,7 @@ public void DeleteWhenEmpty() } [Test] - [TinyFixme] + [StandaloneFixme] public void DeleteWhenEmptyArray() { var entities = new Entity[512]; @@ -136,7 +136,7 @@ public void DeleteWhenEmptyArray() } [Test] - [TinyFixme] + [StandaloneFixme] public void DeleteWhenEmptyArray2() { var entities = new Entity[512]; @@ -192,7 +192,7 @@ public void DeleteWhenEmptyArray2() } [Test] - [TinyFixme] + [StandaloneFixme] public void DoNotInstantiateSystemState() { var entity0 = m_Manager.CreateEntity( @@ -219,7 +219,7 @@ public void InstantiateResidueEntityThrows() } [Test] - [TinyFixme] + [StandaloneFixme] public void DeleteFromEntity() { var entities = new Entity[512]; @@ -267,7 +267,7 @@ public void DeleteFromEntity() } [Test] - [TinyFixme] + [StandaloneFixme] public void DeleteFromComponentGroup() { var entities = new Entity[512]; @@ -312,7 +312,7 @@ public void DeleteFromComponentGroup() } [Test] - [TinyFixme] + [StandaloneFixme] public void DeleteTagFromComponentGroup() { var entities = new Entity[512]; diff --git a/package/Unity.Entities.Tests/SystemStateComponentTests.cs b/package/Unity.Entities.Tests/SystemStateComponentTests.cs index 881b7638f..cdf4740bb 100755 --- a/package/Unity.Entities.Tests/SystemStateComponentTests.cs +++ b/package/Unity.Entities.Tests/SystemStateComponentTests.cs @@ -41,7 +41,7 @@ void VerifyQueryCount(ComponentGroup group, int expectedCount) } [Test] - [TinyFixme] + [StandaloneFixme] public void DeleteWhenEmpty() { var entity = m_Manager.CreateEntity( @@ -69,7 +69,7 @@ public void DeleteWhenEmpty() } [Test] - [TinyFixme] + [StandaloneFixme] public void DeleteWhenEmptyArray() { var entities = new Entity[512]; @@ -124,7 +124,7 @@ public void DeleteWhenEmptyArray() } [Test] - [TinyFixme] + [StandaloneFixme] public void DeleteWhenEmptyArray2() { var entities = new Entity[512]; diff --git a/package/Unity.Entities.Tests/TestComponentSystems.cs b/package/Unity.Entities.Tests/TestComponentSystems.cs new file mode 100755 index 000000000..a3b473c03 --- /dev/null +++ b/package/Unity.Entities.Tests/TestComponentSystems.cs @@ -0,0 +1,22 @@ +using Unity.Jobs; + +namespace Unity.Entities.Tests +{ + [DisableAutoCreation] + public class TestEcsChangeSystem : JobComponentSystem + { + public int NumChanged; + ComponentGroup ChangeGroup; + protected override void OnCreateManager() + { + ChangeGroup = GetComponentGroup(typeof(EcsTestData)); + ChangeGroup.SetFilterChanged(typeof(EcsTestData)); + } + + protected override JobHandle OnUpdate(JobHandle inputDeps) + { + NumChanged = ChangeGroup.CalculateLength(); + return inputDeps; + } + } +} diff --git a/package/Unity.Entities.Tests/TestComponentSystems.cs.meta b/package/Unity.Entities.Tests/TestComponentSystems.cs.meta new file mode 100755 index 000000000..b146e4e54 --- /dev/null +++ b/package/Unity.Entities.Tests/TestComponentSystems.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 23e31bd3ce710874e8d1ea250f1ab7d8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package/Unity.Entities.Tests/TypeIndexOrderTests.cs b/package/Unity.Entities.Tests/TypeIndexOrderTests.cs index b6d65a9bf..f3a735f80 100755 --- a/package/Unity.Entities.Tests/TypeIndexOrderTests.cs +++ b/package/Unity.Entities.Tests/TypeIndexOrderTests.cs @@ -113,7 +113,7 @@ void MatchesChunkTypes(params ComponentTypeInArchetype[] types) } [Test] - [TinyFixme] + [StandaloneFixme] public unsafe void TypesInArchetypeAreOrderedAsExpected() { var archetype = m_Manager.CreateArchetype( diff --git a/package/Unity.Entities.Tests/TypeManagerTests.cs b/package/Unity.Entities.Tests/TypeManagerTests.cs index da21aa954..2146e2829 100755 --- a/package/Unity.Entities.Tests/TypeManagerTests.cs +++ b/package/Unity.Entities.Tests/TypeManagerTests.cs @@ -71,17 +71,19 @@ public void BufferTypeClassificationWorks() [Test] public void TestTypeManager() { - var entity = ComponentType.ReadWrite(); - var testData = ComponentType.ReadWrite(); + var entityType = ComponentType.ReadWrite(); + var testDataType = ComponentType.ReadWrite(); - Assert.AreEqual(entity, ComponentType.ReadWrite()); - Assert.AreEqual(entity, new ComponentType(typeof(Entity))); - Assert.AreEqual(testData, ComponentType.ReadWrite()); - Assert.AreEqual(testData, new ComponentType(typeof(EcsTestData))); + Assert.AreEqual(entityType, ComponentType.ReadWrite()); + Assert.AreEqual(entityType, new ComponentType(typeof(Entity))); + Assert.AreEqual(testDataType, ComponentType.ReadWrite()); + Assert.AreEqual(testDataType, new ComponentType(typeof(EcsTestData))); Assert.AreNotEqual(ComponentType.ReadWrite(), ComponentType.ReadWrite()); - Assert.AreNotEqual(entity, ComponentType.ReadOnly()); - Assert.AreEqual(typeof(Entity), entity.GetManagedType()); + Assert.AreEqual(ComponentType.AccessMode.ReadOnly, ComponentType.ReadOnly().AccessModeType); + Assert.AreEqual(ComponentType.AccessMode.ReadOnly, ComponentType.ReadOnly(typeof(EcsTestData)).AccessModeType); + + Assert.AreEqual(typeof(Entity), entityType.GetManagedType()); } #if !UNITY_ZEROPLAYER diff --git a/package/Unity.Entities.Tests/WorldDiffTests.cs b/package/Unity.Entities.Tests/WorldDiffTests.cs index 558080cf3..2f434d146 100755 --- a/package/Unity.Entities.Tests/WorldDiffTests.cs +++ b/package/Unity.Entities.Tests/WorldDiffTests.cs @@ -220,7 +220,7 @@ public void TestStressData(int baseIndex, int endIndex, bool testData, bool test public class WorldDiffTests : WorldDiffTestFixture { [Test] - [TinyFixme] + [StandaloneFixme] public void DiffOnly() { using (var diff = WorldDiffer.UpdateDiff(m_After, m_Shadow, Allocator.TempJob)) @@ -266,7 +266,7 @@ public void DiffOnly() } [Test] - [TinyFixme] + [StandaloneFixme] public void CreateWithComponentData() { var guid = GenerateEntityGuid(0); @@ -281,7 +281,7 @@ public void CreateWithComponentData() [Test] - [TinyFixme] + [StandaloneFixme] public void CreateWithPrefabComponent() { var guid = GenerateEntityGuid(0); @@ -295,7 +295,7 @@ public void CreateWithPrefabComponent() } [Test] - [TinyFixme] + [StandaloneFixme] public void CreateWithDisabledComponent() { var guid = GenerateEntityGuid(0); @@ -325,7 +325,7 @@ public void CreateWithPrefabAndDisabledComponent() } [Test] - [TinyFixme] + [StandaloneFixme] public void RemapEntityRef() { // Create extra entity to make sure test doesn't accidentally succeed with no remapping @@ -350,7 +350,7 @@ public void RemapEntityRef() } [Test] - [TinyFixme] + [StandaloneFixme] public void MissingEntityRefBecomesNull() { var guid = GenerateEntityGuid(0); @@ -368,7 +368,7 @@ public void MissingEntityRefBecomesNull() } [Test] - [TinyFixme] + [StandaloneFixme] public void AddComponent() { var guid = GenerateEntityGuid(0); @@ -388,7 +388,7 @@ public void AddComponent() } [Test] - [TinyFixme] + [StandaloneFixme] public void RemoveComponent() { var guid = GenerateEntityGuid(0); @@ -409,7 +409,7 @@ public void RemoveComponent() } [Test] - [TinyFixme] + [StandaloneFixme] public void CreateSharedComponent() { for (int i = 0; i != 3; i++) @@ -429,7 +429,7 @@ public void CreateSharedComponent() } [Test] - [TinyFixme] + [StandaloneFixme] public void ChangeSharedComponent() { var guid = GenerateEntityGuid(0); @@ -448,7 +448,7 @@ public void ChangeSharedComponent() } [Test] - [TinyFixme] + [StandaloneFixme] public void SharedComponentDiff() { var e = m_Manager.CreateEntity(); @@ -466,7 +466,7 @@ public void SharedComponentDiff() } [Test] - [TinyFixme] + [StandaloneFixme] public void ChangeSrcAppliesToAllDstInstances([Values]bool prefabTag) { var guid = GenerateEntityGuid(0); @@ -492,7 +492,7 @@ public void ChangeSrcAppliesToAllDstInstances([Values]bool prefabTag) } [Test] - [TinyFixme] + [StandaloneFixme] public void DynamicBuffer([Values(1, 100)]int bufferLength) { var guid = GenerateEntityGuid(0); @@ -513,7 +513,7 @@ public void DynamicBuffer([Values(1, 100)]int bufferLength) } [Test] - [TinyFixme] + [StandaloneFixme] public void DynamicBufferWithEntityStress() { int[] sizes = {10, 0, 100, 100, 7, 9, 13, 13, 13, 1}; @@ -580,7 +580,7 @@ public void ModifySingleProperty() } [Test] - [TinyFixme] + [StandaloneFixme] public void StressCreation() { // Add shared component to scramble src shared indices @@ -599,7 +599,7 @@ public void StressCreation() } [Test] - [TinyFixme] + [StandaloneFixme] public void StressDestroyOnClient() { CreateStressData(0, 2000, false, true, false); @@ -614,7 +614,7 @@ public void StressDestroyOnClient() } [Test] - [TinyFixme] + [StandaloneFixme] public void StressDestroyOnServer() { CreateStressData(0, 2000, false, true, false); @@ -630,7 +630,7 @@ public void StressDestroyOnServer() [Test] - [TinyFixme] + [StandaloneFixme] public void StressTestRecreation() { // Add shared component to scramble src shared indices @@ -697,7 +697,7 @@ unsafe void Append(ref NativeArray array, T t) where T : struct } [Test] - [TinyFixme] + [StandaloneFixme] public void EntityPatchWithMissingEntityDoesNotThrow() { var guid = GenerateEntityGuid(0); @@ -718,7 +718,7 @@ public void EntityPatchWithMissingEntityDoesNotThrow() } [Test] - [TinyFixme] + [StandaloneFixme] public void EntityPatchWithAmbiguousTargetDoesNotThrow() { var guid = GenerateEntityGuid(0); @@ -738,7 +738,7 @@ public void EntityPatchWithAmbiguousTargetDoesNotThrow() } [Test] - [TinyFixme] + [StandaloneFixme] public void NewEntityIsReplicatedIntoExistingPrefabInstances([Values(1, 10)]int instanceCount) { var rootGUID = GenerateEntityGuid(1); diff --git a/package/Unity.Entities.Tests/WorldTests.cs b/package/Unity.Entities.Tests/WorldTests.cs index 876042dc3..39d5cff7c 100755 --- a/package/Unity.Entities.Tests/WorldTests.cs +++ b/package/Unity.Entities.Tests/WorldTests.cs @@ -23,7 +23,7 @@ public virtual void TearDown() [Test] - [TinyFixme] + [StandaloneFixme] public void ActiveWorldResets() { int count = World.AllWorlds.Count(); @@ -55,7 +55,7 @@ protected override void OnUpdate() {} } [Test] - [TinyFixme] + [StandaloneFixme] public void WorldVersionIsConsistent() { var world = new World("WorldX"); @@ -78,7 +78,7 @@ public void WorldVersionIsConsistent() } [Test] - [TinyFixme] + [StandaloneFixme] public void UsingDisposedWorldThrows() { var world = new World("WorldX"); @@ -99,7 +99,7 @@ public AddWorldDuringConstructorThrowsSystem() protected override void OnUpdate() { } } [Test] - [TinyFixme] + [StandaloneFixme] public void AddWorldDuringConstructorThrows () { var world = new World("WorldX"); @@ -124,7 +124,7 @@ protected override void OnCreateManager() protected override void OnUpdate() { } } [Test] - [TinyFixme] + [StandaloneFixme] public void SystemThrowingInOnCreateManagerIsRemoved() { var world = new World("WorldX"); @@ -150,7 +150,7 @@ protected override void OnCreateManager() protected override void OnUpdate() { } } [Test] - [TinyFixme] + [StandaloneFixme] public void SystemIsAccessibleDuringOnCreateManager () { var world = new World("WorldX"); diff --git a/package/Unity.Entities.Tests/WriteGroupTests.cs b/package/Unity.Entities.Tests/WriteGroupTests.cs index 1d3753104..e4dffe550 100755 --- a/package/Unity.Entities.Tests/WriteGroupTests.cs +++ b/package/Unity.Entities.Tests/WriteGroupTests.cs @@ -47,7 +47,7 @@ struct TestInputD : IComponentData [Test] - [TinyFixme] + [StandaloneFixme] public void WG_AllOnlyMatchesExplicit() { var archetype0 = m_Manager.CreateArchetype(typeof(TestOutputA), typeof(TestInputB), typeof(TestInputC)); @@ -75,7 +75,7 @@ public void WG_AllOnlyMatchesExplicit() } [Test] - [TinyFixme] + [StandaloneFixme] public void WG_AllOnlyMatchesExplicitLateDefinition() { var group0 = m_Manager.CreateComponentGroup(new EntityArchetypeQuery() @@ -132,7 +132,7 @@ public void WG_AllOnlyMatchesExtended() } [Test] - [TinyFixme] + [StandaloneFixme] public void WG_AnyOnlyMatchesExplicit() { var archetype0 = m_Manager.CreateArchetype(typeof(TestOutputA), typeof(TestInputB), typeof(TestInputC)); @@ -246,7 +246,7 @@ public void WG_AllAllowsDependentWriteGroups() } [Test] - [TinyFixme] + [StandaloneFixme] public void WG_AllExcludesFromDependentWriteGroup() { var archetype0 = m_Manager.CreateArchetype(typeof(TestOutputA), typeof(TestOutputB), typeof(TestInputB), diff --git a/package/Unity.Entities/ArchetypeManager.cs b/package/Unity.Entities/ArchetypeManager.cs index 641319ad6..dcb627657 100755 --- a/package/Unity.Entities/ArchetypeManager.cs +++ b/package/Unity.Entities/ArchetypeManager.cs @@ -502,7 +502,7 @@ public ref UnsafePtrList ChunksWithEmptySlotsUnsafePtrList get { return ref *(UnsafePtrList*)UnsafeUtility.AddressOf(ref ChunksWithEmptySlots); } } - public void AddToChunkList(Chunk *chunk, SharedComponentValues sharedComponentIndices) + public void AddToChunkList(Chunk *chunk, SharedComponentValues sharedComponentIndices, uint changeVersion) { chunk->ListIndex = Chunks.Count; if (Chunks.Count == Chunks.Capacity) @@ -1115,7 +1115,7 @@ private bool ArchetypeSystemStateCleanupNeeded(Archetype* archetype) public void AddExistingChunk(Chunk* chunk, int* sharedComponentIndices) { var archetype = chunk->Archetype; - archetype->AddToChunkList(chunk, sharedComponentIndices); + archetype->AddToChunkList(chunk, sharedComponentIndices, m_Entities->GlobalSystemVersion); archetype->EntityCount += chunk->Count; for (var i = 0; i < archetype->NumSharedComponents; ++i) @@ -1145,7 +1145,7 @@ public void ConstructChunk(Archetype* archetype, Chunk* chunk, SharedComponentVa } } - archetype->AddToChunkList(chunk, sharedComponentValues); + archetype->AddToChunkList(chunk, sharedComponentValues, m_Entities->GlobalSystemVersion); Assert.IsTrue(archetype->Chunks.Count != 0); @@ -1497,13 +1497,17 @@ public void Execute(int index) srcArchetype->FreeChunksBySharedComponents.Init(16); } - // Zero change versions - for (int i = 0; i < dstArchetype->TypesCount; ++i) + var globalSystemVersion = dstEntityDataManager->GlobalSystemVersion; + // Set change versions to GlobalSystemVersion + for (int iType = 0; iType < dstArchetype->TypesCount; ++iType) { - var dstArray = dstArchetype->Chunks.GetChangeVersionArrayForType(i) + dstChunkCount; - UnsafeUtility.MemClear(dstArray, srcChunkCount*sizeof(uint)); + var dstArray = dstArchetype->Chunks.GetChangeVersionArrayForType(iType) + dstChunkCount; + for (int i = 0; i < srcChunkCount; ++i) + { + dstArray[i] = globalSystemVersion; + } } - + // Copy chunk count array var dstCountArray = dstArchetype->Chunks.GetChunkEntityCountArray() + dstChunkCount; UnsafeUtility.MemCpy(dstCountArray, srcArchetype->Chunks.GetChunkEntityCountArray(), sizeof(int) * srcChunkCount); @@ -1672,6 +1676,7 @@ struct MoveChunksBetweenArchetypeJob : IJob { [ReadOnly] public NativeArray remapChunks; [ReadOnly] public NativeArray remapShared; + public uint globalSystemVersion; public void Execute() { @@ -1702,7 +1707,7 @@ public void Execute() chunk->Archetype = dstArchetype; dstArchetype->EntityCount += chunk->Count; - dstArchetype->AddToChunkList(chunk, sharedComponentValues); + dstArchetype->AddToChunkList(chunk, sharedComponentValues, globalSystemVersion); if (chunk->Count < chunk->Capacity) EmptySlotTrackingAddChunk(chunk); } @@ -1767,7 +1772,8 @@ public static void MoveChunks(EntityManager srcEntities, NativeArrayGlobalSystemVersion }.Schedule(remapChunksJob); moveChunksBetweenArchetypeJob.Complete(); diff --git a/package/Unity.Entities/Blobs.cs b/package/Unity.Entities/Blobs.cs index ae5e10c70..af59499e5 100755 --- a/package/Unity.Entities/Blobs.cs +++ b/package/Unity.Entities/Blobs.cs @@ -162,7 +162,7 @@ public void ValidateNotNull() } } - public unsafe struct BlobAssetReference where T : struct + public unsafe struct BlobAssetReference : IEquatable> where T : struct { internal BlobAssetReferenceData m_data; @@ -224,6 +224,33 @@ public static BlobAssetReference Create(T value) { return Create(UnsafeUtility.AddressOf(ref value), UnsafeUtility.SizeOf()); } + + public static BlobAssetReference Null => new BlobAssetReference(); + + public static bool operator ==(BlobAssetReference lhs, BlobAssetReference rhs) + { + return lhs.m_data.m_Ptr == rhs.m_data.m_Ptr; + } + + public static bool operator !=(BlobAssetReference lhs, BlobAssetReference rhs) + { + return lhs.m_data.m_Ptr != rhs.m_data.m_Ptr; + } + + public bool Equals(BlobAssetReference other) + { + return m_data.Equals(other.m_data); + } + + public override bool Equals(object obj) + { + return this == (BlobAssetReference)obj; + } + + public override int GetHashCode() + { + return m_data.GetHashCode(); + } } unsafe public struct BlobPtr where T : struct diff --git a/package/Unity.Entities/ChangeVersionUtility.cs b/package/Unity.Entities/ChangeVersionUtility.cs index 74dd14981..024654b05 100755 --- a/package/Unity.Entities/ChangeVersionUtility.cs +++ b/package/Unity.Entities/ChangeVersionUtility.cs @@ -4,9 +4,6 @@ static public class ChangeVersionUtility { public static bool DidChange(uint changeVersion, uint requiredVersion) { - // initial state data always triggers a change - if (changeVersion == 0) - return true; // When a system runs for the first time, everything is considered changed. if (requiredVersion == 0) return true; diff --git a/package/Unity.Entities/ComponentSystem.cs b/package/Unity.Entities/ComponentSystem.cs index d0dc4a835..8fcbc86a2 100755 --- a/package/Unity.Entities/ComponentSystem.cs +++ b/package/Unity.Entities/ComponentSystem.cs @@ -307,7 +307,10 @@ internal void AddReaderWriter(ComponentType componentType) internal void AddReaderWriters(ComponentGroup group) { - group.AddReaderWritersToLists(ref JobDependencyForReadingManagersUnsafeList, ref JobDependencyForWritingManagersUnsafeList); + if (group.AddReaderWritersToLists(ref JobDependencyForReadingManagersUnsafeList, ref JobDependencyForWritingManagersUnsafeList)) + { + CompleteDependencyInternal(); + } } internal ComponentGroup GetComponentGroupInternal(ComponentType* componentTypes, int count) @@ -424,17 +427,17 @@ internal void CompleteDependencyInternal() public abstract partial class ComponentSystem : ComponentSystemBase { EntityCommandBuffer m_DeferredEntities; - ComponentQueryCache m_ComponentQueryCache; + EntityQueryCache m_EntityQueryCache; public EntityCommandBuffer PostUpdateCommands => m_DeferredEntities; - protected internal void InitComponentQueryCache(int cacheSize) => - m_ComponentQueryCache = new ComponentQueryCache(cacheSize); + protected internal void InitEntityQueryCache(int cacheSize) => + m_EntityQueryCache = new EntityQueryCache(cacheSize); - internal ComponentQueryCache GetOrCreateComponentQueryCache() - => m_ComponentQueryCache ?? (m_ComponentQueryCache = new ComponentQueryCache()); + internal EntityQueryCache GetOrCreateEntityQueryCache() + => m_EntityQueryCache ?? (m_EntityQueryCache = new EntityQueryCache()); - protected internal ComponentQueryBuilder Entities => new ComponentQueryBuilder(this); + protected internal EntityQueryBuilder Entities => new EntityQueryBuilder(this); unsafe void BeforeOnUpdate() { @@ -701,7 +704,7 @@ unsafe void AddDependencyInternal(JobHandle dependency) m_PreviousFrameDependency = m_SafetyManager.AddDependency(m_JobDependencyForReadingManagers.p, m_JobDependencyForReadingManagers.Count, m_JobDependencyForWritingManagers.p, m_JobDependencyForWritingManagers.Count, dependency); } } - + [Obsolete("BarrierSystem has been renamed. Use EntityCommandBufferSystem instead (UnityUpgradable) -> EntityCommandBufferSystem", true)] [System.ComponentModel.EditorBrowsable(EditorBrowsableState.Never)] public struct BarrierSystem { } diff --git a/package/Unity.Entities/ComponentSystemGroup.cs b/package/Unity.Entities/ComponentSystemGroup.cs index 897b7e6a9..eddd27804 100755 --- a/package/Unity.Entities/ComponentSystemGroup.cs +++ b/package/Unity.Entities/ComponentSystemGroup.cs @@ -137,21 +137,34 @@ struct SysAndDep } public struct TypeHeapElement : IComparable { - private int typeHash; - public Type type; + private string typeName; + public int unsortedIndex; - public TypeHeapElement(Type t) + public TypeHeapElement(int index, Type t) { - type = t; - typeHash = t.GetHashCode(); + unsortedIndex = index; + typeName = TypeManager.SystemName(t); } public int CompareTo(TypeHeapElement other) { - if (typeHash < other.typeHash) +#if UNITY_CSHARP_TINY + // Workaround for missing string.CompareTo() in HPC#. This is not a fully compatible substitute, + // but should be suitable for comparing system names. + if (typeName.Length < other.typeName.Length) return -1; - else if (typeHash > other.typeHash) + if (typeName.Length > other.typeName.Length) return 1; + for (int i = 0; i < typeName.Length; ++i) + { + if (typeName[i] < other.typeName[i]) + return -1; + if (typeName[i] > other.typeName[i]) + return 1; + } return 0; +#else + return typeName.CompareTo(other.typeName); +#endif } } @@ -259,18 +272,18 @@ public virtual void SortSystemUpdateList() } // Clear the systems list and rebuild it in sorted order from the lookup table - var readySystems = new Heap(m_systemsToUpdate.Count); + var readySystems = new Heap(m_systemsToUpdate.Count); m_systemsToUpdate.Clear(); for (int i = 0; i < sysAndDep.Length; ++i) { if (sysAndDep[i].nAfter == 0) { - readySystems.Insert(i); + readySystems.Insert(new TypeHeapElement(i, sysAndDep[i].system.GetType())); } } while (!readySystems.Empty) { - int sysIndex = readySystems.Extract(); + int sysIndex = readySystems.Extract().unsortedIndex; SysAndDep sd = sysAndDep[sysIndex]; Type sysType = sd.system.GetType(); @@ -285,7 +298,7 @@ public virtual void SortSystemUpdateList() sysAndDep[beforeIndex].nAfter--; if (sysAndDep[beforeIndex].nAfter == 0) { - readySystems.Insert(beforeIndex); + readySystems.Insert(new TypeHeapElement(beforeIndex, sysAndDep[beforeIndex].system.GetType())); } } } @@ -343,7 +356,14 @@ protected override void OnUpdate() { foreach (var sys in m_systemsToUpdate) { - sys.Update(); + try + { + sys.Update(); + } + catch (Exception e) + { + Debug.LogException(e); + } if (World.QuitUpdate) break; } diff --git a/package/Unity.Entities/EntityDataManager.cs b/package/Unity.Entities/EntityDataManager.cs index 88fcf2e72..abe1e1464 100755 --- a/package/Unity.Entities/EntityDataManager.cs +++ b/package/Unity.Entities/EntityDataManager.cs @@ -1096,7 +1096,8 @@ public void MoveChunkToNewArchetype(Chunk* chunk, Archetype* newArchetype, uint var oldTypes = oldArchetype->Types; chunk->Archetype = newArchetype; - newArchetype->AddToChunkList(chunk, sharedComponentValues); + //Change version is overriden below + newArchetype->AddToChunkList(chunk, sharedComponentValues, 0); int chunkIndexInNewArchetype = chunk->ListIndex; //Copy change versions from old to new archetype diff --git a/package/Unity.Entities/EntityManager.cs b/package/Unity.Entities/EntityManager.cs index ee607d57b..6f5a59090 100755 --- a/package/Unity.Entities/EntityManager.cs +++ b/package/Unity.Entities/EntityManager.cs @@ -20,38 +20,100 @@ namespace Unity.Entities // Static Analysis or runtime checks? //@TODO: safety? + + /// + /// An EntityArchetype is a unique combination of component types. The + /// uses the archetype to group all entities that have the same sets of components. + /// + /// + /// An entity can change archetype fluidly over its lifespan. For example, when you add or + /// remove components, the archetype of the affected entity changes. + /// + /// An archetype object is not a container; rather it is an identifier to each unique combination + /// of component types that an application has created at run time, either directly or implicitly. + /// + /// You can create archetypes directly using . + /// You also implicitly create archetypes whenever you add or remove a component from an entity. An EntityArchetype + /// object is an immutable singleton; creating an archetype with the same set of components, either directly or + /// implicitly, results in the same archetype for a given EntityManager. + /// + /// The ECS framework uses archetypes to group entities that have the same structure together. The ECS framework + /// stores component data in blocks of memory called *chunks*. A given chunk stores only entities having the same + /// archetype. You can get the EntityArchetype object for a chunk from its + /// property. + /// [DebuggerTypeProxy(typeof(EntityArchetypeDebugView))] public unsafe struct EntityArchetype : IEquatable { [NativeDisableUnsafePtrRestriction] internal Archetype* Archetype; + /// + /// Reports whether this EntityArchetype instance references a non-null archetype. + /// + /// True, if the archetype is valid. public bool Valid => Archetype != null; + /// + /// Compares the archetypes for equality. + /// + /// A EntityArchetype object. + /// Another EntityArchetype object. + /// True, if these EntityArchetype instances reference the same archetype. public static bool operator ==(EntityArchetype lhs, EntityArchetype rhs) { return lhs.Archetype == rhs.Archetype; } + /// + /// Compares the archetypes for inequality. + /// + /// A EntityArchetype object. + /// Another EntityArchetype object. + /// True, if these EntityArchetype instances reference different archetypes. public static bool operator !=(EntityArchetype lhs, EntityArchetype rhs) { return lhs.Archetype != rhs.Archetype; } + /// + /// Reports whether this EntityArchetype references the same archetype as another object. + /// + /// The object to compare. + /// True, if the compare parameter is a EntityArchetype instance that points to the same + /// archetype. public override bool Equals(object compare) { return this == (EntityArchetype) compare; } + /// + /// Compares archetypes for equality. + /// + /// The EntityArchetype to compare. + /// Returns true, if both EntityArchetype instances reference the same archetype. public bool Equals(EntityArchetype entityArchetype) { return Archetype == entityArchetype.Archetype; } + /// + /// Returns the hash of the archetype. + /// + /// Two EntityArchetype instances referencing the same archetype return the same hash. + /// An integer hash code. public override int GetHashCode() { return (int) Archetype; } + /// + /// Gets the types of the components making up this archetype. + /// + /// The set of component types in an archetype cannot change; adding components to an entity or + /// removing components from an entity changes the archetype of that entity (possibly resulting in the + /// creation of a new archetype). The original archetype remains unchanged. + /// The allocation type to use for the returned NativeArray. + /// A native array containing the objects of this archetype. public NativeArray GetComponentTypes(Allocator allocator = Allocator.Temp) { var types = new NativeArray(Archetype->TypesCount, allocator); @@ -60,49 +122,149 @@ public NativeArray GetComponentTypes(Allocator allocator = Alloca return types; } + /// + /// The current number of chunks storing entities having this archetype. + /// + /// The number of chunks. + /// This value can change whenever structural changes occur. + /// Structural changes include creating or destroying entities, adding components to or removing them from + /// an entity, and changing the value of shared components, all of which alter where entities are stored. + /// public int ChunkCount => Archetype->Chunks.Count; + /// + /// The number of entities having this archetype that can fit into a single chunk of memory. + /// + /// Capacity is determined by the fixed, 16KB size of the memory blocks allocated by the ECS framework + /// and the total storage size of all the component types in the archetype. public int ChunkCapacity => Archetype->ChunkCapacity; } + /// + /// Identifies an entity. + /// + /// + /// The entity is a fundamental part of the Entity Component System. Everything in your game that has data or an + /// identity of its own is an entity. However, an entity does not contain either data or behavior itself. Instead, + /// the data is stored in the components and the behavior is provided by the systems that process those + /// components. The entity acts as an identifier or key to the data stored in components. + /// + /// Entities are managed by the class and exist within a . An + /// Entity struct refers to an entity, but is not a reference. Rather the Entity struct contains an + /// used to access entity data and a used to check whether the Index is + /// still valid. Note that you generally do not use the Index or Version values directly, but instead pass the + /// Entity struct to the relevant API methods. + /// + /// Pass an Entity struct to methods of the , the , + /// or the in order to add or remove components, to access components, or to destroy + /// the entity. + /// public struct Entity : IEquatable { + /// + /// The ID of an entity. + /// + /// The index into the internal list of entities. + /// + /// Entity indexes are recycled when an entity is destroyed. When an entity is destroyed, the + /// EntityManager increments the version identifier. To represent the same entity, both the Index and the + /// Version fields of the Entity object must match. If the Index is the same, but the Version is different, + /// then the entity has been recycled. + /// public int Index; + /// + /// The generational version of the entity. + /// + /// The Version number can, theoretically, overflow and wrap around within the lifetime of an + /// application. For this reason, you cannot assume that an Entity instance with a larger Version is a more + /// recent incarnation of the entity than one with a smaller Version (and the same Index). + /// Used to determine whether this Entity object still identifies an existing entity. public int Version; + /// + /// Entity instances are equal if they refer to the same entity. + /// + /// An Entity object. + /// Another Entity object. + /// True, if both Index and Version are identical. public static bool operator ==(Entity lhs, Entity rhs) { return lhs.Index == rhs.Index && lhs.Version == rhs.Version; } + /// + /// Entity instances are equal if they refer to the same entity. + /// + /// An Entity object. + /// Another Entity object. + /// True, if either Index or Version are different. public static bool operator !=(Entity lhs, Entity rhs) { - return lhs.Index != rhs.Index || lhs.Version != rhs.Version; + return !(lhs == rhs); } + /// + /// Entity instances are equal if they refer to the same entity. + /// + /// The object to compare to this Entity. + /// True, if the compare parameter contains an Entity object having the same Index and Version + /// as this Entity. public override bool Equals(object compare) { return this == (Entity) compare; } + /// + /// A hash used for comparisons. + /// + /// A unique hash code. public override int GetHashCode() { return Index; } + /// + /// A "blank" Entity object that does not refer to an actual entity. + /// public static Entity Null => new Entity(); + /// + /// Entity instances are equal if they represent the same entity. + /// + /// The other Entity. + /// True, if the Entity instances have the same Index and Version. public bool Equals(Entity entity) { return entity.Index == Index && entity.Version == Version; } + /// + /// Provides a debugging string. + /// + /// A string containing the entity index and generational version. public override string ToString() { return $"Entity Index: {Index} Version: {Version}"; } } + /// + /// The EntityManager manages entities and components in a World. + /// + /// + /// The EntityManager provides an API to create, read, update, and destroy entities. + /// + /// A has one EntityManager, which manages all the entities for that World. + /// + /// Many EntityManager operations result in *structural changes* that change the layout of entities in memory. + /// Before it can perform such operations, the EntityManager must wait for all running Jobs to complete, an event + /// called a *sync point*. A sync point both blocks the main thread and prevents the application from taking + /// advantage of all available cores as the running Jobs wind down. + /// + /// Although you cannot prevent sync points entirely, you should avoid them as much as possible. To this end, the ECS + /// framework provides the , which allows you to queue structural changes so that + /// they all occur at one time in the frame. + /// [Preserve] [DebuggerTypeProxy(typeof(EntityManagerDebugView))] public sealed unsafe class EntityManager : ScriptBehaviourManager @@ -118,6 +280,9 @@ public sealed unsafe class EntityManager : ScriptBehaviourManager World m_World; private ComponentGroup m_UniversalGroup; // matches all components + /// + /// A ComponentGroup instance that matches all components. + /// public ComponentGroup UniversalGroup => m_UniversalGroup; #if ENABLE_UNITY_COLLECTIONS_CHECKS @@ -154,12 +319,41 @@ internal ArchetypeManager ArchetypeManager get { return m_ArchetypeManager; } } + /// + /// The latest entity generational version. + /// + /// This is the version number that is assigned to a new entity. See . public int Version => IsCreated ? m_Entities->Version : 0; + /// + /// A counter that increments after every system update. + /// + /// + /// The ECS framework uses the GlobalSystemVersion to track changes in a conservative, efficient fashion. + /// Changes are recorded per component per chunk. + /// + /// + /// public uint GlobalSystemVersion => IsCreated ? Entities->GlobalSystemVersion : 0; + /// + /// Reports whether the EntityManager has been initialized yet. + /// + /// True, if the EntityManager's OnCreateManager() function has finished. public bool IsCreated => m_Entities != null; + /// + /// The capacity of the internal entities array. + /// + /// The number of entities the array can hold before it must be resized. + /// + /// The entities array automatically resizes itself when the entity count approaches the capacity. + /// You should rarely need to set this value directly. + /// + /// **Important:** when you set this value (or when the array automatically resizes), the EntityManager + /// first ensures that all Jobs finish. This can prevent the Job scheduler from utilizing available CPU + /// cores and threads, resulting in a temporary performance drop. + /// public int EntityCapacity { get { return Entities->Capacity; } @@ -172,6 +366,10 @@ public int EntityCapacity internal ComponentJobSafetyManager ComponentJobSafetyManager { get; private set; } + /// + /// The Job dependencies of the exclusive entity transaction. + /// + /// public JobHandle ExclusiveEntityTransactionDependency { get { return ComponentJobSafetyManager.ExclusiveTransactionDependency; } @@ -180,6 +378,9 @@ public JobHandle ExclusiveEntityTransactionDependency EntityManagerDebug m_Debug; + /// + /// An object providing debugging information and operations. + /// public EntityManagerDebug Debug => m_Debug ?? (m_Debug = new EntityManagerDebug(this)); protected override void OnBeforeCreateManagerInternal(World world) @@ -264,6 +465,12 @@ internal static int FillSortedArchetypeArray(ComponentTypeInArchetype* dst, Comp return count + 1; } + /// + /// Creates a ComponentGroup from an array of component types. + /// + /// An array containing the component types. + /// The ComponentGroup derived from the specified array of component types. + /// public ComponentGroup CreateComponentGroup(params ComponentType[] requiredComponents) { fixed (ComponentType* requiredComponentsPtr = requiredComponents) @@ -275,6 +482,11 @@ internal ComponentGroup CreateComponentGroup(ComponentType* requiredComponents, { return m_GroupManager.CreateEntityGroup(ArchetypeManager, Entities, requiredComponents, count); } + /// + /// Creates a ComponentGroup from an EntityArchetypeQuery. + /// + /// A query identifying a set of component types. + /// The ComponentGroup corresponding to the query. public ComponentGroup CreateComponentGroup(params EntityArchetypeQuery[] queries) { return m_GroupManager.CreateEntityGroup(ArchetypeManager, Entities, queries); @@ -300,6 +512,14 @@ internal EntityArchetype CreateArchetype(ComponentType* types, int count) return entityArchetype; } + /// + /// Creates an archetype from a set of component types. + /// + /// + /// Creates a new archetype in the ECS framework's internal type registry, unless the archetype already exists. + /// + /// The component types to include as part of the archetype. + /// The EntityArchetype object for the archetype. public EntityArchetype CreateArchetype(params ComponentType[] types) { fixed (ComponentType* typesPtr = types) @@ -309,30 +529,68 @@ public EntityArchetype CreateArchetype(params ComponentType[] types) } /// - /// Create a set of Entity of the specified EntityArchetype. + /// Creates a set of entities of the specified archetype. /// - /// - /// + /// Fills the [NativeArray](https://docs.unity3d.com/ScriptReference/Unity.Collections.NativeArray_1.html) + /// object assigned to the `entities` parameter with the Entity objects of the created entities. Each entity + /// has the components specified by the object assigned + /// to the `archetype` parameter. The EntityManager adds these entities to the entity list. Use the + /// Entity objects in the array for further processing, such as setting the component values. + /// The archetype defining the structure for the new entities. + /// An array to hold the Entity objects needed to access the new entities. + /// The length of the array determines how many entities are created. public void CreateEntity(EntityArchetype archetype, NativeArray entities) { CreateEntityInternal(archetype, (Entity*) entities.GetUnsafePtr(), entities.Length); } + /// + /// Protects a chunk, and the entities within it, from structural changes. + /// + /// + /// When locked, entities cannot be added to or removed from the chunk; components cannot be added to or + /// removed from the entities in the chunk; the values of shared components cannot be changed; and entities + /// in the chunk cannot be destroyed. You can change the values of components, other than shared components. + /// + /// Call to unlock the chunk. + /// + /// You can lock a chunk temporarily and then unlock it, or you can lock it for the lifespan of your application. + /// For example, if you have a gameboard with a fixed number of tiles, you may want the entities representing + /// those tiles in a specific order. Locking the chunk prevents the ECS framework from rearranging them once you + /// have set the desired order. + /// + /// Use to re-order entities in a chunk. + /// + /// The chunk to lock. public void LockChunk(ArchetypeChunk chunk) { LockChunksInternal(&chunk, 1, ChunkFlags.Locked); } + /// + /// Locks a set of chunks. + /// + /// An array of chunks to lock. + /// public void LockChunk(NativeArray chunks) { LockChunksInternal(chunks.GetUnsafePtr(), chunks.Length, ChunkFlags.Locked); } + + /// + /// Unlocks a chunk + /// + /// The chunk to unlock. public void UnlockChunk(ArchetypeChunk chunk) { UnlockChunksInternal(&chunk, 1, ChunkFlags.Locked); } + /// + /// Unlocks a set of chunks. + /// + /// An array of chunks to unlock. public void UnlockChunk(NativeArray chunks) { UnlockChunksInternal(chunks.GetUnsafePtr(), chunks.Length, ChunkFlags.Locked); @@ -377,22 +635,49 @@ internal void LockChunksInternal(void* chunks, int count, ChunkFlags flags) } /// - /// Create a set of Chunk of the specified EntityArchetype. + /// Creates a set of chunks containing the specified number of entities having the specified archetype. /// - /// - /// - /// + /// + /// The EntityManager creates enough chunks to hold the required number of entities. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before creating these chunks and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The archetype for the chunk and entities. + /// An empty array to receive the created chunks. + /// The number of entities to create. public void CreateChunk(EntityArchetype archetype, NativeArray chunks, int entityCount) { CreateChunkInternal(archetype, (ArchetypeChunk*) chunks.GetUnsafePtr(), entityCount); } + /// + /// Gets the chunk in which the specified entity is stored. + /// + /// The entity. + /// The chunk containing the entity. public ArchetypeChunk GetChunk(Entity entity) { var chunk = Entities->GetComponentChunk(entity); return new ArchetypeChunk {m_Chunk = chunk}; } + /// + /// Creates an entity having the specified archetype. + /// + /// + /// The EntityManager creates the entity in the first available chunk with the matching archetype that has + /// enough space. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before creating the entity and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The archetype for the new entity. + /// The Entity object that you can use to access the entity. public Entity CreateEntity(EntityArchetype archetype) { Entity entity; @@ -400,6 +685,20 @@ public Entity CreateEntity(EntityArchetype archetype) return entity; } + /// + /// Creates an entity having components of the specified types. + /// + /// + /// The EntityManager creates the entity in the first available chunk with the matching archetype that has + /// enough space. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before creating the entity and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The types of components to add to the new entity. + /// The Entity object that you can use to access the entity. public Entity CreateEntity(params ComponentType[] types) { return CreateEntity(CreateArchetype(types)); @@ -432,6 +731,12 @@ NativeArray GetTempEntityArray(ComponentGroup group) return entityArray; } + /// + /// Destroy all entities having a common set of component types. + /// + /// Since entities in the same chunk share the same component structure, this function effectively destroys + /// the chunks holding any entities identified by the `componentGroupFilter` parameter. + /// Defines the components an entity must have to qualify for destruction. public void DestroyEntity(ComponentGroup componentGroupFilter) { //@TODO: When destroying entities with componentGroupFilter we assume that any LinkedEntityGroup also get destroyed @@ -458,16 +763,46 @@ public void DestroyEntity(ComponentGroup componentGroupFilter) Profiler.EndSample(); } + /// + /// Destroys all entities in an array. + /// + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before destroying the entity and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// An array containing the Entity objects of the entities to destroy. public void DestroyEntity(NativeArray entities) { DestroyEntityInternal((Entity*) entities.GetUnsafeReadOnlyPtr(), entities.Length); } + /// + /// Destroys all entities in a slice of an array. + /// + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before destroying the entity and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The slice of an array containing the Entity objects of the entities to destroy. public void DestroyEntity(NativeSlice entities) { DestroyEntityInternal((Entity*) entities.GetUnsafeReadOnlyPtr(), entities.Length); } + /// + /// Destroys an entity. + /// + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before destroying the entity and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The Entity object of the entity to destroy. public void DestroyEntity(Entity entity) { DestroyEntityInternal(&entity, 1); @@ -481,37 +816,104 @@ internal void DestroyEntityInternal(Entity* entities, int count) } #if UNITY_EDITOR + /// + /// Gets the name assigned to an entity. + /// + /// For performance, entity names only exist when running in the Unity Editor. + /// The Entity object of the entity of interest. + /// The entity name. public string GetName(Entity entity) { return Entities->GetName(entity); } + /// + /// Sets the name of an entity. + /// + /// For performance, entity names only exist when running in the Unity Editor. + /// The Entity object of the entity to name. + /// The name to assign. public void SetName(Entity entity, string name) { Entities->SetName(entity, name); } #endif + // @TODO Point to documentation for multithreaded way to check Entity validity. + /// + /// Reports whether an Entity object is still valid. + /// + /// + /// An Entity object does not contain a reference to its entity. Instead, the Entity struct contains an index + /// and a generational version number. When an entity is destroyed, the EntityManager increments the version + /// of the entity within the internal array of entities. The index of a destroyed entity is recycled when a + /// new entity is created. + /// + /// After an entity is destroyed, any existing Entity objects will still contain the + /// older version number. This function compares the version numbers of the specified Entity object and the + /// current version of the entity recorded in the entities array. If the versions are different, the Entity + /// object no longer refers to an existing entity and cannot be used. + /// + /// The Entity object to check. + /// True, if matches the version of the current entity at + /// in the entities array. public bool Exists(Entity entity) { return Entities->Exists(entity); } + /// + /// Checks whether an entity has a specific type of component. + /// + /// Always returns false for an entity that has been destroyed. + /// The Entity object. + /// The data type of the component. + /// True, if the specified entity has the component. public bool HasComponent(Entity entity) { return Entities->HasComponent(entity, ComponentType.ReadWrite()); } + /// + /// Checks whether an entity has a specific type of component. + /// + /// Always returns false for an entity that has been destroyed. + /// The Entity object. + /// The data type of the component. + /// True, if the specified entity has the component. public bool HasComponent(Entity entity, ComponentType type) { return Entities->HasComponent(entity, type); } + /// + /// Checks whether the chunk containing an entity has a specific type of component. + /// + /// Always returns false for an entity that has been destroyed. + /// The Entity object. + /// The data type of the chunk component. + /// True, if the chunk containing the specified entity has the component. public bool HasChunkComponent(Entity entity) { return Entities->HasComponent(entity, ComponentType.ChunkComponent()); } + /// + /// Clones an entity. + /// + /// + /// The new entity has the same archetype and component values as the original. + /// + /// If the source entity has a component, the entire group is cloned as a new + /// set of entities. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before creating the entity and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The entity to clone + /// The Entity object for the new entity. public Entity Instantiate(Entity srcEntity) { Entity entity; @@ -519,6 +921,23 @@ public Entity Instantiate(Entity srcEntity) return entity; } + /// + /// Makes multiple clones of an entity. + /// + /// + /// The new entities have the same archetype and component values as the original. + /// + /// If the source entity has a component, the entire group is cloned as a new + /// set of entities. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before creating these entities and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The entity to clone + /// An array to receive the Entity objects of the root entity in each clone. + /// The length of this array determines the number of clones. public void Instantiate(Entity srcEntity, NativeArray outputEntities) { InstantiateInternal(srcEntity, (Entity*) outputEntities.GetUnsafePtr(), outputEntities.Length); @@ -531,6 +950,25 @@ internal void InstantiateInternal(Entity srcEntity, Entity* outputEntities, int Entities->InstantiateEntities(ArchetypeManager, m_SharedComponentManager, srcEntity, outputEntities, count); } + /// + /// Adds a component to an entity. + /// + /// + /// Adding a component changes the entity's archetype and results in the entity being moved to a different + /// chunk. + /// + /// The added component has the default values for the type. + /// + /// If the object refers to an entity that has been destroyed, this function throws an ArgumentError + /// exception. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before adding thes component and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The Entity object. + /// The type of component to add. public void AddComponent(Entity entity, ComponentType componentType) { BeforeStructuralChange(); @@ -538,6 +976,22 @@ public void AddComponent(Entity entity, ComponentType componentType) Entities->AddComponent(entity, componentType, ArchetypeManager, m_SharedComponentManager, m_GroupManager); } + /// + /// Adds a component to a set of entities defined by a ComponentGroup. + /// + /// + /// Adding a component changes an entity's archetype and results in the entity being moved to a different + /// chunk. + /// + /// The added components have the default values for the type. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before adding the component and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The ComponentGroup defining the entities to modify. + /// The type of component to add. public void AddComponent(ComponentGroup componentGroup, ComponentType componentType) { using (var chunks = componentGroup.CreateArchetypeChunkArray(Allocator.TempJob)) @@ -551,12 +1005,50 @@ public void AddComponent(ComponentGroup componentGroup, ComponentType componentT } //@TODO: optimize for batch + /// + /// Adds a component to a set of entities. + /// + /// + /// Adding a component changes an entity's archetype and results in the entity being moved to a different + /// chunk. + /// + /// The added components have the default values for the type. + /// + /// If an object in the `entities` array refers to an entity that has been destroyed, this function + /// throws an ArgumentError exception. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before creating these chunks and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// An array of Entity objects. + /// The type of component to add. public void AddComponent(NativeArray entities, ComponentType componentType) { for(int i =0;i != entities.Length;i++) AddComponent(entities[i], componentType); } + /// + /// Adds a set of component to an entity. + /// + /// + /// Adding components changes the entity's archetype and results in the entity being moved to a different + /// chunk. + /// + /// The added components have the default values for the type. + /// + /// If the object refers to an entity that has been destroyed, this function throws an ArgumentError + /// exception. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before adding these components and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The entity to modify. + /// The types of components to add. public void AddComponents(Entity entity, ComponentTypes types) { BeforeStructuralChange(); @@ -564,12 +1056,40 @@ public void AddComponents(Entity entity, ComponentTypes types) Entities->AddComponents(entity, types, ArchetypeManager, m_SharedComponentManager, m_GroupManager); } + /// + /// Removes a component from an entity. + /// + /// + /// Removing a component changes an entity's archetype and results in the entity being moved to a different + /// chunk. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before removing the component and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The entity to modify. + /// The type of component to remove. public void RemoveComponent(Entity entity, ComponentType type) { BeforeStructuralChange(); EntityDataManager.RemoveComponent(entity, type, Entities, ArchetypeManager, m_SharedComponentManager, m_GroupManager); } + /// + /// Removes a component from a set of entities defined by a ComponentGroup. + /// + /// + /// Removing a component changes an entity's archetype and results in the entity being moved to a different + /// chunk. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before removing the component and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The ComponentGroup defining the entities to modify. + /// The type of component to remove. public void RemoveComponent(ComponentGroup componentGroup, ComponentType componentType) { using (var chunks = componentGroup.CreateArchetypeChunkArray(Allocator.TempJob)) @@ -593,17 +1113,60 @@ public void RemoveComponent(ComponentGroup componentGroupFilter, ComponentTypes } //@TODO: optimize for batch + /// + /// Removes a component from a set of entities. + /// + /// + /// Removing a component changes an entity's archetype and results in the entity being moved to a different + /// chunk. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before removing the component and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// An array identifying the entities to modify. + /// The type of component to remove. public void RemoveComponent(NativeArray entities, ComponentType type) { for(int i =0;i != entities.Length;i++) RemoveComponent(entities[i], type); } + /// + /// Removes a component from an entity. + /// + /// + /// Removing a component changes an entity's archetype and results in the entity being moved to a different + /// chunk. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before removing the component and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The entity. + /// The type of component to remove. public void RemoveComponent(Entity entity) { RemoveComponent(entity, ComponentType.ReadWrite()); } + /// + /// Adds a component to an entity and set the value of that component. + /// + /// + /// Adding a component changes an entity's archetype and results in the entity being moved to a different + /// chunk. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before adding the component and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The entity. + /// The data to set. + /// The type of component. public void AddComponentData(Entity entity, T componentData) where T : struct, IComponentData { var type = ComponentType.ReadWrite(); @@ -612,16 +1175,68 @@ public void AddComponentData(Entity entity, T componentData) where T : struct SetComponentData(entity, componentData); } + /// + /// Removes a chunk component from the specified entity. + /// + /// + /// A chunk component is common to all entities in a chunk. Removing the chunk component from an entity changes + /// that entity's archetype and results in the entity being moved to a different chunk (that does not have the + /// removed component). + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before removing the component and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The entity. + /// The type of component to remove. public void RemoveChunkComponent(Entity entity) { RemoveComponent(entity, ComponentType.ChunkComponent()); } + /// + /// Adds a chunk component to the specified entity. + /// + /// + /// Adding a chunk component to an entity changes that entity's archetype and results in the entity being moved + /// to a different chunk, either one that already has an archetype containing the chunk component or a new + /// chunk. + /// + /// A chunk component is common to all entities in a chunk. You can access a chunk + /// instance through either the chunk itself or through an entity stored in that chunk. In either case, getting + /// or setting the component reads or writes the same data. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before adding the component and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The entity. + /// The type of component, which must implement IComponentData. public void AddChunkComponentData(Entity entity) where T : struct, IComponentData { AddComponent(entity, ComponentType.ChunkComponent()); } + /// + /// Adds a component to each of the chunks identified by a ComponentGroup and set the component values. + /// + /// + /// This function finds all chunks whose archetype satisfies the ComponentGroup and adds the specified + /// component to them. + /// + /// A chunk component is common to all entities in a chunk. You can access a chunk + /// instance through either the chunk itself or through an entity stored in that chunk. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before adding the component and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The ComponentGroup identifying the chunks to modify. + /// The data to set. + /// The type of component, which must implement IComponentData. public void AddChunkComponentData(ComponentGroup componentGroup, T componentData) where T : struct, IComponentData { using (var chunks = componentGroup.CreateArchetypeChunkArray(Allocator.TempJob)) @@ -634,6 +1249,20 @@ public void AddChunkComponentData(ComponentGroup componentGroup, T componentD } } + /// + /// Removes a component from the chunks identified by a ComponentGroup. + /// + /// + /// A chunk component is common to all entities in a chunk. You can access a chunk + /// instance through either the chunk itself or through an entity stored in that chunk. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before removing the component and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The ComponentGroup identifying the chunks to modify. + /// The type of component to remove. public void RemoveChunkComponentData(ComponentGroup componentGroup) { using (var chunks = componentGroup.CreateArchetypeChunkArray(Allocator.TempJob)) @@ -645,6 +1274,26 @@ public void RemoveChunkComponentData(ComponentGroup componentGroup) } } + /// + /// Adds a dynamic buffer component to an entity. + /// + /// + /// A buffer component stores the number of elements inside the chunk defined by the [InternalBufferCapacity] + /// attribute applied to the buffer element type declaration. Any additional elements are stored in a separate memory + /// block that is managed by the EntityManager. + /// + /// Adding a component changes an entity's archetype and results in the entity being moved to a different + /// chunk. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before adding the buffer and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The entity. + /// The type of buffer element. Must implement IBufferElementData. + /// The buffer. + /// public DynamicBuffer AddBuffer(Entity entity) where T : struct, IBufferElementData { AddComponent(entity, ComponentType.ReadWrite()); @@ -687,6 +1336,13 @@ internal BufferFromEntity GetBufferFromEntity(int typeIndex, bool isReadOn #endif } + /// + /// Gets the value of a component for an entity. + /// + /// The entity. + /// The type of component to retrieve. + /// A struct of type T containing the component value. + /// Thrown if the component type has no fields. public T GetComponentData(Entity entity) where T : struct, IComponentData { var typeIndex = TypeManager.GetTypeIndex(); @@ -707,6 +1363,13 @@ public T GetComponentData(Entity entity) where T : struct, IComponentData return value; } + /// + /// Sets the value of a component of an entity. + /// + /// The entity. + /// The data to set. + /// The component type. + /// Thrown if the component type has no fields. public void SetComponentData(Entity entity, T componentData) where T : struct, IComponentData { var typeIndex = TypeManager.GetTypeIndex(); @@ -724,6 +1387,17 @@ public void SetComponentData(Entity entity, T componentData) where T : struct UnsafeUtility.CopyStructureToPtr(ref componentData, ptr); } + /// + /// Gets the value of a chunk component. + /// + /// + /// A chunk component is common to all entities in a chunk. You can access a chunk + /// instance through either the chunk itself or through an entity stored in that chunk. + /// + /// The chunk. + /// The component type. + /// A struct of type T containing the component value. + /// Thrown if the ArchetypeChunk object is invalid. public T GetChunkComponentData(ArchetypeChunk chunk) where T : struct, IComponentData { #if ENABLE_UNITY_COLLECTIONS_CHECKS @@ -734,6 +1408,16 @@ public T GetChunkComponentData(ArchetypeChunk chunk) where T : struct, ICompo return GetComponentData(metaChunkEntity); } + /// + /// Gets the value of chunk component for the chunk containing the specified entity. + /// + /// + /// A chunk component is common to all entities in a chunk. You can access a chunk + /// instance through either the chunk itself or through an entity stored in that chunk. + /// + /// The entity. + /// The component type. + /// A struct of type T containing the component value. public T GetChunkComponentData(Entity entity) where T : struct, IComponentData { Entities->AssertEntitiesExist(&entity, 1); @@ -742,6 +1426,17 @@ public T GetChunkComponentData(Entity entity) where T : struct, IComponentDat return GetComponentData(metaChunkEntity); } + /// + /// Sets the value of a chunk component. + /// + /// + /// A chunk component is common to all entities in a chunk. You can access a chunk + /// instance through either the chunk itself or through an entity stored in that chunk. + /// + /// The chunk to modify. + /// The component data to set. + /// The component type. + /// Thrown if the ArchetypeChunk object is invalid. public void SetChunkComponentData(ArchetypeChunk chunk, T componentValue) where T : struct, IComponentData { #if ENABLE_UNITY_COLLECTIONS_CHECKS @@ -752,6 +1447,26 @@ public void SetChunkComponentData(ArchetypeChunk chunk, T componentValue) whe SetComponentData(metaChunkEntity, componentValue); } + /// + /// Adds a managed [UnityEngine.Component](https://docs.unity3d.com/ScriptReference/Component.html) + /// object to an entity. + /// + /// + /// Accessing data in a managed object forfeits many opportunities for increased performance. Adding + /// managed objects to an entity should be avoided or used sparingly. + /// + /// Adding a component changes an entity's archetype and results in the entity being moved to a different + /// chunk. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before adding the object and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The entity to modify. + /// An object inheriting UnityEngine.Component. + /// If the componentData object is not an instance of + /// UnityEngine.Component. public void AddComponentObject(Entity entity, object componentData) { #if ENABLE_UNITY_COLLECTIONS_CHECKS @@ -765,6 +1480,13 @@ public void AddComponentObject(Entity entity, object componentData) SetComponentObject(entity, type, componentData); } + /// + /// Gets the managed [UnityEngine.Component](https://docs.unity3d.com/ScriptReference/Component.html) object + /// from an entity. + /// + /// The entity. + /// The type of the managed object. + /// The managed object, cast to type T. public T GetComponentObject(Entity entity) { var componentType = ComponentType.ReadWrite(); @@ -787,23 +1509,60 @@ internal void SetComponentObject(Entity entity, ComponentType componentType, obj ArchetypeManager.SetManagedObject(chunk, componentType, chunkIndex, componentObject); } + /// + /// Gets the number of shared components managed by this EntityManager. + /// + /// The shared component count public int GetSharedComponentCount() { return m_SharedComponentManager.GetSharedComponentCount(); } + /// + /// Gets a list of all the unique instances of a shared component type. + /// + /// + /// All entities with the same archetype and the same values for a shared component are stored in the same set + /// of chunks. This function finds the unique shared components existing across chunks and archetype and + /// fills a list with copies of those components. + /// + /// A List object to receive the unique instances of the + /// shared component of type T. + /// The type of shared component. public void GetAllUniqueSharedComponentData(List sharedComponentValues) where T : struct, ISharedComponentData { m_SharedComponentManager.GetAllUniqueSharedComponents(sharedComponentValues); } + /// + /// Gets a list of all unique shared components of the same type and a corresponding list of indices into the + /// internal shared component list. + /// + /// + /// All entities with the same archetype and the same values for a shared component are stored in the same set + /// of chunks. This function finds the unique shared components existing across chunks and archetype and + /// fills a list with copies of those components and fills in a separate list with the indices of those components + /// in the internal shared component list. You can use the indices to ask the same shared components directly + /// by calling , passing in the index. An index remains valid until + /// the shared component order version changes. Check this version using + /// . + /// + /// + /// + /// public void GetAllUniqueSharedComponentData(List sharedComponentValues, List sharedComponentIndices) where T : struct, ISharedComponentData { m_SharedComponentManager.GetAllUniqueSharedComponents(sharedComponentValues, sharedComponentIndices); } + /// + /// Gets a shared component from an entity. + /// + /// The entity. + /// The type of shared component. + /// A copy of the shared component. public T GetSharedComponentData(Entity entity) where T : struct, ISharedComponentData { var typeIndex = TypeManager.GetTypeIndex(); @@ -813,11 +1572,43 @@ public T GetSharedComponentData(Entity entity) where T : struct, ISharedCompo return m_SharedComponentManager.GetSharedComponentData(sharedComponentIndex); } + /// + /// Gets a shared component by index. + /// + /// + /// The ECS framework maintains an internal list of unique shared components. You can get the components in this + /// list, along with their indices using + /// . An + /// index in the list is valid and points to the same shared component index as long as the shared component + /// order version from remains the same. + /// + /// The index of the shared component in the internal shared component + /// list. + /// The data type of the shared component. + /// A copy of the shared component. public T GetSharedComponentData(int sharedComponentIndex) where T : struct, ISharedComponentData { return m_SharedComponentManager.GetSharedComponentData(sharedComponentIndex); } + /// + /// Adds a shared component to an entity. + /// + /// + /// The fields of the `componentData` parameter are assigned to the added shared component. + /// + /// Adding a component to an entity changes its archetype and results in the entity being moved to a + /// different chunk. The entity moves to a chunk with other entities that have the same shared component values. + /// A new chunk is created if no chunk with the same archetype and shared component values currently exists. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before adding the component and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The entity. + /// An instance of the shared component having the values to set. + /// The shared component type. public void AddSharedComponentData(Entity entity, T componentData) where T : struct, ISharedComponentData { //TODO: optimize this (no need to move the entity to a new chunk twice) @@ -825,6 +1616,24 @@ public void AddSharedComponentData(Entity entity, T componentData) where T : SetSharedComponentData(entity, componentData); } + /// + /// Adds a shared component to a set of entities defined by a ComponentGroup. + /// + /// + /// The fields of the `componentData` parameter are assigned to all of the added shared components. + /// + /// Adding a component to an entity changes its archetype and results in the entity being moved to a + /// different chunk. The entity moves to a chunk with other entities that have the same shared component values. + /// A new chunk is created if no chunk with the same archetype and shared component values currently exists. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before adding the component and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The ComponentGroup defining a set of entities to modify. + /// The data to set. + /// The data type of the shared component. public void AddSharedComponentData(ComponentGroup componentGroup, T componentData) where T : struct, ISharedComponentData { var componentType = ComponentType.ReadWrite(); @@ -847,6 +1656,22 @@ internal void AddSharedComponentDataBoxed(Entity entity, int typeIndex, int hash SetSharedComponentDataBoxed(entity, typeIndex, hashCode, componentData); } + /// + /// Sets the shared component of an entity. + /// + /// + /// Changing a shared component value of an entity results in the entity being moved to a + /// different chunk. The entity moves to a chunk with other entities that have the same shared component values. + /// A new chunk is created if no chunk with the same archetype and shared component values currently exists. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before setting the component and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The entity + /// A shared component object containing the values to set. + /// The shared component type. public void SetSharedComponentData(Entity entity, T componentData) where T : struct, ISharedComponentData { BeforeStructuralChange(); @@ -882,6 +1707,13 @@ internal void SetSharedComponentDataBoxed(Entity entity, int typeIndex, int hash m_SharedComponentManager.RemoveReference(newSharedComponentDataIndex); } + /// + /// Gets the dynamic buffer of an entity. + /// + /// The entity. + /// The type of the buffer's elements. + /// The DynamicBuffer object for accessing the buffer contents. + /// Thrown if T is an unsupported type. public DynamicBuffer GetBuffer(Entity entity) where T : struct, IBufferElementData { var typeIndex = TypeManager.GetTypeIndex(); @@ -951,6 +1783,17 @@ internal uint GetChunkVersionHash(Entity entity) return hash; } + /// + /// Gets all the entities managed by this EntityManager. + /// + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before getting the entities and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The type of allocation for creating the NativeArray to hold the Entity objects. + /// An array of Entity objects referring to all the entities in the World. public NativeArray GetAllEntities(Allocator allocator = Allocator.Temp) { BeforeStructuralChange(); @@ -973,6 +1816,18 @@ public NativeArray GetAllEntities(Allocator allocator = Allocator.Temp) return array; } + /// + /// Gets all the chunks managed by this EntityManager. + /// + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before getting these chunks and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The type of allocation for creating the NativeArray to hold the ArchetypeChunk + /// objects. + /// An array of ArchetypeChunk objects referring to all the chunks in the . public NativeArray GetAllChunks(Allocator allocator = Allocator.TempJob) { BeforeStructuralChange(); @@ -980,6 +1835,13 @@ public NativeArray GetAllChunks(Allocator allocator = Allocator. return m_UniversalGroup.CreateArchetypeChunkArray(allocator); } + /// + /// Gets an entity's component types. + /// + /// The entity. + /// The type of allocation for creating the NativeArray to hold the ComponentType + /// objects. + /// An array of ComponentType containing all the types of components associated with the entity. public NativeArray GetComponentTypes(Entity entity, Allocator allocator = Allocator.Temp) { Entities->AssertEntitiesExist(&entity, 1); @@ -1007,6 +1869,11 @@ internal void SetBufferRaw(Entity entity, int componentTypeIndex, BufferHeader* UnsafeUtility.MemCpy(ptr, tempBuffer, sizeInChunk); } + /// + /// Gets the number of component types associated with an entity. + /// + /// The entity. + /// The number of components. public int GetComponentCount(Entity entity) { Entities->AssertEntitiesExist(&entity, 1); @@ -1079,16 +1946,64 @@ internal object GetSharedComponentData(Entity entity, int typeIndex) return m_SharedComponentManager.GetSharedComponentDataBoxed(sharedComponentIndex, typeIndex); } + /// + /// Gets the version number of the specified component type. + /// + /// 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 . + /// + /// Version numbers can overflow. To compare if one version is more recent than another use a calculation such as: + /// + /// + /// bool VersionBisNewer = (VersionB - VersionA) > 0; + /// + /// + /// The component type. + /// The current version number. public int GetComponentOrderVersion() { return Entities->GetComponentTypeOrderVersion(TypeManager.GetTypeIndex()); } + /// + /// Gets the version number of the specified shared component. + /// + /// + /// This version number is incremented each time there is a structural change involving entities in the chunk of + /// the specified shared component. Such changes include creating or destroying entities or anything that changes + /// the archetype of an entity. + /// + /// Version numbers can overflow. To compare if one version is more recent than another use a calculation such as: + /// + /// + /// bool VersionBisNewer = (VersionB - VersionA) > 0; + /// + /// + /// The shared component instance. + /// The shared component type. + /// The current version number. public int GetSharedComponentOrderVersion(T sharedComponent) where T : struct, ISharedComponentData { return m_SharedComponentManager.GetSharedComponentVersion(sharedComponent); } + /// + /// Begins an exclusive entity transaction, which allows you to make structural changes inside a Job. + /// + /// + /// allows you to create & destroy entities from a job. The purpose is + /// to enable procedural generation scenarios where instantiation on big scale must happen on jobs. As the + /// name implies it is exclusive to any other access to the EntityManager. + /// + /// An exclusive entity transaction should be used on a manually created that acts as a + /// staging area to construct and setup entities. + /// + /// After the job has completed you can end the transaction and use + /// to move the entities to an active . + /// + /// A transaction object that provides an functions for making structural changes. public ExclusiveEntityTransaction BeginExclusiveEntityTransaction() { ComponentJobSafetyManager.BeginExclusiveTransaction(); @@ -1098,6 +2013,11 @@ public ExclusiveEntityTransaction BeginExclusiveEntityTransaction() return m_ExclusiveEntityTransaction; } + /// + /// Ends an exclusive entity transaction. + /// + /// + /// public void EndExclusiveEntityTransaction() { ComponentJobSafetyManager.EndExclusiveTransaction(); @@ -1111,18 +2031,37 @@ private void BeforeStructuralChange() "Access to EntityManager is not allowed after EntityManager.BeginExclusiveEntityTransaction(); has been called."); if (m_InsideForEach != 0) - throw new InvalidOperationException("EntityManager.AddComponent/RemoveComponent/CreateEntity/DestroyEntity are not allowed during ForEach. Please use PostUpdateCommandBuffer to delay applying those changes until after ForEach."); + throw new InvalidOperationException("EntityManager.AddComponent/RemoveComponent/CreateEntity/DestroyEntity are not allowed during Entities.ForEach. Please use PostUpdateCommandBuffer to delay applying those changes until after ForEach."); #endif ComponentJobSafetyManager.CompleteAllJobsAndInvalidateArrays(); } //@TODO: Not clear to me what this method is really for... + /// + /// Waits for all Jobs to complete. + /// + /// Calling CompleteAllJobs() blocks the main thread until all currently running Jobs finish. public void CompleteAllJobs() { ComponentJobSafetyManager.CompleteAllJobsAndInvalidateArrays(); } + /// + /// Moves all entities managed by the specified EntityManager to the world of this EntityManager. + /// + /// + /// The entities moved are owned by this EntityManager. + /// + /// Each has one EntityManager, which manages all the entities in that world. This function + /// allows you to transfer entities from one World to another. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before moving the entities and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The EntityManager whose entities are appropriated. public void MoveEntitiesFrom(EntityManager srcEntities) { var entityRemapping = srcEntities.CreateEntityRemapArray(Allocator.TempJob); @@ -1135,6 +2074,25 @@ public void MoveEntitiesFrom(EntityManager srcEntities) entityRemapping.Dispose(); } } + // @TODO Proper description of remap utility. + /// + /// Moves all entities managed by the specified EntityManager to the of this EntityManager. + /// + /// + /// After the move, the entities are managed by this EntityManager. + /// + /// Each World has one EntityManager, which manages all the entities in that world. This function + /// allows you to transfer entities from one world to another. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before moving the entities and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The EntityManager whose entities are appropriated. + /// A set of entity transformations to make during the transfer. + /// Thrown if you attempt to transfer entities to the EntityManager + /// that already owns them. public void MoveEntitiesFrom(EntityManager srcEntities, NativeArray entityRemapping) { #if ENABLE_UNITY_COLLECTIONS_CHECKS @@ -1153,11 +2111,36 @@ public void MoveEntitiesFrom(EntityManager srcEntities, NativeArray + /// Creates a remapping array with one element for each entity in the . + /// + /// The type of memory allocation to use when creating the array. + /// An array containing a no-op identity transformation for each entity. public NativeArray CreateEntityRemapArray(Allocator allocator) { return new NativeArray(m_Entities->Capacity, allocator); } + /// + /// Moves a selection of the entities managed by the specified EntityManager to the of this EntityManager. + /// + /// + /// After the move, the entities are managed by this EntityManager. + /// + /// Each world has one EntityManager, which manages all the entities in that world. This function + /// allows you to transfer entities from one World to another. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before moving the entities and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// The EntityManager whose entities are appropriated. + /// A ComponentGroup that defines the entities to move. Must be part of the source + /// World. + /// A set of entity transformations to make during the transfer. + /// Thrown if the ComponentGroup object used as the `filter` comes + /// from a different world than the `srcEntities` EntityManager. public void MoveEntitiesFrom(EntityManager srcEntities, ComponentGroup filter, NativeArray entityRemapping) { #if ENABLE_UNITY_COLLECTIONS_CHECKS @@ -1186,6 +2169,24 @@ internal void MoveEntitiesFrom(EntityManager srcEntities, NativeArray + /// Moves all entities managed by the specified EntityManager to the of this EntityManager and fills + /// an array with their Entity objects. + /// + /// + /// After the move, the entities are managed by this EntityManager. Use the `output` array to make post-move + /// changes to the transferred entities. + /// + /// Each world has one EntityManager, which manages all the entities in that world. This function + /// allows you to transfer entities from one World to another. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before moving the entities and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// An array to receive the Entity objects of the transferred entities. + /// The EntityManager whose entities are appropriated. public void MoveEntitiesFrom(out NativeArray output, EntityManager srcEntities) { var entityRemapping = srcEntities.CreateEntityRemapArray(Allocator.TempJob); @@ -1198,6 +2199,26 @@ public void MoveEntitiesFrom(out NativeArray output, EntityManager srcEn entityRemapping.Dispose(); } } + /// + /// Moves all entities managed by the specified EntityManager to the of this EntityManager and fills + /// an array with their objects. + /// + /// + /// After the move, the entities are managed by this EntityManager. Use the `output` array to make post-move + /// changes to the transferred entities. + /// + /// Each world has one EntityManager, which manages all the entities in that world. This function + /// allows you to transfer entities from one World to another. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before moving the entities and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// An array to receive the Entity objects of the transferred entities. + /// The EntityManager whose entities are appropriated. + /// A set of entity transformations to make during the transfer. + /// public void MoveEntitiesFrom(out NativeArray output, EntityManager srcEntities, NativeArray entityRemapping) { #if ENABLE_UNITY_COLLECTIONS_CHECKS @@ -1216,6 +2237,28 @@ public void MoveEntitiesFrom(out NativeArray output, EntityManager srcEn //@TODO: Need to incrmeent the component versions based the moved chunks... } + /// + /// Moves a selection of the entities managed by the specified EntityManager to the of this EntityManager + /// and fills an array with their objects. + /// + /// + /// After the move, the entities are managed by this EntityManager. Use the `output` array to make post-move + /// changes to the transferred entities. + /// + /// Each world has one EntityManager, which manages all the entities in that world. This function + /// allows you to transfer entities from one World to another. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before moving the entities and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// An array to receive the Entity objects of the transferred entities. + /// The EntityManager whose entities are appropriated. + /// A ComponentGroup that defines the entities to move. Must be part of the source + /// World. + /// A set of entity transformations to make during the transfer. + /// public void MoveEntitiesFrom(out NativeArray output, EntityManager srcEntities, ComponentGroup filter, NativeArray entityRemapping) { #if ENABLE_UNITY_COLLECTIONS_CHECKS @@ -1245,6 +2288,13 @@ internal void MoveEntitiesFrom(out NativeArray output, EntityManager src EntityRemapUtility.GetTargets(out output, entityRemapping); } + /// + /// Gets a list of the types of components that can be assigned to the specified component. + /// + /// Assignable components include those with the same compile-time type and those that + /// inherit from the same compile-time type. + /// The type to check. + /// A new List object containing the System.Types that can be assigned to `interfaceType`. public List GetAssignableComponentTypes(Type interfaceType) { // #todo Cache this. It only can change when TypeManager.GetTypeCount() changes @@ -1361,6 +2411,12 @@ public void AddMatchingArchetypes(EntityArchetypeQuery query, NativeList + /// Gets all the archetypes. + /// + /// The function adds the archetype objects to the existing contents of the list. + /// The list is not cleared. + /// A native list to receive the EntityArchetype objects. public void GetAllArchetypes(NativeList allArchetypes) { for(var i = ArchetypeManager.m_Archetypes.Count - 1; i >= 0; --i) @@ -1393,6 +2449,19 @@ public NativeArray CreateArchetypeChunkArray(EntityArchetypeQuer return chunkStream; } + /// + /// Gets the dynamic type object required to access a chunk component of type T. + /// + /// + /// To access a component stored in a chunk, you must have the type registry information for the component. + /// This function provides that information. Use the returned + /// object with the functions of an object to get information about the components + /// in that chunk and to access the component values. + /// + /// Specify whether the access to the component through this object is read only + /// or read and write. + /// The compile-time type of the component. + /// The run-time type information of the component. public ArchetypeChunkComponentType GetArchetypeChunkComponentType(bool isReadOnly) { #if ENABLE_UNITY_COLLECTIONS_CHECKS @@ -1405,6 +2474,19 @@ public ArchetypeChunkComponentType GetArchetypeChunkComponentType(bool isR #endif } + /// + /// Gets the dynamic type object required to access a chunk buffer containing elements of type T. + /// + /// + /// To access a component stored in a chunk, you must have the type registry information for the component. + /// This function provides that information for buffer components. Use the returned + /// object with the functions of an + /// object to get information about the components in that chunk and to access the component values. + /// + /// Specify whether the access to the component through this object is read only + /// or read and write. + /// The compile-time type of the buffer elements. + /// The run-time type information of the buffer component. public ArchetypeChunkBufferType GetArchetypeChunkBufferType(bool isReadOnly) where T : struct, IBufferElementData { @@ -1419,6 +2501,17 @@ public ArchetypeChunkBufferType GetArchetypeChunkBufferType(bool isReadOnl #endif } + /// + /// Gets the dynamic type object required to access a shared component of type T. + /// + /// + /// To access a component stored in a chunk, you must have the type registry information for the component. + /// This function provides that information for shared components. Use the returned + /// object with the functions of an + /// object to get information about the components in that chunk and to access the component values. + /// + /// The compile-time type of the shared component. + /// The run-time type information of the shared component. public ArchetypeChunkSharedComponentType GetArchetypeChunkSharedComponentType() where T : struct, ISharedComponentData { @@ -1430,6 +2523,18 @@ public ArchetypeChunkSharedComponentType GetArchetypeChunkSharedComponentType #endif } + /// + /// Gets the dynamic type object required to access the component of a chunk. + /// + /// + /// All chunks have an implicit component referring to the entities in that chunk. + /// + /// To access any component stored in a chunk, you must have the type registry information for the component. + /// This function provides that information for the implicit component. Use the returned + /// object with the functions of an + /// object to access the component values. + /// + /// The run-time type information of the Entity component. public ArchetypeChunkEntityType GetArchetypeChunkEntityType() { #if ENABLE_UNITY_COLLECTIONS_CHECKS @@ -1441,20 +2546,49 @@ public ArchetypeChunkEntityType GetArchetypeChunkEntityType() } + /// + /// Swaps the components of two entities. + /// + /// + /// The entities must have the same components. However, this function can swap the components of entities in + /// different worlds, so they do not need to have identical archetype instances. + /// + /// **Important:** This function creates a sync point, which means that the EntityManager waits for all + /// currently running Jobs to complete before swapping the components and no additional Jobs can start before + /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not + /// be able to make use of the processing power of all available cores. + /// + /// A chunk containing one of the entities to swap. + /// The index within the `leftChunk` of the entity and components to swap. + /// The chunk containing the other entity to swap. This chunk can be the same as + /// the `leftChunk`. It also does not need to be in the same World as `leftChunk`. + /// The index within the `rightChunk` of the entity and components to swap. public void SwapComponents(ArchetypeChunk leftChunk, int leftIndex, ArchetypeChunk rightChunk, int rightIndex) { BeforeStructuralChange(); ChunkDataUtility.SwapComponents(leftChunk.m_Chunk,leftIndex,rightChunk.m_Chunk,rightIndex,1, GlobalSystemVersion, GlobalSystemVersion); } + /// + /// The of this EntityManager. + /// + /// A World has one EntityManager and an EntityManager manages the entities of one World. public World World { get { return m_World; } } + // @TODO documentation for serialization/deserialization + /// + /// Prepares an empty to load serialized entities. + /// public void PrepareForDeserialize() { Assert.AreEqual(0, Debug.EntityCount); m_SharedComponentManager.PrepareForDeserialize(); } + // @TODO document EntityManagerDebug + /// + /// Provides information and utility functions for debugging. + /// public class EntityManagerDebug { private readonly EntityManager m_Manager; @@ -1512,7 +2646,7 @@ public int EntityCount return count; } } - + internal Entity GetMetaChunkEntity(Entity entity) { return m_Manager.GetChunk(entity).m_Chunk->metaChunkEntity; @@ -1528,7 +2662,7 @@ public string GetEntityInfo(Entity entity) var archetype = m_Manager.Entities->GetArchetype(entity); #if !UNITY_CSHARP_TINY var str = new System.Text.StringBuilder(); - str.Append($"Entity {entity.Index}.{entity.Version}"); + str.Append(entity.ToString()); for (var i = 0; i < archetype->TypesCount; i++) { var componentTypeInArchetype = archetype->Types[i]; diff --git a/package/Unity.Entities/EntityQueryBuilder.cs b/package/Unity.Entities/EntityQueryBuilder.cs new file mode 100755 index 000000000..92a070b22 --- /dev/null +++ b/package/Unity.Entities/EntityQueryBuilder.cs @@ -0,0 +1,151 @@ +using System; +using System.Diagnostics; +using Unity.Collections; +using Unity.Mathematics; + +namespace Unity.Entities +{ + public partial struct EntityQueryBuilder + { + // TODO: add ReadOnly support for Any/All + + ComponentSystem m_System; + ResizableArray64Byte m_Any, m_None, m_All; + ComponentGroup m_Group; + + internal EntityQueryBuilder(ComponentSystem system) + { + m_System = system; + m_Any = new ResizableArray64Byte(); + m_None = new ResizableArray64Byte(); + m_All = new ResizableArray64Byte(); + m_Group = null; + } + + // this is a specialized function intended only for validation that builders are hashing and getting cached + // correctly without unexpected collisions. "Equals" is hard to truly validate because the type may not + // fully be constructed yet due to ForEach not getting called yet. + internal bool ShallowEquals(ref EntityQueryBuilder other) + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + if (!ReferenceEquals(m_System, other.m_System)) + throw new InvalidOperationException($"Suspicious comparison of {nameof(EntityQueryBuilder)}s with different {nameof(ComponentSystem)}s"); + #endif + + return + m_Any .Equals(ref other.m_Any) && + m_None.Equals(ref other.m_None) && + m_All .Equals(ref other.m_All) && + ReferenceEquals(m_Group, other.m_Group); + } + + public override int GetHashCode() => + throw new InvalidOperationException("Hashing implies storage, but this type should only live on the stack in user code"); + public override bool Equals(object obj) => + throw new InvalidOperationException("Calling this function is a sign of inadvertent boxing"); + + [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")] + void ValidateHasNoGroup() => ThrowIfInvalidMixing(m_Group != null); + + [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")] + void ValidateHasNoSpec() => ThrowIfInvalidMixing(m_Any.Length != 0 || m_None.Length != 0 || m_All.Length != 0); + + [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")] + void ThrowIfInvalidMixing(bool throwIfTrue) + { + if (throwIfTrue) + throw new InvalidOperationException($"Cannot mix {nameof(WithAny)}/{nameof(WithNone)}/{nameof(WithAll)} and {nameof(With)}({nameof(ComponentGroup)})"); + } + + public EntityQueryBuilder With(ComponentGroup componentGroup) + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + if (componentGroup == null) + throw new ArgumentNullException(nameof(componentGroup)); + if (m_Group != null) + throw new InvalidOperationException($"{nameof(ComponentGroup)} has already been set"); + ValidateHasNoSpec(); + #endif + + m_Group = componentGroup; + return this; + } + + EntityArchetypeQuery ToEntityArchetypeQuery(int delegateTypeCount) + { + ComponentType[] ToComponentTypes(ref ResizableArray64Byte typeIndices, ComponentType.AccessMode mode, int extraCapacity = 0) + { + var length = typeIndices.Length + extraCapacity; + if (length == 0) + return Array.Empty(); + + var types = new ComponentType[length]; + for (var i = 0; i < typeIndices.Length; ++i) + types[i] = new ComponentType { TypeIndex = typeIndices[i], AccessModeType = mode }; + + return types; + } + + return new EntityArchetypeQuery + { + Any = ToComponentTypes(ref m_Any, ComponentType.AccessMode.ReadWrite), + None = ToComponentTypes(ref m_None, ComponentType.AccessMode.ReadOnly), + All = ToComponentTypes(ref m_All, ComponentType.AccessMode.ReadWrite, delegateTypeCount), + }; + } + + public EntityArchetypeQuery ToEntityArchetypeQuery() => + ToEntityArchetypeQuery(0); + + public ComponentGroup ToComponentGroup() => + m_Group ?? (m_Group = m_System.GetComponentGroup(ToEntityArchetypeQuery())); + + // see EntityQueryBuilder.tt for the template that is converted into EntityQueryBuilder.gen.cs, + // which contains ForEach and other generated methods. + + #if ENABLE_UNITY_COLLECTIONS_CHECKS + EntityManager.InsideForEach InsideForEach() => + new EntityManager.InsideForEach(m_System.EntityManager); + #endif + + unsafe ComponentGroup ResolveComponentGroup(int* delegateTypeIndices, int delegateTypeCount) + { + var hash + = (uint)m_Any .GetHashCode() * 0xEA928FF9 + ^ (uint)m_None.GetHashCode() * 0x4B772F25 + ^ (uint)m_All .GetHashCode() * 0xBAEE8991 + ^ math.hash(delegateTypeIndices, sizeof(int) * delegateTypeCount); + + var cache = m_System.GetOrCreateEntityQueryCache(); + var found = cache.FindQueryInCache(hash); + + if (found < 0) + { + // base query from builder spec, but reserve some extra room for the types detected from the delegate + var eaq = ToEntityArchetypeQuery(delegateTypeCount); + + // now fill out the extra types + for (var i = 0 ; i < delegateTypeCount; ++i) + eaq.All[i + m_All.Length] = ComponentType.FromTypeIndex(delegateTypeIndices[i]); + + var group = m_System.GetComponentGroup(eaq); + + #if ENABLE_UNITY_COLLECTIONS_CHECKS + found = cache.CreateCachedQuery(hash, group, ref this, delegateTypeIndices, delegateTypeCount); + #else + found = cache.CreateCachedQuery(hash, group); + #endif + } + #if ENABLE_UNITY_COLLECTIONS_CHECKS + else + { + cache.ValidateMatchesCache(found, ref this, delegateTypeIndices, delegateTypeCount); + + // TODO: also validate that m_Group spec matches m_Any/All/None and delegateTypeIndices + } + #endif + + return cache.GetCachedQuery(found); + } + } +} diff --git a/package/Unity.Entities/EntityQueryBuilder.cs.meta b/package/Unity.Entities/EntityQueryBuilder.cs.meta new file mode 100755 index 000000000..12f10ad65 --- /dev/null +++ b/package/Unity.Entities/EntityQueryBuilder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e36b7083e0f83d142a906d5d72874127 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package/Unity.Entities/EntityQueryBuilder.gen.cs b/package/Unity.Entities/EntityQueryBuilder.gen.cs new file mode 100755 index 000000000..2437d48cc --- /dev/null +++ b/package/Unity.Entities/EntityQueryBuilder.gen.cs @@ -0,0 +1,5453 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ +// Generated by EntityQueryBuilder.tt (89 `foreach` combinations) + +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; + +namespace Unity.Entities +{ + public partial struct EntityQueryBuilder + { + // ** FLUENT QUERY ** + + public EntityQueryBuilder WithAny() + { + ValidateHasNoGroup(); + m_Any.Add(TypeManager.GetTypeIndex()); + return this; + } + + public EntityQueryBuilder WithAny() + { + ValidateHasNoGroup(); + m_Any.Add(TypeManager.GetTypeIndex()); + m_Any.Add(TypeManager.GetTypeIndex()); + return this; + } + + public EntityQueryBuilder WithAny() + { + ValidateHasNoGroup(); + m_Any.Add(TypeManager.GetTypeIndex()); + m_Any.Add(TypeManager.GetTypeIndex()); + m_Any.Add(TypeManager.GetTypeIndex()); + return this; + } + + public EntityQueryBuilder WithAny() + { + ValidateHasNoGroup(); + m_Any.Add(TypeManager.GetTypeIndex()); + m_Any.Add(TypeManager.GetTypeIndex()); + m_Any.Add(TypeManager.GetTypeIndex()); + m_Any.Add(TypeManager.GetTypeIndex()); + return this; + } + + public EntityQueryBuilder WithAny() + { + ValidateHasNoGroup(); + m_Any.Add(TypeManager.GetTypeIndex()); + m_Any.Add(TypeManager.GetTypeIndex()); + m_Any.Add(TypeManager.GetTypeIndex()); + m_Any.Add(TypeManager.GetTypeIndex()); + m_Any.Add(TypeManager.GetTypeIndex()); + return this; + } + + public EntityQueryBuilder WithNone() + { + ValidateHasNoGroup(); + m_None.Add(TypeManager.GetTypeIndex()); + return this; + } + + public EntityQueryBuilder WithNone() + { + ValidateHasNoGroup(); + m_None.Add(TypeManager.GetTypeIndex()); + m_None.Add(TypeManager.GetTypeIndex()); + return this; + } + + public EntityQueryBuilder WithNone() + { + ValidateHasNoGroup(); + m_None.Add(TypeManager.GetTypeIndex()); + m_None.Add(TypeManager.GetTypeIndex()); + m_None.Add(TypeManager.GetTypeIndex()); + return this; + } + + public EntityQueryBuilder WithNone() + { + ValidateHasNoGroup(); + m_None.Add(TypeManager.GetTypeIndex()); + m_None.Add(TypeManager.GetTypeIndex()); + m_None.Add(TypeManager.GetTypeIndex()); + m_None.Add(TypeManager.GetTypeIndex()); + return this; + } + + public EntityQueryBuilder WithNone() + { + ValidateHasNoGroup(); + m_None.Add(TypeManager.GetTypeIndex()); + m_None.Add(TypeManager.GetTypeIndex()); + m_None.Add(TypeManager.GetTypeIndex()); + m_None.Add(TypeManager.GetTypeIndex()); + m_None.Add(TypeManager.GetTypeIndex()); + return this; + } + + public EntityQueryBuilder WithAll() + { + ValidateHasNoGroup(); + m_All.Add(TypeManager.GetTypeIndex()); + return this; + } + + public EntityQueryBuilder WithAll() + { + ValidateHasNoGroup(); + m_All.Add(TypeManager.GetTypeIndex()); + m_All.Add(TypeManager.GetTypeIndex()); + return this; + } + + public EntityQueryBuilder WithAll() + { + ValidateHasNoGroup(); + m_All.Add(TypeManager.GetTypeIndex()); + m_All.Add(TypeManager.GetTypeIndex()); + m_All.Add(TypeManager.GetTypeIndex()); + return this; + } + + public EntityQueryBuilder WithAll() + { + ValidateHasNoGroup(); + m_All.Add(TypeManager.GetTypeIndex()); + m_All.Add(TypeManager.GetTypeIndex()); + m_All.Add(TypeManager.GetTypeIndex()); + m_All.Add(TypeManager.GetTypeIndex()); + return this; + } + + public EntityQueryBuilder WithAll() + { + ValidateHasNoGroup(); + m_All.Add(TypeManager.GetTypeIndex()); + m_All.Add(TypeManager.GetTypeIndex()); + m_All.Add(TypeManager.GetTypeIndex()); + m_All.Add(TypeManager.GetTypeIndex()); + m_All.Add(TypeManager.GetTypeIndex()); + return this; + } + + // ** FOREACH ** + + public delegate void F_E(Entity entity); + + public unsafe void ForEach(F_E action) + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + group = ResolveComponentGroup(null, 0); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i]); + } + } + } + } + + public delegate void F_ED(Entity entity, ref T0 c0) + where T0 : struct, IComponentData; + + public unsafe void ForEach(F_ED action) + where T0 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[1]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 1); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], ref UnsafeUtilityEx.ArrayElementAsRef(array0, i)); + } + } + } + } + + public delegate void F_D(ref T0 c0) + where T0 : struct, IComponentData; + + public unsafe void ForEach(F_D action) + where T0 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[1]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 1); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(ref UnsafeUtilityEx.ArrayElementAsRef(array0, i)); + } + } + } + } + + public delegate void F_EC(Entity entity, T0 c0) + where T0 : class; + + public unsafe void ForEach(F_EC action) + where T0 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[1]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 1); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i]); + } + } + } + } + + public delegate void F_C(T0 c0) + where T0 : class; + + public unsafe void ForEach(F_C action) + where T0 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[1]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 1); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i]); + } + } + } + } + + public delegate void F_EB(Entity entity, DynamicBuffer c0) + where T0 : struct, IBufferElementData; + + public unsafe void ForEach(F_EB action) + where T0 : struct, IBufferElementData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[1]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 1); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i]); + } + } + } + } + + public delegate void F_B(DynamicBuffer c0) + where T0 : struct, IBufferElementData; + + public unsafe void ForEach(F_B action) + where T0 : struct, IBufferElementData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[1]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 1); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i]); + } + } + } + } + + public delegate void F_ES(Entity entity, T0 c0) + where T0 : struct, ISharedComponentData; + + public unsafe void ForEach(F_ES action) + where T0 : struct, ISharedComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[1]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 1); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0); + } + } + } + } + + public delegate void F_S(T0 c0) + where T0 : struct, ISharedComponentData; + + public unsafe void ForEach(F_S action) + where T0 : struct, ISharedComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[1]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 1); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0); + } + } + } + } + + public delegate void F_EDD(Entity entity, ref T0 c0, ref T1 c1) + where T0 : struct, IComponentData + where T1 : struct, IComponentData; + + public unsafe void ForEach(F_EDD action) + where T0 : struct, IComponentData + where T1 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[2]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 2); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), ref UnsafeUtilityEx.ArrayElementAsRef(array1, i)); + } + } + } + } + + public delegate void F_DD(ref T0 c0, ref T1 c1) + where T0 : struct, IComponentData + where T1 : struct, IComponentData; + + public unsafe void ForEach(F_DD action) + where T0 : struct, IComponentData + where T1 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[2]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 2); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), ref UnsafeUtilityEx.ArrayElementAsRef(array1, i)); + } + } + } + } + + public delegate void F_EDDD(Entity entity, ref T0 c0, ref T1 c1, ref T2 c2) + where T0 : struct, IComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData; + + public unsafe void ForEach(F_EDDD action) + where T0 : struct, IComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[3]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 3); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i)); + } + } + } + } + + public delegate void F_DDD(ref T0 c0, ref T1 c1, ref T2 c2) + where T0 : struct, IComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData; + + public unsafe void ForEach(F_DDD action) + where T0 : struct, IComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[3]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 3); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i)); + } + } + } + } + + public delegate void F_EDDDD(Entity entity, ref T0 c0, ref T1 c1, ref T2 c2, ref T3 c3) + where T0 : struct, IComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData; + + public unsafe void ForEach(F_EDDDD action) + where T0 : struct, IComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[4]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 4); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i)); + } + } + } + } + + public delegate void F_DDDD(ref T0 c0, ref T1 c1, ref T2 c2, ref T3 c3) + where T0 : struct, IComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData; + + public unsafe void ForEach(F_DDDD action) + where T0 : struct, IComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[4]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 4); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i)); + } + } + } + } + + public delegate void F_EDDDDD(Entity entity, ref T0 c0, ref T1 c1, ref T2 c2, ref T3 c3, ref T4 c4) + where T0 : struct, IComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData; + + public unsafe void ForEach(F_EDDDDD action) + where T0 : struct, IComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[5]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 5); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var array4 = chunk.GetNativeArray(chunkComponentType4).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i), ref UnsafeUtilityEx.ArrayElementAsRef(array4, i)); + } + } + } + } + + public delegate void F_DDDDD(ref T0 c0, ref T1 c1, ref T2 c2, ref T3 c3, ref T4 c4) + where T0 : struct, IComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData; + + public unsafe void ForEach(F_DDDDD action) + where T0 : struct, IComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[5]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 5); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var array4 = chunk.GetNativeArray(chunkComponentType4).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i), ref UnsafeUtilityEx.ArrayElementAsRef(array4, i)); + } + } + } + } + + public delegate void F_EDDDDDD(Entity entity, ref T0 c0, ref T1 c1, ref T2 c2, ref T3 c3, ref T4 c4, ref T5 c5) + where T0 : struct, IComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + where T5 : struct, IComponentData; + + public unsafe void ForEach(F_EDDDDDD action) + where T0 : struct, IComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + where T5 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[6]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + delegateTypes[5] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 6); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType5 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var array4 = chunk.GetNativeArray(chunkComponentType4).GetUnsafePtr(); + var array5 = chunk.GetNativeArray(chunkComponentType5).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i), ref UnsafeUtilityEx.ArrayElementAsRef(array4, i), ref UnsafeUtilityEx.ArrayElementAsRef(array5, i)); + } + } + } + } + + public delegate void F_DDDDDD(ref T0 c0, ref T1 c1, ref T2 c2, ref T3 c3, ref T4 c4, ref T5 c5) + where T0 : struct, IComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + where T5 : struct, IComponentData; + + public unsafe void ForEach(F_DDDDDD action) + where T0 : struct, IComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + where T5 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[6]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + delegateTypes[5] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 6); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType5 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var array4 = chunk.GetNativeArray(chunkComponentType4).GetUnsafePtr(); + var array5 = chunk.GetNativeArray(chunkComponentType5).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i), ref UnsafeUtilityEx.ArrayElementAsRef(array4, i), ref UnsafeUtilityEx.ArrayElementAsRef(array5, i)); + } + } + } + } + + public delegate void F_ECD(Entity entity, T0 c0, ref T1 c1) + where T0 : class + where T1 : struct, IComponentData; + + public unsafe void ForEach(F_ECD action) + where T0 : class + where T1 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[2]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 2); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i)); + } + } + } + } + + public delegate void F_CD(T0 c0, ref T1 c1) + where T0 : class + where T1 : struct, IComponentData; + + public unsafe void ForEach(F_CD action) + where T0 : class + where T1 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[2]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 2); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i)); + } + } + } + } + + public delegate void F_ECDD(Entity entity, T0 c0, ref T1 c1, ref T2 c2) + where T0 : class + where T1 : struct, IComponentData + where T2 : struct, IComponentData; + + public unsafe void ForEach(F_ECDD action) + where T0 : class + where T1 : struct, IComponentData + where T2 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[3]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 3); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i)); + } + } + } + } + + public delegate void F_CDD(T0 c0, ref T1 c1, ref T2 c2) + where T0 : class + where T1 : struct, IComponentData + where T2 : struct, IComponentData; + + public unsafe void ForEach(F_CDD action) + where T0 : class + where T1 : struct, IComponentData + where T2 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[3]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 3); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i)); + } + } + } + } + + public delegate void F_ECDDD(Entity entity, T0 c0, ref T1 c1, ref T2 c2, ref T3 c3) + where T0 : class + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData; + + public unsafe void ForEach(F_ECDDD action) + where T0 : class + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[4]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 4); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i)); + } + } + } + } + + public delegate void F_CDDD(T0 c0, ref T1 c1, ref T2 c2, ref T3 c3) + where T0 : class + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData; + + public unsafe void ForEach(F_CDDD action) + where T0 : class + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[4]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 4); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i)); + } + } + } + } + + public delegate void F_ECDDDD(Entity entity, T0 c0, ref T1 c1, ref T2 c2, ref T3 c3, ref T4 c4) + where T0 : class + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData; + + public unsafe void ForEach(F_ECDDDD action) + where T0 : class + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[5]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 5); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var array4 = chunk.GetNativeArray(chunkComponentType4).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i), ref UnsafeUtilityEx.ArrayElementAsRef(array4, i)); + } + } + } + } + + public delegate void F_CDDDD(T0 c0, ref T1 c1, ref T2 c2, ref T3 c3, ref T4 c4) + where T0 : class + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData; + + public unsafe void ForEach(F_CDDDD action) + where T0 : class + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[5]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 5); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var array4 = chunk.GetNativeArray(chunkComponentType4).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i), ref UnsafeUtilityEx.ArrayElementAsRef(array4, i)); + } + } + } + } + + public delegate void F_ECDDDDD(Entity entity, T0 c0, ref T1 c1, ref T2 c2, ref T3 c3, ref T4 c4, ref T5 c5) + where T0 : class + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + where T5 : struct, IComponentData; + + public unsafe void ForEach(F_ECDDDDD action) + where T0 : class + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + where T5 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[6]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + delegateTypes[5] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 6); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType5 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var array4 = chunk.GetNativeArray(chunkComponentType4).GetUnsafePtr(); + var array5 = chunk.GetNativeArray(chunkComponentType5).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i), ref UnsafeUtilityEx.ArrayElementAsRef(array4, i), ref UnsafeUtilityEx.ArrayElementAsRef(array5, i)); + } + } + } + } + + public delegate void F_CDDDDD(T0 c0, ref T1 c1, ref T2 c2, ref T3 c3, ref T4 c4, ref T5 c5) + where T0 : class + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + where T5 : struct, IComponentData; + + public unsafe void ForEach(F_CDDDDD action) + where T0 : class + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + where T5 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[6]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + delegateTypes[5] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 6); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType5 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var array4 = chunk.GetNativeArray(chunkComponentType4).GetUnsafePtr(); + var array5 = chunk.GetNativeArray(chunkComponentType5).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i), ref UnsafeUtilityEx.ArrayElementAsRef(array4, i), ref UnsafeUtilityEx.ArrayElementAsRef(array5, i)); + } + } + } + } + + public delegate void F_EBD(Entity entity, DynamicBuffer c0, ref T1 c1) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData; + + public unsafe void ForEach(F_EBD action) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[2]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 2); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i)); + } + } + } + } + + public delegate void F_BD(DynamicBuffer c0, ref T1 c1) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData; + + public unsafe void ForEach(F_BD action) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[2]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 2); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i)); + } + } + } + } + + public delegate void F_EBDD(Entity entity, DynamicBuffer c0, ref T1 c1, ref T2 c2) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData + where T2 : struct, IComponentData; + + public unsafe void ForEach(F_EBDD action) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[3]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 3); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i)); + } + } + } + } + + public delegate void F_BDD(DynamicBuffer c0, ref T1 c1, ref T2 c2) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData + where T2 : struct, IComponentData; + + public unsafe void ForEach(F_BDD action) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[3]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 3); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i)); + } + } + } + } + + public delegate void F_EBDDD(Entity entity, DynamicBuffer c0, ref T1 c1, ref T2 c2, ref T3 c3) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData; + + public unsafe void ForEach(F_EBDDD action) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[4]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 4); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i)); + } + } + } + } + + public delegate void F_BDDD(DynamicBuffer c0, ref T1 c1, ref T2 c2, ref T3 c3) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData; + + public unsafe void ForEach(F_BDDD action) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[4]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 4); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i)); + } + } + } + } + + public delegate void F_EBDDDD(Entity entity, DynamicBuffer c0, ref T1 c1, ref T2 c2, ref T3 c3, ref T4 c4) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData; + + public unsafe void ForEach(F_EBDDDD action) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[5]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 5); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var array4 = chunk.GetNativeArray(chunkComponentType4).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i), ref UnsafeUtilityEx.ArrayElementAsRef(array4, i)); + } + } + } + } + + public delegate void F_BDDDD(DynamicBuffer c0, ref T1 c1, ref T2 c2, ref T3 c3, ref T4 c4) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData; + + public unsafe void ForEach(F_BDDDD action) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[5]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 5); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var array4 = chunk.GetNativeArray(chunkComponentType4).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i), ref UnsafeUtilityEx.ArrayElementAsRef(array4, i)); + } + } + } + } + + public delegate void F_EBDDDDD(Entity entity, DynamicBuffer c0, ref T1 c1, ref T2 c2, ref T3 c3, ref T4 c4, ref T5 c5) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + where T5 : struct, IComponentData; + + public unsafe void ForEach(F_EBDDDDD action) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + where T5 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[6]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + delegateTypes[5] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 6); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType5 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var array4 = chunk.GetNativeArray(chunkComponentType4).GetUnsafePtr(); + var array5 = chunk.GetNativeArray(chunkComponentType5).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i), ref UnsafeUtilityEx.ArrayElementAsRef(array4, i), ref UnsafeUtilityEx.ArrayElementAsRef(array5, i)); + } + } + } + } + + public delegate void F_BDDDDD(DynamicBuffer c0, ref T1 c1, ref T2 c2, ref T3 c3, ref T4 c4, ref T5 c5) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + where T5 : struct, IComponentData; + + public unsafe void ForEach(F_BDDDDD action) + where T0 : struct, IBufferElementData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + where T5 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[6]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + delegateTypes[5] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 6); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType5 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var array4 = chunk.GetNativeArray(chunkComponentType4).GetUnsafePtr(); + var array5 = chunk.GetNativeArray(chunkComponentType5).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i), ref UnsafeUtilityEx.ArrayElementAsRef(array4, i), ref UnsafeUtilityEx.ArrayElementAsRef(array5, i)); + } + } + } + } + + public delegate void F_ESD(Entity entity, T0 c0, ref T1 c1) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData; + + public unsafe void ForEach(F_ESD action) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[2]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 2); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0, ref UnsafeUtilityEx.ArrayElementAsRef(array1, i)); + } + } + } + } + + public delegate void F_SD(T0 c0, ref T1 c1) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData; + + public unsafe void ForEach(F_SD action) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[2]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 2); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0, ref UnsafeUtilityEx.ArrayElementAsRef(array1, i)); + } + } + } + } + + public delegate void F_ESDD(Entity entity, T0 c0, ref T1 c1, ref T2 c2) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData; + + public unsafe void ForEach(F_ESDD action) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[3]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 3); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0, ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i)); + } + } + } + } + + public delegate void F_SDD(T0 c0, ref T1 c1, ref T2 c2) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData; + + public unsafe void ForEach(F_SDD action) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[3]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 3); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0, ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i)); + } + } + } + } + + public delegate void F_ESDDD(Entity entity, T0 c0, ref T1 c1, ref T2 c2, ref T3 c3) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData; + + public unsafe void ForEach(F_ESDDD action) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[4]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 4); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0, ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i)); + } + } + } + } + + public delegate void F_SDDD(T0 c0, ref T1 c1, ref T2 c2, ref T3 c3) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData; + + public unsafe void ForEach(F_SDDD action) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[4]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 4); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0, ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i)); + } + } + } + } + + public delegate void F_ESDDDD(Entity entity, T0 c0, ref T1 c1, ref T2 c2, ref T3 c3, ref T4 c4) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData; + + public unsafe void ForEach(F_ESDDDD action) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[5]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 5); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var array4 = chunk.GetNativeArray(chunkComponentType4).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0, ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i), ref UnsafeUtilityEx.ArrayElementAsRef(array4, i)); + } + } + } + } + + public delegate void F_SDDDD(T0 c0, ref T1 c1, ref T2 c2, ref T3 c3, ref T4 c4) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData; + + public unsafe void ForEach(F_SDDDD action) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[5]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 5); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var array4 = chunk.GetNativeArray(chunkComponentType4).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0, ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i), ref UnsafeUtilityEx.ArrayElementAsRef(array4, i)); + } + } + } + } + + public delegate void F_ESDDDDD(Entity entity, T0 c0, ref T1 c1, ref T2 c2, ref T3 c3, ref T4 c4, ref T5 c5) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + where T5 : struct, IComponentData; + + public unsafe void ForEach(F_ESDDDDD action) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + where T5 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[6]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + delegateTypes[5] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 6); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType5 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var array4 = chunk.GetNativeArray(chunkComponentType4).GetUnsafePtr(); + var array5 = chunk.GetNativeArray(chunkComponentType5).GetUnsafePtr(); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0, ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i), ref UnsafeUtilityEx.ArrayElementAsRef(array4, i), ref UnsafeUtilityEx.ArrayElementAsRef(array5, i)); + } + } + } + } + + public delegate void F_SDDDDD(T0 c0, ref T1 c1, ref T2 c2, ref T3 c3, ref T4 c4, ref T5 c5) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + where T5 : struct, IComponentData; + + public unsafe void ForEach(F_SDDDDD action) + where T0 : struct, ISharedComponentData + where T1 : struct, IComponentData + where T2 : struct, IComponentData + where T3 : struct, IComponentData + where T4 : struct, IComponentData + where T5 : struct, IComponentData + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[6]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + delegateTypes[5] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 6); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType5 = m_System.GetArchetypeChunkComponentType(false); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetNativeArray(chunkComponentType1).GetUnsafePtr(); + var array2 = chunk.GetNativeArray(chunkComponentType2).GetUnsafePtr(); + var array3 = chunk.GetNativeArray(chunkComponentType3).GetUnsafePtr(); + var array4 = chunk.GetNativeArray(chunkComponentType4).GetUnsafePtr(); + var array5 = chunk.GetNativeArray(chunkComponentType5).GetUnsafePtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0, ref UnsafeUtilityEx.ArrayElementAsRef(array1, i), ref UnsafeUtilityEx.ArrayElementAsRef(array2, i), ref UnsafeUtilityEx.ArrayElementAsRef(array3, i), ref UnsafeUtilityEx.ArrayElementAsRef(array4, i), ref UnsafeUtilityEx.ArrayElementAsRef(array5, i)); + } + } + } + } + + public delegate void F_EDC(Entity entity, ref T0 c0, T1 c1) + where T0 : struct, IComponentData + where T1 : class; + + public unsafe void ForEach(F_EDC action) + where T0 : struct, IComponentData + where T1 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[2]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 2); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), array1[i]); + } + } + } + } + + public delegate void F_DC(ref T0 c0, T1 c1) + where T0 : struct, IComponentData + where T1 : class; + + public unsafe void ForEach(F_DC action) + where T0 : struct, IComponentData + where T1 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[2]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 2); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), array1[i]); + } + } + } + } + + public delegate void F_EDCC(Entity entity, ref T0 c0, T1 c1, T2 c2) + where T0 : struct, IComponentData + where T1 : class + where T2 : class; + + public unsafe void ForEach(F_EDCC action) + where T0 : struct, IComponentData + where T1 : class + where T2 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[3]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 3); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), array1[i], array2[i]); + } + } + } + } + + public delegate void F_DCC(ref T0 c0, T1 c1, T2 c2) + where T0 : struct, IComponentData + where T1 : class + where T2 : class; + + public unsafe void ForEach(F_DCC action) + where T0 : struct, IComponentData + where T1 : class + where T2 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[3]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 3); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), array1[i], array2[i]); + } + } + } + } + + public delegate void F_EDCCC(Entity entity, ref T0 c0, T1 c1, T2 c2, T3 c3) + where T0 : struct, IComponentData + where T1 : class + where T2 : class + where T3 : class; + + public unsafe void ForEach(F_EDCCC action) + where T0 : struct, IComponentData + where T1 : class + where T2 : class + where T3 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[4]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 4); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), array1[i], array2[i], array3[i]); + } + } + } + } + + public delegate void F_DCCC(ref T0 c0, T1 c1, T2 c2, T3 c3) + where T0 : struct, IComponentData + where T1 : class + where T2 : class + where T3 : class; + + public unsafe void ForEach(F_DCCC action) + where T0 : struct, IComponentData + where T1 : class + where T2 : class + where T3 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[4]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 4); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), array1[i], array2[i], array3[i]); + } + } + } + } + + public delegate void F_EDCCCC(Entity entity, ref T0 c0, T1 c1, T2 c2, T3 c3, T4 c4) + where T0 : struct, IComponentData + where T1 : class + where T2 : class + where T3 : class + where T4 : class; + + public unsafe void ForEach(F_EDCCCC action) + where T0 : struct, IComponentData + where T1 : class + where T2 : class + where T3 : class + where T4 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[5]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 5); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var array4 = chunk.GetComponentObjects(chunkComponentType4, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), array1[i], array2[i], array3[i], array4[i]); + } + } + } + } + + public delegate void F_DCCCC(ref T0 c0, T1 c1, T2 c2, T3 c3, T4 c4) + where T0 : struct, IComponentData + where T1 : class + where T2 : class + where T3 : class + where T4 : class; + + public unsafe void ForEach(F_DCCCC action) + where T0 : struct, IComponentData + where T1 : class + where T2 : class + where T3 : class + where T4 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[5]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 5); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var array4 = chunk.GetComponentObjects(chunkComponentType4, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), array1[i], array2[i], array3[i], array4[i]); + } + } + } + } + + public delegate void F_EDCCCCC(Entity entity, ref T0 c0, T1 c1, T2 c2, T3 c3, T4 c4, T5 c5) + where T0 : struct, IComponentData + where T1 : class + where T2 : class + where T3 : class + where T4 : class + where T5 : class; + + public unsafe void ForEach(F_EDCCCCC action) + where T0 : struct, IComponentData + where T1 : class + where T2 : class + where T3 : class + where T4 : class + where T5 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[6]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + delegateTypes[5] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 6); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType5 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var array4 = chunk.GetComponentObjects(chunkComponentType4, m_System.EntityManager); + var array5 = chunk.GetComponentObjects(chunkComponentType5, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), array1[i], array2[i], array3[i], array4[i], array5[i]); + } + } + } + } + + public delegate void F_DCCCCC(ref T0 c0, T1 c1, T2 c2, T3 c3, T4 c4, T5 c5) + where T0 : struct, IComponentData + where T1 : class + where T2 : class + where T3 : class + where T4 : class + where T5 : class; + + public unsafe void ForEach(F_DCCCCC action) + where T0 : struct, IComponentData + where T1 : class + where T2 : class + where T3 : class + where T4 : class + where T5 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[6]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + delegateTypes[5] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 6); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType5 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetNativeArray(chunkComponentType0).GetUnsafePtr(); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var array4 = chunk.GetComponentObjects(chunkComponentType4, m_System.EntityManager); + var array5 = chunk.GetComponentObjects(chunkComponentType5, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(ref UnsafeUtilityEx.ArrayElementAsRef(array0, i), array1[i], array2[i], array3[i], array4[i], array5[i]); + } + } + } + } + + public delegate void F_ECC(Entity entity, T0 c0, T1 c1) + where T0 : class + where T1 : class; + + public unsafe void ForEach(F_ECC action) + where T0 : class + where T1 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[2]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 2); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], array1[i]); + } + } + } + } + + public delegate void F_CC(T0 c0, T1 c1) + where T0 : class + where T1 : class; + + public unsafe void ForEach(F_CC action) + where T0 : class + where T1 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[2]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 2); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], array1[i]); + } + } + } + } + + public delegate void F_ECCC(Entity entity, T0 c0, T1 c1, T2 c2) + where T0 : class + where T1 : class + where T2 : class; + + public unsafe void ForEach(F_ECCC action) + where T0 : class + where T1 : class + where T2 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[3]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 3); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], array1[i], array2[i]); + } + } + } + } + + public delegate void F_CCC(T0 c0, T1 c1, T2 c2) + where T0 : class + where T1 : class + where T2 : class; + + public unsafe void ForEach(F_CCC action) + where T0 : class + where T1 : class + where T2 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[3]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 3); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], array1[i], array2[i]); + } + } + } + } + + public delegate void F_ECCCC(Entity entity, T0 c0, T1 c1, T2 c2, T3 c3) + where T0 : class + where T1 : class + where T2 : class + where T3 : class; + + public unsafe void ForEach(F_ECCCC action) + where T0 : class + where T1 : class + where T2 : class + where T3 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[4]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 4); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], array1[i], array2[i], array3[i]); + } + } + } + } + + public delegate void F_CCCC(T0 c0, T1 c1, T2 c2, T3 c3) + where T0 : class + where T1 : class + where T2 : class + where T3 : class; + + public unsafe void ForEach(F_CCCC action) + where T0 : class + where T1 : class + where T2 : class + where T3 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[4]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 4); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], array1[i], array2[i], array3[i]); + } + } + } + } + + public delegate void F_ECCCCC(Entity entity, T0 c0, T1 c1, T2 c2, T3 c3, T4 c4) + where T0 : class + where T1 : class + where T2 : class + where T3 : class + where T4 : class; + + public unsafe void ForEach(F_ECCCCC action) + where T0 : class + where T1 : class + where T2 : class + where T3 : class + where T4 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[5]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 5); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var array4 = chunk.GetComponentObjects(chunkComponentType4, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], array1[i], array2[i], array3[i], array4[i]); + } + } + } + } + + public delegate void F_CCCCC(T0 c0, T1 c1, T2 c2, T3 c3, T4 c4) + where T0 : class + where T1 : class + where T2 : class + where T3 : class + where T4 : class; + + public unsafe void ForEach(F_CCCCC action) + where T0 : class + where T1 : class + where T2 : class + where T3 : class + where T4 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[5]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 5); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var array4 = chunk.GetComponentObjects(chunkComponentType4, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], array1[i], array2[i], array3[i], array4[i]); + } + } + } + } + + public delegate void F_ECCCCCC(Entity entity, T0 c0, T1 c1, T2 c2, T3 c3, T4 c4, T5 c5) + where T0 : class + where T1 : class + where T2 : class + where T3 : class + where T4 : class + where T5 : class; + + public unsafe void ForEach(F_ECCCCCC action) + where T0 : class + where T1 : class + where T2 : class + where T3 : class + where T4 : class + where T5 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[6]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + delegateTypes[5] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 6); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType5 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var array4 = chunk.GetComponentObjects(chunkComponentType4, m_System.EntityManager); + var array5 = chunk.GetComponentObjects(chunkComponentType5, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], array1[i], array2[i], array3[i], array4[i], array5[i]); + } + } + } + } + + public delegate void F_CCCCCC(T0 c0, T1 c1, T2 c2, T3 c3, T4 c4, T5 c5) + where T0 : class + where T1 : class + where T2 : class + where T3 : class + where T4 : class + where T5 : class; + + public unsafe void ForEach(F_CCCCCC action) + where T0 : class + where T1 : class + where T2 : class + where T3 : class + where T4 : class + where T5 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[6]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + delegateTypes[5] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 6); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType5 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetComponentObjects(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var array4 = chunk.GetComponentObjects(chunkComponentType4, m_System.EntityManager); + var array5 = chunk.GetComponentObjects(chunkComponentType5, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], array1[i], array2[i], array3[i], array4[i], array5[i]); + } + } + } + } + + public delegate void F_EBC(Entity entity, DynamicBuffer c0, T1 c1) + where T0 : struct, IBufferElementData + where T1 : class; + + public unsafe void ForEach(F_EBC action) + where T0 : struct, IBufferElementData + where T1 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[2]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 2); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], array1[i]); + } + } + } + } + + public delegate void F_BC(DynamicBuffer c0, T1 c1) + where T0 : struct, IBufferElementData + where T1 : class; + + public unsafe void ForEach(F_BC action) + where T0 : struct, IBufferElementData + where T1 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[2]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 2); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], array1[i]); + } + } + } + } + + public delegate void F_EBCC(Entity entity, DynamicBuffer c0, T1 c1, T2 c2) + where T0 : struct, IBufferElementData + where T1 : class + where T2 : class; + + public unsafe void ForEach(F_EBCC action) + where T0 : struct, IBufferElementData + where T1 : class + where T2 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[3]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 3); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], array1[i], array2[i]); + } + } + } + } + + public delegate void F_BCC(DynamicBuffer c0, T1 c1, T2 c2) + where T0 : struct, IBufferElementData + where T1 : class + where T2 : class; + + public unsafe void ForEach(F_BCC action) + where T0 : struct, IBufferElementData + where T1 : class + where T2 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[3]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 3); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], array1[i], array2[i]); + } + } + } + } + + public delegate void F_EBCCC(Entity entity, DynamicBuffer c0, T1 c1, T2 c2, T3 c3) + where T0 : struct, IBufferElementData + where T1 : class + where T2 : class + where T3 : class; + + public unsafe void ForEach(F_EBCCC action) + where T0 : struct, IBufferElementData + where T1 : class + where T2 : class + where T3 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[4]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 4); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], array1[i], array2[i], array3[i]); + } + } + } + } + + public delegate void F_BCCC(DynamicBuffer c0, T1 c1, T2 c2, T3 c3) + where T0 : struct, IBufferElementData + where T1 : class + where T2 : class + where T3 : class; + + public unsafe void ForEach(F_BCCC action) + where T0 : struct, IBufferElementData + where T1 : class + where T2 : class + where T3 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[4]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 4); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], array1[i], array2[i], array3[i]); + } + } + } + } + + public delegate void F_EBCCCC(Entity entity, DynamicBuffer c0, T1 c1, T2 c2, T3 c3, T4 c4) + where T0 : struct, IBufferElementData + where T1 : class + where T2 : class + where T3 : class + where T4 : class; + + public unsafe void ForEach(F_EBCCCC action) + where T0 : struct, IBufferElementData + where T1 : class + where T2 : class + where T3 : class + where T4 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[5]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 5); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var array4 = chunk.GetComponentObjects(chunkComponentType4, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], array1[i], array2[i], array3[i], array4[i]); + } + } + } + } + + public delegate void F_BCCCC(DynamicBuffer c0, T1 c1, T2 c2, T3 c3, T4 c4) + where T0 : struct, IBufferElementData + where T1 : class + where T2 : class + where T3 : class + where T4 : class; + + public unsafe void ForEach(F_BCCCC action) + where T0 : struct, IBufferElementData + where T1 : class + where T2 : class + where T3 : class + where T4 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[5]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 5); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var array4 = chunk.GetComponentObjects(chunkComponentType4, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], array1[i], array2[i], array3[i], array4[i]); + } + } + } + } + + public delegate void F_EBCCCCC(Entity entity, DynamicBuffer c0, T1 c1, T2 c2, T3 c3, T4 c4, T5 c5) + where T0 : struct, IBufferElementData + where T1 : class + where T2 : class + where T3 : class + where T4 : class + where T5 : class; + + public unsafe void ForEach(F_EBCCCCC action) + where T0 : struct, IBufferElementData + where T1 : class + where T2 : class + where T3 : class + where T4 : class + where T5 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[6]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + delegateTypes[5] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 6); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType5 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var array4 = chunk.GetComponentObjects(chunkComponentType4, m_System.EntityManager); + var array5 = chunk.GetComponentObjects(chunkComponentType5, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0[i], array1[i], array2[i], array3[i], array4[i], array5[i]); + } + } + } + } + + public delegate void F_BCCCCC(DynamicBuffer c0, T1 c1, T2 c2, T3 c3, T4 c4, T5 c5) + where T0 : struct, IBufferElementData + where T1 : class + where T2 : class + where T3 : class + where T4 : class + where T5 : class; + + public unsafe void ForEach(F_BCCCCC action) + where T0 : struct, IBufferElementData + where T1 : class + where T2 : class + where T3 : class + where T4 : class + where T5 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[6]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + delegateTypes[5] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 6); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkBufferType(false); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType5 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetBufferAccessor(chunkComponentType0); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var array4 = chunk.GetComponentObjects(chunkComponentType4, m_System.EntityManager); + var array5 = chunk.GetComponentObjects(chunkComponentType5, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0[i], array1[i], array2[i], array3[i], array4[i], array5[i]); + } + } + } + } + + public delegate void F_ESC(Entity entity, T0 c0, T1 c1) + where T0 : struct, ISharedComponentData + where T1 : class; + + public unsafe void ForEach(F_ESC action) + where T0 : struct, ISharedComponentData + where T1 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[2]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 2); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0, array1[i]); + } + } + } + } + + public delegate void F_SC(T0 c0, T1 c1) + where T0 : struct, ISharedComponentData + where T1 : class; + + public unsafe void ForEach(F_SC action) + where T0 : struct, ISharedComponentData + where T1 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[2]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 2); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0, array1[i]); + } + } + } + } + + public delegate void F_ESCC(Entity entity, T0 c0, T1 c1, T2 c2) + where T0 : struct, ISharedComponentData + where T1 : class + where T2 : class; + + public unsafe void ForEach(F_ESCC action) + where T0 : struct, ISharedComponentData + where T1 : class + where T2 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[3]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 3); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0, array1[i], array2[i]); + } + } + } + } + + public delegate void F_SCC(T0 c0, T1 c1, T2 c2) + where T0 : struct, ISharedComponentData + where T1 : class + where T2 : class; + + public unsafe void ForEach(F_SCC action) + where T0 : struct, ISharedComponentData + where T1 : class + where T2 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[3]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 3); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0, array1[i], array2[i]); + } + } + } + } + + public delegate void F_ESCCC(Entity entity, T0 c0, T1 c1, T2 c2, T3 c3) + where T0 : struct, ISharedComponentData + where T1 : class + where T2 : class + where T3 : class; + + public unsafe void ForEach(F_ESCCC action) + where T0 : struct, ISharedComponentData + where T1 : class + where T2 : class + where T3 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[4]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 4); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0, array1[i], array2[i], array3[i]); + } + } + } + } + + public delegate void F_SCCC(T0 c0, T1 c1, T2 c2, T3 c3) + where T0 : struct, ISharedComponentData + where T1 : class + where T2 : class + where T3 : class; + + public unsafe void ForEach(F_SCCC action) + where T0 : struct, ISharedComponentData + where T1 : class + where T2 : class + where T3 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[4]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 4); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0, array1[i], array2[i], array3[i]); + } + } + } + } + + public delegate void F_ESCCCC(Entity entity, T0 c0, T1 c1, T2 c2, T3 c3, T4 c4) + where T0 : struct, ISharedComponentData + where T1 : class + where T2 : class + where T3 : class + where T4 : class; + + public unsafe void ForEach(F_ESCCCC action) + where T0 : struct, ISharedComponentData + where T1 : class + where T2 : class + where T3 : class + where T4 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[5]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 5); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var array4 = chunk.GetComponentObjects(chunkComponentType4, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0, array1[i], array2[i], array3[i], array4[i]); + } + } + } + } + + public delegate void F_SCCCC(T0 c0, T1 c1, T2 c2, T3 c3, T4 c4) + where T0 : struct, ISharedComponentData + where T1 : class + where T2 : class + where T3 : class + where T4 : class; + + public unsafe void ForEach(F_SCCCC action) + where T0 : struct, ISharedComponentData + where T1 : class + where T2 : class + where T3 : class + where T4 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[5]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 5); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var array4 = chunk.GetComponentObjects(chunkComponentType4, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0, array1[i], array2[i], array3[i], array4[i]); + } + } + } + } + + public delegate void F_ESCCCCC(Entity entity, T0 c0, T1 c1, T2 c2, T3 c3, T4 c4, T5 c5) + where T0 : struct, ISharedComponentData + where T1 : class + where T2 : class + where T3 : class + where T4 : class + where T5 : class; + + public unsafe void ForEach(F_ESCCCCC action) + where T0 : struct, ISharedComponentData + where T1 : class + where T2 : class + where T3 : class + where T4 : class + where T5 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[6]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + delegateTypes[5] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 6); + } + + var entityType = m_System.GetArchetypeChunkEntityType(); + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType5 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var array4 = chunk.GetComponentObjects(chunkComponentType4, m_System.EntityManager); + var array5 = chunk.GetComponentObjects(chunkComponentType5, m_System.EntityManager); + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(entityArray[i], array0, array1[i], array2[i], array3[i], array4[i], array5[i]); + } + } + } + } + + public delegate void F_SCCCCC(T0 c0, T1 c1, T2 c2, T3 c3, T4 c4, T5 c5) + where T0 : struct, ISharedComponentData + where T1 : class + where T2 : class + where T3 : class + where T4 : class + where T5 : class; + + public unsafe void ForEach(F_SCCCCC action) + where T0 : struct, ISharedComponentData + where T1 : class + where T2 : class + where T3 : class + where T4 : class + where T5 : class + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { + var delegateTypes = stackalloc int[6]; + delegateTypes[0] = TypeManager.GetTypeIndex(); + delegateTypes[1] = TypeManager.GetTypeIndex(); + delegateTypes[2] = TypeManager.GetTypeIndex(); + delegateTypes[3] = TypeManager.GetTypeIndex(); + delegateTypes[4] = TypeManager.GetTypeIndex(); + delegateTypes[5] = TypeManager.GetTypeIndex(); + + group = ResolveComponentGroup(delegateTypes, 6); + } + + var chunkComponentType0 = m_System.GetArchetypeChunkSharedComponentType(); + var chunkComponentType1 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType2 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType3 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType4 = m_System.GetArchetypeChunkComponentType(); + var chunkComponentType5 = m_System.GetArchetypeChunkComponentType(); + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { + var array0 = chunk.GetSharedComponentData(chunkComponentType0, m_System.EntityManager); + var array1 = chunk.GetComponentObjects(chunkComponentType1, m_System.EntityManager); + var array2 = chunk.GetComponentObjects(chunkComponentType2, m_System.EntityManager); + var array3 = chunk.GetComponentObjects(chunkComponentType3, m_System.EntityManager); + var array4 = chunk.GetComponentObjects(chunkComponentType4, m_System.EntityManager); + var array5 = chunk.GetComponentObjects(chunkComponentType5, m_System.EntityManager); + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(array0, array1[i], array2[i], array3[i], array4[i], array5[i]); + } + } + } + } + + } + + // BACK-COMPAT - TO BE REMOVED + + public partial class ComponentSystem + { + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_E action, ComponentGroup group = null) + + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ED action, ComponentGroup group = null) + where T0 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_D action, ComponentGroup group = null) + where T0 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EC action, ComponentGroup group = null) + where T0 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_C action, ComponentGroup group = null) + where T0 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EB action, ComponentGroup group = null) + where T0 : struct, IBufferElementData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_B action, ComponentGroup group = null) + where T0 : struct, IBufferElementData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ES action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_S action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EDD action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_DD action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EDDD action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_DDD action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EDDDD action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_DDDD action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EDDDDD action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_DDDDD action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EDDDDDD action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData where T5 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_DDDDDD action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData where T5 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ECD action, ComponentGroup group = null) + where T0 : class where T1 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_CD action, ComponentGroup group = null) + where T0 : class where T1 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ECDD action, ComponentGroup group = null) + where T0 : class where T1 : struct, IComponentData where T2 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_CDD action, ComponentGroup group = null) + where T0 : class where T1 : struct, IComponentData where T2 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ECDDD action, ComponentGroup group = null) + where T0 : class where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_CDDD action, ComponentGroup group = null) + where T0 : class where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ECDDDD action, ComponentGroup group = null) + where T0 : class where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_CDDDD action, ComponentGroup group = null) + where T0 : class where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ECDDDDD action, ComponentGroup group = null) + where T0 : class where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData where T5 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_CDDDDD action, ComponentGroup group = null) + where T0 : class where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData where T5 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EBD action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_BD action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EBDD action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : struct, IComponentData where T2 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_BDD action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : struct, IComponentData where T2 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EBDDD action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_BDDD action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EBDDDD action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_BDDDD action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EBDDDDD action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData where T5 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_BDDDDD action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData where T5 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ESD action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_SD action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ESDD action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_SDD action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ESDDD action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_SDDD action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ESDDDD action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_SDDDD action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ESDDDDD action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData where T5 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_SDDDDD action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData where T5 : struct, IComponentData + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EDC action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_DC action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EDCC action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : class where T2 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_DCC action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : class where T2 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EDCCC action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : class where T2 : class where T3 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_DCCC action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : class where T2 : class where T3 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EDCCCC action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : class where T2 : class where T3 : class where T4 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_DCCCC action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : class where T2 : class where T3 : class where T4 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EDCCCCC action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_DCCCCC action, ComponentGroup group = null) + where T0 : struct, IComponentData where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ECC action, ComponentGroup group = null) + where T0 : class where T1 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_CC action, ComponentGroup group = null) + where T0 : class where T1 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ECCC action, ComponentGroup group = null) + where T0 : class where T1 : class where T2 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_CCC action, ComponentGroup group = null) + where T0 : class where T1 : class where T2 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ECCCC action, ComponentGroup group = null) + where T0 : class where T1 : class where T2 : class where T3 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_CCCC action, ComponentGroup group = null) + where T0 : class where T1 : class where T2 : class where T3 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ECCCCC action, ComponentGroup group = null) + where T0 : class where T1 : class where T2 : class where T3 : class where T4 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_CCCCC action, ComponentGroup group = null) + where T0 : class where T1 : class where T2 : class where T3 : class where T4 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ECCCCCC action, ComponentGroup group = null) + where T0 : class where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_CCCCCC action, ComponentGroup group = null) + where T0 : class where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EBC action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_BC action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EBCC action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : class where T2 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_BCC action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : class where T2 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EBCCC action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : class where T2 : class where T3 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_BCCC action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : class where T2 : class where T3 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EBCCCC action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : class where T2 : class where T3 : class where T4 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_BCCCC action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : class where T2 : class where T3 : class where T4 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_EBCCCCC action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_BCCCCC action, ComponentGroup group = null) + where T0 : struct, IBufferElementData where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ESC action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_SC action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ESCC action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : class where T2 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_SCC action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : class where T2 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ESCCC action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : class where T2 : class where T3 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_SCCC action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : class where T2 : class where T3 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ESCCCC action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : class where T2 : class where T3 : class where T4 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_SCCCC action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : class where T2 : class where T3 : class where T4 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_ESCCCCC action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach(EntityQueryBuilder.F_SCCCCC action, ComponentGroup group = null) + where T0 : struct, ISharedComponentData where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + + } +} + diff --git a/package/Unity.Entities/EntityQueryBuilder.gen.cs.meta b/package/Unity.Entities/EntityQueryBuilder.gen.cs.meta new file mode 100755 index 000000000..5ee87395b --- /dev/null +++ b/package/Unity.Entities/EntityQueryBuilder.gen.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 71b6bf888bcea364696d5cc546629b7a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package/Unity.Entities/EntityQueryBuilder.tt b/package/Unity.Entities/EntityQueryBuilder.tt new file mode 100755 index 000000000..bbc6fd1df --- /dev/null +++ b/package/Unity.Entities/EntityQueryBuilder.tt @@ -0,0 +1,301 @@ +<#/*THIS IS A T4 FILE - see HACKING.md for what it is and how to run codegen*/#> +<#@ assembly name="System.Collections" #> +<#@ assembly name="System.Core" #> +<#@ assembly name="System.Linq" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ import namespace="System.Linq" #> +<#@ output extension=".gen.cs" #> +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ +<# var combinations = InitCombinations(); #> +// Generated by EntityQueryBuilder.tt (<#=combinations.Count * 2 - 1#> `foreach` combinations) + +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; + +namespace Unity.Entities +{ + public partial struct EntityQueryBuilder + { + // ** FLUENT QUERY ** + +<# +foreach (var (name, count) in new[] { ("Any", 5), ( "None", 5), ("All", 5) }) { + for (var it = 1; it <= count; ++it) { +#> + public EntityQueryBuilder With<#=name#><<#=Series("T{0}", it, ", ")#>>() + { + ValidateHasNoGroup(); +<# for (var ia = 0; ia < it; ++ia) {#> + m_<#=name#>.Add(TypeManager.GetTypeIndex>()); +<# }#> + return this; + } + +<#}}#> + // ** FOREACH ** + +<# +foreach (var categories in combinations) { + foreach (var hasEntity in new[] { true, false }) { + if (!categories.Any() && !hasEntity) + continue; + var mappedCategories = categories.Select((c, i) => (c: (int)c, i: i)); + var delegateName = GetDelegateName(categories, hasEntity); + var delegateParameters = GetDelegateParameters(categories, hasEntity); + var genericTypes = categories.Any() ? ("<" + Series("T{0}", categories.Length, ", ") + ">") : ""; + var genericConstraints = GetGenericConstraints(categories); + var actionParams = GetActionParams(categories, hasEntity); +#> + public delegate void <#=delegateName#><#=genericTypes#>(<#=delegateParameters#>)<#=categories.Any() ? "" : ";"#> +<# foreach (var constraint in Smart(genericConstraints)) {#> + <#=constraint.Value#><#=constraint.IfLast(";")#> +<# }#> + + public unsafe void ForEach<#=genericTypes#>(<#=delegateName#><#=genericTypes#> action) +<# foreach (var constraint in genericConstraints) {#> + <#=constraint#> +<# }#> + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + using (InsideForEach()) + #endif + { + var group = m_Group; + if (group == null) + { +<# if (categories.Any()) {#> + var delegateTypes = stackalloc int[<#=categories.Length#>]; +<# foreach (var (c, i) in mappedCategories) { /*TODO: when tiny on c# 7.3 switch to initializer syntax */#> + delegateTypes[<#=i#>] = TypeManager.GetTypeIndex>(); +<# }#> + +<# }#> + group = ResolveComponentGroup(<#=categories.Any() ? "delegateTypes" : "null"#>, <#=categories.Length#>); + } + +<# if (hasEntity) {#> + var entityType = m_System.GetArchetypeChunkEntityType(); +<# }#> +<# foreach (var (c, i) in mappedCategories) {#> + var chunkComponentType<#=i#> = m_System.<#=AccessFunction[c]#>>(<#=IsReadOnly[c]#>); +<# }#> + + using (var chunks = group.CreateArchetypeChunkArray(Allocator.TempJob)) + { + foreach (var chunk in chunks) + { +<# foreach (var (c, i) in mappedCategories) {#> + var array<#=i#> = chunk.<#=string.Format(ChunkGetArray[c], i)#>; +<# }#> +<# if (hasEntity) {#> + var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); +<# }#> + + for (int i = 0, count = chunk.Count; i < count; ++i) + action(<#=actionParams#>); + } + } + } + } + +<#}}#> + } + + // BACK-COMPAT - TO BE REMOVED + + public partial class ComponentSystem + { +<# +foreach (var categories in combinations) { + foreach (var hasEntity in new[] { true, false }) { + if (!categories.Any() && !hasEntity) + continue; + var delegateName = GetDelegateName(categories, hasEntity); + var genericTypes = categories.Any() ? ("<" + Series("T{0}", categories.Length, ", ") + ">") : ""; + var genericConstraints = GetGenericConstraints(categories); +#> + [System.Obsolete("Call Entities.ForEach() or Entities.With(group).ForEach() instead")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public unsafe void ForEach<#=genericTypes#>(EntityQueryBuilder.<#=delegateName#><#=genericTypes#> action, ComponentGroup group = null) + <#=string.Join(" ", genericConstraints)#> + { + var q = Entities; + if (group != null) + q = q.With(group); + q.ForEach(action); + } + +<#}}#> + } +} + +<#+ +enum Category +{ + D, // ComponentData + I, // in ComponentData + C, // class + B, // IBufferElementData + K, // in IBufferElementData + S, // ISharedComponentData +} + +static string GetDelegateName(Category[] categories, bool hasEntity) +{ + var parts = string.Join("", categories.Select(c => c.ToString())); + return $"F_{(hasEntity ? "E" : "")}{parts}"; +} + +string[] Param = +{ + "ref T{0} c{0}", // ComponentData + "in T{0} c{0}", // in ComponentData + "T{0} c{0}", // class + "DynamicBuffer c{0}", // IBufferElementData + "in DynamicBuffer c{0}", // in IBufferElementData + "T{0} c{0}", // ISharedComponentData +}; + +string[] FwdParam = +{ + "ref c{0}", // ComponentData + "c{0}", // in ComponentData + "c{0}", // class + "c{0}", // IBufferElementData + "c{0}", // in IBufferElementData + "c{0}", // ISharedComponentData +}; + +string GetDelegateParameters(Category[] categories, bool hasEntity) +{ + var parts = categories.Select((c, i) => string.Format(Param[(int)c], i)); + if (hasEntity) + parts = parts.Prepend("Entity entity"); + return string.Join(", ", parts); +} + +string[] GenericConstraints = +{ + "where T{0} : struct, IComponentData", // ComponentData + "where T{0} : struct, IComponentData", // in ComponentData + "where T{0} : class", // class + "where T{0} : struct, IBufferElementData", // IBufferElementData + "where T{0} : struct, IBufferElementData", // in IBufferElementData + "where T{0} : struct, ISharedComponentData", // ISharedComponentData +}; + +IEnumerable GetGenericConstraints(Category[] categories) => + categories.Select((c, i) => string.Format(GenericConstraints[(int)c], i)); + +string[] AccessFunction = +{ + "GetArchetypeChunkComponentType", // ComponentData + "GetArchetypeChunkComponentType", // in ComponentData + "GetArchetypeChunkComponentType", // class + "GetArchetypeChunkBufferType", // IBufferElementData + "GetArchetypeChunkBufferType", // in IBufferElementData + "GetArchetypeChunkSharedComponentType", // ISharedComponentData +}; + +static string[] IsReadOnly= +{ + "false", // ComponentData + "true", // in ComponentData + "", // class + "false", // IBufferElementData + "true", // in IBufferElementData + "", // ISharedComponentData +}; + +string[] ChunkGetArray = +{ + "GetNativeArray(chunkComponentType{0}).GetUnsafePtr()", // ComponentData + "GetNativeArray(chunkComponentType{0}).GetUnsafeReadOnlyPtr()", // in ComponentData + "GetComponentObjects(chunkComponentType{0}, m_System.EntityManager)", // class + "GetBufferAccessor(chunkComponentType{0})", // IBufferElementData + "GetBufferAccessor(chunkComponentType{0})", // in IBufferElementData + "GetSharedComponentData(chunkComponentType{0}, m_System.EntityManager)", // ISharedComponentData +}; + +string[] ArrayAccess = +{ + "ref UnsafeUtilityEx.ArrayElementAsRef(array{0}, i)", // ComponentData + "in UnsafeUtilityEx.ArrayElementAsRef(array{0}, i)", // in ComponentData + "array{0}[i]", // class + "array{0}[i]", // IBufferElementData + "array{0}[i]", // in IBufferElementData + "array{0}", // ISharedComponentData +}; + +string GetActionParams(Category[] categories, bool hasEntity) +{ + var parts = categories.Select((c, i) => string.Format(ArrayAccess[(int)c], i)); + if (hasEntity) + parts = parts.Prepend("entityArray[i]"); + return string.Join(", ", parts); +} + +static List InitCombinations() +{ + var combinations = new List(); + + GetCombinations(new[] { Category.D, Category.C, Category.B, Category.S }, new Category[0], 1); + + var baseCount = combinations.Count; + for (int i = 0; i != baseCount; ++i) + GetCombinations(new[] { Category.D }, combinations[i], 5); + for (int i = 0; i != baseCount; ++i) + GetCombinations(new[] { Category.C }, combinations[i], 5); + + combinations.Insert(0, new Category[0]); + + void GetCombinations(Category[] supported, Category[] parent, int depth) + { + for (int i = 0; i != supported.Length; ++i) + { + var categories = new Category[parent.Length + 1]; + parent.CopyTo(categories, 0); + categories[categories.Length - 1] = supported[i]; + + combinations.Add(categories); + + if (depth-1 > 0) + GetCombinations(supported, categories, depth-1); + } + } + + return combinations; +} + +// misc support utils + +class SmartElement +{ + public T Value; + public int Index; + public int Count; + + public bool First => Index == 0; + public bool Last => Index == Count - 1; + + public string IfFirst(string text) => First ? text : ""; + public string IfLast(string text) => Last ? text : ""; +} + +static IEnumerable> Smart(IEnumerable items) +{ + var list = items.ToList(); + for (var i = 0; i < list.Count; ++i) + yield return new SmartElement { Value = list[i], Index = i, Count = list.Count }; +} + +static string Series(string formatString, int count, string separator) => + string.Join(separator, Enumerable.Range(0, count).Select(i => string.Format(formatString, i))); +#> diff --git a/package/Unity.Entities/EntityQueryBuilder.tt.meta b/package/Unity.Entities/EntityQueryBuilder.tt.meta new file mode 100755 index 000000000..ec9bb529b --- /dev/null +++ b/package/Unity.Entities/EntityQueryBuilder.tt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: df0a5c4fe61ce2c42bcab398bb71d5ce +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package/Unity.Entities/EntityQueryCache.cs b/package/Unity.Entities/EntityQueryCache.cs new file mode 100755 index 000000000..4a1e501a6 --- /dev/null +++ b/package/Unity.Entities/EntityQueryCache.cs @@ -0,0 +1,130 @@ +using System; + +namespace Unity.Entities +{ + class EntityQueryCache + { + uint[] m_CacheHashes; // combined hash of QueryComponentBuilder and delegate types + ComponentGroup[] m_CacheComponentGroups; + #if ENABLE_UNITY_COLLECTIONS_CHECKS + EntityQueryBuilder[] m_CacheCheckQueryBuilders; + int[][] m_CacheCheckDelegateTypeIndices; + #endif + + public EntityQueryCache(int cacheSize = 10) + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + if (cacheSize <= 0) + throw new ArgumentOutOfRangeException(nameof(cacheSize), "Cache size must be > 0"); + #endif + + m_CacheHashes = new uint[cacheSize]; + m_CacheComponentGroups = new ComponentGroup[cacheSize]; + + // we use these for an additional equality check to avoid accidental hash collisions + #if ENABLE_UNITY_COLLECTIONS_CHECKS + m_CacheCheckQueryBuilders = new EntityQueryBuilder[cacheSize]; + m_CacheCheckDelegateTypeIndices = new int[cacheSize][]; + #endif + } + + public int FindQueryInCache(uint hash) + { + for (var i = 0; i < m_CacheHashes.Length && m_CacheComponentGroups[i] != null; ++i) + { + if (m_CacheHashes[i] == hash) + return i; + } + + return -1; + } + + public unsafe int CreateCachedQuery(uint hash, ComponentGroup group + #if ENABLE_UNITY_COLLECTIONS_CHECKS + , ref EntityQueryBuilder builder, int* delegateTypeIndices, int delegateTypeCount + #endif + ) + { + #if ENABLE_UNITY_COLLECTIONS_CHECKS + if (group == null) + throw new ArgumentNullException(nameof(group)); + #endif + + var index = 0; + + // find open slot or create one + + for (;;) + { + if (index == m_CacheHashes.Length) + { + var newSize = m_CacheHashes.Length + Math.Max(m_CacheHashes.Length / 2, 1); + + UnityEngine.Debug.LogError( + $"{nameof(EntityQueryCache)} is too small to hold the current number of queries this {nameof(ComponentSystem)} is running. The cache automatically expanded to {newSize}, " + + $"but this may cause a GC. Set cache size at init time via {nameof(ComponentSystem.InitEntityQueryCache)}() to a large enough number to ensure no allocations are required at run time."); + + Array.Resize(ref m_CacheHashes, newSize); + Array.Resize(ref m_CacheComponentGroups, newSize); + + #if ENABLE_UNITY_COLLECTIONS_CHECKS + Array.Resize(ref m_CacheCheckQueryBuilders, newSize); + Array.Resize(ref m_CacheCheckDelegateTypeIndices, newSize); + #endif + break; + } + + if (m_CacheComponentGroups[index] == null) + break; + + #if ENABLE_UNITY_COLLECTIONS_CHECKS + if (m_CacheHashes[index] == hash) + throw new InvalidOperationException($"Unexpected {nameof(CreateCachedQuery)} with hash {hash} that already exists in cache at slot {index}"); + #endif + + ++index; + } + + // store in cache + + m_CacheHashes[index] = hash; + m_CacheComponentGroups[index] = group; + + #if ENABLE_UNITY_COLLECTIONS_CHECKS + m_CacheCheckQueryBuilders[index] = builder; + var checkDelegateTypeIndices = new int[delegateTypeCount]; + for (var i = 0; i < delegateTypeCount; ++i) + checkDelegateTypeIndices[i] = delegateTypeIndices[i]; + m_CacheCheckDelegateTypeIndices[index] = checkDelegateTypeIndices; + #endif + + return index; + } + + public ComponentGroup GetCachedQuery(int cacheIndex) + => m_CacheComponentGroups[cacheIndex]; + + #if ENABLE_UNITY_COLLECTIONS_CHECKS + public unsafe void ValidateMatchesCache(int foundCacheIndex, ref EntityQueryBuilder builder, int* delegateTypeIndices, int delegateTypeCount) + { + if (!builder.ShallowEquals(ref m_CacheCheckQueryBuilders[foundCacheIndex])) + goto bad; + + var cached = m_CacheCheckDelegateTypeIndices[foundCacheIndex]; + if (cached.Length != delegateTypeCount) + goto bad; + + for (var i = 0; i < delegateTypeCount; ++i) + { + if (cached[i] != delegateTypeIndices[i]) + goto bad; + } + + return; + + bad: + throw new InvalidOperationException("Type signature does not match cached"); + } + #endif + } +} diff --git a/package/Unity.Entities/EntityQueryCache.cs.meta b/package/Unity.Entities/EntityQueryCache.cs.meta new file mode 100755 index 000000000..c4967d854 --- /dev/null +++ b/package/Unity.Entities/EntityQueryCache.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37d2d67d783b48e4d90b3a7c75087275 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package/Unity.Entities/IJobChunk.cs b/package/Unity.Entities/IJobChunk.cs index 32ea0da2f..79aaaba4a 100755 --- a/package/Unity.Entities/IJobChunk.cs +++ b/package/Unity.Entities/IJobChunk.cs @@ -7,10 +7,12 @@ namespace Unity.Entities { #if !UNITY_ZEROPLAYER - [JobProducerType(typeof(JobChunkExtensions.JobChunkLiveFilter_Process<>))] + [JobProducerType(typeof(JobChunkExtensions.JobChunk_Process<>))] #endif public interface IJobChunk { + // firstEntityIndex refers to the index of the first entity in the current chunk within the ComponentGroup the job was scheduled with + // For example, if the job operates on 3 chunks with 20 entities each, then the firstEntityIndices will be [0, 20, 40] respectively void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex); } @@ -24,17 +26,20 @@ internal struct EntitySafetyHandle } #endif - internal struct JobDataLiveFilter where T : struct + internal struct JobChunkData where T : struct { #if ENABLE_UNITY_COLLECTIONS_CHECKS #pragma warning disable 414 [ReadOnly] public EntitySafetyHandle safety; #pragma warning restore #endif - public ComponentChunkIterator iterator; - public T data; - } + public T Data; + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; + } + public static unsafe JobHandle Schedule(this T jobData, ComponentGroup group, JobHandle dependsOn = default(JobHandle)) where T : struct, IJobChunk { @@ -52,28 +57,52 @@ internal static unsafe JobHandle ScheduleInternal(ref T jobData, ComponentGro where T : struct, IJobChunk { ComponentChunkIterator iterator = group.GetComponentChunkIterator(); - JobDataLiveFilter fullData = new JobDataLiveFilter + + var unfilteredChunkCount = group.CalculateNumberOfChunksWithoutFiltering(); + + var prefilterHandle = ComponentChunkIterator.PreparePrefilteredChunkLists(unfilteredChunkCount, + iterator.m_MatchingArchetypeList, iterator.m_Filter, dependsOn, mode, out var prefilterData, + out var deferredCountData); + + JobChunkData fullData = new JobChunkData { #if ENABLE_UNITY_COLLECTIONS_CHECKS // All IJobChunk jobs have a EntityManager safety handle to ensure that BeforeStructuralChange throws an error if // jobs without any other safety handles are still running (haven't been synced). safety = new EntitySafetyHandle{m_Safety = group.SafetyManager.GetEntityManagerSafetyHandle()}, #endif - data = jobData, - iterator = iterator, + Data = jobData, + PrefilterData = prefilterData, }; - var totalChunks = group.CalculateNumberOfChunksWithoutFiltering(); var scheduleParams = new JobsUtility.JobScheduleParameters( UnsafeUtility.AddressOf(ref fullData), - JobChunkLiveFilter_Process.Initialize(), - dependsOn, - mode); - - return JobsUtility.ScheduleParallelFor(ref scheduleParams, totalChunks, 1); + JobChunk_Process.Initialize(), + prefilterHandle, + mode); + +#if ENABLE_UNITY_COLLECTIONS_CHECKS + try + { +#endif + if(mode == ScheduleMode.Batched) + return JobsUtility.ScheduleParallelForDeferArraySize(ref scheduleParams, 1, deferredCountData, null); + else + { + var count = unfilteredChunkCount; + return JobsUtility.ScheduleParallelFor(ref scheduleParams, count, 1); + } +#if ENABLE_UNITY_COLLECTIONS_CHECKS + } + catch (InvalidOperationException e) + { + prefilterData.Dispose(); + throw e; + } +#endif } - internal struct JobChunkLiveFilter_Process + internal struct JobChunk_Process where T : struct, IJobChunk { public static IntPtr jobReflectionData; @@ -81,31 +110,30 @@ internal struct JobChunkLiveFilter_Process public static IntPtr Initialize() { if (jobReflectionData == IntPtr.Zero) - jobReflectionData = JobsUtility.CreateJobReflectionData(typeof(JobDataLiveFilter), + jobReflectionData = JobsUtility.CreateJobReflectionData(typeof(JobChunkData), typeof(T), JobType.ParallelFor, (ExecuteJobFunction)Execute); return jobReflectionData; } - public delegate void ExecuteJobFunction(ref JobDataLiveFilter data, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex); + public delegate void ExecuteJobFunction(ref JobChunkData data, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex); - public unsafe static void Execute(ref JobDataLiveFilter jobData, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex) + public unsafe static void Execute(ref JobChunkData jobData, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex) { ExecuteInternal(ref jobData, ref ranges, jobIndex); } - internal unsafe static void ExecuteInternal(ref JobDataLiveFilter jobData, ref JobRanges ranges, int jobIndex) + internal unsafe static void ExecuteInternal(ref JobChunkData jobData, ref JobRanges ranges, int jobIndex) { + var filteredChunks = (ArchetypeChunk*)NativeArrayUnsafeUtility.GetUnsafePtr(jobData.PrefilterData); + var entityIndices = (int*) (filteredChunks + ranges.TotalIterationCount); + int chunkIndex, end; while (JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out chunkIndex, out end)) { - jobData.iterator.MoveToChunkWithoutFiltering(chunkIndex); - if (!jobData.iterator.MatchesFilter()) - continue; - - jobData.iterator.GetFilteredChunkAndEntityIndices(out var filteredChunkIndex, out var entityOffset); - - var chunk = jobData.iterator.GetCurrentChunk(); - jobData.data.Execute(chunk, filteredChunkIndex, entityOffset); + var chunk = filteredChunks[chunkIndex]; + var entityOffset = entityIndices[chunkIndex]; + + jobData.Data.Execute(chunk, chunkIndex, entityOffset); } } } diff --git a/package/Unity.Entities/IJobProcessComponentData.cs b/package/Unity.Entities/IJobProcessComponentData.cs index 9e1159639..3e3f63230 100755 --- a/package/Unity.Entities/IJobProcessComponentData.cs +++ b/package/Unity.Entities/IJobProcessComponentData.cs @@ -4,6 +4,7 @@ using System.Reflection; using System.Runtime.InteropServices; using Unity.Assertions; +using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Jobs; using Unity.Jobs.LowLevel.Unsafe; @@ -149,7 +150,7 @@ static void PrepareComponentGroup(ComponentSystemBase system, Type jobType) static unsafe void Initialize(ComponentSystemBase system, ComponentGroup componentGroup, Type jobType, Type wrapperJobType, bool isParallelFor, ref JobProcessComponentDataCache cache, out ProcessIterationData iterator) { - // Get the job reflection data and cache it if we don't already have it cached. + // Get the job reflection data and cache it if we don't already have it cached. if (isParallelFor && cache.JobReflectionDataParallelFor == IntPtr.Zero || !isParallelFor && cache.JobReflectionData == IntPtr.Zero) { @@ -202,26 +203,25 @@ static unsafe void Initialize(ComponentSystemBase system, ComponentGroup compone for (var i = 0; i != cache.ProcessTypesCount; i++) isReadOnly[i] = cache.Types[i].AccessModeType == ComponentType.AccessMode.ReadOnly ? 1 : 0; } - - // Set process iteration data's ComponentChunkIterator - iterator.Iterator = group.GetComponentChunkIterator(); - - // Get each type's index in the component group and store them on the process iteration data for output. - iterator.IndexInGroup0 = iterator.IndexInGroup1 = iterator.IndexInGroup2 = iterator.IndexInGroup3 = iterator.IndexInGroup4 = iterator.IndexInGroup5 = -1; - fixed (int* groupIndices = &iterator.IndexInGroup0) + + iterator.TypeIndex0 = iterator.TypeIndex1 = iterator.TypeIndex2 = iterator.TypeIndex3 = iterator.TypeIndex4 = iterator.TypeIndex5 = -1; + fixed (int* typeIndices = &iterator.TypeIndex0) { for (var i = 0; i != cache.ProcessTypesCount; i++) - groupIndices[i] = group.GetIndexInComponentGroup(cache.Types[i].TypeIndex); + typeIndices[i] = cache.Types[i].TypeIndex; } iterator.m_IsParallelFor = isParallelFor; iterator.m_Length = group.CalculateNumberOfChunksWithoutFiltering(); + iterator.GlobalSystemVersion = group.GetComponentChunkIterator().m_GlobalSystemVersion; + #if ENABLE_UNITY_COLLECTIONS_CHECKS iterator.m_MaxIndex = iterator.m_Length - 1; iterator.m_MinIndex = 0; - iterator.m_Safety0 = iterator.m_Safety1 = iterator.m_Safety2 = iterator.m_Safety3 = iterator.m_Safety4 = iterator.m_Safety5= default(AtomicSafetyHandle); + iterator.m_Safety0 = iterator.m_Safety1 = iterator.m_Safety2 = iterator.m_Safety3 = iterator.m_Safety4 = + iterator.m_Safety5 = default(AtomicSafetyHandle); iterator.m_SafetyReadOnlyCount = 0; fixed (AtomicSafetyHandle* safety = &iterator.m_Safety0) @@ -229,7 +229,8 @@ static unsafe void Initialize(ComponentSystemBase system, ComponentGroup compone for (var i = 0; i != cache.ProcessTypesCount; i++) if (cache.Types[i].AccessModeType == ComponentType.AccessMode.ReadOnly) { - safety[iterator.m_SafetyReadOnlyCount] = group.GetSafetyHandle(group.GetIndexInComponentGroup(cache.Types[i].TypeIndex)); + safety[iterator.m_SafetyReadOnlyCount] = + group.GetSafetyHandle(group.GetIndexInComponentGroup(cache.Types[i].TypeIndex)); iterator.m_SafetyReadOnlyCount++; } } @@ -240,7 +241,8 @@ static unsafe void Initialize(ComponentSystemBase system, ComponentGroup compone for (var i = 0; i != cache.ProcessTypesCount; i++) if (cache.Types[i].AccessModeType == ComponentType.AccessMode.ReadWrite) { - safety[iterator.m_SafetyReadOnlyCount + iterator.m_SafetyReadWriteCount] = group.GetSafetyHandle(group.GetIndexInComponentGroup(cache.Types[i].TypeIndex)); + safety[iterator.m_SafetyReadOnlyCount + iterator.m_SafetyReadWriteCount] = + group.GetSafetyHandle(group.GetIndexInComponentGroup(cache.Types[i].TypeIndex)); iterator.m_SafetyReadWriteCount++; } } @@ -272,13 +274,14 @@ internal struct JobProcessComponentDataCache [StructLayout(LayoutKind.Sequential)] internal struct ProcessIterationData { - public ComponentChunkIterator Iterator; - public int IndexInGroup0; - public int IndexInGroup1; - public int IndexInGroup2; - public int IndexInGroup3; - public int IndexInGroup4; - public int IndexInGroup5; + public uint GlobalSystemVersion; + + public int TypeIndex0; + public int TypeIndex1; + public int TypeIndex2; + public int TypeIndex3; + public int TypeIndex4; + public int TypeIndex5; public int IsReadOnly0; public int IsReadOnly1; @@ -333,24 +336,34 @@ public static int CalculateEntityCount(this T jobData, ComponentSystemBase sy return CalculateEntityCount(system, typeof(T)); } - - - static unsafe JobHandle Schedule(void* fullData, int length, int innerloopBatchCount, - bool isParallelFor, ref JobProcessComponentDataCache cache, JobHandle dependsOn, ScheduleMode mode) + static unsafe JobHandle Schedule(void* fullData, NativeArray prefilterData, int unfilteredLength, int innerloopBatchCount, + bool isParallelFor, bool isFiltered, ref JobProcessComponentDataCache cache, void* deferredCountData, JobHandle dependsOn, ScheduleMode mode) { +#if ENABLE_UNITY_COLLECTIONS_CHECKS + try + { +#endif if (isParallelFor) { - var scheduleParams = - new JobsUtility.JobScheduleParameters(fullData, cache.JobReflectionDataParallelFor, dependsOn, - mode); - return JobsUtility.ScheduleParallelFor(ref scheduleParams, length, innerloopBatchCount); + var scheduleParams = new JobsUtility.JobScheduleParameters(fullData, cache.JobReflectionDataParallelFor, dependsOn, mode); + if(isFiltered) + return JobsUtility.ScheduleParallelForDeferArraySize(ref scheduleParams, innerloopBatchCount, deferredCountData, null); + else + return JobsUtility.ScheduleParallelFor(ref scheduleParams, unfilteredLength, innerloopBatchCount); } else { - var scheduleParams = - new JobsUtility.JobScheduleParameters(fullData, cache.JobReflectionData, dependsOn, mode); + var scheduleParams = new JobsUtility.JobScheduleParameters(fullData, cache.JobReflectionData, dependsOn, mode); return JobsUtility.Schedule(ref scheduleParams); } +#if ENABLE_UNITY_COLLECTIONS_CHECKS + } + catch (InvalidOperationException e) + { + prefilterData.Dispose(); + throw e; + } +#endif } } } diff --git a/package/Unity.Entities/IJobProcessComponentData.generated.cs b/package/Unity.Entities/IJobProcessComponentData.generated.cs index 06ca3e509..ff16e4d1f 100755 --- a/package/Unity.Entities/IJobProcessComponentData.generated.cs +++ b/package/Unity.Entities/IJobProcessComponentData.generated.cs @@ -9,6 +9,7 @@ //------------------------------------------------------------------------------ #if !UNITY_ZEROPLAYER +using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Jobs; using Unity.Jobs.LowLevel.Unsafe; @@ -333,9 +334,14 @@ internal static unsafe JobHandle ScheduleInternal_D(ref T jobData, ComponentS var isParallelFor = innerloopBatchCount != -1; Initialize(system, componentGroup, typeof(T), typeof(JobStruct_Process_D<,>), isParallelFor, ref JobStruct_ProcessInfer_D.Cache, out fullData.Iterator); - return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, ref JobStruct_ProcessInfer_D.Cache, dependsOn, mode); - } + + var unfilteredChunkCount = fullData.Iterator.m_Length; + var iterator = JobStruct_ProcessInfer_D.Cache.ComponentGroup.GetComponentChunkIterator(); + var prefilterHandle = ComponentChunkIterator.PreparePrefilteredChunkLists(unfilteredChunkCount, iterator.m_MatchingArchetypeList, iterator.m_Filter, dependsOn, mode, out fullData.PrefilterData, out var deferredCountData); + + return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.PrefilterData, fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, iterator.RequiresFilter(), ref JobStruct_ProcessInfer_D.Cache, deferredCountData, prefilterHandle, mode); + } [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public interface IBaseJobProcessComponentData_D : IBaseJobProcessComponentData { } @@ -347,6 +353,10 @@ private struct JobStruct_ProcessInfer_D where T : struct public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; } [StructLayout(LayoutKind.Sequential)] @@ -356,6 +366,10 @@ internal struct JobStruct_Process_D { public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; [Preserve] public static IntPtr Initialize(JobType jobType) @@ -367,42 +381,38 @@ public static IntPtr Initialize(JobType jobType) public static unsafe void Execute(ref JobStruct_Process_D jobData, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex) { + var chunks = (ArchetypeChunk*)NativeArrayUnsafeUtility.GetUnsafePtr(jobData.PrefilterData); + var entityIndices = (int*) (chunks + jobData.Iterator.m_Length); + var chunkCount = *(entityIndices + jobData.Iterator.m_Length); + if (jobData.Iterator.m_IsParallelFor) { int begin, end; while (JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out begin, out end)) - ExecuteChunk(ref jobData, bufferRangePatchData, begin, end); + ExecuteChunk(ref jobData, bufferRangePatchData, begin, end, chunks, entityIndices); } else { - ExecuteChunk(ref jobData, bufferRangePatchData, 0, jobData.Iterator.m_Length); + ExecuteChunk(ref jobData, bufferRangePatchData, 0, chunkCount, chunks, entityIndices); } } - static unsafe void ExecuteChunk(ref JobStruct_Process_D jobData, IntPtr bufferRangePatchData, int begin, int end) + static unsafe void ExecuteChunk(ref JobStruct_Process_D jobData, IntPtr bufferRangePatchData, int begin, int end, ArchetypeChunk* chunks, int* entityIndices) { - ref ComponentChunkIterator chunkIterator = ref jobData.Iterator.Iterator; - + var typeLookupCache0 = 0; + for (var blockIndex = begin; blockIndex != end; ++blockIndex) - { - jobData.Iterator.Iterator.MoveToChunkWithoutFiltering(blockIndex); - - var processBlock = jobData.Iterator.Iterator.MatchesFilter(); - - if (!processBlock) - continue; - - int beginIndex, endIndex; - chunkIterator.GetCurrentChunkRange(out beginIndex, out endIndex); + { + var chunk = chunks[blockIndex]; + int beginIndex = entityIndices[blockIndex]; + var count = chunk.Count; #if ENABLE_UNITY_COLLECTIONS_CHECKS - JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, endIndex - beginIndex); - #endif - - var count = chunkIterator.GetCurrentChunkCount(); - - var ptr0 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly0 == 0, jobData.Iterator.IndexInGroup0)); + JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, beginIndex + count); + #endif + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex0, ref typeLookupCache0); + var ptr0 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly0 == 0, typeLookupCache0, jobData.Iterator.GlobalSystemVersion)); + - for (var i = 0; i != count; i++) { jobData.Data.Execute(ref UnsafeUtilityEx.ArrayElementAsRef(ptr0, i)); @@ -419,9 +429,14 @@ internal static unsafe JobHandle ScheduleInternal_ED(ref T jobData, Component var isParallelFor = innerloopBatchCount != -1; Initialize(system, componentGroup, typeof(T), typeof(JobStruct_Process_ED<,>), isParallelFor, ref JobStruct_ProcessInfer_ED.Cache, out fullData.Iterator); - return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, ref JobStruct_ProcessInfer_ED.Cache, dependsOn, mode); - } + + var unfilteredChunkCount = fullData.Iterator.m_Length; + var iterator = JobStruct_ProcessInfer_ED.Cache.ComponentGroup.GetComponentChunkIterator(); + var prefilterHandle = ComponentChunkIterator.PreparePrefilteredChunkLists(unfilteredChunkCount, iterator.m_MatchingArchetypeList, iterator.m_Filter, dependsOn, mode, out fullData.PrefilterData, out var deferredCountData); + + return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.PrefilterData, fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, iterator.RequiresFilter(), ref JobStruct_ProcessInfer_ED.Cache, deferredCountData, prefilterHandle, mode); + } [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public interface IBaseJobProcessComponentData_ED : IBaseJobProcessComponentData { } @@ -433,6 +448,10 @@ private struct JobStruct_ProcessInfer_ED where T : struct public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; } [StructLayout(LayoutKind.Sequential)] @@ -442,6 +461,10 @@ internal struct JobStruct_Process_ED { public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; [Preserve] public static IntPtr Initialize(JobType jobType) @@ -453,43 +476,39 @@ public static IntPtr Initialize(JobType jobType) public static unsafe void Execute(ref JobStruct_Process_ED jobData, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex) { + var chunks = (ArchetypeChunk*)NativeArrayUnsafeUtility.GetUnsafePtr(jobData.PrefilterData); + var entityIndices = (int*) (chunks + jobData.Iterator.m_Length); + var chunkCount = *(entityIndices + jobData.Iterator.m_Length); + if (jobData.Iterator.m_IsParallelFor) { int begin, end; while (JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out begin, out end)) - ExecuteChunk(ref jobData, bufferRangePatchData, begin, end); + ExecuteChunk(ref jobData, bufferRangePatchData, begin, end, chunks, entityIndices); } else { - ExecuteChunk(ref jobData, bufferRangePatchData, 0, jobData.Iterator.m_Length); + ExecuteChunk(ref jobData, bufferRangePatchData, 0, chunkCount, chunks, entityIndices); } } - static unsafe void ExecuteChunk(ref JobStruct_Process_ED jobData, IntPtr bufferRangePatchData, int begin, int end) + static unsafe void ExecuteChunk(ref JobStruct_Process_ED jobData, IntPtr bufferRangePatchData, int begin, int end, ArchetypeChunk* chunks, int* entityIndices) { - ref ComponentChunkIterator chunkIterator = ref jobData.Iterator.Iterator; - + var typeLookupCache0 = 0; + for (var blockIndex = begin; blockIndex != end; ++blockIndex) - { - jobData.Iterator.Iterator.MoveToChunkWithoutFiltering(blockIndex); - - var processBlock = jobData.Iterator.Iterator.MatchesFilter(); - - if (!processBlock) - continue; - - int beginIndex, endIndex; - chunkIterator.GetCurrentChunkRange(out beginIndex, out endIndex); + { + var chunk = chunks[blockIndex]; + int beginIndex = entityIndices[blockIndex]; + var count = chunk.Count; #if ENABLE_UNITY_COLLECTIONS_CHECKS - JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, endIndex - beginIndex); - #endif - - var count = chunkIterator.GetCurrentChunkCount(); - - var ptrE = (Entity*)UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(false, 0)); - var ptr0 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly0 == 0, jobData.Iterator.IndexInGroup0)); + JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, beginIndex + count); + #endif + var ptrE = (Entity*)UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, false, 0, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex0, ref typeLookupCache0); + var ptr0 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly0 == 0, typeLookupCache0, jobData.Iterator.GlobalSystemVersion)); + - for (var i = 0; i != count; i++) { jobData.Data.Execute(ptrE[i], i + beginIndex, ref UnsafeUtilityEx.ArrayElementAsRef(ptr0, i)); @@ -506,9 +525,14 @@ internal static unsafe JobHandle ScheduleInternal_DD(ref T jobData, Component var isParallelFor = innerloopBatchCount != -1; Initialize(system, componentGroup, typeof(T), typeof(JobStruct_Process_DD<,,>), isParallelFor, ref JobStruct_ProcessInfer_DD.Cache, out fullData.Iterator); - return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, ref JobStruct_ProcessInfer_DD.Cache, dependsOn, mode); - } + + var unfilteredChunkCount = fullData.Iterator.m_Length; + var iterator = JobStruct_ProcessInfer_DD.Cache.ComponentGroup.GetComponentChunkIterator(); + var prefilterHandle = ComponentChunkIterator.PreparePrefilteredChunkLists(unfilteredChunkCount, iterator.m_MatchingArchetypeList, iterator.m_Filter, dependsOn, mode, out fullData.PrefilterData, out var deferredCountData); + + return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.PrefilterData, fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, iterator.RequiresFilter(), ref JobStruct_ProcessInfer_DD.Cache, deferredCountData, prefilterHandle, mode); + } [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public interface IBaseJobProcessComponentData_DD : IBaseJobProcessComponentData { } @@ -520,6 +544,10 @@ private struct JobStruct_ProcessInfer_DD where T : struct public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; } [StructLayout(LayoutKind.Sequential)] @@ -530,6 +558,10 @@ internal struct JobStruct_Process_DD { public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; [Preserve] public static IntPtr Initialize(JobType jobType) @@ -541,43 +573,41 @@ public static IntPtr Initialize(JobType jobType) public static unsafe void Execute(ref JobStruct_Process_DD jobData, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex) { + var chunks = (ArchetypeChunk*)NativeArrayUnsafeUtility.GetUnsafePtr(jobData.PrefilterData); + var entityIndices = (int*) (chunks + jobData.Iterator.m_Length); + var chunkCount = *(entityIndices + jobData.Iterator.m_Length); + if (jobData.Iterator.m_IsParallelFor) { int begin, end; while (JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out begin, out end)) - ExecuteChunk(ref jobData, bufferRangePatchData, begin, end); + ExecuteChunk(ref jobData, bufferRangePatchData, begin, end, chunks, entityIndices); } else { - ExecuteChunk(ref jobData, bufferRangePatchData, 0, jobData.Iterator.m_Length); + ExecuteChunk(ref jobData, bufferRangePatchData, 0, chunkCount, chunks, entityIndices); } } - static unsafe void ExecuteChunk(ref JobStruct_Process_DD jobData, IntPtr bufferRangePatchData, int begin, int end) + static unsafe void ExecuteChunk(ref JobStruct_Process_DD jobData, IntPtr bufferRangePatchData, int begin, int end, ArchetypeChunk* chunks, int* entityIndices) { - ref ComponentChunkIterator chunkIterator = ref jobData.Iterator.Iterator; - + var typeLookupCache0 = 0; + var typeLookupCache1 = 0; + for (var blockIndex = begin; blockIndex != end; ++blockIndex) - { - jobData.Iterator.Iterator.MoveToChunkWithoutFiltering(blockIndex); - - var processBlock = jobData.Iterator.Iterator.MatchesFilter(); - - if (!processBlock) - continue; - - int beginIndex, endIndex; - chunkIterator.GetCurrentChunkRange(out beginIndex, out endIndex); + { + var chunk = chunks[blockIndex]; + int beginIndex = entityIndices[blockIndex]; + var count = chunk.Count; #if ENABLE_UNITY_COLLECTIONS_CHECKS - JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, endIndex - beginIndex); - #endif - - var count = chunkIterator.GetCurrentChunkCount(); - - var ptr0 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly0 == 0, jobData.Iterator.IndexInGroup0)); - var ptr1 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly1 == 0, jobData.Iterator.IndexInGroup1)); + JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, beginIndex + count); + #endif + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex0, ref typeLookupCache0); + var ptr0 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly0 == 0, typeLookupCache0, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex1, ref typeLookupCache1); + var ptr1 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly1 == 0, typeLookupCache1, jobData.Iterator.GlobalSystemVersion)); + - for (var i = 0; i != count; i++) { jobData.Data.Execute(ref UnsafeUtilityEx.ArrayElementAsRef(ptr0, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr1, i)); @@ -594,9 +624,14 @@ internal static unsafe JobHandle ScheduleInternal_EDD(ref T jobData, Componen var isParallelFor = innerloopBatchCount != -1; Initialize(system, componentGroup, typeof(T), typeof(JobStruct_Process_EDD<,,>), isParallelFor, ref JobStruct_ProcessInfer_EDD.Cache, out fullData.Iterator); - return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, ref JobStruct_ProcessInfer_EDD.Cache, dependsOn, mode); - } + + var unfilteredChunkCount = fullData.Iterator.m_Length; + var iterator = JobStruct_ProcessInfer_EDD.Cache.ComponentGroup.GetComponentChunkIterator(); + var prefilterHandle = ComponentChunkIterator.PreparePrefilteredChunkLists(unfilteredChunkCount, iterator.m_MatchingArchetypeList, iterator.m_Filter, dependsOn, mode, out fullData.PrefilterData, out var deferredCountData); + + return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.PrefilterData, fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, iterator.RequiresFilter(), ref JobStruct_ProcessInfer_EDD.Cache, deferredCountData, prefilterHandle, mode); + } [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public interface IBaseJobProcessComponentData_EDD : IBaseJobProcessComponentData { } @@ -608,6 +643,10 @@ private struct JobStruct_ProcessInfer_EDD where T : struct public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; } [StructLayout(LayoutKind.Sequential)] @@ -618,6 +657,10 @@ internal struct JobStruct_Process_EDD { public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; [Preserve] public static IntPtr Initialize(JobType jobType) @@ -629,44 +672,42 @@ public static IntPtr Initialize(JobType jobType) public static unsafe void Execute(ref JobStruct_Process_EDD jobData, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex) { + var chunks = (ArchetypeChunk*)NativeArrayUnsafeUtility.GetUnsafePtr(jobData.PrefilterData); + var entityIndices = (int*) (chunks + jobData.Iterator.m_Length); + var chunkCount = *(entityIndices + jobData.Iterator.m_Length); + if (jobData.Iterator.m_IsParallelFor) { int begin, end; while (JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out begin, out end)) - ExecuteChunk(ref jobData, bufferRangePatchData, begin, end); + ExecuteChunk(ref jobData, bufferRangePatchData, begin, end, chunks, entityIndices); } else { - ExecuteChunk(ref jobData, bufferRangePatchData, 0, jobData.Iterator.m_Length); + ExecuteChunk(ref jobData, bufferRangePatchData, 0, chunkCount, chunks, entityIndices); } } - static unsafe void ExecuteChunk(ref JobStruct_Process_EDD jobData, IntPtr bufferRangePatchData, int begin, int end) + static unsafe void ExecuteChunk(ref JobStruct_Process_EDD jobData, IntPtr bufferRangePatchData, int begin, int end, ArchetypeChunk* chunks, int* entityIndices) { - ref ComponentChunkIterator chunkIterator = ref jobData.Iterator.Iterator; - + var typeLookupCache0 = 0; + var typeLookupCache1 = 0; + for (var blockIndex = begin; blockIndex != end; ++blockIndex) - { - jobData.Iterator.Iterator.MoveToChunkWithoutFiltering(blockIndex); - - var processBlock = jobData.Iterator.Iterator.MatchesFilter(); - - if (!processBlock) - continue; - - int beginIndex, endIndex; - chunkIterator.GetCurrentChunkRange(out beginIndex, out endIndex); + { + var chunk = chunks[blockIndex]; + int beginIndex = entityIndices[blockIndex]; + var count = chunk.Count; #if ENABLE_UNITY_COLLECTIONS_CHECKS - JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, endIndex - beginIndex); - #endif - - var count = chunkIterator.GetCurrentChunkCount(); - - var ptrE = (Entity*)UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(false, 0)); - var ptr0 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly0 == 0, jobData.Iterator.IndexInGroup0)); - var ptr1 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly1 == 0, jobData.Iterator.IndexInGroup1)); + JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, beginIndex + count); + #endif + var ptrE = (Entity*)UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, false, 0, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex0, ref typeLookupCache0); + var ptr0 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly0 == 0, typeLookupCache0, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex1, ref typeLookupCache1); + var ptr1 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly1 == 0, typeLookupCache1, jobData.Iterator.GlobalSystemVersion)); + - for (var i = 0; i != count; i++) { jobData.Data.Execute(ptrE[i], i + beginIndex, ref UnsafeUtilityEx.ArrayElementAsRef(ptr0, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr1, i)); @@ -683,9 +724,14 @@ internal static unsafe JobHandle ScheduleInternal_DDD(ref T jobData, Componen var isParallelFor = innerloopBatchCount != -1; Initialize(system, componentGroup, typeof(T), typeof(JobStruct_Process_DDD<,,,>), isParallelFor, ref JobStruct_ProcessInfer_DDD.Cache, out fullData.Iterator); - return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, ref JobStruct_ProcessInfer_DDD.Cache, dependsOn, mode); - } + + var unfilteredChunkCount = fullData.Iterator.m_Length; + var iterator = JobStruct_ProcessInfer_DDD.Cache.ComponentGroup.GetComponentChunkIterator(); + var prefilterHandle = ComponentChunkIterator.PreparePrefilteredChunkLists(unfilteredChunkCount, iterator.m_MatchingArchetypeList, iterator.m_Filter, dependsOn, mode, out fullData.PrefilterData, out var deferredCountData); + + return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.PrefilterData, fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, iterator.RequiresFilter(), ref JobStruct_ProcessInfer_DDD.Cache, deferredCountData, prefilterHandle, mode); + } [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public interface IBaseJobProcessComponentData_DDD : IBaseJobProcessComponentData { } @@ -697,6 +743,10 @@ private struct JobStruct_ProcessInfer_DDD where T : struct public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; } [StructLayout(LayoutKind.Sequential)] @@ -708,6 +758,10 @@ internal struct JobStruct_Process_DDD { public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; [Preserve] public static IntPtr Initialize(JobType jobType) @@ -719,44 +773,44 @@ public static IntPtr Initialize(JobType jobType) public static unsafe void Execute(ref JobStruct_Process_DDD jobData, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex) { + var chunks = (ArchetypeChunk*)NativeArrayUnsafeUtility.GetUnsafePtr(jobData.PrefilterData); + var entityIndices = (int*) (chunks + jobData.Iterator.m_Length); + var chunkCount = *(entityIndices + jobData.Iterator.m_Length); + if (jobData.Iterator.m_IsParallelFor) { int begin, end; while (JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out begin, out end)) - ExecuteChunk(ref jobData, bufferRangePatchData, begin, end); + ExecuteChunk(ref jobData, bufferRangePatchData, begin, end, chunks, entityIndices); } else { - ExecuteChunk(ref jobData, bufferRangePatchData, 0, jobData.Iterator.m_Length); + ExecuteChunk(ref jobData, bufferRangePatchData, 0, chunkCount, chunks, entityIndices); } } - static unsafe void ExecuteChunk(ref JobStruct_Process_DDD jobData, IntPtr bufferRangePatchData, int begin, int end) + static unsafe void ExecuteChunk(ref JobStruct_Process_DDD jobData, IntPtr bufferRangePatchData, int begin, int end, ArchetypeChunk* chunks, int* entityIndices) { - ref ComponentChunkIterator chunkIterator = ref jobData.Iterator.Iterator; - + var typeLookupCache0 = 0; + var typeLookupCache1 = 0; + var typeLookupCache2 = 0; + for (var blockIndex = begin; blockIndex != end; ++blockIndex) - { - jobData.Iterator.Iterator.MoveToChunkWithoutFiltering(blockIndex); - - var processBlock = jobData.Iterator.Iterator.MatchesFilter(); - - if (!processBlock) - continue; - - int beginIndex, endIndex; - chunkIterator.GetCurrentChunkRange(out beginIndex, out endIndex); + { + var chunk = chunks[blockIndex]; + int beginIndex = entityIndices[blockIndex]; + var count = chunk.Count; #if ENABLE_UNITY_COLLECTIONS_CHECKS - JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, endIndex - beginIndex); - #endif - - var count = chunkIterator.GetCurrentChunkCount(); - - var ptr0 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly0 == 0, jobData.Iterator.IndexInGroup0)); - var ptr1 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly1 == 0, jobData.Iterator.IndexInGroup1)); - var ptr2 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly2 == 0, jobData.Iterator.IndexInGroup2)); + JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, beginIndex + count); + #endif + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex0, ref typeLookupCache0); + var ptr0 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly0 == 0, typeLookupCache0, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex1, ref typeLookupCache1); + var ptr1 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly1 == 0, typeLookupCache1, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex2, ref typeLookupCache2); + var ptr2 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly2 == 0, typeLookupCache2, jobData.Iterator.GlobalSystemVersion)); + - for (var i = 0; i != count; i++) { jobData.Data.Execute(ref UnsafeUtilityEx.ArrayElementAsRef(ptr0, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr1, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr2, i)); @@ -773,9 +827,14 @@ internal static unsafe JobHandle ScheduleInternal_EDDD(ref T jobData, Compone var isParallelFor = innerloopBatchCount != -1; Initialize(system, componentGroup, typeof(T), typeof(JobStruct_Process_EDDD<,,,>), isParallelFor, ref JobStruct_ProcessInfer_EDDD.Cache, out fullData.Iterator); - return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, ref JobStruct_ProcessInfer_EDDD.Cache, dependsOn, mode); - } + + var unfilteredChunkCount = fullData.Iterator.m_Length; + var iterator = JobStruct_ProcessInfer_EDDD.Cache.ComponentGroup.GetComponentChunkIterator(); + var prefilterHandle = ComponentChunkIterator.PreparePrefilteredChunkLists(unfilteredChunkCount, iterator.m_MatchingArchetypeList, iterator.m_Filter, dependsOn, mode, out fullData.PrefilterData, out var deferredCountData); + + return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.PrefilterData, fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, iterator.RequiresFilter(), ref JobStruct_ProcessInfer_EDDD.Cache, deferredCountData, prefilterHandle, mode); + } [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public interface IBaseJobProcessComponentData_EDDD : IBaseJobProcessComponentData { } @@ -787,6 +846,10 @@ private struct JobStruct_ProcessInfer_EDDD where T : struct public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; } [StructLayout(LayoutKind.Sequential)] @@ -798,6 +861,10 @@ internal struct JobStruct_Process_EDDD { public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; [Preserve] public static IntPtr Initialize(JobType jobType) @@ -809,45 +876,45 @@ public static IntPtr Initialize(JobType jobType) public static unsafe void Execute(ref JobStruct_Process_EDDD jobData, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex) { + var chunks = (ArchetypeChunk*)NativeArrayUnsafeUtility.GetUnsafePtr(jobData.PrefilterData); + var entityIndices = (int*) (chunks + jobData.Iterator.m_Length); + var chunkCount = *(entityIndices + jobData.Iterator.m_Length); + if (jobData.Iterator.m_IsParallelFor) { int begin, end; while (JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out begin, out end)) - ExecuteChunk(ref jobData, bufferRangePatchData, begin, end); + ExecuteChunk(ref jobData, bufferRangePatchData, begin, end, chunks, entityIndices); } else { - ExecuteChunk(ref jobData, bufferRangePatchData, 0, jobData.Iterator.m_Length); + ExecuteChunk(ref jobData, bufferRangePatchData, 0, chunkCount, chunks, entityIndices); } } - static unsafe void ExecuteChunk(ref JobStruct_Process_EDDD jobData, IntPtr bufferRangePatchData, int begin, int end) + static unsafe void ExecuteChunk(ref JobStruct_Process_EDDD jobData, IntPtr bufferRangePatchData, int begin, int end, ArchetypeChunk* chunks, int* entityIndices) { - ref ComponentChunkIterator chunkIterator = ref jobData.Iterator.Iterator; - + var typeLookupCache0 = 0; + var typeLookupCache1 = 0; + var typeLookupCache2 = 0; + for (var blockIndex = begin; blockIndex != end; ++blockIndex) - { - jobData.Iterator.Iterator.MoveToChunkWithoutFiltering(blockIndex); - - var processBlock = jobData.Iterator.Iterator.MatchesFilter(); - - if (!processBlock) - continue; - - int beginIndex, endIndex; - chunkIterator.GetCurrentChunkRange(out beginIndex, out endIndex); + { + var chunk = chunks[blockIndex]; + int beginIndex = entityIndices[blockIndex]; + var count = chunk.Count; #if ENABLE_UNITY_COLLECTIONS_CHECKS - JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, endIndex - beginIndex); - #endif - - var count = chunkIterator.GetCurrentChunkCount(); - - var ptrE = (Entity*)UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(false, 0)); - var ptr0 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly0 == 0, jobData.Iterator.IndexInGroup0)); - var ptr1 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly1 == 0, jobData.Iterator.IndexInGroup1)); - var ptr2 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly2 == 0, jobData.Iterator.IndexInGroup2)); + JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, beginIndex + count); + #endif + var ptrE = (Entity*)UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, false, 0, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex0, ref typeLookupCache0); + var ptr0 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly0 == 0, typeLookupCache0, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex1, ref typeLookupCache1); + var ptr1 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly1 == 0, typeLookupCache1, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex2, ref typeLookupCache2); + var ptr2 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly2 == 0, typeLookupCache2, jobData.Iterator.GlobalSystemVersion)); + - for (var i = 0; i != count; i++) { jobData.Data.Execute(ptrE[i], i + beginIndex, ref UnsafeUtilityEx.ArrayElementAsRef(ptr0, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr1, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr2, i)); @@ -864,9 +931,14 @@ internal static unsafe JobHandle ScheduleInternal_DDDD(ref T jobData, Compone var isParallelFor = innerloopBatchCount != -1; Initialize(system, componentGroup, typeof(T), typeof(JobStruct_Process_DDDD<,,,,>), isParallelFor, ref JobStruct_ProcessInfer_DDDD.Cache, out fullData.Iterator); - return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, ref JobStruct_ProcessInfer_DDDD.Cache, dependsOn, mode); - } + + var unfilteredChunkCount = fullData.Iterator.m_Length; + var iterator = JobStruct_ProcessInfer_DDDD.Cache.ComponentGroup.GetComponentChunkIterator(); + var prefilterHandle = ComponentChunkIterator.PreparePrefilteredChunkLists(unfilteredChunkCount, iterator.m_MatchingArchetypeList, iterator.m_Filter, dependsOn, mode, out fullData.PrefilterData, out var deferredCountData); + + return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.PrefilterData, fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, iterator.RequiresFilter(), ref JobStruct_ProcessInfer_DDDD.Cache, deferredCountData, prefilterHandle, mode); + } [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public interface IBaseJobProcessComponentData_DDDD : IBaseJobProcessComponentData { } @@ -878,6 +950,10 @@ private struct JobStruct_ProcessInfer_DDDD where T : struct public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; } [StructLayout(LayoutKind.Sequential)] @@ -890,6 +966,10 @@ internal struct JobStruct_Process_DDDD { public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; [Preserve] public static IntPtr Initialize(JobType jobType) @@ -901,45 +981,47 @@ public static IntPtr Initialize(JobType jobType) public static unsafe void Execute(ref JobStruct_Process_DDDD jobData, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex) { + var chunks = (ArchetypeChunk*)NativeArrayUnsafeUtility.GetUnsafePtr(jobData.PrefilterData); + var entityIndices = (int*) (chunks + jobData.Iterator.m_Length); + var chunkCount = *(entityIndices + jobData.Iterator.m_Length); + if (jobData.Iterator.m_IsParallelFor) { int begin, end; while (JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out begin, out end)) - ExecuteChunk(ref jobData, bufferRangePatchData, begin, end); + ExecuteChunk(ref jobData, bufferRangePatchData, begin, end, chunks, entityIndices); } else { - ExecuteChunk(ref jobData, bufferRangePatchData, 0, jobData.Iterator.m_Length); + ExecuteChunk(ref jobData, bufferRangePatchData, 0, chunkCount, chunks, entityIndices); } } - static unsafe void ExecuteChunk(ref JobStruct_Process_DDDD jobData, IntPtr bufferRangePatchData, int begin, int end) + static unsafe void ExecuteChunk(ref JobStruct_Process_DDDD jobData, IntPtr bufferRangePatchData, int begin, int end, ArchetypeChunk* chunks, int* entityIndices) { - ref ComponentChunkIterator chunkIterator = ref jobData.Iterator.Iterator; - + var typeLookupCache0 = 0; + var typeLookupCache1 = 0; + var typeLookupCache2 = 0; + var typeLookupCache3 = 0; + for (var blockIndex = begin; blockIndex != end; ++blockIndex) - { - jobData.Iterator.Iterator.MoveToChunkWithoutFiltering(blockIndex); - - var processBlock = jobData.Iterator.Iterator.MatchesFilter(); - - if (!processBlock) - continue; - - int beginIndex, endIndex; - chunkIterator.GetCurrentChunkRange(out beginIndex, out endIndex); + { + var chunk = chunks[blockIndex]; + int beginIndex = entityIndices[blockIndex]; + var count = chunk.Count; #if ENABLE_UNITY_COLLECTIONS_CHECKS - JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, endIndex - beginIndex); - #endif - - var count = chunkIterator.GetCurrentChunkCount(); - - var ptr0 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly0 == 0, jobData.Iterator.IndexInGroup0)); - var ptr1 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly1 == 0, jobData.Iterator.IndexInGroup1)); - var ptr2 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly2 == 0, jobData.Iterator.IndexInGroup2)); - var ptr3 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly3 == 0, jobData.Iterator.IndexInGroup3)); + JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, beginIndex + count); + #endif + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex0, ref typeLookupCache0); + var ptr0 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly0 == 0, typeLookupCache0, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex1, ref typeLookupCache1); + var ptr1 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly1 == 0, typeLookupCache1, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex2, ref typeLookupCache2); + var ptr2 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly2 == 0, typeLookupCache2, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex3, ref typeLookupCache3); + var ptr3 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly3 == 0, typeLookupCache3, jobData.Iterator.GlobalSystemVersion)); + - for (var i = 0; i != count; i++) { jobData.Data.Execute(ref UnsafeUtilityEx.ArrayElementAsRef(ptr0, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr1, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr2, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr3, i)); @@ -956,9 +1038,14 @@ internal static unsafe JobHandle ScheduleInternal_EDDDD(ref T jobData, Compon var isParallelFor = innerloopBatchCount != -1; Initialize(system, componentGroup, typeof(T), typeof(JobStruct_Process_EDDDD<,,,,>), isParallelFor, ref JobStruct_ProcessInfer_EDDDD.Cache, out fullData.Iterator); - return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, ref JobStruct_ProcessInfer_EDDDD.Cache, dependsOn, mode); - } + + var unfilteredChunkCount = fullData.Iterator.m_Length; + var iterator = JobStruct_ProcessInfer_EDDDD.Cache.ComponentGroup.GetComponentChunkIterator(); + var prefilterHandle = ComponentChunkIterator.PreparePrefilteredChunkLists(unfilteredChunkCount, iterator.m_MatchingArchetypeList, iterator.m_Filter, dependsOn, mode, out fullData.PrefilterData, out var deferredCountData); + + return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.PrefilterData, fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, iterator.RequiresFilter(), ref JobStruct_ProcessInfer_EDDDD.Cache, deferredCountData, prefilterHandle, mode); + } [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public interface IBaseJobProcessComponentData_EDDDD : IBaseJobProcessComponentData { } @@ -970,6 +1057,10 @@ private struct JobStruct_ProcessInfer_EDDDD where T : struct public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; } [StructLayout(LayoutKind.Sequential)] @@ -982,6 +1073,10 @@ internal struct JobStruct_Process_EDDDD { public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; [Preserve] public static IntPtr Initialize(JobType jobType) @@ -993,46 +1088,48 @@ public static IntPtr Initialize(JobType jobType) public static unsafe void Execute(ref JobStruct_Process_EDDDD jobData, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex) { + var chunks = (ArchetypeChunk*)NativeArrayUnsafeUtility.GetUnsafePtr(jobData.PrefilterData); + var entityIndices = (int*) (chunks + jobData.Iterator.m_Length); + var chunkCount = *(entityIndices + jobData.Iterator.m_Length); + if (jobData.Iterator.m_IsParallelFor) { int begin, end; while (JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out begin, out end)) - ExecuteChunk(ref jobData, bufferRangePatchData, begin, end); + ExecuteChunk(ref jobData, bufferRangePatchData, begin, end, chunks, entityIndices); } else { - ExecuteChunk(ref jobData, bufferRangePatchData, 0, jobData.Iterator.m_Length); + ExecuteChunk(ref jobData, bufferRangePatchData, 0, chunkCount, chunks, entityIndices); } } - static unsafe void ExecuteChunk(ref JobStruct_Process_EDDDD jobData, IntPtr bufferRangePatchData, int begin, int end) + static unsafe void ExecuteChunk(ref JobStruct_Process_EDDDD jobData, IntPtr bufferRangePatchData, int begin, int end, ArchetypeChunk* chunks, int* entityIndices) { - ref ComponentChunkIterator chunkIterator = ref jobData.Iterator.Iterator; - + var typeLookupCache0 = 0; + var typeLookupCache1 = 0; + var typeLookupCache2 = 0; + var typeLookupCache3 = 0; + for (var blockIndex = begin; blockIndex != end; ++blockIndex) - { - jobData.Iterator.Iterator.MoveToChunkWithoutFiltering(blockIndex); - - var processBlock = jobData.Iterator.Iterator.MatchesFilter(); - - if (!processBlock) - continue; - - int beginIndex, endIndex; - chunkIterator.GetCurrentChunkRange(out beginIndex, out endIndex); + { + var chunk = chunks[blockIndex]; + int beginIndex = entityIndices[blockIndex]; + var count = chunk.Count; #if ENABLE_UNITY_COLLECTIONS_CHECKS - JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, endIndex - beginIndex); - #endif - - var count = chunkIterator.GetCurrentChunkCount(); - - var ptrE = (Entity*)UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(false, 0)); - var ptr0 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly0 == 0, jobData.Iterator.IndexInGroup0)); - var ptr1 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly1 == 0, jobData.Iterator.IndexInGroup1)); - var ptr2 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly2 == 0, jobData.Iterator.IndexInGroup2)); - var ptr3 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly3 == 0, jobData.Iterator.IndexInGroup3)); + JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, beginIndex + count); + #endif + var ptrE = (Entity*)UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, false, 0, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex0, ref typeLookupCache0); + var ptr0 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly0 == 0, typeLookupCache0, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex1, ref typeLookupCache1); + var ptr1 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly1 == 0, typeLookupCache1, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex2, ref typeLookupCache2); + var ptr2 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly2 == 0, typeLookupCache2, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex3, ref typeLookupCache3); + var ptr3 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly3 == 0, typeLookupCache3, jobData.Iterator.GlobalSystemVersion)); + - for (var i = 0; i != count; i++) { jobData.Data.Execute(ptrE[i], i + beginIndex, ref UnsafeUtilityEx.ArrayElementAsRef(ptr0, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr1, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr2, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr3, i)); @@ -1049,9 +1146,14 @@ internal static unsafe JobHandle ScheduleInternal_DDDDD(ref T jobData, Compon var isParallelFor = innerloopBatchCount != -1; Initialize(system, componentGroup, typeof(T), typeof(JobStruct_Process_DDDDD<,,,,,>), isParallelFor, ref JobStruct_ProcessInfer_DDDDD.Cache, out fullData.Iterator); - return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, ref JobStruct_ProcessInfer_DDDDD.Cache, dependsOn, mode); - } + + var unfilteredChunkCount = fullData.Iterator.m_Length; + var iterator = JobStruct_ProcessInfer_DDDDD.Cache.ComponentGroup.GetComponentChunkIterator(); + var prefilterHandle = ComponentChunkIterator.PreparePrefilteredChunkLists(unfilteredChunkCount, iterator.m_MatchingArchetypeList, iterator.m_Filter, dependsOn, mode, out fullData.PrefilterData, out var deferredCountData); + + return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.PrefilterData, fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, iterator.RequiresFilter(), ref JobStruct_ProcessInfer_DDDDD.Cache, deferredCountData, prefilterHandle, mode); + } [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public interface IBaseJobProcessComponentData_DDDDD : IBaseJobProcessComponentData { } @@ -1063,6 +1165,10 @@ private struct JobStruct_ProcessInfer_DDDDD where T : struct public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; } [StructLayout(LayoutKind.Sequential)] @@ -1076,6 +1182,10 @@ internal struct JobStruct_Process_DDDDD { public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; [Preserve] public static IntPtr Initialize(JobType jobType) @@ -1087,46 +1197,50 @@ public static IntPtr Initialize(JobType jobType) public static unsafe void Execute(ref JobStruct_Process_DDDDD jobData, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex) { + var chunks = (ArchetypeChunk*)NativeArrayUnsafeUtility.GetUnsafePtr(jobData.PrefilterData); + var entityIndices = (int*) (chunks + jobData.Iterator.m_Length); + var chunkCount = *(entityIndices + jobData.Iterator.m_Length); + if (jobData.Iterator.m_IsParallelFor) { int begin, end; while (JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out begin, out end)) - ExecuteChunk(ref jobData, bufferRangePatchData, begin, end); + ExecuteChunk(ref jobData, bufferRangePatchData, begin, end, chunks, entityIndices); } else { - ExecuteChunk(ref jobData, bufferRangePatchData, 0, jobData.Iterator.m_Length); + ExecuteChunk(ref jobData, bufferRangePatchData, 0, chunkCount, chunks, entityIndices); } } - static unsafe void ExecuteChunk(ref JobStruct_Process_DDDDD jobData, IntPtr bufferRangePatchData, int begin, int end) + static unsafe void ExecuteChunk(ref JobStruct_Process_DDDDD jobData, IntPtr bufferRangePatchData, int begin, int end, ArchetypeChunk* chunks, int* entityIndices) { - ref ComponentChunkIterator chunkIterator = ref jobData.Iterator.Iterator; - + var typeLookupCache0 = 0; + var typeLookupCache1 = 0; + var typeLookupCache2 = 0; + var typeLookupCache3 = 0; + var typeLookupCache4 = 0; + for (var blockIndex = begin; blockIndex != end; ++blockIndex) - { - jobData.Iterator.Iterator.MoveToChunkWithoutFiltering(blockIndex); - - var processBlock = jobData.Iterator.Iterator.MatchesFilter(); - - if (!processBlock) - continue; - - int beginIndex, endIndex; - chunkIterator.GetCurrentChunkRange(out beginIndex, out endIndex); + { + var chunk = chunks[blockIndex]; + int beginIndex = entityIndices[blockIndex]; + var count = chunk.Count; #if ENABLE_UNITY_COLLECTIONS_CHECKS - JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, endIndex - beginIndex); - #endif - - var count = chunkIterator.GetCurrentChunkCount(); - - var ptr0 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly0 == 0, jobData.Iterator.IndexInGroup0)); - var ptr1 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly1 == 0, jobData.Iterator.IndexInGroup1)); - var ptr2 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly2 == 0, jobData.Iterator.IndexInGroup2)); - var ptr3 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly3 == 0, jobData.Iterator.IndexInGroup3)); - var ptr4 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly4 == 0, jobData.Iterator.IndexInGroup4)); + JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, beginIndex + count); + #endif + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex0, ref typeLookupCache0); + var ptr0 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly0 == 0, typeLookupCache0, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex1, ref typeLookupCache1); + var ptr1 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly1 == 0, typeLookupCache1, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex2, ref typeLookupCache2); + var ptr2 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly2 == 0, typeLookupCache2, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex3, ref typeLookupCache3); + var ptr3 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly3 == 0, typeLookupCache3, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex4, ref typeLookupCache4); + var ptr4 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly4 == 0, typeLookupCache4, jobData.Iterator.GlobalSystemVersion)); + - for (var i = 0; i != count; i++) { jobData.Data.Execute(ref UnsafeUtilityEx.ArrayElementAsRef(ptr0, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr1, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr2, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr3, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr4, i)); @@ -1143,9 +1257,14 @@ internal static unsafe JobHandle ScheduleInternal_EDDDDD(ref T jobData, Compo var isParallelFor = innerloopBatchCount != -1; Initialize(system, componentGroup, typeof(T), typeof(JobStruct_Process_EDDDDD<,,,,,>), isParallelFor, ref JobStruct_ProcessInfer_EDDDDD.Cache, out fullData.Iterator); - return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, ref JobStruct_ProcessInfer_EDDDDD.Cache, dependsOn, mode); - } + + var unfilteredChunkCount = fullData.Iterator.m_Length; + var iterator = JobStruct_ProcessInfer_EDDDDD.Cache.ComponentGroup.GetComponentChunkIterator(); + var prefilterHandle = ComponentChunkIterator.PreparePrefilteredChunkLists(unfilteredChunkCount, iterator.m_MatchingArchetypeList, iterator.m_Filter, dependsOn, mode, out fullData.PrefilterData, out var deferredCountData); + + return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.PrefilterData, fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, iterator.RequiresFilter(), ref JobStruct_ProcessInfer_EDDDDD.Cache, deferredCountData, prefilterHandle, mode); + } [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public interface IBaseJobProcessComponentData_EDDDDD : IBaseJobProcessComponentData { } @@ -1157,6 +1276,10 @@ private struct JobStruct_ProcessInfer_EDDDDD where T : struct public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; } [StructLayout(LayoutKind.Sequential)] @@ -1170,6 +1293,10 @@ internal struct JobStruct_Process_EDDDDD { public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; [Preserve] public static IntPtr Initialize(JobType jobType) @@ -1181,47 +1308,51 @@ public static IntPtr Initialize(JobType jobType) public static unsafe void Execute(ref JobStruct_Process_EDDDDD jobData, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex) { + var chunks = (ArchetypeChunk*)NativeArrayUnsafeUtility.GetUnsafePtr(jobData.PrefilterData); + var entityIndices = (int*) (chunks + jobData.Iterator.m_Length); + var chunkCount = *(entityIndices + jobData.Iterator.m_Length); + if (jobData.Iterator.m_IsParallelFor) { int begin, end; while (JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out begin, out end)) - ExecuteChunk(ref jobData, bufferRangePatchData, begin, end); + ExecuteChunk(ref jobData, bufferRangePatchData, begin, end, chunks, entityIndices); } else { - ExecuteChunk(ref jobData, bufferRangePatchData, 0, jobData.Iterator.m_Length); + ExecuteChunk(ref jobData, bufferRangePatchData, 0, chunkCount, chunks, entityIndices); } } - static unsafe void ExecuteChunk(ref JobStruct_Process_EDDDDD jobData, IntPtr bufferRangePatchData, int begin, int end) + static unsafe void ExecuteChunk(ref JobStruct_Process_EDDDDD jobData, IntPtr bufferRangePatchData, int begin, int end, ArchetypeChunk* chunks, int* entityIndices) { - ref ComponentChunkIterator chunkIterator = ref jobData.Iterator.Iterator; - + var typeLookupCache0 = 0; + var typeLookupCache1 = 0; + var typeLookupCache2 = 0; + var typeLookupCache3 = 0; + var typeLookupCache4 = 0; + for (var blockIndex = begin; blockIndex != end; ++blockIndex) - { - jobData.Iterator.Iterator.MoveToChunkWithoutFiltering(blockIndex); - - var processBlock = jobData.Iterator.Iterator.MatchesFilter(); - - if (!processBlock) - continue; - - int beginIndex, endIndex; - chunkIterator.GetCurrentChunkRange(out beginIndex, out endIndex); + { + var chunk = chunks[blockIndex]; + int beginIndex = entityIndices[blockIndex]; + var count = chunk.Count; #if ENABLE_UNITY_COLLECTIONS_CHECKS - JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, endIndex - beginIndex); - #endif - - var count = chunkIterator.GetCurrentChunkCount(); - - var ptrE = (Entity*)UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(false, 0)); - var ptr0 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly0 == 0, jobData.Iterator.IndexInGroup0)); - var ptr1 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly1 == 0, jobData.Iterator.IndexInGroup1)); - var ptr2 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly2 == 0, jobData.Iterator.IndexInGroup2)); - var ptr3 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly3 == 0, jobData.Iterator.IndexInGroup3)); - var ptr4 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly4 == 0, jobData.Iterator.IndexInGroup4)); + JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, beginIndex + count); + #endif + var ptrE = (Entity*)UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, false, 0, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex0, ref typeLookupCache0); + var ptr0 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly0 == 0, typeLookupCache0, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex1, ref typeLookupCache1); + var ptr1 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly1 == 0, typeLookupCache1, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex2, ref typeLookupCache2); + var ptr2 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly2 == 0, typeLookupCache2, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex3, ref typeLookupCache3); + var ptr3 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly3 == 0, typeLookupCache3, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex4, ref typeLookupCache4); + var ptr4 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly4 == 0, typeLookupCache4, jobData.Iterator.GlobalSystemVersion)); + - for (var i = 0; i != count; i++) { jobData.Data.Execute(ptrE[i], i + beginIndex, ref UnsafeUtilityEx.ArrayElementAsRef(ptr0, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr1, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr2, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr3, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr4, i)); @@ -1238,9 +1369,14 @@ internal static unsafe JobHandle ScheduleInternal_DDDDDD(ref T jobData, Compo var isParallelFor = innerloopBatchCount != -1; Initialize(system, componentGroup, typeof(T), typeof(JobStruct_Process_DDDDDD<,,,,,,>), isParallelFor, ref JobStruct_ProcessInfer_DDDDDD.Cache, out fullData.Iterator); - return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, ref JobStruct_ProcessInfer_DDDDDD.Cache, dependsOn, mode); - } + + var unfilteredChunkCount = fullData.Iterator.m_Length; + var iterator = JobStruct_ProcessInfer_DDDDDD.Cache.ComponentGroup.GetComponentChunkIterator(); + var prefilterHandle = ComponentChunkIterator.PreparePrefilteredChunkLists(unfilteredChunkCount, iterator.m_MatchingArchetypeList, iterator.m_Filter, dependsOn, mode, out fullData.PrefilterData, out var deferredCountData); + + return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.PrefilterData, fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, iterator.RequiresFilter(), ref JobStruct_ProcessInfer_DDDDDD.Cache, deferredCountData, prefilterHandle, mode); + } [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public interface IBaseJobProcessComponentData_DDDDDD : IBaseJobProcessComponentData { } @@ -1252,6 +1388,10 @@ private struct JobStruct_ProcessInfer_DDDDDD where T : struct public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; } [StructLayout(LayoutKind.Sequential)] @@ -1266,6 +1406,10 @@ internal struct JobStruct_Process_DDDDDD { public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; [Preserve] public static IntPtr Initialize(JobType jobType) @@ -1277,47 +1421,53 @@ public static IntPtr Initialize(JobType jobType) public static unsafe void Execute(ref JobStruct_Process_DDDDDD jobData, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex) { + var chunks = (ArchetypeChunk*)NativeArrayUnsafeUtility.GetUnsafePtr(jobData.PrefilterData); + var entityIndices = (int*) (chunks + jobData.Iterator.m_Length); + var chunkCount = *(entityIndices + jobData.Iterator.m_Length); + if (jobData.Iterator.m_IsParallelFor) { int begin, end; while (JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out begin, out end)) - ExecuteChunk(ref jobData, bufferRangePatchData, begin, end); + ExecuteChunk(ref jobData, bufferRangePatchData, begin, end, chunks, entityIndices); } else { - ExecuteChunk(ref jobData, bufferRangePatchData, 0, jobData.Iterator.m_Length); + ExecuteChunk(ref jobData, bufferRangePatchData, 0, chunkCount, chunks, entityIndices); } } - static unsafe void ExecuteChunk(ref JobStruct_Process_DDDDDD jobData, IntPtr bufferRangePatchData, int begin, int end) + static unsafe void ExecuteChunk(ref JobStruct_Process_DDDDDD jobData, IntPtr bufferRangePatchData, int begin, int end, ArchetypeChunk* chunks, int* entityIndices) { - ref ComponentChunkIterator chunkIterator = ref jobData.Iterator.Iterator; - + var typeLookupCache0 = 0; + var typeLookupCache1 = 0; + var typeLookupCache2 = 0; + var typeLookupCache3 = 0; + var typeLookupCache4 = 0; + var typeLookupCache5 = 0; + for (var blockIndex = begin; blockIndex != end; ++blockIndex) - { - jobData.Iterator.Iterator.MoveToChunkWithoutFiltering(blockIndex); - - var processBlock = jobData.Iterator.Iterator.MatchesFilter(); - - if (!processBlock) - continue; - - int beginIndex, endIndex; - chunkIterator.GetCurrentChunkRange(out beginIndex, out endIndex); + { + var chunk = chunks[blockIndex]; + int beginIndex = entityIndices[blockIndex]; + var count = chunk.Count; #if ENABLE_UNITY_COLLECTIONS_CHECKS - JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, endIndex - beginIndex); - #endif - - var count = chunkIterator.GetCurrentChunkCount(); - - var ptr0 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly0 == 0, jobData.Iterator.IndexInGroup0)); - var ptr1 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly1 == 0, jobData.Iterator.IndexInGroup1)); - var ptr2 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly2 == 0, jobData.Iterator.IndexInGroup2)); - var ptr3 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly3 == 0, jobData.Iterator.IndexInGroup3)); - var ptr4 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly4 == 0, jobData.Iterator.IndexInGroup4)); - var ptr5 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly5 == 0, jobData.Iterator.IndexInGroup5)); + JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, beginIndex + count); + #endif + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex0, ref typeLookupCache0); + var ptr0 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly0 == 0, typeLookupCache0, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex1, ref typeLookupCache1); + var ptr1 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly1 == 0, typeLookupCache1, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex2, ref typeLookupCache2); + var ptr2 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly2 == 0, typeLookupCache2, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex3, ref typeLookupCache3); + var ptr3 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly3 == 0, typeLookupCache3, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex4, ref typeLookupCache4); + var ptr4 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly4 == 0, typeLookupCache4, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex5, ref typeLookupCache5); + var ptr5 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly5 == 0, typeLookupCache5, jobData.Iterator.GlobalSystemVersion)); + - for (var i = 0; i != count; i++) { jobData.Data.Execute(ref UnsafeUtilityEx.ArrayElementAsRef(ptr0, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr1, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr2, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr3, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr4, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr5, i)); @@ -1334,9 +1484,14 @@ internal static unsafe JobHandle ScheduleInternal_EDDDDDD(ref T jobData, Comp var isParallelFor = innerloopBatchCount != -1; Initialize(system, componentGroup, typeof(T), typeof(JobStruct_Process_EDDDDDD<,,,,,,>), isParallelFor, ref JobStruct_ProcessInfer_EDDDDDD.Cache, out fullData.Iterator); - return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, ref JobStruct_ProcessInfer_EDDDDDD.Cache, dependsOn, mode); - } + + var unfilteredChunkCount = fullData.Iterator.m_Length; + var iterator = JobStruct_ProcessInfer_EDDDDDD.Cache.ComponentGroup.GetComponentChunkIterator(); + var prefilterHandle = ComponentChunkIterator.PreparePrefilteredChunkLists(unfilteredChunkCount, iterator.m_MatchingArchetypeList, iterator.m_Filter, dependsOn, mode, out fullData.PrefilterData, out var deferredCountData); + + return Schedule(UnsafeUtility.AddressOf(ref fullData), fullData.PrefilterData, fullData.Iterator.m_Length, innerloopBatchCount, isParallelFor, iterator.RequiresFilter(), ref JobStruct_ProcessInfer_EDDDDDD.Cache, deferredCountData, prefilterHandle, mode); + } [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public interface IBaseJobProcessComponentData_EDDDDDD : IBaseJobProcessComponentData { } @@ -1348,6 +1503,10 @@ private struct JobStruct_ProcessInfer_EDDDDDD where T : struct public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; } [StructLayout(LayoutKind.Sequential)] @@ -1362,6 +1521,10 @@ internal struct JobStruct_Process_EDDDDDD { public ProcessIterationData Iterator; public T Data; + + [DeallocateOnJobCompletion] + [NativeDisableContainerSafetyRestriction] + public NativeArray PrefilterData; [Preserve] public static IntPtr Initialize(JobType jobType) @@ -1373,48 +1536,54 @@ public static IntPtr Initialize(JobType jobType) public static unsafe void Execute(ref JobStruct_Process_EDDDDDD jobData, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex) { + var chunks = (ArchetypeChunk*)NativeArrayUnsafeUtility.GetUnsafePtr(jobData.PrefilterData); + var entityIndices = (int*) (chunks + jobData.Iterator.m_Length); + var chunkCount = *(entityIndices + jobData.Iterator.m_Length); + if (jobData.Iterator.m_IsParallelFor) { int begin, end; while (JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out begin, out end)) - ExecuteChunk(ref jobData, bufferRangePatchData, begin, end); + ExecuteChunk(ref jobData, bufferRangePatchData, begin, end, chunks, entityIndices); } else { - ExecuteChunk(ref jobData, bufferRangePatchData, 0, jobData.Iterator.m_Length); + ExecuteChunk(ref jobData, bufferRangePatchData, 0, chunkCount, chunks, entityIndices); } } - static unsafe void ExecuteChunk(ref JobStruct_Process_EDDDDDD jobData, IntPtr bufferRangePatchData, int begin, int end) + static unsafe void ExecuteChunk(ref JobStruct_Process_EDDDDDD jobData, IntPtr bufferRangePatchData, int begin, int end, ArchetypeChunk* chunks, int* entityIndices) { - ref ComponentChunkIterator chunkIterator = ref jobData.Iterator.Iterator; - + var typeLookupCache0 = 0; + var typeLookupCache1 = 0; + var typeLookupCache2 = 0; + var typeLookupCache3 = 0; + var typeLookupCache4 = 0; + var typeLookupCache5 = 0; + for (var blockIndex = begin; blockIndex != end; ++blockIndex) - { - jobData.Iterator.Iterator.MoveToChunkWithoutFiltering(blockIndex); - - var processBlock = jobData.Iterator.Iterator.MatchesFilter(); - - if (!processBlock) - continue; - - int beginIndex, endIndex; - chunkIterator.GetCurrentChunkRange(out beginIndex, out endIndex); + { + var chunk = chunks[blockIndex]; + int beginIndex = entityIndices[blockIndex]; + var count = chunk.Count; #if ENABLE_UNITY_COLLECTIONS_CHECKS - JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, endIndex - beginIndex); - #endif - - var count = chunkIterator.GetCurrentChunkCount(); - - var ptrE = (Entity*)UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(false, 0)); - var ptr0 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly0 == 0, jobData.Iterator.IndexInGroup0)); - var ptr1 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly1 == 0, jobData.Iterator.IndexInGroup1)); - var ptr2 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly2 == 0, jobData.Iterator.IndexInGroup2)); - var ptr3 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly3 == 0, jobData.Iterator.IndexInGroup3)); - var ptr4 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly4 == 0, jobData.Iterator.IndexInGroup4)); - var ptr5 = UnsafeUtilityEx.RestrictNoAlias(chunkIterator.GetCurrentChunkComponentDataPtr(jobData.Iterator.IsReadOnly5 == 0, jobData.Iterator.IndexInGroup5)); + JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), beginIndex, beginIndex + count); + #endif + var ptrE = (Entity*)UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, false, 0, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex0, ref typeLookupCache0); + var ptr0 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly0 == 0, typeLookupCache0, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex1, ref typeLookupCache1); + var ptr1 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly1 == 0, typeLookupCache1, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex2, ref typeLookupCache2); + var ptr2 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly2 == 0, typeLookupCache2, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex3, ref typeLookupCache3); + var ptr3 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly3 == 0, typeLookupCache3, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex4, ref typeLookupCache4); + var ptr4 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly4 == 0, typeLookupCache4, jobData.Iterator.GlobalSystemVersion)); + ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, jobData.Iterator.TypeIndex5, ref typeLookupCache5); + var ptr5 = UnsafeUtilityEx.RestrictNoAlias(ComponentChunkIterator.GetChunkComponentDataPtr(chunk.m_Chunk, jobData.Iterator.IsReadOnly5 == 0, typeLookupCache5, jobData.Iterator.GlobalSystemVersion)); + - for (var i = 0; i != count; i++) { jobData.Data.Execute(ptrE[i], i + beginIndex, ref UnsafeUtilityEx.ArrayElementAsRef(ptr0, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr1, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr2, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr3, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr4, i), ref UnsafeUtilityEx.ArrayElementAsRef(ptr5, i)); diff --git a/package/Unity.Entities/Injection/DefaultTinyWorldInitialization.cs b/package/Unity.Entities/Injection/DefaultTinyWorldInitialization.cs index 0f6636d12..288434ea4 100755 --- a/package/Unity.Entities/Injection/DefaultTinyWorldInitialization.cs +++ b/package/Unity.Entities/Injection/DefaultTinyWorldInitialization.cs @@ -5,13 +5,37 @@ namespace Unity.Entities { + public delegate void ConfigInit(World world); + public static class DefaultTinyWorldInitialization { + /// + /// Initialize the DOTS-RT World with all the boilerplate that needs to be done. + /// ComponentSystems will be created and sorted into the high level ComponentSystemGroups. + /// + /// + /// + /// + /// public static World Initialize(string worldName) + { + World world = InitializeWorld(worldName); + InitializeSystems(world); + SortSystems(world); + return world; + } + + public static World InitializeWorld(string worldName) { var world = new World(worldName); World.Active = world; + // Entity manager must be first so that other things can find it. + world.AddManager(new EntityManager()); + return world; + } + public static void InitializeSystems(World world) + { var allSystemTypes = TypeManager.GetSystems(); var allSystemNames = TypeManager.SystemNames; @@ -20,9 +44,6 @@ public static World Initialize(string worldName) throw new InvalidOperationException("DefaultTinyWorldInitialization: No Systems found."); } - // Entity manager must be first so that other things can find it. - world.AddManager(new EntityManager()); - // Create top level presentation system and simulation systems. InitializationSystemGroup initializationSystemGroup = new InitializationSystemGroup(); world.AddManager(initializationSystemGroup); @@ -88,12 +109,9 @@ public static World Initialize(string worldName) groupSystem.AddSystemToUpdateList(system); } } - - SortSystems(world); - return world; } - static public void SortSystems(World world) + public static void SortSystems(World world) { var initializationSystemGroup = world.GetExistingManager(); var simulationSystemGroup = world.GetExistingManager(); diff --git a/package/Unity.Entities/Iterators/ChunkDataGatherJobs.cs b/package/Unity.Entities/Iterators/ChunkDataGatherJobs.cs index 2f9e7dc71..0230b9887 100755 --- a/package/Unity.Entities/Iterators/ChunkDataGatherJobs.cs +++ b/package/Unity.Entities/Iterators/ChunkDataGatherJobs.cs @@ -24,6 +24,46 @@ public void Execute(int index) UnsafeUtility.MemCpy(dstChunksPtr + offset, archetype->Chunks.p, chunkCount * sizeof(Chunk*)); } } + + [BurstCompile] + internal unsafe struct GatherChunksAndOffsetsJob : IJob + { + public MatchingArchetypeList Archetypes; + + [NativeDisableUnsafePtrRestriction] + public void* PrefilterData; + public int UnfilteredChunkCount; + + public void Execute() + { + var chunks = (ArchetypeChunk*) PrefilterData; + var entityIndices = (int*) (chunks + UnfilteredChunkCount); + + var chunkCounter = 0; + var entityOffsetPrefixSum = 0; + + for (var m = Archetypes.Count - 1; m >= 0; --m) + { + var match = Archetypes.p[m]; + if (match->Archetype->EntityCount <= 0) + continue; + + var archetype = match->Archetype; + int chunkCount = archetype->Chunks.Count; + var chunkEntityCountArray = archetype->Chunks.GetChunkEntityCountArray(); + + for (int chunkIndex = 0; chunkIndex < chunkCount; ++chunkIndex) + { + chunks[chunkCounter] = new ArchetypeChunk {m_Chunk = archetype->Chunks.p[chunkIndex]}; + entityIndices[chunkCounter++] = entityOffsetPrefixSum; + entityOffsetPrefixSum += chunkEntityCountArray[chunkIndex]; + } + } + + var outChunkCounter = entityIndices + UnfilteredChunkCount; + *outChunkCounter = chunkCounter; + } + } [BurstCompile] unsafe struct GatherChunksWithFiltering : IJobParallelFor @@ -109,6 +149,128 @@ public void Execute(int index) FilteredCounts[index] = filteredCount; } } + + [BurstCompile] + internal unsafe struct GatherChunksAndOffsetsWithFilteringJob : IJob + { + public MatchingArchetypeList Archetypes; + public ComponentGroupFilter Filter; + + [NativeDisableUnsafePtrRestriction] + public void* PrefilterData; + public int UnfilteredChunkCount; + + public void Execute() + { + var chunks = (ArchetypeChunk*) PrefilterData; + var entityIndices = (int*) (chunks + UnfilteredChunkCount); + + var filter = Filter; + var filteredChunkCount = 0; + var filteredEntityOffset = 0; + + for (var m = Archetypes.Count - 1; m >= 0; --m) + { + var match = Archetypes.p[m]; + if (match->Archetype->EntityCount <= 0) + continue; + + var archetype = match->Archetype; + int chunkCount = archetype->Chunks.Count; + var chunkEntityCountArray = archetype->Chunks.GetChunkEntityCountArray(); + + if (filter.Type == FilterType.SharedComponent) + { + var indexInComponentGroup0 = filter.Shared.IndexInComponentGroup[0]; + var sharedComponentIndex0 = filter.Shared.SharedComponentIndex[0]; + var componentIndexInChunk0 = + match->IndexInArchetype[indexInComponentGroup0] - archetype->FirstSharedComponent; + var sharedComponents0 = + archetype->Chunks.GetSharedComponentValueArrayForType(componentIndexInChunk0); + + if (filter.Shared.Count == 1) + { + for (var i = 0; i < chunkCount; ++i) + { + if (sharedComponents0[i] == sharedComponentIndex0) + { + chunks[filteredChunkCount] = new ArchetypeChunk + {m_Chunk = archetype->Chunks.p[i]}; + entityIndices[filteredChunkCount++] = filteredEntityOffset; + filteredEntityOffset += chunkEntityCountArray[i]; + } + } + } + else + { + var indexInComponentGroup1 = filter.Shared.IndexInComponentGroup[1]; + var sharedComponentIndex1 = filter.Shared.SharedComponentIndex[1]; + var componentIndexInChunk1 = + match->IndexInArchetype[indexInComponentGroup1] - archetype->FirstSharedComponent; + var sharedComponents1 = + archetype->Chunks.GetSharedComponentValueArrayForType(componentIndexInChunk1); + + for (var i = 0; i < chunkCount; ++i) + { + if (sharedComponents0[i] == sharedComponentIndex0 && + sharedComponents1[i] == sharedComponentIndex1) + { + chunks[filteredChunkCount] = new ArchetypeChunk + {m_Chunk = archetype->Chunks.p[i]}; + entityIndices[filteredChunkCount++] = filteredEntityOffset; + filteredEntityOffset += chunkEntityCountArray[i]; + } + } + } + } + else + { + var indexInComponentGroup0 = filter.Changed.IndexInComponentGroup[0]; + var componentIndexInChunk0 = match->IndexInArchetype[indexInComponentGroup0]; + var changeVersions0 = archetype->Chunks.GetChangeVersionArrayForType(componentIndexInChunk0); + + var requiredVersion = filter.RequiredChangeVersion; + if (filter.Changed.Count == 1) + { + for (var i = 0; i < chunkCount; ++i) + { + if (ChangeVersionUtility.DidChange(changeVersions0[i], requiredVersion)) + { + chunks[filteredChunkCount] = new ArchetypeChunk + {m_Chunk = archetype->Chunks.p[i]}; + entityIndices[filteredChunkCount++] = filteredEntityOffset; + filteredEntityOffset += chunkEntityCountArray[i]; + } + } + } + else + { + var indexInComponentGroup1 = filter.Shared.IndexInComponentGroup[1]; + var componentIndexInChunk1 = match->IndexInArchetype[indexInComponentGroup1]; + var changeVersions1 = + archetype->Chunks.GetChangeVersionArrayForType(componentIndexInChunk1); + + for (var i = 0; i < chunkCount; ++i) + { + if (ChangeVersionUtility.DidChange(changeVersions0[i], requiredVersion) || + ChangeVersionUtility.DidChange(changeVersions1[i], requiredVersion)) + { + chunks[filteredChunkCount] = new ArchetypeChunk + {m_Chunk = archetype->Chunks.p[i]}; + entityIndices[filteredChunkCount++] = filteredEntityOffset; + filteredEntityOffset += chunkEntityCountArray[i]; + } + } + } + } + } + + UnsafeUtility.MemMove(chunks + filteredChunkCount, chunks + UnfilteredChunkCount, filteredChunkCount * sizeof(int)); + + var chunkCounter = entityIndices + UnfilteredChunkCount; + *chunkCounter = filteredChunkCount; + } + } unsafe struct JoinChunksJob : IJobParallelFor { diff --git a/package/Unity.Entities/Iterators/ComponentChunkIterator.cs b/package/Unity.Entities/Iterators/ComponentChunkIterator.cs index 26bc33490..ac8b748a8 100755 --- a/package/Unity.Entities/Iterators/ComponentChunkIterator.cs +++ b/package/Unity.Entities/Iterators/ComponentChunkIterator.cs @@ -4,6 +4,7 @@ using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Jobs; +using Unity.Jobs.LowLevel.Unsafe; using Unity.Mathematics; namespace Unity.Entities @@ -71,7 +72,7 @@ internal unsafe struct ComponentChunkCache /// internal unsafe struct ComponentChunkIterator { - private readonly MatchingArchetypeList m_MatchingArchetypeList; + internal readonly MatchingArchetypeList m_MatchingArchetypeList; private int m_CurrentMatchingArchetypeIndex; private int m_CurrentMatchingArchetypeIndexNext => m_CurrentMatchingArchetypeIndex - 1; @@ -90,9 +91,9 @@ internal unsafe struct ComponentChunkIterator private int m_CurrentArchetypeIndex; private int m_CurrentChunkIndex; - private ComponentGroupFilter m_Filter; + internal ComponentGroupFilter m_Filter; - private readonly uint m_GlobalSystemVersion; + internal readonly uint m_GlobalSystemVersion; public int IndexInComponentGroup; @@ -590,16 +591,20 @@ public void GetCurrentChunkRange(out int beginIndex, out int endIndex) endIndex = beginIndex + (*m_CurrentChunk)->Count; } - public void* GetCurrentChunkComponentDataPtr(bool isWriting, int indexInComponentGroup) + internal static void* GetChunkComponentDataPtr(Chunk* chunk, bool isWriting, int indexInArchetype, uint systemVersion) { - var archetype = m_CurrentMatchingArchetype->Archetype; - - int indexInArchetype = m_CurrentMatchingArchetype->IndexInArchetype[indexInComponentGroup]; + var archetype = chunk->Archetype; if (isWriting) - (*m_CurrentChunk)->SetChangeVersion(indexInArchetype, m_GlobalSystemVersion); + chunk->SetChangeVersion(indexInArchetype, systemVersion); - return (*m_CurrentChunk)->Buffer + archetype->Offsets[indexInArchetype]; + return chunk->Buffer + archetype->Offsets[indexInArchetype]; + } + + public void* GetCurrentChunkComponentDataPtr(bool isWriting, int indexInComponentGroup) + { + int indexInArchetype = m_CurrentMatchingArchetype->IndexInArchetype[indexInComponentGroup]; + return GetChunkComponentDataPtr(*m_CurrentChunk, isWriting, indexInArchetype, m_GlobalSystemVersion); } public void UpdateChangeVersion() @@ -706,5 +711,54 @@ internal int GetIndexOfFirstEntityInCurrentChunk() return index; } + + internal static JobHandle PreparePrefilteredChunkLists(int unfilteredChunkCount, MatchingArchetypeList archetypes, ComponentGroupFilter filter, JobHandle dependsOn, ScheduleMode mode, out NativeArray prefilterDataArray, out void* deferredCountData) + { + // Allocate one buffer for all prefilter data and distribute it + // We keep the full buffer as a "dummy array" so we can deallocate it later with [DeallocateOnJobCompletion] + var sizeofChunkArray = sizeof(ArchetypeChunk) * unfilteredChunkCount; + var sizeofIndexArray = sizeof(int) * unfilteredChunkCount; + var prefilterDataSize = sizeofChunkArray + sizeofIndexArray + sizeof(int); + + prefilterDataArray = new NativeArray(prefilterDataSize, Allocator.TempJob); + var prefilterData = (byte*)prefilterDataArray.GetUnsafePtr(); + + JobHandle prefilterHandle = default(JobHandle); + + if (filter.RequiresMatchesFilter) + { + var prefilteringJob = new GatherChunksAndOffsetsWithFilteringJob + { + Archetypes = archetypes, + Filter = filter, + PrefilterData = prefilterData, + UnfilteredChunkCount = unfilteredChunkCount + }; + if (mode == ScheduleMode.Batched) + prefilterHandle = prefilteringJob.Schedule(dependsOn); + else + prefilteringJob.Run(); + } + else + { + var gatherJob = new GatherChunksAndOffsetsJob + { + Archetypes = archetypes, + PrefilterData = prefilterData, + UnfilteredChunkCount = unfilteredChunkCount + }; + if (mode == ScheduleMode.Batched) + prefilterHandle = gatherJob.Schedule(dependsOn); + else + gatherJob.Run(); + } + + // ScheduleParallelForDeferArraySize expects a ptr to a structure with a void* and a count. + // It only uses the count, so this is safe to fudge + deferredCountData = prefilterData + sizeofChunkArray + sizeofIndexArray; + deferredCountData = (byte*)deferredCountData - sizeof(void*); + + return prefilterHandle; + } } } diff --git a/package/Unity.Entities/Iterators/ComponentGroup.cs b/package/Unity.Entities/Iterators/ComponentGroup.cs index d51398f4a..5f6d41fc2 100755 --- a/package/Unity.Entities/Iterators/ComponentGroup.cs +++ b/package/Unity.Entities/Iterators/ComponentGroup.cs @@ -8,40 +8,116 @@ namespace Unity.Entities { /// - /// Define a query to find archetypes with specific component(s). - /// Any - Gets archetypes that have one or more of the given components - /// None - Gets archetypes that do not have the given components - /// All - Gets archetypes that have all the given components - /// Example: - /// Player has components: Position, Rotation, Player - /// Enemy1 has components: Position, Rotation, Melee - /// Enemy2 has components: Position, Rotation, Ranger - /// The query below would give you all of the archetypes that: - /// have any of [Melee or Ranger], AND have none of [Player], AND have all of [Position and Rotation] - /// new EntityArchetypeQuery { + /// Defines a query to find archetypes with specific components. + /// + /// + /// A query combines components in the All, Any, and None sets according to the + /// following rules: + /// + /// * All - Includes archetypes that have every component in this set + /// * Any - Includes archetypes that have at least one component in this set + /// * None - Excludes archetypes that have any component in this set + /// + /// For example, given entities with the following components: + /// + /// * Player has components: Position, Rotation, Player + /// * Enemy1 has components: Position, Rotation, Melee + /// * Enemy2 has components: Position, Rotation, Ranger + /// + /// The query below would give you all of the archetypes that: + /// have any of [Melee or Ranger], AND have none of [Player], AND have all of [Position and Rotation] + /// + /// new EntityArchetypeQuery { /// Any = new ComponentType[] {typeof(Melee), typeof(Ranger)}, /// None = new ComponentType[] {typeof(Player)}, - /// All = new ComponentType[] {typeof(Position), typeof(Rotation)} } - /// - + /// All = new ComponentType[] {typeof(Position), typeof(Rotation)} + /// } + /// + /// + /// In other words, the query selects the Enemy1 and Enemy2 entities, but not the Player entity. + /// public class EntityArchetypeQuery { + /// + /// The query includes archetypes that contain at least one (but possibly more) of the + /// components in the Any list. + /// public ComponentType[] Any = Array.Empty(); + /// + /// The query excludes archetypes that contain any of the + /// components in the None list. + /// public ComponentType[] None = Array.Empty(); + /// + /// The query includes archetypes that contain all of the + /// components in the All list. + /// public ComponentType[] All = Array.Empty(); + /// + /// Specialized query options. + /// + /// + /// You should not need to set these options for most queries. + /// + /// Options is a bit mask; use the bitwise OR operator to combine multiple options. + /// public EntityArchetypeQueryOptions Options = EntityArchetypeQueryOptions.Default; } + /// + /// The bit flags to use for the field. + /// [Flags] public enum EntityArchetypeQueryOptions { + /// + /// No options specified. + /// Default = 0, + /// + /// The query includes the special component. + /// IncludePrefab = 1, + /// + /// The query includes the special component. + /// IncludeDisabled = 2, + /// + /// The query should filter selected entities based on the + /// settings of the components specified in the query. + /// FilterWriteGroup = 4, } - //@TODO: Rename to ComponentQuery + //@TODO: Rename to EntityView + /// + /// A ComponentGroup provides a query-based view of your component data. + /// + /// + /// A ComponentGroup defines a view of your data based on a query for the set of + /// component types that an archetype must contain in order for its chunks and entities + /// to be included in the view. You can also exclude archetypes that contain specific types + /// of components. For simple queries, you can create a ComponentGroup based on an array of + /// component types. The following example defines a ComponentGroup that finds all entities + /// with both RotationQuaternion and RotationSpeed components. + /// + /// + /// ComponentGroup m_Group = GetComponentGroup(typeof(RotationQuaternion), + /// ComponentType.ReadOnly{RotationSpeed}()); + /// + /// + /// The query uses `ComponentType.ReadOnly` instead of the simpler `typeof` expression + /// to designate that the system does not write to RotationSpeed. Always specify read only + /// when possible, since there are fewer constraints on read access to data, which can help + /// the Job scheduler execute your Jobs more efficiently. + /// + /// For more complex queries, you can use an instead of a + /// simple list of component types. + /// + /// Use the or + /// functions + /// to get a ComponentGroup instance. + /// public unsafe class ComponentGroup : IDisposable { readonly ComponentJobSafetyManager m_SafetyManager; @@ -112,7 +188,7 @@ internal T[] ToArray() #endif /// - /// Gets array of all ComponentTypes in this ComponentGroup's ArchetypeQueries. + /// Gets the array of objects included in this ComponentGroup. /// /// Array of ComponentTypes internal ComponentType[] GetQueryTypes() @@ -219,11 +295,15 @@ bool GetIsReadOnly(int indexInComponentGroup) } /// - /// Calculates number of entities in this ComponentGroup. + /// Calculates the number of entities selected by this ComponentGroup. /// - /// Number of entities + /// + /// The ComponentGroup must run the query and apply any filters to calculate the entity count. + /// + /// The number of entities based on the current ComponentGroup properties. public int CalculateLength() { + SyncFilterTypes(); return ComponentChunkIterator.CalculateLength(m_GroupData->MatchingArchetypes, ref m_Filter); } @@ -366,7 +446,7 @@ public BufferArray GetBufferArray() where T : struct, IBufferElementData /// Gives the caller a job handle so it can wait for GatherChunks to finish. /// /// Allocator to use for the array. - /// Handle to the GatherChunks job used to fill the output array. + /// Handle to the GatherChunks job used to fill the output array. /// NativeArray of all the chunks in this ComponentChunkIterator. public NativeArray CreateArchetypeChunkArray(Allocator allocator, out JobHandle jobhandle) { @@ -394,15 +474,7 @@ public NativeArray CreateArchetypeChunkArray(Allocator allocator /// NativeArray of all the chunks in this ComponentChunkIterator. public NativeArray CreateArchetypeChunkArray(Allocator allocator) { - if (m_Filter.Type == FilterType.Changed) - { - fixed (int* indexInComponentGroupPtr = m_Filter.Changed.IndexInComponentGroup) - for (int i = 0; i < m_Filter.Changed.Count; ++i) - { - var type = m_GroupData->RequiredComponents[indexInComponentGroupPtr[i]]; - SafetyManager.CompleteWriteDependency(type.TypeIndex); - } - } + SyncFilterTypes(); JobHandle job; var res = ComponentChunkIterator.CreateArchetypeChunkArray(m_GroupData->MatchingArchetypes, allocator, out job, ref m_Filter); job.Complete(); @@ -410,6 +482,13 @@ public NativeArray CreateArchetypeChunkArray(Allocator allocator } + /// + /// Creates a NativeArray containing the selected entities. + /// + /// The type of memory to allocate. + /// A handle that you can use as a dependency for a Job + /// that uses the NativeArray. + /// An array containing all the entities selected by the ComponentGroup. public NativeArray ToEntityArray(Allocator allocator, out JobHandle jobhandle) { #if ENABLE_UNITY_COLLECTIONS_CHECKS @@ -421,6 +500,12 @@ public NativeArray ToEntityArray(Allocator allocator, out JobHandle jobh return ComponentChunkIterator.CreateEntityArray(m_GroupData->MatchingArchetypes, allocator, entityType, this, ref m_Filter, out jobhandle, GetDependency()); } + /// + /// Creates a NativeArray containing the selected entities. + /// + /// This version of the function blocks until the Job used to fill the array is complete. + /// The type of memory to allocate. + /// An array containing all the entities selected by the ComponentGroup. public NativeArray ToEntityArray(Allocator allocator) { #if ENABLE_UNITY_COLLECTIONS_CHECKS @@ -434,6 +519,15 @@ public NativeArray ToEntityArray(Allocator allocator) return res; } + /// + /// Creates a NativeArray containing the components of type T for the selected entities. + /// + /// The type of memory to allocate. + /// A handle that you can use as a dependency for a Job + /// that uses the NativeArray. + /// The component type. + /// An array containing the specified component for all the entities selected + /// by the ComponentGroup. public NativeArray ToComponentDataArray(Allocator allocator, out JobHandle jobhandle) where T : struct,IComponentData { @@ -445,6 +539,15 @@ public NativeArray ToComponentDataArray(Allocator allocator, out JobHandle return ComponentChunkIterator.CreateComponentDataArray(m_GroupData->MatchingArchetypes, allocator, componentType, this, ref m_Filter, out jobhandle, GetDependency()); } + /// + /// Creates a NativeArray containing the components of type T for the selected entities. + /// + /// The type of memory to allocate. + /// The component type. + /// An array containing the specified component for all the entities selected + /// by the ComponentGroup. + /// Thrown if you ask for a component that is not part of + /// the group. public NativeArray ToComponentDataArray(Allocator allocator) where T : struct, IComponentData { @@ -527,6 +630,14 @@ public EntityArray GetEntityArray() return output; } + /// + /// Gets the value of a singleton component. + /// + /// A singleton component is a component of which only one instance exists in the world + /// and which has been set with . + /// The component type. + /// A copy of the singleton component. + /// public T GetSingleton() where T : struct, IComponentData { @@ -549,6 +660,37 @@ public T GetSingleton() return value; } + /// + /// Sets the value of a singleton component. + /// + /// + /// For a component to be a singleton, there can be only one instance of that component + /// in a . The component must be the only component in its archetype + /// and you cannot use the same type of component as a normal component. + /// + /// To create a singleton, create an entity with the singleton component as its only component, + /// and then use `SetSingleton()` to assign a value. + /// + /// For example, if you had a component defined as: + /// + /// public struct Singlet: IComponentData{ public int Value; } + /// + /// + /// You could create a singleton as follows: + /// + /// + /// var entityManager = World.Active.EntityManager; + /// var singletonEntity = entityManager.CreateEntity(typeof(Singlet)); + /// var singletonGroup = entityManager.CreateComponentGroup(typeof(Singlet)); + /// singletonGroup.SetSingleton<Singlet>(new Singlet {Value = 1}); + /// + /// + /// You can set and get the singleton value from a ComponentGroup or a ComponentSystem. + /// + /// An instance of type T containing the values to set. + /// The component type. + /// Thrown if more than one instance of this component type + /// exists in the world or the component type appears in more than one archetype. public void SetSingleton(T value) where T : struct, IComponentData { @@ -575,6 +717,12 @@ internal bool CompareComponents(ComponentType* componentTypes, int count) return EntityGroupManager.CompareComponents(componentTypes, count, m_GroupData); } + // @TODO: Define what CompareComponents() does + /// + /// + /// + /// + /// public bool CompareComponents(ComponentType[] componentTypes) { fixed (ComponentType* componentTypesPtr = componentTypes) @@ -583,20 +731,32 @@ public bool CompareComponents(ComponentType[] componentTypes) } } + /// + /// + /// + /// + /// public bool CompareComponents(NativeArray componentTypes) { return EntityGroupManager.CompareComponents((ComponentType*)componentTypes.GetUnsafeReadOnlyPtr(), componentTypes.Length, m_GroupData); } + /// + /// + /// + /// + /// public bool CompareQuery(EntityArchetypeQuery[] query) { return EntityGroupManager.CompareQuery(query, m_GroupData); } /// - /// Resets this ComponentGroup's filter. - /// Removes references to shared component data, if applicable, then resets the filter type to None. + /// Resets this ComponentGroup's filter. /// + /// + /// Removes references to shared component data, if applicable, then resets the filter type to None. + /// public void ResetFilter() { if (m_Filter.Type == FilterType.SharedComponent) @@ -630,9 +790,12 @@ void SetFilter(ref ComponentGroupFilter filter) } /// - /// Creates a new SharedComponent filter on a given ISharedComponentData type for this ComponentGroup. + /// Filters this ComponentGroup so that it only selects entities with shared component values + /// matching the values specified by the `sharedComponent1` parameter. /// - /// A struct that implements ISharedComponentData + /// The shared component values on which to filter. + /// The type of shared component. (The type must also be + /// one of the types used to create the ComponentGroup. public void SetFilter(SharedComponent1 sharedComponent1) where SharedComponent1 : struct, ISharedComponentData { @@ -647,6 +810,19 @@ public void SetFilter(SharedComponent1 sharedComponent1) SetFilter(ref filter); } + /// + /// Filters this ComponentGroup based on the values of two separate shared components. + /// + /// + /// The filter only selects entities for which both shared component values + /// specified by the `sharedComponent1` and `sharedComponent2` parameters match. + /// + /// Shared component values on which to filter. + /// Shared component values on which to filter. + /// The type of shared component. (The type must also be + /// one of the types used to create the ComponentGroup. + /// The type of shared component. (The type must also be + /// one of the types used to create the ComponentGroup. public void SetFilter(SharedComponent1 sharedComponent1, SharedComponent2 sharedComponent2) where SharedComponent1 : struct, ISharedComponentData @@ -667,8 +843,11 @@ public void SetFilter(SharedComponent1 share } /// - /// Saves a given ComponentType's index in RequiredComponents in this group's Changed filter. + /// Filters out entities in chunks for which the specified component has not changed. /// + /// + /// Saves a given ComponentType's index in RequiredComponents in this group's Changed filter. + /// /// ComponentType to mark as changed on this ComponentGroup's filter. public void SetFilterChanged(ComponentType componentType) { @@ -686,9 +865,12 @@ internal void SetFilterChangedRequiredVersion(uint requiredVersion) } /// - /// Saves given ComponentTypes' indices in RequiredComponents in this group's Changed filter. + /// Filters out entities in chunks for which the specified components have not changed. /// - /// Array of ComponentTypes to mark as changed on this ComponentGroup's filter. + /// + /// Saves given ComponentTypes' indices in RequiredComponents in this group's Changed filter. + /// + /// Array of up to two ComponentTypes to mark as changed on this ComponentGroup's filter. public void SetFilterChanged(ComponentType[] componentType) { if (componentType.Length > ComponentGroupFilter.ChangedFilter.Capacity) @@ -735,6 +917,10 @@ public void AddDependency(JobHandle job) m_GroupData->WriterTypes, m_GroupData->WriterTypesCount, job); } + /// + /// + /// + /// public int GetCombinedComponentOrderVersion() { var version = 0; @@ -755,13 +941,33 @@ internal int CalculateNumberOfChunksWithoutFiltering() return ComponentChunkIterator.CalculateNumberOfChunksWithoutFiltering(m_GroupData->MatchingArchetypes); } - internal void AddReaderWritersToLists(ref UnsafeList reading, ref UnsafeList writing) + internal bool AddReaderWritersToLists(ref UnsafeList reading, ref UnsafeList writing) { + bool anyAdded = false; for (int i = 0; i < m_GroupData->ReaderTypesCount; ++i) - CalculateReaderWriterDependency.AddReaderTypeIndex(m_GroupData->ReaderTypes[i], ref reading, ref writing); - + anyAdded |= CalculateReaderWriterDependency.AddReaderTypeIndex(m_GroupData->ReaderTypes[i], ref reading, ref writing); + for (int i = 0; i < m_GroupData->WriterTypesCount; ++i) - CalculateReaderWriterDependency.AddWriterTypeIndex(m_GroupData->WriterTypes[i], ref reading, ref writing); + anyAdded |=CalculateReaderWriterDependency.AddWriterTypeIndex(m_GroupData->WriterTypes[i], ref reading, ref writing); + return anyAdded; + } + + /// + /// Syncs the needed types for the filter. + /// For every type that is change filtered we need to CompleteWriteDependency to avoid race conditions on the + /// change version of those types + /// + internal void SyncFilterTypes() + { + if (m_Filter.Type == FilterType.Changed) + { + fixed (int* indexInComponentGroupPtr = m_Filter.Changed.IndexInComponentGroup) + for (int i = 0; i < m_Filter.Changed.Count; ++i) + { + var type = m_GroupData->RequiredComponents[indexInComponentGroupPtr[i]]; + SafetyManager.CompleteWriteDependency(type.TypeIndex); + } + } } } } diff --git a/package/Unity.Entities/SerializeUtility.cs b/package/Unity.Entities/SerializeUtility.cs index 9abf55db5..9dc8b85df 100755 --- a/package/Unity.Entities/SerializeUtility.cs +++ b/package/Unity.Entities/SerializeUtility.cs @@ -141,7 +141,7 @@ public static unsafe void DeserializeWorld(ExclusiveEntityTransaction manager, B if (totalBlobAssetSize != 0) { manager.DataManager->AddSharedComponent(blobAssetRefChunks, ComponentType.ReadWrite(), manager.ArchetypeManager, manager.EntityGroupManager, blobAssetOwnerIndex); - manager.SharedComponentDataManager.AddReference(blobAssetRefChunks.Length - 1); + manager.SharedComponentDataManager.AddReference(blobAssetOwnerIndex, blobAssetRefChunks.Length - 1); blobAssetRefChunks.Dispose(); } diff --git a/package/Unity.Entities/Types/TypeManager.cs b/package/Unity.Entities/Types/TypeManager.cs index 67ad66504..093c2951a 100755 --- a/package/Unity.Entities/Types/TypeManager.cs +++ b/package/Unity.Entities/Types/TypeManager.cs @@ -506,7 +506,7 @@ private static int FindTypeIndex(Type type) return c.TypeIndex; } - throw new InvalidOperationException("Tried to GetTypeIndex for type that has not been set up by the static type registry."); + throw new ArgumentException("Tried to GetTypeIndex for type that has not been set up by the static type registry."); } #endif @@ -610,9 +610,13 @@ public static string[] SystemNames public static string SystemName(Type t) { +#if UNITY_CSHARP_TINY int index = GetSystemTypeIndex(t); if (index < 0 || index >= SystemNames.Length) return "null"; return SystemNames[index]; +#else + return t.FullName; +#endif } public static int GetSystemTypeIndex(Type t) @@ -987,7 +991,7 @@ public static int CreateTypeIndexForBufferElement() where T : struct, IBuffer #else private static int CreateTypeIndexThreadSafe(Type type) { - throw new InvalidOperationException("Tried to GetTypeIndex for type that has not been set up by the static registry."); + throw new ArgumentException("Tried to GetTypeIndex for type that has not been set up by the static registry."); } #endif } diff --git a/package/Unity.Entities/WorldDiff.cs b/package/Unity.Entities/WorldDiff.cs index cdc2b9123..d62ec2a51 100755 --- a/package/Unity.Entities/WorldDiff.cs +++ b/package/Unity.Entities/WorldDiff.cs @@ -44,6 +44,21 @@ public struct EntityGuid : IComponentData, IEquatable, IComparable() != null; + + var willBeConverted = convertToEntity | isSubScene; + + if (!willBeConverted) + { + Type convertType = null; + foreach (var behaviour in gameobject.GetComponents()) + { + if (behaviour.GetType().GetCustomAttribute(true) != null) + { + convertType = behaviour.GetType(); + break; + } + } + + if (convertType != null) + return $"The {convertType.Name} component on '{gameobject.name}' is meant for entity conversion, but it is not part of a SubScene or ConvertToEntity component.\nPlease move the game object to a SubScene or add the ConvertToEntity component."; + } + + if (isSubScene && convertToEntity) + return $"'{gameobject.name}' will be converted due to being in a SubScene. ConvertToEntity will have no effect.\nPlease remove the ConvertToEntity component."; + + if (isSubScene && gameobject.GetComponent() != null) + return $"'{gameobject.name}' will be converted due to being in a SubScene. GameObjectEntity will have no effect the game object will not be loaded.\nPlease remove the GameObjectEntity component"; + + if (convertToEntity && gameobject.GetComponent() != null) + return $"'{gameobject.name}' will be converted due to being in a ConvertToEntity hierarchy. GameObjectEntity will have no effect.\nPlease remove the GameObjectEntity component."; + + return null; + } + } +} diff --git a/package/Unity.Scenes.Editor/ConversionWarningsEditor.cs.meta b/package/Unity.Scenes.Editor/ConversionWarningsEditor.cs.meta new file mode 100755 index 000000000..9d735b3ee --- /dev/null +++ b/package/Unity.Scenes.Editor/ConversionWarningsEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2a7b0dae627144f0cb92e693ef8e2175 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package/Unity.Scenes.Editor/EditorEntityScenes.cs b/package/Unity.Scenes.Editor/EditorEntityScenes.cs index d1cc88301..fee1efc07 100755 --- a/package/Unity.Scenes.Editor/EditorEntityScenes.cs +++ b/package/Unity.Scenes.Editor/EditorEntityScenes.cs @@ -21,7 +21,14 @@ public class EditorEntityScenes static readonly ProfilerMarker k_ProfileEntitiesSceneSave = new ProfilerMarker("EntitiesScene.Save"); static readonly ProfilerMarker k_ProfileEntitiesSceneCreatePrefab = new ProfilerMarker("EntitiesScene.CreatePrefab"); static readonly ProfilerMarker k_ProfileEntitiesSceneSaveHeader = new ProfilerMarker("EntitiesScene.WriteHeader"); - + + + public static bool IsEntitySubScene(Scene scene) + { + return scene.isSubScene; + } + + public static void WriteEntityScene(SubScene scene) { Entities.Hash128 guid = new GUID(AssetDatabase.AssetPathToGUID(scene.EditableScenePath)); diff --git a/package/Unity.Scenes.Editor/SubSceneLiveLinkSystem.cs b/package/Unity.Scenes.Editor/SubSceneLiveLinkSystem.cs index 5e95b5f6e..ef01e457a 100755 --- a/package/Unity.Scenes.Editor/SubSceneLiveLinkSystem.cs +++ b/package/Unity.Scenes.Editor/SubSceneLiveLinkSystem.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Reflection; using Unity.Entities; @@ -61,11 +61,11 @@ protected override void OnUpdate() if (PreviousGlobalDirtyID != GlobalDirtyID) { - ForEach((SubScene subScene) => subScene.LiveLinkDirtyID = -1); + Entities.ForEach((SubScene subScene) => subScene.LiveLinkDirtyID = -1); PreviousGlobalDirtyID = GlobalDirtyID; } - ForEach((SubScene subScene) => + Entities.ForEach((SubScene subScene) => { // We are editing with live link. Ensure it is active & up to date if (subScene.IsLoaded && SubSceneInspectorUtility.LiveLinkEnabled) @@ -254,7 +254,7 @@ UndoPropertyModification[] PostprocessModifications(UndoPropertyModification[] m if (target) { var targetScene = target.scene; - ForEach((SubScene scene) => + Entities.ForEach((SubScene scene) => { if (scene.IsLoaded && scene.LoadedScene == targetScene) { diff --git a/package/Unity.Scenes.Hybrid/SubSceneStreamingSystem.cs b/package/Unity.Scenes.Hybrid/SubSceneStreamingSystem.cs index 1401cf923..a84d43606 100755 --- a/package/Unity.Scenes.Hybrid/SubSceneStreamingSystem.cs +++ b/package/Unity.Scenes.Hybrid/SubSceneStreamingSystem.cs @@ -46,8 +46,6 @@ struct Stream int MaximumMoveEntitiesFromPerFrame = 1; Stream[] m_Streams = new Stream[LoadScenesPerFrame]; - ComponentGroup m_PendingStreamRequests; - ComponentGroup m_UnloadStreamRequests; ComponentGroup m_SceneFilter; ComponentGroup m_SceneFilterPrefabs; ComponentGroup m_PublicRefFilter; @@ -62,18 +60,6 @@ protected override void OnCreateManager() for (int i = 0; i < LoadScenesPerFrame; ++i) CreateStreamWorld(i); - m_PendingStreamRequests = GetComponentGroup(new EntityArchetypeQuery() - { - All = new[] {ComponentType.ReadWrite(), ComponentType.ReadWrite()}, - None = new[] {ComponentType.ReadWrite(), ComponentType.ReadWrite() } - }); - - m_UnloadStreamRequests = GetComponentGroup(new EntityArchetypeQuery() - { - All = new[] {ComponentType.ReadWrite()}, - None = new[] {ComponentType.ReadWrite(), ComponentType.ReadWrite()} - }); - m_PublicRefFilter = GetComponentGroup ( ComponentType.ReadWrite(), @@ -357,23 +343,25 @@ protected override void OnUpdate() var destroySubScenes = new NativeList(Allocator.Temp); var commands = new EntityCommandBuffer(Allocator.Temp); - ForEach((Entity entity) => - { - var streamIndex = CreateAsyncLoadScene(entity); - if (streamIndex != -1) + Entities + .WithAll() + .WithNone() + .ForEach(entity => { - var streamingState = new StreamingState { ActiveStreamIndex = streamIndex, Status = StreamingStatus.NotYetProcessed}; - commands.AddComponent(entity, streamingState); - } - }, m_PendingStreamRequests); + var streamIndex = CreateAsyncLoadScene(entity); + if (streamIndex != -1) + { + var streamingState = new StreamingState { ActiveStreamIndex = streamIndex, Status = StreamingStatus.NotYetProcessed}; + commands.AddComponent(entity, streamingState); + } + }); commands.Playback(EntityManager); commands.Dispose(); - - ForEach((Entity entity) => - { - destroySubScenes.Add(entity); - }, m_UnloadStreamRequests); + Entities + .WithAll() + .WithNone() + .ForEach(entity => destroySubScenes.Add(entity)); foreach (var destroyScene in destroySubScenes.AsArray()) UnloadSceneImmediate(destroyScene); diff --git a/package/Unity.TestComponents/MockDataProxy.cs b/package/Unity.TestComponents/MockDataProxy.cs index 9b913831d..8182a9f55 100755 --- a/package/Unity.TestComponents/MockDataProxy.cs +++ b/package/Unity.TestComponents/MockDataProxy.cs @@ -10,6 +10,7 @@ public struct MockData : IComponentData } [DisallowMultipleComponent] + [UnityEngine.AddComponentMenu("Hidden/DontUse")] public class MockDataProxy : ComponentDataProxy { } diff --git a/package/Unity.TestComponents/MockSharedDataProxy.cs b/package/Unity.TestComponents/MockSharedDataProxy.cs index ed4f72063..8dc8c2de6 100755 --- a/package/Unity.TestComponents/MockSharedDataProxy.cs +++ b/package/Unity.TestComponents/MockSharedDataProxy.cs @@ -8,6 +8,7 @@ public struct MockSharedData : ISharedComponentData public int Value; } + [UnityEngine.AddComponentMenu("Hidden/DontUse")] public class MockSharedDataProxy : SharedComponentDataProxy { } diff --git a/package/Unity.TestComponents/MockSharedDisallowMultipleProxy.cs b/package/Unity.TestComponents/MockSharedDisallowMultipleProxy.cs index b9dd4c01d..52f0666b5 100755 --- a/package/Unity.TestComponents/MockSharedDisallowMultipleProxy.cs +++ b/package/Unity.TestComponents/MockSharedDisallowMultipleProxy.cs @@ -9,6 +9,7 @@ public struct MockSharedDisallowMultiple : ISharedComponentData } [UnityEngine.DisallowMultipleComponent] + [UnityEngine.AddComponentMenu("Hidden/DontUse")] public class MockSharedDisallowMultipleProxy : SharedComponentDataProxy { diff --git a/package/Unity.Transforms.Hybrid/LocalToWorldProxy.cs b/package/Unity.Transforms.Hybrid/LocalToWorldProxy.cs index b2a885d8b..953754f75 100755 --- a/package/Unity.Transforms.Hybrid/LocalToWorldProxy.cs +++ b/package/Unity.Transforms.Hybrid/LocalToWorldProxy.cs @@ -4,6 +4,7 @@ namespace Unity.Transforms { [UnityEngine.DisallowMultipleComponent] + [UnityEngine.AddComponentMenu("DOTS/Deprecated/LocalToWorldProxy-Deprecated")] public class LocalToWorldProxy : ComponentDataProxy { } diff --git a/package/Unity.Transforms.Hybrid/NonUniformScaleProxy.cs b/package/Unity.Transforms.Hybrid/NonUniformScaleProxy.cs index 4b1d8ebf7..18460e186 100755 --- a/package/Unity.Transforms.Hybrid/NonUniformScaleProxy.cs +++ b/package/Unity.Transforms.Hybrid/NonUniformScaleProxy.cs @@ -4,6 +4,8 @@ namespace Unity.Transforms { [UnityEngine.DisallowMultipleComponent] + [UnityEngine.AddComponentMenu("DOTS/Deprecated/NonUniformScaleProxy-Deprecated")] + public class NonUniformScaleProxy : ComponentDataProxy { } diff --git a/package/Unity.Transforms.Hybrid/RotationProxy.cs b/package/Unity.Transforms.Hybrid/RotationProxy.cs index bf4c94e65..c424ad782 100755 --- a/package/Unity.Transforms.Hybrid/RotationProxy.cs +++ b/package/Unity.Transforms.Hybrid/RotationProxy.cs @@ -5,6 +5,7 @@ namespace Unity.Transforms { [UnityEngine.DisallowMultipleComponent] + [UnityEngine.AddComponentMenu("DOTS/Deprecated/Rotation-Deprecated")] public class RotationProxy : ComponentDataProxy { protected override void ValidateSerializedData(ref Rotation serializedData) diff --git a/package/Unity.Transforms.Hybrid/TransformConversion.cs b/package/Unity.Transforms.Hybrid/TransformConversion.cs index 133f57bf7..e992c5496 100755 --- a/package/Unity.Transforms.Hybrid/TransformConversion.cs +++ b/package/Unity.Transforms.Hybrid/TransformConversion.cs @@ -7,7 +7,7 @@ class TransformConversion : GameObjectConversionSystem { protected override void OnUpdate() { - ForEach((Transform transform) => + Entities.ForEach((Transform transform) => { var entity = GetPrimaryEntity(transform); diff --git a/package/Unity.Transforms.Hybrid/TranslationProxy.cs b/package/Unity.Transforms.Hybrid/TranslationProxy.cs index 76386c598..3d541d959 100755 --- a/package/Unity.Transforms.Hybrid/TranslationProxy.cs +++ b/package/Unity.Transforms.Hybrid/TranslationProxy.cs @@ -4,6 +4,7 @@ namespace Unity.Transforms { [UnityEngine.DisallowMultipleComponent] + [UnityEngine.AddComponentMenu("DOTS/Deprecated/Translation-Deprecated")] public class TranslationProxy : ComponentDataProxy { } diff --git a/package/Unity.Transforms/EndFrameTransformSystems.cs b/package/Unity.Transforms/EndFrameTransformSystems.cs index f6efa7439..eb656bf83 100755 --- a/package/Unity.Transforms/EndFrameTransformSystems.cs +++ b/package/Unity.Transforms/EndFrameTransformSystems.cs @@ -42,6 +42,7 @@ public class EndFrameCompositeRotationSystem : CompositeRotationSystem [UpdateInGroup(typeof(TransformSystemGroup))] [UpdateAfter(typeof(EndFrameCompositeRotationSystem))] [UpdateAfter(typeof(EndFrameCompositeScaleSystem))] + [UpdateBefore(typeof(EndFrameLocalToParentSystem))] public class EndFrameTRSToLocalToWorldSystem : TRSToLocalToWorldSystem { } diff --git a/package/Unity.Transforms/ParentScaleInverse.cs b/package/Unity.Transforms/ParentScaleInverse.cs index d4acf615c..332d43690 100755 --- a/package/Unity.Transforms/ParentScaleInverse.cs +++ b/package/Unity.Transforms/ParentScaleInverse.cs @@ -9,6 +9,7 @@ namespace Unity.Transforms { [Serializable] + [WriteGroup(typeof(LocalToParent))] public struct ParentScaleInverse : IComponentData { public float4x4 Value; diff --git a/package/package.json b/package/package.json index 376d30b95..f58fa0bd3 100755 --- a/package/package.json +++ b/package/package.json @@ -1,15 +1,15 @@ { "name": "com.unity.entities", "unity": "2019.1", - "version": "0.0.12-preview.27", + "version": "0.0.12-preview.28", "dependencies": { "nuget.mono-cecil": "0.1.6-preview", "com.unity.test-framework.performance": "1.0.6-preview", "com.unity.properties": "0.4.0-preview", "com.unity.mathematics": "1.0.0-preview.1", - "com.unity.collections": "0.0.9-preview.14", - "com.unity.burst": "0.2.4-preview.48", - "com.unity.jobs": "0.0.7-preview.8" + "com.unity.collections": "0.0.9-preview.15", + "com.unity.burst": "1.0.0-preview.3", + "com.unity.jobs": "0.0.7-preview.9" }, "keywords": [ "entities", diff --git a/versions.txt b/versions.txt index cc07c5cdd..602e02436 100755 --- a/versions.txt +++ b/versions.txt @@ -35,3 +35,4 @@ 0.0.12-preview.25 0.0.12-preview.26 0.0.12-preview.27 +0.0.12-preview.28