Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
## [0.0.12-preview.31] - 2019-05-01

### New Features

### Upgrade guide

* Serialized entities file format version has changed, Sub Scenes entity caches will require rebuilding.

### Changes

* Adding components to entities that already have them is now properly ignored in the cases where no data would be overwritten. That means the inspectable state does not change and thus determinism can still be guaranteed.
* Restored backwards compatibility for `ForEach` API directly on `ComponentSystem` to ease people upgrading to the latest Unity.Entities package on top of Megacity.
* Rebuilding the entity cache files for sub scenes will now properly request checkout from source control if required.

### Fixes

* `IJobForEach` will only create new entity queries when scheduled, and won't rely on injection anymore. This avoids the creation of useless queries when explicit ones are used to schedule those jobs. Those useless queries could cause systems to keep updating even though the actual queries were empty.
* APIs changed in the previous version now have better obsolete stubs and upgrade paths.  All obsolete APIs requiring manual code changes will now soft warn and continue to work, instead of erroring at compile time.  These respective APIs will be removed in a future release after that date.
* LODGroup conversion now handles renderers being present in a LOD Group in multipe LOD levels correctly
* Fixed an issue where chunk utilization histograms weren't properly clipped in EntityDebugger
* Fixed an issue where tag components were incorrectly shown as subtractive in EntityDebugger
* ComponentSystem.ShouldRunSystem() exception message now more accurately reports the most likely reason for the error when the system does not exist.

### Known Issues

* It might happen that shared component data with managed references is not compared for equality correctly with certain profiles.
  • Loading branch information
Unity Technologies committed Apr 30, 2019
1 parent 8bb5e65 commit 87fafef
Show file tree
Hide file tree
Showing 159 changed files with 23,848 additions and 5,286 deletions.
97 changes: 97 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Change log

## [0.0.12-preview.31] - 2019-05-01

### New Features

### Upgrade guide

* Serialized entities file format version has changed, Sub Scenes entity caches will require rebuilding.

### Changes

* Adding components to entities that already have them is now properly ignored in the cases where no data would be overwritten. That means the inspectable state does not change and thus determinism can still be guaranteed.
* Restored backwards compatibility for `ForEach` API directly on `ComponentSystem` to ease people upgrading to the latest Unity.Entities package on top of Megacity.
* Rebuilding the entity cache files for sub scenes will now properly request checkout from source control if required.

### Fixes

* `IJobForEach` will only create new entity queries when scheduled, and won't rely on injection anymore. This avoids the creation of useless queries when explicit ones are used to schedule those jobs. Those useless queries could cause systems to keep updating even though the actual queries were empty.
* APIs changed in the previous version now have better obsolete stubs and upgrade paths. All obsolete APIs requiring manual code changes will now soft warn and continue to work, instead of erroring at compile time. These respective APIs will be removed in a future release after that date.
* LODGroup conversion now handles renderers being present in a LOD Group in multipe LOD levels correctly
* Fixed an issue where chunk utilization histograms weren't properly clipped in EntityDebugger
* Fixed an issue where tag components were incorrectly shown as subtractive in EntityDebugger
* ComponentSystem.ShouldRunSystem() exception message now more accurately reports the most likely reason for the error when the system does not exist.

### Known Issues

* It might happen that shared component data with managed references is not compared for equality correctly with certain profiles.


## [0.0.12-preview.30] - 2019-04-05

### New Features
Script templates have been added to help you create new component types and systems, similar to Unity's built-in template for new MonoBehaviours. Use them via the Assets/Create/ECS menu.

### Upgrade guide

Some APIs have been deprecated in this release:

[API Deprecation FAQ](https://forum.unity.com/threads/api-deprecation-faq-0-0-23.636994/)

** Removed obsolete ComponentSystem.ForEach
** Removed obsolete [Inject]
** Removed obsolete ComponentDataArray
** Removed obsolete SharedComponentDataArray
** Removed obsolete BufferArray
** Removed obsolete EntityArray
** Removed obsolete ComponentGroupArray

####ScriptBehaviourManager removal
* The ScriptBehaviourManager class has been removed.
* ComponentSystem and JobComponentSystem remain as system base classes (with a common ComponentSystemBase class)
* ComponentSystems have overridable methods OnCreateManager and OnDestroyManager. These have been renamed to OnCreate and OnDestroy.
* This is NOT handled by the obsolete API updater and will need to be done manually.
* The old OnCreateManager/OnDestroyManager will continue to work temporarily, but will print a warning if a system contains them.
* World APIs have been updated as follows:
* CreateManager, GetOrCreateManager, GetExistingManager, DestroyManager, BehaviourManagers have been renamed to CreateSystem, GetOrCreateSystem, GetExistingSystem, DestroySystem, Systems.
* These should be handled by the obsolete API updater.
* EntityManager is no longer accessed via GetExistingManager. There is now a property directly on World: World.EntityManager.
* This is NOT handled by the obsolete API updater and will need to be done manually.
* Searching and replacing Manager<EntityManager> should locate the right spots. For example, world.GetExistingManager<EntityManager>() should become just world.EntityManager.

#### IJobProcessComponentData renamed to IJobForeach
This rename unfortunately cannot be handled by the obsolete API updater.
A global search and replace of IJobProcessComponentData to IJobForEach should be sufficient.

#### ComponentGroup renamed to EntityQuery
ComponentGroup has been renamed to EntityQuery to better represent what it does.
All APIs that refer to ComponentGroup have been changed to refer to EntityQuery in their name, e.g. CreateEntityQuery, GetEntityQuery, etc.

#### EntityArchetypeQuery renamed to EntityQueryDesc
EntityArchetypeQuery has been renamed to EntityQueryDesc

### Changes
* Minimum required Unity version is now 2019.1.0b9
* Adding components to entities that already have them is now properly ignored in the cases where no data would be overwritten.
* UNITY_CSHARP_TINY is now NET_DOTS to match our other NET_* defines

### Fixes
* Fixed exception in inspector when Script is missing
* The presence of chunk components could lead to corruption of the entity remapping during deserialization of SubScene sections.
* Fix for an issue causing filtering with IJobForEachWithEntity to try to access entities outside of the range of the group it was scheduled with.

<!-- Template for version sections
## [0.0.0-preview.0]
### New Features
### Upgrade guide
### Changes
### Fixes
-->

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

1 change: 1 addition & 0 deletions Documentation~/TableOfContents.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* [Using ComponentSystem and ForEach](entity_iteration_foreach.md)
* [Manual iteration](manual_iteration.md)
* [Component Groups](component_group.md)
* [Component WriteGroups](ecs_write_groups.md)
* [Versions and Generations](version_numbers.md)
* [Jobs in ECS](ecs_job_overview.md)
* [ECS Job System extensions](ecs_job_extensions.md)
Expand Down
165 changes: 163 additions & 2 deletions Documentation~/ecs_write_groups.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,164 @@
# Write Groups
---
uid: ecs-writegroups
---

# WriteGroups

A common ECS pattern is for a system to read one set of *input* components and write to another, *output* component. However, you may want to override that system and update the output component based on your own set of inputs.

WriteGroups allow you to override whether a system writes to a component without having to change the overridden system. A WriteGroup identifies a set of components used as the source for writing to a particular component. The system defining that WriteGroup must also enable WriteGroup filtering on the EntityQuery objects it uses to select the entities to update.

Define a WriteGroup using the WriteGroup attribute. This attribute takes the type of the target, output component as a parameter. Place the attribute on every component used as a source when updating the target component. For example, the following declaration specifies that component A is part of the WriteGroup targeting component W:

```
[WriteGroup(typeof(W))]
public struct A : IComponentData{ public int Value; }
```

Note that the target component of the WriteGroup must be included in the query and accessed as writable. Otherwise, the WriteGroup is ignored for that query.

When you turn on WriteGroup filtering in a query, the query adds all components in a WriteGroup to the *None* list of the query unless you explicitly add them to the *All* or *Any* lists. As a result, the query only selects an entity if every component on that entity from a particular WriteGroup is explicitly required by the query. If an entity has one or more additional components from that WriteGroup, the query rejects it.

So far, WriteGroups don’t do anything that you couldn’t achieve by just rewriting the query. However, the benefit comes when you are working with a system that you cannot rewrite. You can add your own component to any WriteGroup defined by that system and, when you put that component on an entity along with the preexisting components, the system no longer selects and updates that entity. Your own system can then update the entity without contention from the other system.

**WriteGroup Example:**

Given:
* Components A and B in a WriteGroup targeting component W
* Query:
* All: A, W
* WriteGroup filtering enabled
* Entities:

| Entity X | Entity Y |
| :--------- | :---------- |
| A | A |
| W | B |
| | W |

The query selects Entity X, but not Y.

Entity Y is not selected because it has component B, which is part of the same WriteGroup, but is not required by the query. Enabling WriteGroup filtering changes the query to be:
* All: A, W
* None: B

Without WriteGroup filtering, the query would select both Entity X and Y.

**Note:** for more examples you can look at the Unity.Transforms code, which uses WriteGroups for every component it updates, including LocalToWorld.

## Creating WriteGroups

You can create WriteGroups by adding the WriteGroup attribute to the declarations of each component in the WriteGroup. The WriteGroup attribute takes one parameter, which is the type of component that the components in the group are used to update. A single component can be a member of more than one WriteGroup.

For example, if component W = A + B, then you would define a WriteGroup for W as follows:

```
public struct W : IComponentData
{
public int Value;
}
[WriteGroup(typeof(W))]
public struct A : IComponentData
{
public int Value;
}
[WriteGroup(typeof(W))]
public struct B : IComponentData
{
public int Value;
}
```

Note that you do not add the target of the WriteGroup (struct W in the example above) to its own WriteGroup.

## Enabling WriteGroup filtering

To enable WriteGroup filtering, set the FilterWriteGroups flag on the query description object you use to create the query:

```
public class AddingSystem : JobComponentSystem
{
private EntityQuery m_Query;
protected override void OnCreate()
{
var queryDescription = new EntityQueryDesc
{
All = new ComponentType[] {typeof(A), typeof(B)},
Options = EntityQueryOptions.FilterWriteGroup
};
m_Query = GetEntityQuery(queryDescription);
}
// Define Job and schedule...
}
```

## Overriding another system that uses WriteGroups

If a system defines WriteGroups for the components it writes to, you can override that system and write to those components using your own system. To override the system, add your own components to the WriteGroups defined by that system. Since WriteGroup filtering excludes any components in the WriteGroup that aren’t explicitly required by a query, any entities that have your components will then be ignored by the other system.

For example, if you wanted to set the orientation of your entities by specifying the angle and axis of rotation, you could create a component and a system to convert the angle and axis values into a quaternion and write that to the Unity.Transforms.Rotation component. To prevent the Unity.Transforms systems from updating Rotation, no matter what other components besides yours are present, you can put your component in the Rotation WriteGroup:

```
using System;
using Unity.Collections;
using Unity.Entities;
using Unity.Transforms;
using Unity.Mathematics;
[Serializable]
[WriteGroup(typeof(Rotation))]
public struct RotationAngleAxis : IComponentData
{
public float Angle;
public float3 Axis;
}
You can then update any entities containing RotationAngleAxis without contention:
using Unity.Burst;
using Unity.Entities;
using Unity.Jobs;
using Unity.Collections;
using Unity.Mathematics;
using Unity.Transforms;
public class RotationAngleAxisSystem : JobComponentSystem
{
[BurstCompile]
struct RotationAngleAxisSystemJob : IJobForEach<RotationAngleAxis, Rotation>
{
public void Execute([ReadOnly] ref RotationAngleAxis source, ref Rotation destination)
{
destination.Value = quaternion.AxisAngle(math.normalize(source.Axis), source.Angle);
}
}
protected override JobHandle OnUpdate(JobHandle inputDependencies)
{
var job = new RotationAngleAxisSystemJob();
return job.Schedule(this, inputDependencies);
}
}
```

## Extending another system that uses WriteGroups

If you want to extend the other system rather than just override it, and further, you want to allow future systems to override or extend your system, then you can enable WriteGroup filtering on your own system. When you do this, however, no combinations of components will be handled by either system by default. You must explicitly query for and process each combination.

As an example, let’s return to the AddingSystem example described earlier, which defined a WriteGroup containing components A and B that targeted component W. If you simply add a new component, call it “C”, to the WriteGroup, then the new system that knows about C can query for entities containing C and it does not matter if those entities also have components A or B. However, if the new system also enables WriteGroup filtering, that is no longer true. If you only require component C, then WriteGroup filtering excludes any entities with either A or B. Instead, you must explicitly query for each combination of components that make sense. (You can use the “Any” clause of the query when appropriate.)

```
var query = new EntityQueryDesc
{
All = new ComponentType[] {ComponentType.ReadOnly<C>(), ComponentType.ReadWrite<W>()},
Any = new ComponentType[] {ComponentType.ReadOnly<A>(), ComponentType.ReadOnly<B>()},
Options = EntityQueryOptions.FilterWriteGroup
};
```

Any entities containing combinations of components in the WriteGroup that are not explicitly handled will not be handled by any system that writes to the target of the WriterGroup (and filters on WriteGroups). But then, it is most likely a logical error in the program to create such entities in the first place.

Write Groups are a mechanism that a system can use to allow extensions.
65 changes: 63 additions & 2 deletions Documentation~/entity_iteration_foreach.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ __Important:__ Making structural changes forces the completion of all Jobs. This

## Iterating with ForEach delegates

The ComponentSystem provides a Entities.ForEach function that simplifies the task of iterating over a set of entities. Call ForEach in the system’s OnUpdate() function passing in a lambda function that takes the relevant components as parameters and whose function body performs the necessary work.
The ComponentSystem provides an Entities.ForEach function that simplifies the task of iterating over a set of entities. Call ForEach in the system’s OnUpdate() function passing in a lambda function that takes the relevant components as parameters and whose function body performs the necessary work.

The following example, from the HelloCube_01_ForEach sample, animates the rotation for any entities that have both a RotationQuaternion and a RotationSpeed component:

Expand All @@ -28,7 +28,7 @@ The following example, from the HelloCube_01_ForEach sample, animates the rotati

You can use ForEach lambda functions with up to six types of components.

If you need to make structural changes to existing entities, you can add an Entity component to your lambda function parameters and use it to add the commands to the ComponentSystem post-update command buffer. (If you were allowed to make structural changes inside the lambda function, you might change the layout of the data in the arrays you are iterating over, leading to bugs or other undefined behavior.)
If you need to make structural changes to existing entities, you can add an Entity component to your lambda function parameters and use it to add the commands to your `ComponentSystem`'s `PostUpdateCommands` buffer. (If you were allowed to make structural changes inside the lambda function, you might change the layout of the data in the arrays you are iterating over, leading to bugs or other undefined behavior.)

For example, if you wanted to remove the RotationSpeed component form any entities whose rotation speed is currently zero, you could alter your ForEach function as follows:

Expand All @@ -46,3 +46,64 @@ Entities.ForEach( (Entity entity, ref RotationSpeed rotationSpeed, ref RotationQ

The system executes the commands in the post-update buffer after the OnUpdate() function is finished.

## Fluent Queries

You can use a [fluent-style](https://en.wikipedia.org/wiki/Fluent_interface) query to constrain a ForEach lambda such that it executes on a specific set of entities satisfying some constraints. These queries can specify whether the work should be done on entities that have any, all or none of a set of components. Constraints can be chained together and should look very familiar to users of C#'s LINQ system.

Note that any components passed as parameters to the ForEach lambda function are automatically included in the WithAll set and must not be included explicitly in the WithAll, WithAny, or WithNone portions of the query.

A **WithAll** constraint allows you to specify that an entity have all of a set of components. For example, with the following query, the ComponentSystem executes a lambda function for all entities that have the Rotation and Scale component:

```csharp
Entities.WithAll<Rotation, Scale>().ForEach( (Entity e) =>
{
// do stuff
});
```

Use WithAll for components that must exist on an entity, but which you do not need to read or write (add components that you want to access, as parameters of the ForEach lambda function). For example:

```csharp
Entities.WithAll<SpinningTag>().ForEach( (Entity e, ref Rotation r) =>
{
// do stuff
});
```

A **WithAny** constraint allows you to specify that an entity must have at least one of a set of components. The ComponentSystem executes the following lambda function for all entities that have both Rotation and Scale, AND either RenderDataA or RenderDataB (or both):

```csharp
Entities.WithAll<Rotation, Scale>().WithAny<RenderDataA, RenderDataB>().ForEach( (Entity e) =>
{
// do stuff
});
```

Note that there is no way to know which components in the WithAny set exist for a specific entity. If you need to treat entities differently depending on which of these components exist, you must either create a specific query for each situation, or use a JobComponentSystem with [IJobChunk](chunk_iteration_job.md).

A **WithNone** constraint allows you to exclude entities that have at least one of a set of components. The ComponentSystem executes the following lambda function for all entities that do not have a Rotation component:

```csharp
Entities.WithNone<Rotation>().ForEach( (Entity e) =>
{
// do stuff
});
```

You can also specify a number of options for a query using **With**:

| Option | Description |
|---|---|
| Default | No options specified. |
| IncludePrefab | The query does not implicitly exclude entities with the special Prefab component. |
| IncludeDisabled | The query does not implicitly exclude entities with the special Disabled component. |
| FilterWriteGroup | The query should filter selected entities based on the WriteGroupAttribute settings of the components specified in the query. |

The ComponentSystem executes the following lambda function for all entities that do not have a Rotation component, including those that do have the special Disabled component:

```csharp
Entities.WithNone<Rotation>().With(EntityQueryOptions.IncludeDisabled).ForEach( (Entity e) =>
{
// do stuff
});
```
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Unity Companion License (“License”)
Software Copyright © 2017 Unity Technologies ApS
Software Copyright © 2017-19 Unity Technologies ApS

Unity Technologies ApS (“Unity”) grants to you a worldwide, non-exclusive, no-charge, and royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute the software that is made available under this License (“Software”), subject to the following terms and conditions:

Expand Down
Loading

0 comments on commit 87fafef

Please sign in to comment.