Target Code Architecture¶
Problems in mixing DOTS and Managed code¶
- To retrieve data from DOTS, queries are needed
- Query is not efficient to be created from outside systems
- SystemAPI is not accessible outside of systems
- Managed code breaks DOTS features
- Make it not Burstable, and reduce performance
- Incompatible with Jobs, and reduce performance
- Making DOTS changes from Managed code
- Require queries and archetypes, which is not readily available in managed code
- Changes made is out of system orders. So the changed value is only available next frame. Multiple changes could lead to multiple frames delay.
- Detect changes on DOTS data
- Require ReactiveComponent, which sequentialise DOTS code
- Direct detection is limited because of requirement of queries
- Mixed of Hybrid Baking and SubScene Baking
- Hybrid Baking is executed at runtime, while SubScene Baking is executed in Editor time. This makes sharing data between the two difficult.
Hybrid Architecture¶
The game consists of three layers: DOTS
, Managed
and Bridge
.
- DOTS Layer uses Pure-DOTS
implementations with ECS and HPC# (High Performance C#). It mostly deal with game simulation and logics, processing player inputs, configs and backend data. It computes data and events for the Bridge Layer
.
- Managed Layer use all other Unity and C# features. It mostly deal with visualization, capturing player inputs and baking config data.
- Bridge Layer facilitates data communication between the two layers. Captures data from the DOTS Layer and populates the Managed Layer with it, similarly, it also fowards and converts data from the Managed Layer into the DOTS Layer.
Why¶
- To get the best of both worlds (Unity & DOTS) while not affected by DOTS shortcommings.
- Encapsulation and abstraction in each layer simplify the complexity of writing code.
DOTS Layer¶
Pure DOTS, strictly using only Burstable code. No usage of any C# feature that is outside of High Performance C#
Managed Layer¶
This layer has full access to all C# features and should not use DOTS at all. The idea is to utilise all that C# has to offer and not get restricted by DOTS' shortcomings, or the incompatibility of two different programming paradigms (Object Oriented vs Data Oriented). In this layer we can do everything that DOTS is not good at or not designed for: - Object oriented programming - Async - UI - Other system features: sound, payment, plugin, etc... - Visualization that can't be done in DOTS using Game Objects - The game flow starts and ends in this layer
Bridge Layer¶
This layer has access to both DOTS and all other Unity features. This layer facilitate data communication between the other two layers.
Pull Data from Managed Layer¶
- Data is pulled from Managed Layer and store in singleton entities. Runtime data is updated every frame.
- The data output out from Managed Layer should be in DOTS-compatible formats.
- This is designed to limit managed components, which is causing problems in burstifying and jobifying code.
Push Data to Managed Layer¶
- Events happened in the DOTS Layer (value changes, new entities, ...) are translated to a list of event objects so that the Bridge Layer can consume in the next frame and forward them to the Managed Layer. Only subscribed events will be translated.
Pull Data from DOTS Layer¶
- Systems are used to expose data using query. Public method on these systems are exposed via interfaces. Data could be retrieve with keys such as Entity or other ids.
- This abstraction layer helps insulate Managed Layer from using Systems and get restricted by DOTS shortcommings.
Push Data to DOTS Layer¶
- For occasional data changes, this happen via
Commands
. Method to create these commands are available in this layer. Commands are used to create changes to the game, which happens in DOTS Layer - Every-frame data changes should not be pushed to DOTS Layer, it should be pulled instead.
Modules and Layers¶
Each module could have assemblies representing different layers. The Bridge Layer should depend on both DOTS and Managed layer to be able to properly integrate them. Note that Managed Layer could also refer to DOTS Layer, mainly to use the Components as data parameters.
block-beta
columns 1
block:ML["Managed Layer\n \n "]
columns 5
MMA["Module A"]
space
space
space
MMC["Module C"]
MMC --> MMA
end
space
block:BL["Bridge Layer\n \n \n \n \n \n "]
columns 5
space
space
BMB["Module B"]
space
space
BMA["Module A"]
space
space
space
BMC["Module C"]
BMB --> BMA
BMB --> BMC
end
space
block:DL["DOTS Layer\n \n \n \n \n \n "]
columns 5
DMA["Module A"]
space
DMB["Module B"]
space
space
DMB --> DMA
end
BMA --> MMA
BMB --> MMC
BMC --> MMC
BMA --> DMA
BMA --> DMB
BMB --> DMB
BMC --> DMB
Module groupping could be flexible
block-beta
columns 1
block:ML["Managed Layer\n \n \n "]
columns 5
MMA["Module A"]
space
space
space
MMC["Module C"]
MMC --> MMA
end
space
space
block:BL["Bridge Layer\n \n \n \n "]
columns 5
space
BM_AB["Module AB"]
space
BM_BC["Module BC"]
space
BM_BC --> BM_AB
end
block:DL["DOTS Layer\n \n \n \n \n \n "]
columns 5
space
space
DMB["Module B"]
space
space
DMA["Module A"]
space
space
space
DMC["Module C"]
DMB --> DMA
DMB --> DMC
DMA --> DMC
end
BM_AB --> MMA
BM_BC --> MMC
MMA --> DMA
MMC --> DMC
BM_AB --> DMA
BM_AB --> DMB
BM_BC --> DMB
BM_BC --> DMC
Migration Strategy¶
- Most of the current modules can be viewed as being in Managed Layer. Whenever possible, code should be split into DOTS Layer and Bridge Layer.
- Some modules that already went through a DOTS conversion could be split into DOTS Layer and Bridge Layer.