目录
EntityCommandBuffer.ParallelWriter
Entity command buffers
EntityCommandBuffer. 用来在main thread 上执行 job 里面不能执行的 structural changes (i.e. create entities, destroy entities, add components, or remove components). 操作。记录的command在调用 Playback() 方法后执行。
EntityCommandBuffer
有许多(但不是全部)与EntityManager相同的方法:
EntityCommandBuffer method | Description |
---|---|
CreateEntity() | Records a command to create a new entity. Returns a temporary entity ID. |
DestroyEntity() | Records a command to destroy an entity. |
AddComponent<T>() | Records a command to add a component of type T to an entity. |
RemoveComponent<T>() | Records a command to temove a component of type T from an entity. |
SetComponent<T>() | Records a command to set a component value of type T. |
AppendToBuffer() | Records a command that will append an individual value to the end of the entity's existing buffer. |
AddBuffer() | Returns a DynamicBuffer which is stored in the recorded command, and the contents of this buffer will be copied to the entity's actual buffer when it is created in playback. Effectively, writing to the returned buffer allows you to set the initial contents of the component. |
SetBuffer() | Like AddBuffer() , but it assumes the entity already has a buffer of the component type. In playback, the entity's already existing buffer content is overwritten by the contents of the returned buffer. |
📝 NOTE |
---|
有些方法没有,是因为有些操作不需要延迟执行,即在command buffer里面执行 |
在调用 played back 方法之后, an EntityCommandBuffer instance 就不能再使用了. 如果需要继续记录,需要创建一个新的,独立的 EntityCommandBuffer instance. |
Job safety
每一个EntityCommandBuffer
都有一个 job safety handle,和每一个commponent 一样
- EntityCommandBuffer还正在被job 使用,在主线程上调用EntityCommandBuffer的方法
⚠ IMPORTANT |
---|
不推荐使用 EntityCommandBuffer.ParallelWriter 跨多个并行job使用, it’s virtually always best to create and use one EntityCommandBuffer per job. |
Temporary entities
EntityCommandBuffer的方法
CreateEntity() or I nstantiate() 在命令执行完之前,不会创建新的实体,所以返回的 entity ID 是 temporary ID, 值是负的,同一个EntityCommandBuffer的方法
AddComponent
, SetComponent
, and SetBuffer将会使用
temporary ID's. In playback,命令执行完之后, temporary ID's 会重新映射到一个真实的实体上。
EntityCommandBuffer.ParallelWriter
To safely record commands from a parallel job, we need an EntityCommandBuffer.ParallelWriter, which is a wrapper around an underlying EntityCommandBuffer
.
A ParallelWriter
has most of the same methods as an EntityCommandBuffer
itself, but the ParallelWriter
methods all take an additional 'sort key' argument for the sake of determinism:
When an EntityCommandBuffer.ParallelWriter
records commands in a parallel job, the order of commands recorded from different threads depends upon thread scheduling, making the order non-deterministic. This isn't ideal because:
- Deterministic code is generally easier to debug.
- Some netcode solutions depend upon determinism to produce consistent results across different machines.
While the recording order of the commands cannot be deterministic, the playback order can be deterministic with a simple trick:
- Each command records a 'sort key' integer passed as the first argument to each command method.
- The
Playback()
method sorts the commands by their sort keys before executing the commands.
As long as the used sort keys map deterministically to each recorded command, the sort makes the playback order deterministic.
So in an IJobEntity
, the sort key we generally want to use is the ChunkIndexInQuery, which is a unique value for every chunk. Because the sort is stable and because all entities of an individual chunk are processed together in a single thread, this index value is suitable as a sort key for the recorded commands. In an IJobChunk
, we can use the equivalent unfilteredChunkIndex
parameter of the Execute
method.
Multi-playback
EntityCommandBuffer
创建的时候选择PlaybackPolicy.MultiPlayback
,它的Playback方法可以被调用多次,否则会报错,
Multi-playback 在对实体执行多次相同的操作时,很有用
EntityCommandBufferSystem
EntityCommandBufferSystem 提供了一种方便的方式执行EntityCommandBuffer
playback. EntityCommandBufferSystem
创建的 EntityCommandBuffer 会在下次
updates 的时候 playback 、dispose
You rarely need to create any EntityCommandBufferSystem
's yourself because the automatic bootstrapping process puts these five into the default world:
BeginInitializationEntityCommandBufferSystem
EndInitializationEntityCommandBufferSystem
BeginSimulationEntityCommandBufferSystem
EndSimulationEntityCommandBufferSystem
BeginPresentationEntityCommandBufferSystem
The EndSimulationEntityCommandBufferSystem
, for example, is updated at the end of the SimulationSystemGroup
. (Notice there's no EndPresentationEntityCommandBufferSystem at the end of the frame, but you can use BeginInitializationEntityCommandBufferSystem
instead: 一帧的结束和下一帧的开始在逻辑上是同一时间点).