diff --git a/Examples/DocumentationExamples/NetworkVariable/DoorExample.cs b/Examples/DocumentationExamples/NetworkVariable/DoorExample.cs
new file mode 100644
index 0000000000..d80ec1bae0
--- /dev/null
+++ b/Examples/DocumentationExamples/NetworkVariable/DoorExample.cs
@@ -0,0 +1,273 @@
+using System.Runtime.CompilerServices;
+using Unity.Netcode;
+using UnityEngine;
+
+///
+/// Example of using a to drive changes
+/// in state.
+///
+///
+/// This is a simple state driven door example.
+/// This script was written with recommended usages patterns in mind.
+///
+public class Door : NetworkBehaviour, INetworkUpdateSystem
+{
+ ///
+ /// The two door states.
+ ///
+ public enum DoorStates
+ {
+ Closed,
+ Open
+ }
+
+ ///
+ /// Initializes the door to a specific state (server side) when first spawned.
+ ///
+ [Tooltip("Configures the door's initial state when 1st spawned.")]
+ public DoorStates InitialState = DoorStates.Closed;
+
+ ///
+ /// Used for example purposes.
+ /// When true, only the server can open and close the door.
+ /// Clients will receive a console log saying they could not open the door.
+ ///
+ public bool IsLocked;
+
+ ///
+ /// A simple door state where the server has write permissions and everyone has read permissions.
+ ///
+ private NetworkVariable m_State = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server);
+
+ ///
+ /// The current state of the door.
+ ///
+ public DoorStates CurrentState => m_State.Value;
+
+ ///
+ /// Invoked while the is in the middle of
+ /// being spawned.
+ ///
+ public override void OnNetworkSpawn()
+ {
+ // The write authority (server) does not need to know about its
+ // own changes (for this example) since it is the "single point
+ // of truth" for the door instance.
+ if (IsServer)
+ {
+ // Host/Server:
+ // Applies the configurable state upon spawning.
+ m_State.Value = InitialState;
+ }
+ else
+ {
+ // Clients:
+ // Subscribe to changes in the door's state.
+ m_State.OnValueChanged += OnStateChanged;
+ }
+ }
+
+ ///
+ /// Invoked once the door and all associated components
+ /// have finished the spawn process.
+ ///
+ protected override void OnNetworkPostSpawn()
+ {
+ // Everyone updates their door state when finished spawning the door
+ // in order to assure the door reflects (visually) its current state.
+ UpdateFromState();
+
+ // Begin to start updating this NetworkBehaviour instance once all
+ // netcode related components have finished the spawn process.
+ NetworkUpdateLoop.RegisterNetworkUpdate(this, NetworkUpdateStage.Update);
+ base.OnNetworkPostSpawn();
+ }
+
+ ///
+ /// Example of using the usage pattern
+ /// where it only updates while spawned.
+ ///
+ /// The current update stage being invoked.
+ public void NetworkUpdate(NetworkUpdateStage updateStage)
+ {
+ switch (updateStage)
+ {
+ case NetworkUpdateStage.Update:
+ {
+ if (Input.GetKeyDown(KeyCode.Space))
+ {
+ Interact();
+ }
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Invoked just before this instance runs through its de-spawn
+ /// sequence. A good time to unsubscribe from things.
+ ///
+ public override void OnNetworkPreDespawn()
+ {
+ if (!IsServer)
+ {
+ m_State.OnValueChanged -= OnStateChanged;
+ }
+
+ // Stop updating this NetworkBehaviour instance prior to running
+ // through the de-spawn process.
+ NetworkUpdateLoop.RegisterNetworkUpdate(this, NetworkUpdateStage.Update);
+ base.OnNetworkPreDespawn();
+ }
+
+ ///
+ /// Server makes changes to the state.
+ /// Clients receive the changes in state.
+ ///
+ ///
+ /// When the previous state equals the current state, we are a client
+ /// that is doing its 1st synchronization of this door instance.
+ ///
+ /// The previous state.
+ /// The current state.
+ public void OnStateChanged(DoorStates previous, DoorStates current)
+ {
+ UpdateFromState();
+ }
+
+ ///
+ /// Invoke when the state is updated in order to apply the change
+ /// in door state to the door asset itself.
+ ///
+ private void UpdateFromState()
+ {
+ switch(m_State.Value)
+ {
+ case DoorStates.Closed:
+ {
+ // door is open:
+ // - rotate door transform
+ // - play animations, sound etc.
+ ///
+ /// Override to apply specific checks (like a player having the right
+ /// key to open the door) or make it a non-virtual class and add logic
+ /// directly to this method.
+ ///
+ /// The player attempting to open the door.
+ ///
+ protected virtual bool CanPlayerToggleState(NetworkObject player)
+ {
+ // For this example, if the door "is locked" then clients will
+ // not be able to open the door but the host-client's player can.
+ return !IsLocked || player.IsOwnedByServer;
+ }
+
+ ///
+ /// Invoked by either a Host or clients to interact with the door.
+ ///
+ public void Interact()
+ {
+ // Optional:
+ // This is only if you want clients to be able to
+ // interact with doors. A dedicated server would not
+ // be able to do this since it does not have a player.
+ if (IsServer && !IsHost)
+ {
+ // Optional to log a warning about this.
+ return;
+ }
+
+ if (IsHost)
+ {
+ ToggleState(NetworkManager.LocalClientId);
+ }
+ else
+ {
+ // Clients send an RPC to server (write authority) who applies the
+ // change in state that will be synchronized with all client observers.
+ ToggleStateRpc();
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private DoorStates NextToggleState()
+ {
+ return m_State.Value == DoorStates.Open ? DoorStates.Closed : DoorStates.Open;
+ }
+
+ ///
+ /// Invoked only server-side
+ /// Primary method to handle toggling the door state.
+ ///
+ /// The client toggling the door state.
+ private void ToggleState(ulong clientId)
+ {
+ // Get the server-side client player instance
+ var playerObject = NetworkManager.SpawnManager.GetPlayerNetworkObject(clientId);
+ if (playerObject != null)
+ {
+ var nextToggleState = NextToggleState();
+ if (CanPlayerToggleState(playerObject))
+ {
+ // Host toggles the state
+ m_State.Value = nextToggleState;
+ UpdateFromState();
+ }
+ else
+ {
+ ToggleStateFailRpc(nextToggleState, RpcTarget.Single(clientId, RpcTargetUse.Temp));
+ }
+ }
+ else
+ {
+ // Optional as to how you handle this. Since ToggleState is only invoked by
+ // sever-side only script, this could mean many things depending upon whether
+ // or not a client could interact with something and not have a player object.
+ // If that is the case, then don't even bother checking for a player object.
+ // If that is not the case, then there could be a timing issue between when
+ // something can be "interacted with" and when a player is about to be de-spawned.
+ // For this example, we just log a warning as this example was built with
+ // the requirement that a client has a spawned player object that is used for
+ // reference to determine if the client's player can toggle the state of the
+ // door or not.
+ NetworkLog.LogWarningServer($"Client-{clientId} has no spawned player object!");
+ }
+ }
+
+ ///
+ /// Invoked by clients.
+ /// Re-directs to the common method.
+ ///
+ /// includes that is automatically populated for you.
+ [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
+ private void ToggleStateRpc(RpcParams rpcParams = default)
+ {
+ ToggleState(rpcParams.Receive.SenderClientId);
+ }
+
+ ///
+ /// Optional:
+ /// Handling when a player cannot open a door.
+ ///
+ /// includes that is automatically populated for you.
+ [Rpc(SendTo.SpecifiedInParams, InvokePermission = RpcInvokePermission.Server)]
+ private void ToggleStateFailRpc(DoorStates doorState, RpcParams rpcParams = default)
+ {
+ // Provide player feedback that toggling failed.
+ Debug.Log($"Failed to {doorState} the door!");
+ }
+}
diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md
index 063b6c3375..9d1075d0b3 100644
--- a/com.unity.netcode.gameobjects/CHANGELOG.md
+++ b/com.unity.netcode.gameobjects/CHANGELOG.md
@@ -22,7 +22,6 @@ Additional documentation and release notes are available at [Multiplayer Documen
### Fixed
-- Fixed issue where if the `NetworkManager` player prefab is not assigned an exception is thrown upon starting a host and/or when a client joins. (#3965)
### Security
@@ -30,6 +29,12 @@ Additional documentation and release notes are available at [Multiplayer Documen
### Obsolete
+### [2.11.2] - 2026-05-01
+
+### Fixed
+
+- Fixed issue where if the `NetworkManager` player prefab is not assigned an exception is thrown upon starting a host and/or when a client joins. (#3965)
+
## [2.11.1] - 2026-04-26
### Changed
diff --git a/com.unity.netcode.gameobjects/package.json b/com.unity.netcode.gameobjects/package.json
index d4a1bf74c6..04492deaa0 100644
--- a/com.unity.netcode.gameobjects/package.json
+++ b/com.unity.netcode.gameobjects/package.json
@@ -2,7 +2,7 @@
"name": "com.unity.netcode.gameobjects",
"displayName": "Netcode for GameObjects",
"description": "Netcode for GameObjects is a high-level netcode SDK that provides networking capabilities to GameObject/MonoBehaviour workflows within Unity and sits on top of underlying transport layer.",
- "version": "2.11.2",
+ "version": "2.11.3",
"unity": "6000.0",
"dependencies": {
"com.unity.nuget.mono-cecil": "1.11.4",