Skip to content

Commit 8c45138

Browse files
author
Unity Technologies
committed
com.unity.netcode@0.4.0-preview.1
## [0.4.0] - 2020-09-10 ### New features * Code gen support for ICommandData, serialization for command data can now be generated instead of hand-written. You can opt out of code generation by adding `[NetCodeDisableCommandCodeGen]`. * `NetCodeConversionSettings` has a new Client And Server mode, which makes it possible to build a single standalong build supporting both client and server. * There is a new static method to generate predicted spawn version of a prefab, `GhostCollectionSystem.CreatePredictedSpawnPrefab`. ### Changes * When not using code-gen for rpcs or commands the systems for registering them (the ones extending `RpcCommandRequestSystem<TActionSerializer, TActionRequest>`, `CommandSendSystem<TCommandDataSerializer, TCommandData>` and `CommandReceiveSystem<TCommandDataSerializer, TCommandData>`) need some more code to setup the jobs. * The `ICommandData` interface no longer takes an additional generic type. * Added a `CommandSendSystemGroup` and a `CommandReceiveSystemGroup` which can be used for dependencies when generating code for `ICommandData`. * Moved the GameObjects used for authoring to a separate assembly. * Fixed tickrate on the client is no longer supported. This also means that the render interpolation has been removed. * Using multiple rendering clients in the editor is no longer supported, thin clients are still supported. * The `GhostPrefabCollectionComponent` now only contains a single prefab list, and the `GhostPrefabBuffer` for it is attached to the same entity. ### Deprecated * Deprecated `ConvertToClientServerEntity`, please use the sub-scene conversion workflow instead. ### Fixes * Fixed a compile error in the generated code for components containing multiple ghosted Entity references. * Fixed a bug where predicted spawn ghosts were not destroyed on mis-prediction. * Fixed a bug where data for child entities on predicted ghosts could be corrupted. ### Upgrade guide * The predicted spawn code must switch to using the new `GhostCollectionSystem.CreatePredictedSpawnPrefab` utility method since there is only a single prefab on the client and it requires some patching before it can be used. * When using the `GhostPrefabCollectionComponent` to find a prefab to find a ghost prefab on the server you must change the code to read the `GhostPrefabBuffer` from the same entity as `GhostPrefabCollectionComponent`. * If you are using fixed tickrate mode on the client you need to remove the creation of the `FixedClientTickRate` singleton and remove the `CurrentSimulatedPosition` and `CurrentSimulatedRotation` if using them. * If you are using "Num Clients" in the PlayMode tools you need to move to using "Num Thin Clients" instead. * RPCs not using code-gen needs to add more code to the `RpcCommandRequestSystem`. The new implementation should look like this: ```c# class MyRequestRpcCommandRequestSystem : RpcCommandRequestSystem<MyRequestSerializer, MyRequest> { [BurstCompile] protected struct SendRpc : IJobEntityBatch { public SendRpcData data; public void Execute(ArchetypeChunk chunk, int orderIndex) { data.Execute(chunk, orderIndex); } } protected override void OnUpdate() { var sendJob = new SendRpc{data = InitJobData()}; ScheduleJobData(sendJob); } } ``` * The `Tick` property in `ICommandData` now requires both a getter and a setter. * ICommandData structs no longer need serialization or implementaions of `CommandSendSystem` and `CommandReceiveSystem` if you are using code-gen, and the interface changed from `ICommandData<T>` to `ICommandData`. * When manually writing serialization code for `ICommandData` you need to move the serialization code to a struct implementing `ICommandDataSerialize<T>`, and the `CommandSendSystem` and `CommandReceiveSystem` implementations need code to schedule the jobs like this: ```c# public class MyCommandSendCommandSystem : CommandSendSystem<MyCommandSerializer, MyCommand> { [BurstCompile] struct SendJob : IJobEntityBatch { public SendJobData data; public void Execute(ArchetypeChunk chunk, int orderIndex) { data.Execute(chunk, orderIndex); } } protected override void OnUpdate() { var sendJob = new SendJob{data = InitJobData()}; ScheduleJobData(sendJob); } } public class MyCommandReceiveCommandSystem : CommandReceiveSystem<MyCommandSerializer, MyCommand> { [BurstCompile] struct ReceiveJob : IJobEntityBatch { public ReceiveJobData data; public void Execute(ArchetypeChunk chunk, int orderIndex) { data.Execute(chunk, orderIndex); } } protected override void OnUpdate() { var recvJob = new ReceiveJob{data = InitJobData()}; ScheduleJobData(recvJob); } } ```
1 parent ebda97e commit 8c45138

File tree

102 files changed

+1985
-1706
lines changed

Some content is hidden

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

102 files changed

+1985
-1706
lines changed

CHANGELOG.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,93 @@
11
# Change log
22

3+
## [0.4.0] - 2020-09-10
4+
### New features
5+
* Code gen support for ICommandData, serialization for command data can now be generated instead of hand-written. You can opt out of code generation by adding `[NetCodeDisableCommandCodeGen]`.
6+
* `NetCodeConversionSettings` has a new Client And Server mode, which makes it possible to build a single standalong build supporting both client and server.
7+
* There is a new static method to generate predicted spawn version of a prefab, `GhostCollectionSystem.CreatePredictedSpawnPrefab`.
8+
9+
### Changes
10+
* When not using code-gen for rpcs or commands the systems for registering them (the ones extending `RpcCommandRequestSystem<TActionSerializer, TActionRequest>`, `CommandSendSystem<TCommandDataSerializer, TCommandData>` and `CommandReceiveSystem<TCommandDataSerializer, TCommandData>`) need some more code to setup the jobs.
11+
* The `ICommandData` interface no longer takes an additional generic type.
12+
* Added a `CommandSendSystemGroup` and a `CommandReceiveSystemGroup` which can be used for dependencies when generating code for `ICommandData`.
13+
* Moved the GameObjects used for authoring to a separate assembly.
14+
* Fixed tickrate on the client is no longer supported. This also means that the render interpolation has been removed.
15+
* Using multiple rendering clients in the editor is no longer supported, thin clients are still supported.
16+
* The `GhostPrefabCollectionComponent` now only contains a single prefab list, and the `GhostPrefabBuffer` for it is attached to the same entity.
17+
18+
### Deprecated
19+
* Deprecated `ConvertToClientServerEntity`, please use the sub-scene conversion workflow instead.
20+
21+
### Fixes
22+
* Fixed a compile error in the generated code for components containing multiple ghosted Entity references.
23+
* Fixed a bug where predicted spawn ghosts were not destroyed on mis-prediction.
24+
* Fixed a bug where data for child entities on predicted ghosts could be corrupted.
25+
26+
### Upgrade guide
27+
* The predicted spawn code must switch to using the new `GhostCollectionSystem.CreatePredictedSpawnPrefab` utility method since there is only a single prefab on the client and it requires some patching before it can be used.
28+
* When using the `GhostPrefabCollectionComponent` to find a prefab to find a ghost prefab on the server you must change the code to read the `GhostPrefabBuffer` from the same entity as `GhostPrefabCollectionComponent`.
29+
* If you are using fixed tickrate mode on the client you need to remove the creation of the `FixedClientTickRate` singleton and remove the `CurrentSimulatedPosition` and `CurrentSimulatedRotation` if using them.
30+
* If you are using "Num Clients" in the PlayMode tools you need to move to using "Num Thin Clients" instead.
31+
* RPCs not using code-gen needs to add more code to the `RpcCommandRequestSystem`. The new implementation should look like this:
32+
```c#
33+
class MyRequestRpcCommandRequestSystem : RpcCommandRequestSystem<MyRequestSerializer, MyRequest>
34+
{
35+
[BurstCompile]
36+
protected struct SendRpc : IJobEntityBatch
37+
{
38+
public SendRpcData data;
39+
public void Execute(ArchetypeChunk chunk, int orderIndex)
40+
{
41+
data.Execute(chunk, orderIndex);
42+
}
43+
}
44+
protected override void OnUpdate()
45+
{
46+
var sendJob = new SendRpc{data = InitJobData()};
47+
ScheduleJobData(sendJob);
48+
}
49+
}
50+
```
51+
* The `Tick` property in `ICommandData` now requires both a getter and a setter.
52+
* ICommandData structs no longer need serialization or implementaions of `CommandSendSystem` and `CommandReceiveSystem` if you are using code-gen, and the interface changed from `ICommandData<T>` to `ICommandData`.
53+
* When manually writing serialization code for `ICommandData` you need to move the serialization code to a struct implementing `ICommandDataSerialize<T>`, and the `CommandSendSystem` and `CommandReceiveSystem` implementations need code to schedule the jobs like this:
54+
```c#
55+
public class MyCommandSendCommandSystem : CommandSendSystem<MyCommandSerializer, MyCommand>
56+
{
57+
[BurstCompile]
58+
struct SendJob : IJobEntityBatch
59+
{
60+
public SendJobData data;
61+
public void Execute(ArchetypeChunk chunk, int orderIndex)
62+
{
63+
data.Execute(chunk, orderIndex);
64+
}
65+
}
66+
protected override void OnUpdate()
67+
{
68+
var sendJob = new SendJob{data = InitJobData()};
69+
ScheduleJobData(sendJob);
70+
}
71+
}
72+
public class MyCommandReceiveCommandSystem : CommandReceiveSystem<MyCommandSerializer, MyCommand>
73+
{
74+
[BurstCompile]
75+
struct ReceiveJob : IJobEntityBatch
76+
{
77+
public ReceiveJobData data;
78+
public void Execute(ArchetypeChunk chunk, int orderIndex)
79+
{
80+
data.Execute(chunk, orderIndex);
81+
}
82+
}
83+
protected override void OnUpdate()
84+
{
85+
var recvJob = new ReceiveJob{data = InitJobData()};
86+
ScheduleJobData(recvJob);
87+
}
88+
}
89+
```
90+
391
## [0.3.0-preview.3] - 2020-08-21
492
### New features
593
* New workflow for generating serialization code for ghosts. In the new workflow code is generated per component and there is no codegen per ghost type prefab.
@@ -14,18 +102,22 @@
14102
* Added visualization of prediction errors to the NetDbg.
15103
* A connection entity on the server can have a `NetworkStreamSnapshotTargetSize` which is used to control the target size for snapshots.
16104
* Added `GhostReceiveSystem.GhostCountOnServer` and `GhostReceiveSystem.GhostCountOnClient` which can be used to check how many ghosts a client should have and how many it does have.
105+
17106
### Changes
18107
* Support for `NativeString64` has been replaced by support for `FixedString64`. Support for `FixedString32`, `FixedString128`, `FixedString512` and `FixedString4096` has also been added.
19108
* In dynamic timestep mode it is now possible to resume prediction from the last full predicted tick instead of rolling back to the latest received snapshot when no new data has been received.
20109
* Added a `DisableLagCompensationComponent` which when added as a singleton prevents the lag compensation system from running.
110+
21111
### Fixes
22112
* Quaternions are renormalized after dequantization to make sure they are still valid rotations.
23113
* Floats are rounded to the nearest int after quantization to improve acuracy.
24114
* It is now possible to send more than one packet with RPC commands per frame, previously commands could be silently dropped when doing that.
115+
25116
### Upgrade guide
26117
* `NativeString64` is no longer uspported, change your code to use `FixedString64` instead.
27118
* `GhostUpdateSystemGroup` no longer exists, references to it for update order should be replaced with `GhostUpdateSystem`
28119
* NetCode now requires Unity 2020.1.2.
120+
29121
#### New ghost workflow
30122
* Change all `[GhostDefaultField]` to `[GhostField]` and all `[GhostDefaultComponent]` to `[GhostComponent]` in your components. The parameters to the constructors have also changed, you need to specify `[GhostField(Quantization=100, Interpolate=true)]` instead of `[GhostDefaultField(100, true)]`.
31123
* For all ghosts which manually adds fields you must add `GhostField` attributes to the component since manual overrides are no longer supported.
@@ -38,6 +130,7 @@
38130
* If you are using predictive spawning the new way to request a predictive spawn is to instantiate the predicted client version of the ghost prefab and add a `PredictedGhostSpawnRequestComponent` to the entity.
39131
* Any custom spawn behavior - including matching entities for pre-spawned ghosts - previously implemented in `MarkPredictedGhosts` must be moved to a spawn classification system.
40132
* Any custom code to modify spawned ghosts previously implemented in `UpdateNewPredictedEntities` or `UpdateNewInterpolatedEntities` must be moved to systems running in the `GhostSpawnSystemGroup` after `GhostSpawnSystem`. Use tag components to deterct which ghosts are new.
133+
41134
#### RPC
42135
* If your `IRpcCommand` component only uses `RpcExecutor.ExecuteCreateRequestComponent` in the execute method you can remove the implementations for `Serialize`, `Deserialize`, `CompileExecute` along with the execute method and burst function pointer for it. You also need to remove the `CommandRequestSystem` implementationf for your component. All of those will be generated by code-gen.
43136
* All RPC implementations which still needs manual serialization or execute must be changed to implement `public struct MyRequest : IComponentData, IRpcCommandSerializer<MyRequest>` instead of `public stuct MyRequest : IRpcCommand`.

Documentation~/client-server-worlds.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
NetCode has a separation of client and server logic, and both the client and server logic are in separate Worlds (the client World, and the server World), based on the [hierarchical update system](https://docs.unity3d.com/Packages/com.unity.entities@latest/index.html?subfolder=/manual/system_update_order.html) of Unity’s Entity Component System (ECS).
44

5-
By default, NetCode places systems in both client and server Worlds, but not in the default World.
5+
By default, NetCode places systems in both client and server Worlds, but not in the default World.
66
> [!NOTE]
77
> Systems that update in the `PresentationSystemGroup` are only added to the client World.
88
@@ -26,7 +26,6 @@ As well as the attributes listed above, you can use the __PlayMode Tools__ windo
2626
|**Property**|**Description**|
2727
|:---|:---|
2828
|__PlayMode Type__|Choose to make Play Mode either __Client__ only, __Server__ only, or __Client & Server__.|
29-
|__Num Clients__|Set the number of clients to run in the same process. You can run several clients in Play mode, all in separate Worlds.|
3029
|__Num Thin Clients__|Set the number of thin clients. Thin clients cannot be presented, and never spawn any entities it receives from the server. However, they can generate fake input to send to the server to simulate a realistic load.|
3130
|__Client send/recv delay__|Use this property to emulate high ping. Specify a time (in ms) to delay each outgoing and incoming network packet by. |
3231
|__Client send/recv jitter__|Use this property to add a random value to the delay, which makes the delay a value between the delay you have set plus or minus the jitter value. For example, if you set __Client send/recv delay__ to 45 and __Client send/recv jitter__ to 5, you will get a random value between 40 and 50.|
@@ -66,7 +65,7 @@ public class ExampleBootstrap : ClientServerBootstrap
6665

6766
When you use NetCode, the server always updates at a fixed timestep. NetCode limits the maximum number of iterations to make sure that the server does not end up in a state where it takes several seconds to simulate a single frame.
6867

69-
The fixed update does not use the [standard Unity update frequency](https://docs.unity3d.com/Manual/class-TimeManager.html). A singleton entity in the server World controls the update with a [ClientServerTickRate](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.ClientServerTickRate.html) component. The `ClientServerTickRate` controls `SimulationTickRate` which sets the number of simulation ticks per second.
68+
The fixed update does not use the [standard Unity update frequency](https://docs.unity3d.com/Manual/class-TimeManager.html). A singleton entity in the server World controls the update with a [ClientServerTickRate](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.ClientServerTickRate.html) component. The `ClientServerTickRate` controls `SimulationTickRate` which sets the number of simulation ticks per second.
7069

7170
> [!NOTE]
7271
> `SimulationTickRate` must be divisible by `NetworkTickRate`.
@@ -77,8 +76,10 @@ The default number of simulation ticks is 60. The component also has values for
7776
* `Sleep` for `Application.TargetFrameRate` to reduce CPU load
7877
* `Auto` to use `Sleep` on headless servers and `BusyWait` otherwise
7978

80-
By default, the client updates at a dynamic time step, with the exception of prediction code which always runs at a fixed time step to match the server. The prediction runs in the [GhostPredictionSystemGroup](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.GhostPredictionSystemGroup.html) and applies its own fixed time step for prediction. To make the client use a fixed time step, create a singleton entry with the `FixedClientTickRate` component. If you use the fixed tick rate, you can add a `CurrentSimulatedPosition` and `CurrentSimulatedRotation` component to an entity to handle render interpolation.
79+
The client updates at a dynamic time step, with the exception of prediction code which always runs at a fixed time step to match the server. The prediction runs in the [GhostPredictionSystemGroup](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.GhostPredictionSystemGroup.html) and applies its own fixed time step for prediction.
8180

8281
## Standalone builds
8382

84-
When you build a standalone game, NetCode uses the __Server Build__ property in the __Build Settings__ window to decide what to build. If the property is enabled, NetCode sets the ```UNITY_SERVER``` define and you get a server-only build. If the property is disabled you get a combined client and server build. You can use a combined client and server build to decide if a game should be client, server or both at runtime. To build a client-only game, add the ```UNITY_CLIENT``` define to the __Scripting Define Symbols__ in the __Player Settings__ (menu: __Edit &gt; Project Settings &gt; Player &gt; Configuration__). You can have the ```UNITY_CLIENT``` define set when you build a server, but the ```UNITY_SERVER``` define takes precedence and you get a server-only build.
83+
When you build a standalone game, NetCode uses the __Server Build__ property in the __Build Settings__ window to decide what to build. If the property is enabled, NetCode sets the ```UNITY_SERVER``` define and you get a server-only build. If the property is disabled you get a combined client and server build. You can use a combined client and server build to decide if a game should be client, server or both at runtime.
84+
85+
To build a client-only game, add the ```UNITY_CLIENT``` define to the __Scripting Define Symbols__ in the __Player Settings__ (menu: __Edit &gt; Project Settings &gt; Player &gt; Configuration__). You can have the ```UNITY_CLIENT``` define set when you build a server, but the ```UNITY_SERVER``` define takes precedence and you get a server-only build.

Documentation~/command-stream.md

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,60 @@
22

33
The client continuously sends a command stream to the server. This stream includes all inputs and acknowledgements of the last received snapshot. When no commands are sent a [NullCommandSendSystem](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.NullCommandSendSystem.html) sends acknowledgements for received snapshots without any inputs. This is an automatic system to make sure the flow works automatically when the game does not need to send any inputs.
44

5-
To create a new input type, create a struct that implements the `ICommandData` interface. To implement that interface you need to provide methods for accessing the `Tick` as well as `Serialize` and `Deserialize`.
5+
To create a new input type, create a struct that implements the `ICommandData` interface. To implement that interface you need to provide a property for accessing the `Tick`.
66

7-
[ICommandData](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.ICommandData-1.html) has two __Serialize__ and two __Deserialize__ methods: one pair for raw values, and one pair for delta compressed values. The system sends multiple inputs in each command packet. The first packet contains raw data but the rest are compressed using delta compression. Delta compression compresses inputs well because the rate of change is low.
8-
9-
As well as creating a struct you need to create specific instances of the generic systems `CommandSendSystem` and `CommandReceiveSystem`. To do this, extend the base system, for example with `class MyCommandSendSystem : CommandSendSystem<MyCommand>{}.`
7+
The serialization and registration code for the `ICommandData` will be generated automatically, but it is also possible to disable that and write the serialization manually.
108

119
As well as setting the input buffer on an entity, your game code must also set the [CommandTargetComponent](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.CommandTargetComponent.html) on the connection entity to reference the entity that the `ICommandData` component has been attached to.
1210

1311
You can have multiple command systems, and NetCode selects the correct one based on the `ICommandData` type of the entity that points to `CommandTargetComponent`.
1412

15-
When you need to access inputs on the client and server, it is important to read the data from the `ICommandData` rather than reading it directly from the system. If you read the data from the system the inputs won’t match between the client and server so your game will not behave as expected.
13+
When you need to access inputs on the client and server, it is important to read the data from the `ICommandData` rather than reading it directly from the system. If you read the data from the system the inputs won’t match between the client and server so your game will not behave as expected.
1614

1715
When you need to access the inputs from the buffer, you can use an extension method for `DynamicBuffer<ICommandData>` called `GetDataAtTick` which gets the matching tick for a specific frame. You can also use the `AddCommandData` utility method which adds more commands to the buffer.
16+
17+
## Manual serialization
18+
19+
In order to implement serialization manually you need to add the `[NetCodeDisableCommandCodeGen]` attribute to the struct implementing the `ICommandData` interface.
20+
21+
You will also need to create a struct implementing `ICommandDataSerializaer<T>` - where `<T>` is your `ICommandData` struct.
22+
23+
[ICommandDataSerializaer](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.ICommandDataSerializer-1.html) has two __Serialize__ and two __Deserialize__ methods: one pair for raw values, and one pair for delta compressed values. The system sends multiple inputs in each command packet. The first packet contains raw data but the rest are compressed using delta compression. Delta compression compresses inputs well because the rate of change is low.
24+
25+
As well as creating a struct you need to create specific instances of the generic systems `CommandSendSystem` and `CommandReceiveSystem`. To do this, extend the base system, for example with
26+
```c#
27+
public class MyCommandSendCommandSystem : CommandSendSystem<MyCommandSerializer, MyCommand>
28+
{
29+
[BurstCompile]
30+
struct SendJob : IJobEntityBatch
31+
{
32+
public SendJobData data;
33+
public void Execute(ArchetypeChunk chunk, int orderIndex)
34+
{
35+
data.Execute(chunk, orderIndex);
36+
}
37+
}
38+
protected override void OnUpdate()
39+
{
40+
var sendJob = new SendJob{data = InitJobData()};
41+
ScheduleJobData(sendJob);
42+
}
43+
}
44+
public class MyCommandReceiveCommandSystem : CommandReceiveSystem<MyCommandSerializer, MyCommand>
45+
{
46+
[BurstCompile]
47+
struct ReceiveJob : IJobEntityBatch
48+
{
49+
public ReceiveJobData data;
50+
public void Execute(ArchetypeChunk chunk, int orderIndex)
51+
{
52+
data.Execute(chunk, orderIndex);
53+
}
54+
}
55+
protected override void OnUpdate()
56+
{
57+
var recvJob = new ReceiveJob{data = InitJobData()};
58+
ScheduleJobData(recvJob);
59+
}
60+
}
61+
```

0 commit comments

Comments
 (0)