# Netcode (Unity) — SDK methods

> Install com.clutchcall.transport via UPM, swap UnityTransport for ClutchCallTransport, and the inspector + UTP surface.

The netcode SDK is a **Unity Package Manager (UPM)** package, not a typed
client library. You install it, drop one component in place of `UnityTransport`,
and Unity Netcode drives it through the standard `INetworkInterface` surface.
Configuration is done in the **inspector** (or in C#), and the public method
surface is **UTP's own** — the package forwards it to the QUIC + MoQT substrate.

## Install (UPM git URL)

Add the package to your Unity project via **Package Manager → Add package from
git URL**:

**Git URL:**
```text
https://github.com/clutchcall/core-sdk.git?path=unity/com.clutchcall.transport
```

**manifest.json:**
```json
{
  "dependencies": {
    "com.clutchcall.transport": "https://github.com/clutchcall/core-sdk.git?path=unity/com.clutchcall.transport",
    "com.unity.netcode.gameobjects": "1.x"
  }
}
```

> **NOTE:**
> The package depends on `com.unity.transport` (it implements UTP's
> `INetworkInterface`) and works with both **Netcode for GameObjects** and
> **Netcode for Entities**. Pin Netcode to a version compatible with your Unity
> editor; the transport tracks UTP's stable interface, not a specific Netcode
> release.

## Swap the transport

In your network manager prefab, **remove `UnityTransport` and add
`ClutchCallTransport`** as the transport component. Unity Netcode discovers it
the same way it discovers UTP, so no other wiring changes.

  1. **Select the NetworkManager**
Open the prefab (or scene object) that holds your `NetworkManager`.
  2. **Replace the transport component**
Remove the existing `UnityTransport` component and add
    `ClutchCallTransport`. If `NetworkManager.NetworkConfig.NetworkTransport`
    referenced the old component, point it at the new one.
  3. **Configure relay host + token**
Set the relay host and an auth token in the inspector — the same way you'd
    configure a relay endpoint for UTP.

## Component: `ClutchCallTransport`

`ClutchCallTransport` is a `NetworkTransport` (Netcode) that implements UTP's
`INetworkInterface`. It is the only type you reference directly; everything else
is standard Netcode.

### Inspector fields

<ParamField path="Relay Host" type="string" required>
  The ClutchCall relay endpoint, e.g. `relay.clutchcall.dev`. Players dial the
  nearest POP behind this host.
</ParamField>

<ParamField path="Token" type="string" required>
  The ClutchCall auth token authorizing the QUIC session. Mint a short-lived,
  room-scoped token from your control-plane API rather than shipping a static
  secret in the build.
</ParamField>

<ParamField path="Room Id" type="string">
  The room / match namespace this player joins. Host and clients of the same
  match share one `Room Id`.
</ParamField>

<ParamField path="Server Certificate Hash" type="string">
  Optional pinned certificate hash for the relay's TLS 1.3 certificate, for
  environments that pin instead of using the public trust store.
</ParamField>

<ParamField path="Max Datagram Size" type="int" default="path MTU">
  Upper bound for the unreliable (QUIC datagram) channel. Reads back through
  `MaxPayloadSize()`; payloads larger than this are rejected, not fragmented.
</ParamField>

### Configure from C#

You can set the same fields in code before `StartHost` / `StartClient`:

```csharp
using Unity.Netcode;
using ClutchCall.Transport; // namespace shipped by com.clutchcall.transport

var nm = GetComponent<NetworkManager>();
var transport = nm.GetComponent<ClutchCallTransport>();

transport.RelayHost = "relay.clutchcall.dev";
transport.Token     = await FetchRoomTokenAsync("duel-42", "alice");
transport.RoomId    = "duel-42";

// Host (authority) vs client is chosen by Netcode, not the transport:
nm.StartHost();   // or nm.StartClient();
```

## UTP method surface

Because the package implements `INetworkInterface`, the methods you call are
**Unity Netcode / UTP methods** — the transport forwards each to the QUIC + MoQT
substrate. The ones that matter for porting:

| UTP / Netcode call | What the transport does |
| ------------------ | ----------------------- |
| `StartHost()` / `StartServer()` | opens the **authority namespace** on the relay |
| `StartClient()` | publishes a **discovery namespace** + per-peer channels, announces to the host |
| `Send(..., NetworkDelivery)` | maps **reliable** delivery to a subgroup stream, **unreliable** to a QUIC datagram |
| `GetCurrentRtt(clientId)` | returns the QUIC transport's **smoothed RTT** in ms |
| `MaxPayloadSize()` | returns the live **max datagram size** for the unreliable lane |
| `DisconnectLocalClient()` / `DisconnectRemoteClient()` | drops the session; the peer leaves every roster via namespace teardown |
| `Shutdown()` | closes the QUIC connection and all tracks |

### NetworkDelivery → lane mapping

Unity's `NetworkDelivery` enum selects the lane:

| `NetworkDelivery` | Lane |
| ----------------- | ---- |
| `Reliable`, `ReliableSequenced`, `ReliableFragmentedSequenced` | MoQT subgroup stream (ordered, guaranteed) |
| `Unreliable`, `UnreliableSequenced` | QUIC datagram (lossy, latest-wins) |

> **TIP:**
> Send high-frequency, latest-wins traffic (transforms, tick snapshots, inputs) as
> `Unreliable`, and reserve `Reliable*` for spawns, despawns, and RPCs. This is the
> same discipline you'd apply with UTP — the transport just realizes each lane over
> QUIC instead of UDP.

## Events

The transport surfaces connection lifecycle through Netcode's standard callbacks
— you do not subscribe to transport-specific events:

| Netcode callback | Fires when |
| ---------------- | ---------- |
| `NetworkManager.OnClientConnectedCallback` | a peer's discovery namespace is announced and accepted |
| `NetworkManager.OnClientDisconnectCallback` | a peer's session drops / namespace tears down |
| `NetworkManager.OnServerStarted` | the authority namespace is open |
| `NetworkManager.OnTransportFailure` | the QUIC session fails unrecoverably |

```csharp
nm.OnClientConnectedCallback += id => Debug.Log($"peer joined: {id}");
nm.OnClientDisconnectCallback += id => Debug.Log($"peer left: {id}");
```

## Non-Unity engines

The Unity component is a thin wrapper over a shared C++ **star session**
(host + N peers with reliable + unreliable + discovery). To integrate a non-Unity
engine you implement a handful of engine-side hooks — **discovery**, **RTT**,
**max-datagram**, **capture-time telemetry**, and the **datagram-lane mapping** —
and reuse the rest of the session machinery. For a fully typed, language-native
surface (TypeScript / Python / Go / Rust / Java / C#) without Unity, use the
**[Games SDK](/modalities/games/sdk-methods)**, which exposes the same
`state` / `input` / `event` channels directly.

  <Tab title="TypeScript">
    ```ts
    import { Games } from "@clutchcall/sdk/games";

    const me = new Games({
      relayHost: "relay.clutchcall.dev",
      token:     await fetchRoomToken("duel-42", "alice"),
      roomId:    "duel-42",
      playerId:  "alice",
    });
    me.subscribeState(bytes => render(deserialize(bytes)));
    const input = await me.publishInput();
    ```
  </Tab>
  <Tab title="Python">
    ```python
    from clutchcall.games import Games

    me = Games(relay_host="relay.clutchcall.dev",
               token=fetch_room_token("duel-42", "alice"),
               room_id="duel-42", player_id="alice")
    me.subscribe_state(lambda b: render(deserialize(b)))
    inp = me.publish_input()
    ```
  </Tab>

## Related

  - **[Cookbook](/modalities/netcode/cookbook)** — Copy-paste snippets for the common porting tasks.
  - **[Games SDK](/modalities/games/sdk-methods)** — The typed, non-Unity surface for the same wire model.
