Skip to content

Commit 11da0cd

Browse files
committed
Release 3
1 parent 09fae9d commit 11da0cd

File tree

83 files changed

+4421
-208
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+4421
-208
lines changed

.editorconfig

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# see http://editorconfig.org/ for docs on this file
2+
3+
root = true
4+
5+
[*]
6+
# help with sharing files across os's (i.e. network share or through local vm)
7+
#end_of_line = lf
8+
#charset temporarily disabled due to bug in VS2017 changing to UTF-8 with BOM (https://favro.com/card/c564ede4ed3337f7b17986b6/Uni-17877)
9+
#charset = utf-8
10+
trim_trailing_whitespace = true
11+
insert_final_newline = true
12+
13+
# formattable file extensions (keep in sync with format.ini from unity-meta repo)
14+
#
15+
# Note: We need to split the formattable files configs into shorter duplicate entries (logically grouped)
16+
# due to known issue in VS editorconfig extension where there is a limit of 51 characters (empirically determined).
17+
# see: https://github.com/editorconfig/editorconfig-visualstudio/issues/21
18+
#
19+
## uncrustify
20+
[*.{c,h,cpp,hpp,m,mm,cc,cs}]
21+
indent_style = space
22+
indent_size = 4
23+
24+
## generic formatter (shaders)
25+
[*.{cg,cginc,glslinc,hlsl,shader,y,ypp,yy}]
26+
indent_style = space
27+
indent_size = 4
28+
29+
## generic formatter (misc)
30+
[*.{asm,s,S,pch,pchmm,java,sh,uss}]
31+
indent_style = space
32+
indent_size = 4
33+
34+
## perltidy
35+
[*.{pl,pm,t,it}]
36+
indent_style = space
37+
indent_size = 4
38+
39+
## unity special
40+
[*.{bindings,mem.xml}]
41+
indent_style = space
42+
indent_size = 4
43+
44+
# other filetypes we want to overwrite default configuration to preserve the standard
45+
[{Makefile,makefile}]
46+
# TAB characters are part of the Makefile format
47+
indent_style = tab
48+
49+
[*.{md,markdown}]
50+
# trailing whitespace is significant in markdown (bad choice, bad!)
51+
trim_trailing_whitespace = false
52+
53+
# keep these and the VS stuff below in sync with .hgeol's CRLF extensions
54+
[*.{vcproj,bat,cmd,xaml,tt,t4,ttinclude}]
55+
end_of_line = crlf
56+
57+
# this VS-specific stuff is based on experiments to see how VS will modify a file after it has been manually edited.
58+
# the settings are meant to closely match what VS does to minimize unnecessary diffs. this duplicates some settings in *
59+
# but let's be explicit here to be safe (in case someone wants to copy-paste this out to another .editorconfig).
60+
[*.{vcxproj,vcxproj.filters,csproj,props,targets}]
61+
indent_style = space
62+
indent_size = 2
63+
end_of_line = crlf
64+
charset = utf-8-bom
65+
trim_trailing_whitespace = true
66+
insert_final_newline = false
67+
[*.{sln,sln.template}]
68+
indent_style = tab
69+
indent_size = 4
70+
end_of_line = crlf
71+
charset = utf-8
72+
trim_trailing_whitespace = true
73+
insert_final_newline = false

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
**/Temp/
33
**/obj/
44

5-
**/.vscode
5+
**/.vscode/
66
**/.vs
7-
**/.editorconfig
87

98
**/Assets/Plugins/*
109
**/Assets/Plugins.meta
@@ -23,3 +22,4 @@
2322
.vs/
2423
build/*
2524
TwoStickShooter/Pure/Library/AnnotationManager
25+
*.rsp

Documentation/content/custom_job_types.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ The final parameter is the schedule mode. There are two scheduling modes to choo
3030
Once the schedule parameters are created we actually schedule the job. There are three ways to schedule jobs depending on their type:
3131
```C#
3232
JobHandle Schedule(ref JobScheduleParameters parameters);
33-
JobHandle ScheduleParallelFor(ref JobScheduleParameters parameters, int arrayLength, int innerloopBatchCount);
34-
JobHandle ScheduleParallelForTransform(ref JobScheduleParameters parameters, IntPtr transfromAccesssArray);
33+
JobHandle ScheduleParallelFor(ref JobScheduleParameters parameters, int arrayLength, int innerLoopBatchCount);
34+
JobHandle ScheduleParallelForTransform(ref JobScheduleParameters parameters, IntPtr transfromAccessArray);
3535
```
3636
Schedule can only be used if the __ScheduleParameters__ are created with __JobType.Single__, the other two schedule functions require __JobType.ParallelFor__.
37-
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).
37+
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).
3838
__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.
3939

4040
## Execution and JobRanges
@@ -51,7 +51,7 @@ The JobRanges contain the batches and indices a ParallelFor job is supposed to p
5151
```C#
5252
JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out begin, out end)
5353
```
54-
This continues until it returns `false`, and after calling it process all items with index between begin and end.
54+
This continues until it returns `false`, and after calling it process all items with index between __begin__ and __end__.
5555
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.
5656

5757
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:

Documentation/content/ecs_in_detail.md

Lines changed: 92 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ IComponentData structs may not contain references to managed objects. Since the
2727

2828
An __EntityArchetype__ is a unique array of __ComponentType__. __EntityManager__ uses EntityArchetypes to group all Entities using the same ComponentTypes in chunks.
2929

30-
```
30+
```C#
3131
// Using typeof to create an EntityArchetype from a set of components
3232
EntityArchetype archetype = EntityManager.CreateArchetype(typeof(MyComponentData), typeof(MySharedComponent));
3333

@@ -98,7 +98,8 @@ The ComponentData for each Entity is stored in what we internally refer to as a
9898

9999
A chunk is always linked to a specific EntityArchetype. Thus all Entities in one chunk follow the exact same memory layout. When iterating over components, memory access of components within a chunk is always completely linear, with no waste loaded into cache lines. This is a hard guarantee.
100100

101-
__ComponentDataArray__ is essentially an iterator over all EntityArchetypes compatible with the set of required components; for each EntityArchetype iterating over all chunks compatible with it and for each chunk iterating over all Entities in that chunk.
101+
__ComponentDataArray__ is essentially a convenience index based iterator for a single component type;
102+
First we iterate over all EntityArchetypes compatible with the ComponentGroup; for each EntityArchetype iterating over all chunks compatible with it and for each chunk iterating over all Entities in that chunk.
102103

103104
Once all Entities of a chunk have been visited, we find the next matching chunk and iterate through those Entities.
104105

@@ -115,6 +116,22 @@ By default we create a single World when entering Play Mode and populate it with
115116

116117
> Note: We are currently working on multiplayer demos, that will show how to work in a setup with separate simulation & presentation Worlds. This is a work in progress, so right now have no clear guidelines and are likely missing features in ECS to enable it.
117118
119+
## System update order
120+
121+
In ECS all systems are updated on the main thread. The order in which the are updated is based on a set of constraints and an optimization pass which tries to order the system in a way so that the time between scheduling a job and waiting for it is as long as possible.
122+
The attributes to specify update order of systems are ```[UpdateBefore(typeof(OtherSystem))]``` and ```[UpdateAfter(typeof(OtherSystem))]```. In addition to update before or after other ECS systems it is possible to update before or after different phases of the Unity PlayerLoop by using typeof([UnityEngine.Experimental.PlayerLoop.FixedUpdate](https://docs.unity3d.com/2018.1/Documentation/ScriptReference/Experimental.PlayerLoop.FixedUpdate.html)) or one of the other phases in the same namespace.
123+
124+
The UpdateInGroup attribute will put the system in a group and the same __UpdateBefore__ and __UpdateAfter__ attributes can be specified on a group or with a group as the target of the before/after dependency.
125+
126+
To use __UpdateInGroup__ you need to create and empty class and pass the type of that to the __UpdateInGroup__ attribute
127+
```cs
128+
public class UpdateGroup
129+
{}
130+
131+
[UpdateInGroup(typeof(UpdateGroup))]
132+
class MySystem : ComponentSystem
133+
```
134+
118135
## Automatic job dependency management (JobComponentSystem)
119136

120137
Managing dependencies is hard. This is why in __JobComponentSystem__ we are doing it automatically for you. The rules are simple: jobs from different systems can read from IComponentData of the same type in parallel. If one of the jobs is writing to the data then they can't run in parallel and will be scheduled with a dependency between the jobs.
@@ -294,7 +311,7 @@ Lastly you can also inject a reference to another system. This will populate the
294311

295312
## ComponentGroup
296313

297-
The ComponentGroup is foundation class on top of which all iteration methods are built (Injection, foreach, IJobProcessComponetnData etc)
314+
The ComponentGroup is foundation class on top of which all iteration methods are built (Injection, foreach, IJobProcessComponentData etc)
298315

299316
Essentially a ComponentGroup is constructed with a set of required components, subtractive components.
300317

@@ -348,7 +365,9 @@ class PositionToRigidbodySystem : ComponentSystem
348365
The Entity struct identifies an Entity. If you need to access component data on another Entity, the only stable way of referencing that component data is via the Entity ID. EntityManager provides a simple get & set component data API for it.
349366
```cs
350367
Entity myEntity = ...;
351-
var position = EntityManager.SetComponentData<LocalPosition>(entity);
368+
var position = EntityManager.GetComponentData<LocalPosition>(entity);
369+
...
370+
EntityManager.SetComponentData(entity, position);
352371
```
353372

354373
However EntityManager can't be used on a C# job. __ComponentDataFromEntity__ gives you a simple API that can also be safely used in a job.
@@ -364,10 +383,78 @@ var position = m_LocalPositions[myEntity];
364383

365384
## ExclusiveEntityTransaction
366385

367-
EntityTransaction is an API to create & destroy entities from a job. The purpose is to enable procedural generation scenarios where construction of massive scale instantiation must happen on jobs. This API is very much a work in progress.
386+
EntityTransaction is an API 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.
387+
388+
ExclusiveEntityTransaction should be used on manually created world that acts as a staging area to construct & setup entities.
389+
After the job has completed you can end the EntityTransaction and use ```EntityManager.MoveEntitiesFrom(EntityManager srcEntities);``` to move the entities to an active world.
390+
368391

369392
## EntityCommandBuffer
370393

394+
The command buffer class solves two important problems:
395+
396+
1. When you're in a job, you can't access the entity manager
397+
2. When you access the entity manager (to say, create an entity) you invalidate all injected arrays and component groups
398+
399+
The command buffer abstraction allows you to queue up changes to be performed (from either a job or from the main thread) so that they can take effect later on the main thread. There are two ways to use a command buffer:
400+
401+
1. `ComponentSystem` subclasses which update on the main thread have one available automatically called `PostUpdateCommands`. To use it, simply reference the attribute and queue up your changes. They will be automatically applied to the world immediately after you return from your system's `Update` function.
402+
403+
Here's an example from the two stick shooter sample:
404+
405+
```cs
406+
PostUpdateCommands.CreateEntity(TwoStickBootstrap.BasicEnemyArchetype);
407+
PostUpdateCommands.SetComponent(new Position2D { Value = spawnPosition });
408+
PostUpdateCommands.SetComponent(new Heading2D { Value = new float2(0.0f, -1.0f) });
409+
PostUpdateCommands.SetComponent(default(Enemy));
410+
PostUpdateCommands.SetComponent(new Health { Value = TwoStickBootstrap.Settings.enemyInitialHealth });
411+
PostUpdateCommands.SetComponent(new EnemyShootState { Cooldown = 0.5f });
412+
PostUpdateCommands.SetComponent(new MoveSpeed { speed = TwoStickBootstrap.Settings.enemySpeed });
413+
PostUpdateCommands.AddSharedComponent(TwoStickBootstrap.EnemyLook);
414+
```
415+
416+
As you can see, the API is very similar to the entity manager API. In this mode, it is helpful to think of the automatic command buffer as a convenience that allows you to prevent array invalidation inside your system while still making changes to the world.
417+
418+
2. For jobs, you must request command buffers from a `Barrier` on the main thread, and pass them to jobs. The barriers will play back in the created order on the main thread when the barrier system updates. This extra step is required so that memory management can be centralized and determinism of the generated entities and components can be guaranteed.
419+
420+
Again let's look at the two stick shooter sample to see how this works in practice.
421+
422+
First, a barrier system is declared:
423+
424+
```cs
425+
public class ShotSpawnBarrier : BarrierSystem
426+
{}
427+
```
428+
429+
There's no code in a barrier system, it just serves as a synchronization point.
430+
431+
Next, we inject this barrier into the system that will request command buffers from it:
432+
433+
```cs
434+
[Inject] private ShotSpawnBarrier m_ShotSpawnBarrier;
435+
```
436+
437+
Now we can access the barrier when we're scheduling jobs and ask for command
438+
buffers from it via `CreateCommandBuffer()`:
439+
440+
```cs
441+
return new SpawnEnemyShots
442+
{
443+
// ...
444+
CommandBuffer = m_ShotSpawnBarrier.CreateCommandBuffer(),
445+
// ...
446+
}.Schedule(inputDeps);
447+
```
448+
449+
In the job, we can use the command buffer normally:
450+
451+
```cs
452+
CommandBuffer.CreateEntity(ShotArchetype);
453+
CommandBuffer.SetComponent(spawn);
454+
```
455+
456+
When the barrier system updates, it will automatically play back the command buffers. It's worth noting that the barrier system will take a dependency on any jobs spawned by systems that access it (so that it can now that the command buffers have been filled in fully). If you see bubbles in the frame, it may make sense to try moving the barrier later in the frame, if your game logic allows for this.
457+
371458
## GameObjectEntity
372459

373460
ECS ships with the __GameObjectEntity__ component. It is a MonoBehaviour. In __OnEnable__, the GameObjectEntity component creates an Entity with all components on the GameObject. As a result the full GameObject and all its components are now iterable by ComponentSystems.

Documentation/content/ecs_principles_and_vision.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ We measure ourselves against the performance that can be achieved in C++ with ha
1111
We are using a combination of compiler technology (Burst), containers (Unity.Collections), data layout of components (ECS) to make it easy to write efficient code by default.
1212

1313
* Data layout & iteration - The Entity Component System gurantees linear data layout when iterating entities in chunks by default. This is a critical part of the performance gains provided by the Entity Component System.
14-
* The C# job system lets you write multithreaded code in a simple way. It also safe. The C# Job Debugger detects any race conditions.
14+
* The C# job system lets you write multithreaded code in a simple way. It is also safe. The C# Job Debugger detects any race conditions.
1515
* Burst is our compiler specifically for C# jobs. C# job code follows certain patterns that we can use to produce more efficient machine code. Code is compiled & optimized for each target platforms taking advantage of SIMD instructions.
1616

1717
An example of this is the performance of Instantiation. Comparing to the theoretical limit, of instantiating 100.000 entities with 320 bytes of a memcpy takes 9ms. Instantiating those entities via the Entity Component System takes 10ms. So we are very close to the theoretical lmit.

0 commit comments

Comments
 (0)