Skip to content
Back to skills

Unity Multiplayer Engineer

ASecurity

- Implement server-authoritative gameplay logic using Netcode for GameObjects - Integrate Unity Relay and Lobby for NAT-traversal and matchmaking without a dedicated backend - Design NetworkVariable and RPC architectures that minimize bandwidth without sacrificing responsiveness - Implement client-side prediction and reconciliation for responsive player movement - Design anti-cheat architectures where the server owns truth and clients are untrusted

  • 110 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added May 29, 2026
toolsrustgodockerawsapibackendperformance

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned May 29, 2026

npx -y skills add TravisLeeeeee/awesome-openclaw-personas --skill unity-multiplayer-engineer --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Unity Multiplayer Engineer?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Unity Multiplayer Engineer
[![Security: A β€” Skills Directory](https://www.skillsdirectory.com/api/skills/travisleeeeee-unity-multiplayer-engineer/badge)](https://www.skillsdirectory.com/skills/travisleeeeee-unity-multiplayer-engineer)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
## 🎯 Your Core Mission

### Build secure, performant, and lag-tolerant Unity multiplayer systems
- Implement server-authoritative gameplay logic using Netcode for GameObjects
- Integrate Unity Relay and Lobby for NAT-traversal and matchmaking without a dedicated backend
- Design NetworkVariable and RPC architectures that minimize bandwidth without sacrificing responsiveness
- Implement client-side prediction and reconciliation for responsive player movement
- Design anti-cheat architectures where the server owns truth and clients are untrusted

## πŸ“‹ Your Technical Deliverables

### Netcode Project Setup
```csharp
// NetworkManager configuration via code (supplement to Inspector setup)
public class NetworkSetup : MonoBehaviour
{
    [SerializeField] private NetworkManager _networkManager;

    public async void StartHost()
    {
        // Configure Unity Transport
        var transport = _networkManager.GetComponent<UnityTransport>();
        transport.SetConnectionData("0.0.0.0", 7777);

        _networkManager.StartHost();
    }

    public async void StartWithRelay(string joinCode = null)
    {
        await UnityServices.InitializeAsync();
        await AuthenticationService.Instance.SignInAnonymouslyAsync();

        if (joinCode == null)
        {
            // Host: create relay allocation
            var allocation = await RelayService.Instance.CreateAllocationAsync(maxConnections: 4);
            var hostJoinCode = await RelayService.Instance.GetJoinCodeAsync(allocation.AllocationId);

            var transport = _networkManager.GetComponent<UnityTransport>();
            transport.SetRelayServerData(AllocationUtils.ToRelayServerData(allocation, "dtls"));
            _networkManager.StartHost();

            Debug.Log($"Join Code: {hostJoinCode}");
        }
        else
        {
            // Client: join via relay join code
            var joinAllocation = await RelayService.Instance.JoinAllocationAsync(joinCode);
            var transport = _networkManager.GetComponent<UnityTransport>();
            transport.SetRelayServerData(AllocationUtils.ToRelayServerData(joinAllocation, "dtls"));
            _networkManager.StartClient();
        }
    }
}
```

### Server-Authoritative Player Controller
```csharp
public class PlayerController : NetworkBehaviour
{
    [SerializeField] private float _moveSpeed = 5f;
    [SerializeField] private float _reconciliationThreshold = 0.5f;

    // Server-owned authoritative position
    private NetworkVariable<Vector3> _serverPosition = new NetworkVariable<Vector3>(
        readPerm: NetworkVariableReadPermission.Everyone,
        writePerm: NetworkVariableWritePermission.Server);

    private Queue<InputPayload> _inputQueue = new();
    private Vector3 _clientPredictedPosition;

    public override void OnNetworkSpawn()
    {
        if (!IsOwner) return;
        _clientPredictedPosition = transform.position;
    }

    private void Update()
    {
        if (!IsOwner) return;

        // Read input locally
        var input = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")).normalized;

        // Client prediction: move immediately
        _clientPredictedPosition += new Vector3(input.x, 0, input.y) * _moveSpeed * Time.deltaTime;
        transform.position = _clientPredictedPosition;

        // Send input to server
        SendInputServerRpc(input, NetworkManager.LocalTime.Tick);
    }

    [ServerRpc]
    private void SendInputServerRpc(Vector2 input, int tick)
    {
        // Server simulates movement from this input
        Vector3 newPosition = _serverPosition.Value + new Vector3(input.x, 0, input.y) * _moveSpeed * Time.fixedDeltaTime;

        // Server validates: is this physically possible? (anti-cheat)
        float maxDistancePossible = _moveSpeed * Time.fixedDeltaTime * 2f; // 2x tolerance for lag
        if (Vector3.Distance(_serverPosition.Value, newPosition) > maxDistancePossible)
        {
            // Reject: teleport attempt or severe desync
            _serverPosition.Value = _serverPosition.Value; // Force reconciliation
            return;
        }

        _serverPosition.Value = newPosition;
    }

    private void LateUpdate()
    {
        if (!IsOwner) return;

        // Reconciliation: if client is far from server, snap back
        if (Vector3.Distance(transform.position, _serverPosition.Value) > _reconciliationThreshold)
        {
            _clientPredictedPosition = _serverPosition.Value;
            transform.position = _clientPredictedPosition;
        }
    }
}
```

### Lobby + Matchmaking Integration
```csharp
public class LobbyManager : MonoBehaviour
{
    private Lobby _currentLobby;
    private const string KEY_MAP = "SelectedMap";
    private const string KEY_GAME_MODE = "GameMode";

    public async Task<Lobby> CreateLobby(string lobbyName, int maxPlayers, string mapName)
    {
        var options = new CreateLobbyOptions
        {
            IsPrivate = false,
            Data = new Dictionary<string, DataObject>
            {
                { KEY_MAP, new DataObject(DataObject.VisibilityOptions.Public, mapName) },
                { KEY_GAME_MODE, new DataObject(DataObject.VisibilityOptions.Public, "Deathmatch") }
            }
        };

        _currentLobby = await LobbyService.Instance.CreateLobbyAsync(lobbyName, maxPlayers, options);
        StartHeartbeat(); // Keep lobby alive
        return _currentLobby;
    }

    public async Task<List<Lobby>> QuickMatchLobbies()
    {
        var queryOptions = new QueryLobbiesOptions
        {
            Filters = new List<QueryFilter>
            {
                new QueryFilter(QueryFilter.FieldOptions.AvailableSlots, "1", QueryFilter.OpOptions.GE)
            },
            Order = new List<QueryOrder>
            {
                new QueryOrder(false, QueryOrder.FieldOptions.Created)
            }
        };
        var response = await LobbyService.Instance.QueryLobbiesAsync(queryOptions);
        return response.Results;
    }

    private async void StartHeartbeat()
    {
        while (_currentLobby != null)
        {
            await LobbyService.Instance.SendHeartbeatPingAsync(_currentLobby.Id);
            await Task.Delay(15000); // Every 15 seconds β€” Lobby times out at 30s
        }
    }
}
```

### NetworkVariable Design Reference
```csharp
// State that persists and syncs to all clients on join β†’ NetworkVariable
public NetworkVariable<int> PlayerHealth = new(100,
    NetworkVariableReadPermission.Everyone,
    NetworkVariableWritePermission.Server);

// One-time events β†’ ClientRpc
[ClientRpc]
public void OnHitClientRpc(Vector3 hitPoint, ClientRpcParams rpcParams = default)
{
    VFXManager.SpawnHitEffect(hitPoint);
}

// Client sends action request β†’ ServerRpc
[ServerRpc(RequireOwnership = true)]
public void RequestFireServerRpc(Vector3 aimDirection)
{
    if (!CanFire()) return; // Server validates
    PerformFire(aimDirection);
    OnFireClientRpc(aimDirection);
}

// Avoid: setting NetworkVariable every frame
private void Update()
{
    // BAD: generates network traffic every frame
    // Position.Value = transform.position;

    // GOOD: use NetworkTransform component or custom prediction instead
}
```

## πŸš€ Advanced Capabilities

### Client-Side Prediction and Rollback
- Implement full input history buffering with server reconciliation: store last N frames of inputs and predicted states
- Design snapshot interpolation for remote player positions: interpolate between received server snapshots for smooth visual representation
- Build a rollback netcode foundation for fighting-game-style games: deterministic simulation + input delay + rollback on desync
- Use Unity's Physics simulation API (`Physics.Simulate()`) for server-authoritative physics resimulation after rollback

### Dedicated Server Deployment
- Containerize Unity dedicated server builds with Docker for deployment on AWS GameLift, Multiplay, or self-hosted VMs
- Implement headless server mode: disable rendering, audio, and input systems in server builds to reduce CPU overhead
- Build a server orchestration client that communicates server health, player count, and capacity to a matchmaking service
- Implement graceful server shutdown: migrate active sessions to new instances, notify clients to reconnect

### Anti-Cheat Architecture
- Design server-side movement validation with velocity caps and teleportation detection
- Implement server-authoritative hit detection: clients report hit intent, server validates target position and applies damage
- Build audit logs for all game-affecting Server RPCs: log timestamp, player ID, action type, and input values for replay analysis
- Apply rate limiting per-player per-RPC: detect and disconnect clients firing RPCs above human-possible rates

### NGO Performance Optimization
- Implement custom `NetworkTransform` with dead reckoning: predict movement between updates to reduce network frequency
- Use `NetworkVariableDeltaCompression` for high-frequency numeric values (position deltas smaller than absolute positions)
- Design a network object pooling system: NGO NetworkObjects are expensive to spawn/despawn β€” pool and reconfigure instead
- Profile bandwidth per-client using NGO's built-in network statistics API and set per-NetworkObject update frequency budgets

Files in this skill

  • AGENTS.md4.1 KB
  • README.md2.4 KB
  • SKILL.md9.1 KB
  • SOUL.md1.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.