Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
## [1.2.0-pre.12] - 2024-02-13

### Added

* Optimisations for the gather-ghost-chunk by batching function pointer calls and using a better hash map.
* BatchScaleImportanceDelegate, a new version of the importance scaling function that work in batches. It is not required to set both the ScaleImportance and the BatchScaleImportance function pointers. If the BatchScaleImportance is set, it is the preferred.
* TempStreamInitialSize, a new parameter in the GhostSendSystemData for tuning the initial size of the temporary buffer used by server to serialise ghosts. By default now the size is 8KB.
* AlwaysRelevantQuery to specify general rules for relevancy without specifying it ghost by ghost.

### Changed

* StreamCompressionDataModel is passed as in parameter to avoid many copy every time a WriteXXX or ReadXXX was called.
* Updated Burst dependency to version 1.8.12

### Fixed

* UI issue disallowing the user from enabling the Network Emulator utility when upgrading with a now-deprecated EditorPref value.
* an issue with pre-serialised ghosts, corrupting memory, crashing or copying wrong data into the snapshot buffer in certain conditions.
* avoided GC allocation and the costly Marshal.GetDelegateFromFunctionPointer every time an FunctionPointer.Invoke is called. This is done by using directly unmanaged function pointers.  All this, compatible with Burst enabled/disabled at any time.
* lot of memory copies for loop invariants. This also reduced some SafetyChecks and costly operations.
* avoid costly re-serialization of the whole chunk when the temp buffer can't fit all the data. This is one of the biggest costs during the serialisation loop. By default now the buffer is 8KB that reduce this possibility almost to 0.
* Assigned InterpolationTick to always be equal ServerTick on the Server simulation (as stated in the summary for this parameter). Additionally the typos pointed out in the parameter summary were corrected.
* Issue where prespawn failed to initialize when relevancy list was updated before replicating internal prespawn ghosts.
  • Loading branch information
Unity Technologies committed Feb 13, 2024
1 parent b55e3ed commit 362f449
Show file tree
Hide file tree
Showing 58 changed files with 3,905 additions and 1,068 deletions.
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,31 @@ uid: changelog

# Changelog

## [1.2.0-pre.12] - 2024-02-13

### Added

* Optimisations for the gather-ghost-chunk by batching function pointer calls and using a better hash map.
* BatchScaleImportanceDelegate, a new version of the importance scaling function that work in batches. It is not required to set both the ScaleImportance and the BatchScaleImportance function pointers. If the BatchScaleImportance is set, it is the preferred.
* TempStreamInitialSize, a new parameter in the GhostSendSystemData for tuning the initial size of the temporary buffer used by server to serialise ghosts. By default now the size is 8KB.
* AlwaysRelevantQuery to specify general rules for relevancy without specifying it ghost by ghost.

### Changed

* StreamCompressionDataModel is passed as in parameter to avoid many copy every time a WriteXXX or ReadXXX was called.
* Updated Burst dependency to version 1.8.12

### Fixed

* UI issue disallowing the user from enabling the Network Emulator utility when upgrading with a now-deprecated EditorPref value.
* an issue with pre-serialised ghosts, corrupting memory, crashing or copying wrong data into the snapshot buffer in certain conditions.
* avoided GC allocation and the costly Marshal.GetDelegateFromFunctionPointer every time an FunctionPointer.Invoke is called. This is done by using directly unmanaged function pointers. All this, compatible with Burst enabled/disabled at any time.
* lot of memory copies for loop invariants. This also reduced some SafetyChecks and costly operations.
* avoid costly re-serialization of the whole chunk when the temp buffer can't fit all the data. This is one of the biggest costs during the serialisation loop. By default now the buffer is 8KB that reduce this possibility almost to 0.
* Assigned InterpolationTick to always be equal ServerTick on the Server simulation (as stated in the summary for this parameter). Additionally the typos pointed out in the parameter summary were corrected.
* Issue where prespawn failed to initialize when relevancy list was updated before replicating internal prespawn ghosts.


## [1.2.0-pre.6] - 2023-12-13

### Changed
Expand Down
55 changes: 55 additions & 0 deletions Documentation~/network-connection.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,58 @@ The request will be then consumed at runtime by the [NetworkStreamReceiveSystem]
Unity Transport provides a [SimulatorUtility](playmode-tool.md#networksimulator), which is available (and configurable) in the Netcode package. Access it via `Multiplayer > PlayMode Tools`.

We strongly recommend that you frequently test your gameplay with the simulator enabled, as it more closely resembles real-world conditions.

## Listening for Client Connection Events
We provide a `public NativeArray<NetCodeConnectionEvent>.ReadOnly ConnectionEventsForTick` collection (via the `NetworkStreamDriver` singleton), allowing you to iterate over (and thus react to) client connection events on the Client & Server.

```csharp
// Example System:
[UpdateAfter(typeof(NetworkReceiveSystemGroup))]
[BurstCompile]
public partial struct NetCodeConnectionEventListener : ISystem
{
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
var connectionEventsForClient = SystemAPI.GetSingleton<NetworkStreamDriver>().ConnectionEventsForTick;
foreach (var evt in connectionEventsForClient)
{
UnityEngine.Debug.Log($"[{state.WorldUnmanaged.Name}] {evt.ToFixedString()}!");
}
}
}
```
> [!NOTE]
> These events will only live for a single `SimulationSystemGroup` tick, and are reset during `NetworkStreamConnectSystem` and `NetworkStreamListenSystem` respectively.
> Therefore, if your system runs **_after_** these aforementioned system's job's execute, you'll receive notifications on the same tick that they were raised.
> However, if you query this collection **_before_** this system's job's execute, you'll be iterating over the **_previous_** tick's values.
> [!NOTE]
> Because the Server runs on a fixed delta-time, the `SimulationSystemGroup` may tick any number of times (including zero times) on each render frame.
> Because of this, `ConnectionEventsForTick` is only valid to be read inside a system running inside the `SimulationSystemGroup`.
> I.e. Trying to access it outside the `SimulationSystemGroup` can lead to a) either **_only_** seeing events for the current tick (meaning you miss events for previous ticks) or b) receiving events multiple times, if the simulation doesn't tick on this render frame.
> Therefore, do not access `ConnectionEventsForTick` inside the `InitializationSystemGroup`, nor inside the `PresentationSystemGroup`, nor inside any `MonoBehaviour` Unity method (non-exhaustive list!).
### NetCodeConnectionEvent's on the Client
| Connection Status | Invocation Rules |
|-------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------|
| `Unknown` | Never raised. |
| `Connecting` | Raised once for your own client, once the `NetworkStreamReceiveSystem` registers your `Connect` call (which may be one frame after you call `Connect`). |
| `Handshake` | Raised once for your own client, once your client has received a message from the server notifying your client that its connection was accepted. |
| `Connected` | Raised once for your own client, once the server sends you your `NetworkId`. |
| `Disconnected` | Raised once for your own client, once you disconnect from / timeout from / are disconnected by the server. The `DisconnectReason` will be set. |

> [!NOTE]
> Clients do **_not_** receive events for other clients. Any events raised in a client world will only be for it's own client connection.
### NetCodeConnectionEvent's on the Server
| Connection Status | Invocation Rules |
|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|
| `Unknown` | Never raised. |
| `Connecting` | Never raised on the server, as the server does not know when a client begins to connect. |
| `Handshake` | Never raised on the server, as accepted clients are assigned `NetworkId`'s immediately. I.e. Handshake is instant. |
| `Connected` | Raised once for every accepted client, on the frame the server accepts the connection (and assigns said client a `NetworkId`). |
| `Disconnected` | Raised once for every accepted client, which then disconnects, on the frame we receive the Disconnect event or state. The `DisconnectReason` will be set. |

> [!NOTE]
> The server does not raise any events when it successfully `Binds`, nor when it begins to `Listen`. Use existing APIs to query these statuses.
8 changes: 6 additions & 2 deletions Documentation~/optimizations.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,12 @@ _Note that applying this setting will cause **all** ghosts to default to **not b
* **SetIsIrrelevant** - Ghosts added to relevancy set (`GhostRelevancySet`, below) are considered "not-relevant to that client", and thus will be not serialized for the specified connection. In other words: Set this mode if you want to specifically ignore specific entities for a given client.

`GhostRelevancySet` is the map that stores a these (connection, ghost) pairs. The behaviour (of adding a (connection, ghost) item) is determined according to the above rule.

> [!NOTE]
`DefaultRelevancyQuery` is a global rule denoting that all ghost chunks matching this query are always considered relevant to all connections (unless you've added the ghosts in said chunk to the `GhostRelevancySet`). This is useful for creating general relevancy rules (e.g. "the entities in charge of tracking player scores are always relevant"). `GhostRelevancySet` takes precedence over this rule. See the [example](https://github.com/Unity-Technologies/EntityComponentSystemSamples/tree/master/NetcodeSamples/Assets/Samples/Asteroids/Authoring/Server/SetAlwaysRelevantSystem.cs) in Asteroids.
```c#
var relevancy = SystemAPI.GetSingletonRW<GhostRelevancy>();
relevancy.ValueRW.DefaultRelevancyQuery = GetEntityQuery(typeof(AsteroidScore));
```
> [!NOTE]~~~~
> If a ghost has been replicated to a client, then is set to **not be** relevant to said client, that client will be notified that this entity has been **destroyed**, and will do so. This misnomer can be confusing, as the entity being despawned does not imply the server entity was destroyed.
> Example: Despawning an enemy monster in a MOBA because it became hidden in the Fog of War should not trigger a death animation (nor S/VFX). Thus, use some other data to notify what kind of entity-destruction state your entity has entered (e.g. enabling an `IsDead`/`IsCorpse` component).
Expand Down
Loading

0 comments on commit 362f449

Please sign in to comment.