Search Unity

Third Party Mirror transform synchronisation in multiplayer

Discussion in 'Multiplayer' started by Solber, Oct 4, 2021.

  1. Solber

    Solber

    Joined:
    Mar 29, 2014
    Posts:
    5
    Hi I'm new to Unity/Mirror and I'm still trying to figure stuff out.

    I followed a tutorial and I'm now trying to implement my own stuff.

    In my case, I instantiating one weapon or another depending on the key pressed. In local it works, but the modification is not propagated to other players, so they still this the player that has switch weapon with the same he started with.

    The thing I don't understand is that in the tuto, he created an object that allows the player to loot and switch weapon and this actually update the transform and other players can see the weapon changing.
    In this case he is using the EquipWeapon function which I'm also using to update the current weapon

    Here's the script to switch weapon :

    Code (CSharp):
    1. using UnityEngine;
    2. using Mirror;
    3. using System.Collections;
    4.  
    5. public class WeaponManager : NetworkBehaviour
    6. {
    7.  
    8.     [SerializeField]
    9.     private WeaponData primaryWeapon;
    10.     [SerializeField]
    11.     private WeaponData secondaryWeapon;
    12.  
    13.     private WeaponData currentWeapon;
    14.     private WeaponGraphics currentGraphics;
    15.  
    16.     [SerializeField]
    17.     private Transform weaponHolder;
    18.  
    19.     [SerializeField]
    20.     private string weaponLayerName = "Weapon";
    21.  
    22.     [HideInInspector]
    23.     public int currentMagazineSize;
    24.  
    25.     public bool isReloading = false;
    26.  
    27.     private bool canSwitchWeapon = true;
    28.  
    29.     void Start()
    30.     {
    31.         EquipWeapon(primaryWeapon);
    32.     }
    33.  
    34.     private void Update()
    35.     {
    36.         if(!isLocalPlayer || (isLocalPlayer && !canSwitchWeapon))
    37.         {
    38.             return;
    39.         }
    40.      
    41.         if (Input.GetAxis("Secondary") != 0)
    42.         {
    43.             EquipWeapon(secondaryWeapon);
    44.         }
    45.         else if (Input.GetAxis("Primary") != 0)
    46.         {
    47.             EquipWeapon(primaryWeapon);
    48.         }
    49.     }
    50.  
    51.     public WeaponData GetCurrentWeapon()
    52.     {
    53.         return currentWeapon;
    54.     }
    55.  
    56.     public WeaponGraphics GetCurrentGraphics()
    57.     {
    58.         return currentGraphics;
    59.     }
    60.  
    61.     public void EquipWeapon(WeaponData _weapon)
    62.     {
    63.         canSwitchWeapon = false;
    64.         if (currentWeapon)
    65.         {
    66.             Destroy(GetCurrentGraphics().gameObject);
    67.         }
    68.      
    69.         currentWeapon = _weapon;
    70.         currentMagazineSize = _weapon.magazineSize;
    71.  
    72.         GameObject weaponIns = Instantiate(_weapon.graphics, weaponHolder.position, weaponHolder.rotation);
    73.         weaponIns.transform.SetParent(weaponHolder);
    74.  
    75.         currentGraphics = weaponIns.GetComponent<WeaponGraphics>();
    76.  
    77.         if(currentGraphics == null)
    78.         {
    79.             Debug.LogError("Pas de script WeaponGraphics sur l'arme : " + weaponIns.name);
    80.         }
    81.  
    82.         if(isLocalPlayer)
    83.         {
    84.             Util.SetLayerRecursively(weaponIns, LayerMask.NameToLayer(weaponLayerName));
    85.         }
    86.  
    87.         canSwitchWeapon = true;
    88.     }
    89.  
    90.     public IEnumerator Reload()
    91.     {
    92.         canSwitchWeapon = false;
    93.         if(isReloading)
    94.         {
    95.             yield break;
    96.         }
    97.  
    98.         Debug.Log("Reloading ...");
    99.  
    100.         isReloading = true;
    101.  
    102.         CmdOnReload();
    103.         yield return new WaitForSeconds(currentWeapon.reloadTime);
    104.         currentMagazineSize = currentWeapon.magazineSize;
    105.  
    106.         isReloading = false;
    107.         canSwitchWeapon = true;
    108.  
    109.         Debug.Log("Reloading finished");
    110.     }
    111.  
    112.     [Command]
    113.     void CmdOnReload()
    114.     {
    115.         RpcOnReload();
    116.     }
    117.  
    118.     [ClientRpc]
    119.     void RpcOnReload()
    120.     {
    121.         Animator animator = currentGraphics.GetComponent<Animator>();
    122.         if(animator != null)
    123.         {
    124.             animator.SetTrigger("Reload");
    125.         }
    126.  
    127.         AudioSource audioSource = GetComponent<AudioSource>();
    128.         audioSource.PlayOneShot(currentWeapon.reloadSound);
    129.     }
    130.  
    131. }
    132.  
    And here is the script to pick up a weapon

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class PickUpWeapon : MonoBehaviour
    6. {
    7.     [SerializeField]
    8.     private WeaponData theWeapon;
    9.  
    10.     [SerializeField]
    11.     private float respawnDelay = 30f;
    12.  
    13.     private GameObject pickUpGraphics;
    14.     private bool canPickUp;
    15.  
    16.     void Start()
    17.     {
    18.         ResetWeapon();
    19.     }
    20.  
    21.     void ResetWeapon()
    22.     {
    23.         pickUpGraphics = Instantiate(theWeapon.graphics, transform);
    24.         pickUpGraphics.transform.position = transform.position;
    25.         canPickUp = true;
    26.     }
    27.  
    28.     private void OnTriggerEnter(Collider other)
    29.     {
    30.         if(other.CompareTag("Player") && canPickUp)
    31.         {
    32.             WeaponManager weaponManager = other.GetComponent<WeaponManager>();
    33.             EquipNewWeapon(weaponManager);
    34.         }
    35.     }
    36.  
    37.     void EquipNewWeapon(WeaponManager weaponManager)
    38.     {
    39.         // Equipe la nouvelle arme
    40.         weaponManager.EquipWeapon(theWeapon);
    41.  
    42.         canPickUp = false;
    43.         Destroy(pickUpGraphics);
    44.  
    45.         StartCoroutine(DelayResetWeapon());
    46.     }
    47.  
    48.     IEnumerator DelayResetWeapon()
    49.     {
    50.         yield return new WaitForSeconds(respawnDelay);
    51.         ResetWeapon();
    52.     }
    53. }
    54.  
    Could you help me figuring out what I'm missing ? Thanks !
     
  2. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,536
    Server has to instantiate things. Check the docs.

    https://mirror-networking.gitbook.io/docs/guides/gameobjects
    https://mirror-networking.gitbook.io/docs/guides/gameobjects/spawning-gameobjects
    https://mirror-networking.gitbook.io/docs/guides/gameobjects/pickups-drops-and-child-objects

    Basically, send a Command to the server that the client changed weapons, then you can local Instantiate() and if your objects are networked synced then server can network NetworkServer.Spawn() and finally the server can send RPC commands to the other clients, and ignore the source client. On the non-server clients, they can locally run the necessary code to change weapons inside their local RPC call method.

    It's important to mentally distinguish what each client is seeing when you're designing. No one sees anything unless you tell them. The flow of events is basically how you enforce server authority and there's no automagic easy way to good multiplayer. It's just hard.
     
  3. Solber

    Solber

    Joined:
    Mar 29, 2014
    Posts:
    5
    Ok that's what I though and tried to accomplish. Ill check your links and update you on my findings :) Thanks !