### Full Game Guides Source: https://github.com/purrnet/purrdocs/blob/main/SUMMARY.md Guides and samples for building different types of full games using PurrNet. ```APIDOC ## Full Game Guides ### Overview This section provides guides and sample projects for creating various types of games using PurrNet. ### Game Samples * **Incremental Game Sample**: A guide to creating an incremental game. * **First Person Shooter**: A guide for developing a first-person shooter. * **Survival Game**: A guide for building a survival game. ``` -------------------------------- ### Steam Transport Setup Source: https://github.com/purrnet/purrdocs/blob/main/SUMMARY.md Guides on setting up Steam transport for PurrNet. ```APIDOC ## GET /guides/steam-setup/connect-with-steam.md ### Description Provides instructions on how to connect with Steam using PurrNet. ### Method GET ### Endpoint /guides/steam-setup/connect-with-steam.md ### Parameters #### Query Parameters None ### Request Example None ### Response #### Success Response (200) - **content** (string) - The content of the Steam transport setup guide. #### Response Example { "content": "# Connect with Steam\n... (rest of the markdown content)" } ``` -------------------------------- ### Movement SyncInput Example (C#) Source: https://github.com/purrnet/purrdocs/blob/main/systems-and-modules/network-modules/sync-types/syncinput.md An example demonstrating how to use SyncInput for movement and SyncInput for jumping in a networked environment. It requires a Rigidbody, collider, and a network transform component. Physics-based movement is handled on the server. ```csharp using UnityEngine; public class MovementSyncExample : MonoBehaviour { [SerializeField] private Rigidbody _rigidbody; [SerializeField] private float _moveSpeed = 5f; [SerializeField] private float _jumpForce = 5f; [SerializeField] private SyncInput _moveInput = new(); [SerializeField] private SyncInput _jumpInput = new(); private bool _jump; private void Awake() { _jumpInput.onChanged += OnJump; _jumpInput.onSentData += OnSentData; } private void OnDestroy() { _jumpInput.onChanged -= OnJump; _jumpInput.onSentData -= OnSentData; } private void OnSentData() { _jump = false; } private void OnJump(bool newInput) { if(newInput) _rigidbody.AddForce(Vector3.up * _jumpForce, ForceMode.Impulse); } private void Update() { if (!isOwner) return; _moveInput.value = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical")); if(!_jump) _jump = Input.GetKeyDown(KeyCode.Space); _jumpInput.value = _jump; } private void FixedUpdate() { if (!isServer) return; Vector3 move = new Vector3(_moveInput.value.x, 0, _moveInput.value.y).normalized; _rigidbody.AddForce(move * _moveSpeed); } } ``` -------------------------------- ### Register, Unregister, and Get Instances (C#) Source: https://github.com/purrnet/purrdocs/blob/main/systems-and-modules/instance-handler.md Provides a comprehensive example of using the Instance Handler to register and unregister custom instances, such as GameManager. It also shows how to retrieve these instances from static methods, with examples for both direct retrieval and a safer try-get approach. ```csharp public class GameManager : NetworkBehaviour { private void Awake() { //We register the GameManager instance InstanceHandler.RegisterInstance(this); } private void OnDestroy() { //Upon being destroyed, we unregister the game manager instance InstanceHandler.UnregisterInstance(); } private static void GetInstanceExample() { //This will fail if the manager isn't registered InstanceHandler.GetInstance().Success(); } private static void TryGetInstanceExample() { //This will only run if we get the manager. Potentially invert the if statement and log and error if you don't get it if(InstanceHandler.TryGetInstance(out GameManager manager)) manager.Success(); } private void Success() { Debug.Log("Now we're logging from the GameManager instance!", this); } } ``` -------------------------------- ### Basic SyncInput Usage Example (C#) Source: https://github.com/purrnet/purrdocs/blob/main/systems-and-modules/network-modules/sync-types/syncinput.md A simple example of using SyncInput to synchronize player input. It includes subscribing and unsubscribing to the onChanged event, and updating the input value in the Update loop. The event is only triggered on the server. ```csharp using UnityEngine; public class SyncInputExample : MonoBehaviour { [SerializeField] private SyncInput _input = new(); private void Awake() { //Subscribe to the input change event _input.onChanged += OnInputChanged; } private void OnDestroy() { //Unsubscribe again _input.onChanged -= OnInputChanged; } private void OnInputChanged(Vector2 newInput) { //Only the server will receive this event //The event will be called whenever input changes Debug.Log($"New input: {newInput}"); } private void Update() { if (!isOwner) return; //The owner will consistently send input - Only the necessary input changes will be sent //Rest is automatically filtered by the SyncInput var input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical")); _input.value = input; } } ``` -------------------------------- ### Initialize and Use SyncQueue in C# Source: https://github.com/purrnet/purrdocs/blob/main/systems-and-modules/network-modules/sync-types/synclist-1-1.md Demonstrates how to create, initialize, and use a SyncQueue in C#. It covers subscribing to change events, enqueuing, dequeuing, clearing, and peeking at elements. Requires Network Module setup. ```csharp using UnityEngine; public class SyncQueueExample : MonoBehaviour { [SerializeField] private SyncQueue myQueue = new(true); protected override void OnSpawned() { myQueue.onChanged += OnQueueChanged; } private void OnQueueChanged(SyncQueueChange change) { Debug.Log($"Queue updated: {change}"); } private void ChangeMyQueue() { myQueue.Enqueue(69); myQueue.Dequeue(); myQueue.Clear(); var myVal = myQueue.Peek(); } } ``` -------------------------------- ### SyncEvent Usage Example in C# Source: https://github.com/purrnet/purrdocs/blob/main/systems-and-modules/network-modules/sync-types/syncevent.md Demonstrates how to create, initialize, listen to, and invoke a SyncEvent in C#. It highlights owner authority for invoking events and how listeners receive invoked values. ```csharp using UnityEngine; public class SyncEventExample : MonoBehaviour { // Creates an instance of the event - True means that it is owner authority [SerializeField] private SyncEvent syncEvent = new(true); protected virtual void OnSpawned() { // Listening to the event syncEvent.AddListener(SyncEventTest); } private void SyncEventTest(int myValue) { // Everyone subscribed to the syncEvent will receive this value when the owner invokes it Debug.Log($"Received value: {myValue} from SyncEvent"); } public void InvokeSyncEvent() { // Because the event is owner auth, only the owner can call the event. if (!isOwner) return; // Invoking the event as the owner with the value 10 syncEvent.Invoke(10); } } ``` -------------------------------- ### SyncDictionary C# Usage Example Source: https://github.com/purrnet/purrdocs/blob/main/systems-and-modules/network-modules/sync-types/syncdictionary.md Demonstrates how to create, initialize, and interact with a SyncDictionary in C#. It includes subscribing to change events and performing operations like adding, removing, clearing, and marking keys as dirty. Requires the Network Module to be set up. ```csharp using UnityEngine; public class SyncDictionaryExample : MonoBehaviour { // Creates a new instance of the dictionary - `true` means it is owner auth. [SerializeField] private SyncDictionary myDictionary = new SyncDictionary(true); protected virtual void OnSpawned() { // Subscribing to changes made to the dictionary myDictionary.onChanged += OnDictionaryChanged; } private void OnDictionaryChanged(SyncDictionaryChange change) { // This is called for everyone when the dictionary changes. // It will log out the Key, Value and operation Debug.Log($"Dictionary updated: {change}"); } private void ChangeMyDictionary() { // This will change or add a value to the dictionary myDictionary[123] = 0.69f; // This will remove the value from the dictionary myDictionary.Remove(123); // This will clear the dictionary myDictionary.Clear(); // This will mark the key as dirty myDictionary.SetDirty(123); } } ``` -------------------------------- ### Generic RPC Example in C# Source: https://github.com/purrnet/purrdocs/blob/main/systems-and-modules/remote-procedure-call-rpc/generic-rpc.md Demonstrates sending different data types using generic RPCs in PurrNet. This example utilizes ServerRpc to receive two generic parameters of potentially different types. ```csharp private void SendFirst() { TestRpc("Purrfect!", true); } private void SendSecond() { TestRpc(69, 4.20f); } [ServerRpc] private void TestRpc(T myData1, P myData2) { Debug.Log($"Received {myData1} with type of: {myData1.GetType()}"); Debug.Log($"Received {myData2} with type of: {myData2.GetType()}"); } ``` -------------------------------- ### Set up Edgegap for Game Server Hosting Source: https://github.com/purrnet/purrdocs/blob/main/SUMMARY.md This guide outlines the process of setting up Edgegap for hosting your game servers, leveraging PurrNet for network communication. It details the integration steps required to deploy your game with Edgegap. ```csharp using PurrNet; using UnityEngine; public class EdgegapSetup : MonoBehaviour { void Start() { // Configure PurrNet to use Edgegap's network infrastructure // This might involve setting specific IP addresses or ports provided by Edgegap // ... Edgegap configuration ... // Start PurrNet server or client based on Edgegap's role PurrNetManager.Instance.StartServer(); // or StartClient() } } ``` -------------------------------- ### Deterministic Identity Example in C# Source: https://github.com/purrnet/purrdocs/blob/main/client-side-prediction/deterministic-identity.md Demonstrates the implementation of a custom Oscillator using DeterministicIdentity. It defines the state structure, initial state, and the core simulation logic using sfloat for deterministic calculations. The example also shows how to handle Unity state synchronization and view updates. ```csharp using PurrNet.Prediction; public struct OscState : IPredictedData { public sfloat phase; public sfloat speed; public sfloat amplitude; public void Dispose() {} } public class Oscillator : DeterministicIdentity { protected override OscState GetInitialState() => new OscState { speed = (sfloat)1.5f, amplitude = (sfloat)2f, phase = 0 }; protected override void GetUnityState(ref OscState s) { /* read if needed */ } protected override void SetUnityState(OscState s) { /* apply on rollback if needed */ } protected override void Simulate(ref OscState s, sfloat dt) { s.phase += s.speed * dt; var y = sfloat.Sin(s.phase) * s.amplitude; // use y for downstream deterministic effects; drive visuals in UpdateView } protected override void UpdateView(OscState view, OscState? verified) { // Convert to float for rendering only } } ``` -------------------------------- ### Initialize and Use SyncList in C# Source: https://github.com/purrnet/purrdocs/blob/main/systems-and-modules/network-modules/sync-types/synclist.md Demonstrates how to create, initialize, and interact with a SyncList in C#. It covers subscribing to list changes, modifying list elements, and various list operations like adding, removing, and clearing. Requires the Network Module setup. ```csharp using UnityEngine; public class SyncListExample : MonoBehaviour { // Creates a new instance of the list - `true` means it is owner auth. [SerializeField] private SyncList myList = new SyncList(true); protected void OnSpawned() { // Subscribing to changes made to the list myList.onChanged += OnListChanged; } private void OnListChanged(SyncListChange change) { // This is called for everyone when the list changes. // It will log out the value, index and operation Debug.Log($"List updated: {change.operation}, Value: {change.value}, Index: {change.index}"); } private void ChangeMyList() { // This will change or add a value if (myList.Count > 0) { myList[0] = 69; } else { myList.Add(69); } // This will remove the value myList.Remove(69); // This will remove the entry at the given index if (myList.Count > 0) { myList.RemoveAt(0); } // This will clear the list myList.Clear(); // This will insert a value at the given index myList.Insert(1, 420); // This will mark the index as dirty if (myList.Count > 0) { myList.SetDirty(0); } } } // Assuming SyncList and SyncListChange are defined elsewhere in the project public class SyncList : System.Collections.Generic.List { public delegate void OnChangedCallback(SyncListChange change); public event OnChangedCallback onChanged; public SyncList(bool ownerAuth) { /* ... initialization ... */ } public void SetDirty(int index) { /* ... */ } public void Add(T item) { /* ... */ OnChanged(new SyncListChange { operation = SyncListOperation.Added, value = item, index = this.Count - 1 }); } public void Remove(T item) { /* ... */ } public void RemoveAt(int index) { /* ... */ } public void Clear() { /* ... */ } public void Insert(int index, T item) { /* ... */ } protected virtual void OnChanged(SyncListChange change) { onChanged?.Invoke(change); } } public enum SyncListOperation { Added, Removed, Set, Cleared, Insert } public struct SyncListChange { public SyncListOperation operation; public T value; public int index; } ``` -------------------------------- ### Addons - Lobby System - Making your own provider Source: https://github.com/purrnet/purrdocs/blob/main/SUMMARY.md Guide on creating custom providers for the Lobby System. ```APIDOC ## GET /addons/lobby-system/making-your-own-provider.md ### Description Instructions on how to develop custom providers for the Lobby System addon. ### Method GET ### Endpoint /addons/lobby-system/making-your-own-provider.md ### Parameters #### Query Parameters None ### Request Example None ### Response #### Success Response (200) - **content** (string) - The content of the custom provider guide. #### Response Example { "content": "# Making Your Own Lobby Provider\n... (rest of the markdown content)" } ``` -------------------------------- ### Minimal State Machine Example (C#) Source: https://github.com/purrnet/purrdocs/blob/main/client-side-prediction/predicted-state-machine/README.md Demonstrates the creation of a minimal predicted state machine with an idle state and a move state. Includes examples of state transitions within a predicted identity. ```csharp public class IdleState : PredictedStateNode { public override void Enter() { /* start idle anim */ } protected override void StateSimulate(ref MyState s, float dt) { /* no-op */ } } public class MoveState : PredictedStateNode { protected override void StateSimulate(in MyInput i, ref MyState s, float dt) { s.velocity = new Vector3(i.x, 0, i.y) * s.speed; } } void HandleTransitions() { if (/* want next */) machine.Next(); if (/* want specific */) machine.SetState(mySpecificNode); } ``` -------------------------------- ### Install PurrDiction using OpenUPM Source: https://github.com/purrnet/purrdocs/blob/main/client-side-prediction/installation.md This command installs the PurrDiction package using the OpenUPM package manager. This is an alternative to direct Git installation. Ensure you have OpenUPM configured in your Unity project. PurrNet v1.14.0 or higher is a prerequisite. ```shell openupm add dev.purrnet.purrdiction ``` -------------------------------- ### Initialize and Use SyncHashSet in C# Source: https://github.com/purrnet/purrdocs/blob/main/systems-and-modules/network-modules/sync-types/synchashset.md Demonstrates how to create, initialize, and subscribe to changes in a SyncHashSet. It highlights owner authority and the callback mechanism for updates. Requires the Network Module. ```csharp using UnityEngine; public class ExampleSyncHashSet : MonoBehaviour { // Creates a new instance of the Hashset - `true` means it is owner auth. [SerializeField] private SyncHashSet myHashSet = new(true); protected override void OnSpawned() { // Subscribing to changes made to the hash set myHashSet.onChanged += OnHashSetChanged; } private void OnHashSetChanged(SyncHashSetChange change) { // This is called for everyone when the hash set changes. // It will log out the Value and operation Debug.Log($"HashSet updated: {change}"); } } ``` -------------------------------- ### PlayerIdentity C# Example Usage Source: https://github.com/purrnet/purrdocs/blob/main/systems-and-modules/network-identity/playeridentity.md Demonstrates how to use PlayerIdentity to get local players, specific players by ID, and all registered players. This example shows teleportation functionality for different player scenarios. ```csharp public class PlayerMovement : PlayerIdentity { public void Teleport(Vector3 destination) { //Do whatever to teleport here } } public class GameManager : NetworkIdentity { [SerializeField] private Transform teleportDestination; public void TeleportPlayer(PlayerID targetPlayer) { //Returns true if it finds the player if (!PlayerMovement.TryGetPlayer(targetPlayer, out var player)) return; player.Teleport(teleportDestination.position); } public void TeleportLocalPlayer() { //Returns true if it finds the local player if (!PlayerMovement.TryGetLocal(out var player)) return; player.Teleport(teleportDestination.position); } public void TeleportAllPlayers() { //allPlayers gives you a dictionary of all the players registered foreach (var player in PlayerMovement.allPlayers) { player.value.Teleport(teleportDestination.position); } } } ``` -------------------------------- ### Start Host Connection with SteamTransport Source: https://github.com/purrnet/purrdocs/blob/main/guides/steam-setup/connect-with-steam.md Initiates a host connection using PurrNet's StartHost() method. It configures the SteamTransport with peer-to-peer and non-dedicated server settings, using user data for the host's Steam account ID. Steam must be initialized before calling this method. ```csharp /// /// This method is responsible for calling PurrNet's StartHost() method. It also gets and configures the /// SteamTransport. It also leverages a UserData struct from Heathens to store the Steam account ID of the host. /// /// /// Feel free to make this method public or private depending on your need. Steam must be initialized before /// this method is called. /// public void StartHost() { var steamTransport = NetworkManager.main.transport as SteamTransport; if (steamTransport == null) { Debug.LogError("SteamTransport missing on NetworkManager", this); return; } // This is a Heathens API call. var user = UserData.Get(); steamTransport.peerToPeer = true; steamTransport.dedicatedServer = false; steamTransport.address = user.id.ToString(); NetworkManager.main.StartHost(); } ``` -------------------------------- ### Add PurrDiction via Git URL (Release Branch) Source: https://github.com/purrnet/purrdocs/blob/main/client-side-prediction/installation.md This code snippet demonstrates how to add the PurrDiction package to your Unity project using a Git URL, specifically targeting the 'release' branch. This method requires Git to be installed on your system. Ensure you have PurrNet v1.14.0 or higher installed. ```clike https://github.com/PurrNet/PurrDiction.git?path=/Assets/PurrDiction#release ``` -------------------------------- ### Add PurrDiction via Git URL (Development Branch) Source: https://github.com/purrnet/purrdocs/blob/main/client-side-prediction/installation.md This code snippet shows how to add the PurrDiction package using a Git URL, targeting the 'dev' branch for the latest features. While this provides access to newer functionalities, it may compromise stability. Git must be installed, and PurrNet v1.14.0+ is required. ```clike https://github.com/PurrNet/PurrDiction.git?path=/Assets/PurrDiction#dev ``` -------------------------------- ### Start Client Connection with SteamTransport Source: https://github.com/purrnet/purrdocs/blob/main/guides/steam-setup/connect-with-steam.md Initiates a client connection using PurrNet's StartClient() method. It configures the SteamTransport and uses a provided Steam ID to connect to a host. Input validation is performed on the Steam ID. Steam must be initialized before calling this method. ```csharp /// /// This method is responsible for calling PurrNet's StartClient() method. It also gets and configures the /// SteamTransport. It also leverages a UserData struct from Heathens to store the Steam account ID of the host. /// /// /// Feel free to make this method public or private depending on your need. Steam must be initialized before /// this method is called. /// public void StartClient(string steamCode) { var steamTransport = NetworkManager.main.transport as SteamTransport; if (steamTransport == null) { Debug.LogError("SteamTransport missing on NetworkManager", this); return; } if (string.IsNullOrEmpty(steamCode)) { Debug.LogError("Connection address is empty.", this); return; } // This is a Heathens API call. var hostAddress = UserData.Get(steamCode); if (!hostAddress.IsValid) { Debug.LogError($"{hostAddress} is an invalid connection address.", this); return; } steamTransport.peerToPeer = true; steamTransport.dedicatedServer = false; steamTransport.address = hostAddress.id.ToString(); NetworkManager.main.StartClient(); } ``` -------------------------------- ### Prepare Character Controller and Drag in C# Source: https://github.com/purrnet/purrdocs/blob/main/community-guides/character-controller-knockback-client-side-prediction.md Prepares the `PredictedKnockback` class by getting a reference to the `CharacterController` component and defining a `drag` variable. This setup is necessary for applying movement and simulating the decay of knockback forces. ```csharp [RequireComponent(typeof(CharacterController))] public class PredictedKnockback : PredictedIdentity { [SerializeField] float drag = 5f; CharacterController controller; protected void Awake() { controller = GetComponent(); } // ... rest of the code remains the same } ``` -------------------------------- ### Use Unity Lobby Provider for PurrNet Lobby System Source: https://github.com/purrnet/purrdocs/blob/main/SUMMARY.md This guide explains how to use Unity's Lobby service as a provider for PurrNet's lobby system. It covers the setup and usage for creating and joining game lobbies within Unity's multiplayer framework. ```csharp using PurrNet; using PurrNet.Lobby.Unity; using UnityEngine; public class UnityLobbyManager : MonoBehaviour { private UnityLobbyProvider unityLobbyProvider; void Start() { unityLobbyProvider = GetComponent(); if (unityLobbyProvider == null) { unityLobbyProvider = gameObject.AddComponent(); } } public async void CreateUnityLobby(int maxPlayers) { await unityLobbyProvider.CreateLobby(maxPlayers); } public async void JoinUnityLobby(string lobbyId) { await unityLobbyProvider.JoinLobby(lobbyId); } } ``` -------------------------------- ### Initialize SyncInput with Simulated Host Ping (C#) Source: https://github.com/purrnet/purrdocs/blob/main/systems-and-modules/network-modules/sync-types/syncinput.md Demonstrates how to initialize a SyncInput with a default value and a simulated host ping delay in milliseconds. This helps ensure fairness by making the host experience similar latency to clients. ```csharp private SyncInput _mySyncInput = new(defaultValue:false, hostPing:100f); ``` -------------------------------- ### SyncArray Initialization and Usage in C# Source: https://github.com/purrnet/purrdocs/blob/main/systems-and-modules/network-modules/sync-types/synclist-1.md Demonstrates how to create, initialize, and use a SyncArray in C#. It covers subscribing to change events and modifying array elements. Requires the Network Module. ```csharp public SyncArray syncArray = new(20, true); protected override void OnSpawned() { syncArray.onChanged += OnArrayChange; } private void OnArrayChange(SyncArrayChange change) { Debug.Log(change); } private void ChangeMyArray() { syncArray [0] = 69; syncArray.Length = 15; } ``` -------------------------------- ### C# Validated SyncVar Example Usage Source: https://github.com/purrnet/purrdocs/blob/main/systems-and-modules/network-modules/sync-types/validated-syncvar.md Demonstrates how to use the Validated SyncVar in C# for managing synchronized integer values. It includes setting up server-side validation, handling validation failures, and reacting to value changes. This example ensures values only increase, preventing downward modifications. ```csharp private ValidatedSyncVar _testVar = new(); private void OnEnable() { _testVar.serverValidation += ServerValidator; _testVar.onValidationFail += OnValidationFail; _testVar.onChangedWithOld += OnChanged; } private void OnDisable() { _testVar.serverValidation -= ServerValidator; _testVar.onValidationFail -= OnValidationFail; _testVar.onChangedWithOld -= OnChanged; } private bool ServerValidator(int oldValue, int newValue) { //Only the server will reach this. This is called whenever a change occurs. if (oldValue > newValue) return false; return true; } private void OnValidationFail(int failedValue, int authoritativeValue) { //Only the owner will receive this if the validation fails Debug.Log($"Validation failed on {failedValue}. Returning to {authoritativeValue}"); } private void OnChanged(int oldValue, int newValue, bool validated) { //This is called immediately with validated false for the owner, //and everyone received with validated = true if it goes through Debug.Log($"Value changed: {oldValue} -> {newValue} | Validated: {validated}"); } ``` -------------------------------- ### SyncVar Usage Example in C# Source: https://github.com/purrnet/purrdocs/blob/main/systems-and-modules/network-modules/sync-types/syncvar.md Demonstrates how to declare, initialize, and manage SyncVars in C#. It shows setting default values, handling owner authorization, and subscribing to value change events. The `OnSpawned` method is used to set initial values and attach event handlers, while `isOwner` and `asServer` flags control server-side and owner-specific updates. ```csharp private SyncVar mySync = new(2); //Now defaults to 2 private SyncVar myOtherSync = new(5, ownerAuth:true); //Defaults to 5, and is owner auth protected override void OnSpawned(bool asServer) { mySync.onChanged += OnMySyncChange; if (asServer) mySync.value = 420; if (isOwner) myOtherSync.value = 69; } private void OnMySyncChange(int newValue) { Debug.Log("SyncVar has changed to: " + newValue); } ``` -------------------------------- ### Spawning and Despawning Objects in Mirror and PurrNet Source: https://github.com/purrnet/purrdocs/blob/main/getting-started/converting-to-purrnet/converting-from-mirror.md Demonstrates the distinct methods for spawning and destroying networked objects in Mirror and PurrNet. Mirror requires explicit instantiation and server spawning, while PurrNet handles this more automatically, allowing ownership modification during spawning. ```csharp GameObject go = Instantiate(myPrefab); NetworkServer.Spawn(go, connectionToClient); NetworkServer.Destroy(go); ``` ```csharp var identity = Instantiate(myIdentityPrefab); identity.GiveOwnership(ownerPlayer); Destroy(identity.gameObject); ``` -------------------------------- ### Purrdicted Character Controller Knockback Source: https://github.com/purrnet/purrdocs/blob/main/SUMMARY.md Guide on implementing knockback for the Purrdicted Character Controller. ```APIDOC ## GET /community-guides/character-controller-knockback-client-side-prediction.md ### Description Explains how to implement knockback functionality for the Purrdicted Character Controller. ### Method GET ### Endpoint /community-guides/character-controller-knockback-client-side-prediction.md ### Parameters #### Query Parameters None ### Request Example None ### Response #### Success Response (200) - **content** (string) - The content of the knockback guide. #### Response Example { "content": "# Purrdicted Character Controller Knockback\n... (rest of the markdown content)" } ``` -------------------------------- ### SyncTimer Basic Usage (C#) Source: https://github.com/purrnet/purrdocs/blob/main/systems-and-modules/network-modules/sync-types/synctimer.md Demonstrates the basic usage of SyncTimer for a server-authorized countdown timer. It shows how to initialize the timer, handle second ticks for display, and pause/resume the timer. The reconcile interval ensures all clients stay synchronized. ```csharp public TMP_Text timerText; //false = OwnerAuth //3 = Reoncile interval //The reconcile interval deciphers how often it will force align all clients private SyncTimer timer = new(); private void Awake() { //onTimerSecondTick is called every 1 second timer.onTimerSecondTick += OnTimerSecondTick; } protected override void OnSpawned(bool asServer) { //This starts the timer with 30 seconds countdown if(isOwner) timer.StartTimer(30f); } private void OnTimerSecondTick() { //You can also get .remaining to get the precise float value //For displaying timers, the remainingInt makes it easy timerText.text = timer.remainingInt.ToString(); } private void PauseGameTimer() { //Pauses the timer and will sync the remaining time because it's set to true timer.PauseTimer(true); } private void ResumeGameTimer() { //Will resume the timer from where it was paused timer.ResumeTimer(); } ``` -------------------------------- ### Handle Host Button Click Event Source: https://github.com/purrnet/purrdocs/blob/main/guides/steam-setup/connect-with-steam.md Manages the click event for the host button. It calls StartHost() and updates UI elements (text field and button color) to reflect the connection status. It also removes listeners to prevent multiple calls. ```csharp /// /// This method is responsible for calling StartHost() and changing the UI visuals. /// private void HandleHostClicked() { if (hostButton == null || hostTextField == null) { Debug.LogError("Host button or host text field is null. " + "Please drag and drop it into the ConnectionManager.", this); return; } StartHost(); if (NetworkManager.main.isOffline) { hostTextField.text = "Server is Offline"; hostButton.image.color = Color.red; return; } hostTextField.text = UserData.Get().HexId; hostButton.image.color = Color.green; hostButton?.onClick.RemoveListener(HandleHostClicked); clientButton?.onClick.RemoveListener(HandleClientClicked); } ``` -------------------------------- ### Client-Side Prediction (PurrDiction) Documentation Source: https://github.com/purrnet/purrdocs/blob/main/SUMMARY.md Comprehensive documentation for PurrDiction, the client-side prediction system, covering its overview, installation, components, and best practices. ```APIDOC ## Client-Side Prediction (PurrDiction) Documentation ### Overview PurrDiction is the client-side prediction system designed to improve the perceived responsiveness of networked games. ### Key Features #### Installation * **Description**: Instructions on how to install and set up PurrDiction. * **Endpoint**: Not applicable (setup guide). #### Predicted Identities * **Description**: How identities are predicted and managed on the client. * **Endpoint**: Not applicable (system concept). #### Predicted Modules * **Description**: Details on various predicted modules, such as the Timer Module. * **Endpoint**: Not applicable (system concept). #### Input Handling * **Description**: How player input is handled and predicted. * **Endpoint**: Not applicable (system concept). #### State Handling * **Description**: Management of predicted game states. * **Endpoint**: Not applicable (system concept). #### Execution Flow * **Description**: Understanding the execution flow within the prediction system. * **Endpoint**: Not applicable (system concept). #### Built-in Components * **Description**: Information on pre-built components like Predicted Transform, Rigidbody, and Projectile. * **Endpoint**: Not applicable (component documentation). #### Deterministic Identity * **Description**: Concepts related to deterministic identities in the prediction system. * **Endpoint**: Not applicable (system concept). #### Predicted Hierarchy * **Description**: How hierarchical relationships are handled with prediction. * **Endpoint**: Not applicable (system concept). #### Interacting With Multiple Identities * **Description**: Guidelines for managing interactions between multiple predicted identities. * **Endpoint**: Not applicable (system concept). #### Predicted State Machine * **Description**: Using state machines within the prediction system. * **Endpoint**: Not applicable (system concept). #### Views and Interpolation * **Description**: Techniques for views and interpolation to smooth out predicted states. * **Endpoint**: Not applicable (system concept). #### Best Practices * **Description**: Recommended practices for using PurrDiction effectively. * **Endpoint**: Not applicable (guidelines). #### Disposable Collections * **Description**: Usage of disposable collections within the prediction system. * **Endpoint**: Not applicable (utility). #### Security Model * **Description**: Security considerations for the client-side prediction system. * **Endpoint**: Not applicable (security guidelines). #### Development Shortcuts * **Description**: Tips and shortcuts for developing with PurrDiction. * **Endpoint**: Not applicable (guidelines). ``` -------------------------------- ### Spawning with Ownership in FishNet Source: https://github.com/purrnet/purrdocs/blob/main/getting-started/converting-to-purrnet/converting-from-fishnet.md Demonstrates how to spawn a GameObject with a specific owner connection in FishNet. This involves instantiating the prefab and then calling the ServerManager.Spawn method with the owner connection as a parameter. ```csharp GameObject go = Instantiate(_yourPrefab); InstanceFinder.ServerManager.Spawn(go, ownerConnection); ``` -------------------------------- ### DisposableDictionary in STATE Source: https://github.com/purrnet/purrdocs/blob/main/client-side-prediction/disposable-collections.md Provides an example of how to manage a DisposableDictionary within a STATE, ensuring it is disposed correctly in the STATE's Dispose method. ```csharp public void Dispose() { players.Dispose(); } ``` -------------------------------- ### Vector3 Delta Serialization Example - C# Source: https://github.com/purrnet/purrdocs/blob/main/systems-and-modules/bitpacker-serialization/delta-packers.md Demonstrates how to use DeltaPacker to efficiently write and read only the changed fields of a Vector3 object, optimizing data transfer. ```csharp // Writing DeltaPacker.Write(packer, oldPosition, newPosition); // Reading Vector3 oldValue = ..; Vector3 result = default; var currentPosition = DeltaPacker.Read(packer, oldValue, ref result); ``` -------------------------------- ### Change Microphone Device (C#) Source: https://github.com/purrnet/purrdocs/blob/main/tools/purrvoice-voice-chat/microphone-input.md Changes the active microphone device for the PurrVoicePlayer. This example demonstrates setting the first device from the available list as the new microphone. ```csharp [SerializeField] private PurrVoicePlayer _voicePlayer; // This should be our local player private void MicChangeTest() { _voicePlayer.ChangeMicrophone(AudioDevices.devices[0]); } ``` -------------------------------- ### Implement Custom Authentication in C# Source: https://context7.com/purrnet/purrdocs/llms.txt Demonstrates how to create a custom authenticator by implementing the AuthenticationBehaviour interface. This allows for password, token, or other custom authentication schemes before full client connection. It requires defining a data structure for login credentials and implementing validation logic on the server. ```csharp using PurrNet; using PurrNet.Authentication; using System.Threading.Tasks; using UnityEngine; // Register the network type for serialization [RegisterNetworkType(typeof(AuthenticationRequest))] public class CustomAuthenticator : AuthenticationBehaviour { [SerializeField] private string serverPassword = "SecretPassword123"; // Client provides login credentials protected override Task> GetClientPayload() { var loginData = new LoginData { username = PlayerPrefs.GetString("Username", "Guest"), password = serverPassword, clientVersion = Application.version }; return Task.FromResult(new AuthenticationRequest(loginData)); } // Server validates the credentials protected override Task ValidateClientPayload(LoginData payload) { // Check password bool passwordValid = payload.password == serverPassword; // Check version compatibility bool versionValid = payload.clientVersion == Application.version; bool isValid = passwordValid && versionValid; if (!isValid) { Debug.Log($"Auth failed for {payload.username}: " + $""Password: {passwordValid}, Version: {versionValid}"); } return Task.FromResult(new AuthenticationResponse(isValid)); } } // Login data structure public struct LoginData : IPackedAuto { public string username; public string password; public string clientVersion; } ``` -------------------------------- ### Initialize Network Modules with OnInitializeModules() (C#) Source: https://github.com/purrnet/purrdocs/blob/main/systems-and-modules/network-modules/common-pitfalls.md Use the OnInitializeModules() callback for creating, overriding, or initializing network modules. This method is called before networking data is sent or IDs are assigned, ensuring modules are ready. ```csharp protected override void OnInitializeModules() { health = new SyncVar(100); // Custom initialization here } ``` -------------------------------- ### Integrate Dissonance with PurrNet Source: https://github.com/purrnet/purrdocs/blob/main/SUMMARY.md This guide explains how to integrate Dissonance, a voice chat solution, with PurrNet. It covers setting up Dissonance to work seamlessly with PurrNet's networking for voice communication. ```csharp using PurrNet; using Dissonance; using UnityEngine; public class DissonanceIntegration : MonoBehaviour { private DissonanceComms dissonance; void Start() { dissonance = GetComponent(); if (dissonance == null) { dissonance = gameObject.AddComponent(); } // Configure Dissonance to use PurrNet for network transport // This typically involves setting up a custom network communicator // or ensuring Dissonance uses the same transport layer as PurrNet. // ... Dissonance setup ... } public void Speak(string text) { dissonance.NetworkProvider.Broadcast(text); } } ```