How to sync Instantiated GameObject on client or host for everyone?

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
using StarterAssets;
using UnityEngine.InputSystem;
using MLAPI;
using MLAPI.Messaging;
using MLAPI.NetworkedVar;
using MLAPI.Spawning;

public class PlayerShootController : NetworkedBehaviour
{
    [SerializeField] private CinemachineVirtualCamera aimCamera;
    [SerializeField] private CinemachineVirtualCamera followCamera;
    [SerializeField] private float normalSensitivity = 1f;
    [SerializeField] private float aimSensitivity = 0.5f;
    [SerializeField] private float aimSprintSpeed = 2.5f;
    [SerializeField] private LayerMask aimColliderLayerMask = new LayerMask();
    [SerializeField] private Transform debugTransform;
    [SerializeField] private Transform bulletTransform;
    [SerializeField] private Transform spawnBulletPos;

    private NetworkedVarBool _shooting =
        new NetworkedVarBool(new NetworkedVarSettings {WritePermission = NetworkedVarPermission.OwnerOnly}, false);

    private StarterAssetsInputs _inputs;
    private ThirdPersonController _thirdPersonController;
   
    private void Awake()
    {
        _inputs = GetComponent<StarterAssetsInputs>();
        _thirdPersonController = GetComponent<ThirdPersonController>();
    }

    private void Update()
    {
        if (IsLocalPlayer)
        {
            _shooting.Value = _inputs.shoot;
           
            Vector3 mouseWorldPosition = Vector3.zero;
            Vector2 screenCenter = new Vector2(Screen.width / 2f, Screen.height / 2f);
            Ray ray = Camera.main.ScreenPointToRay(screenCenter);
            Transform hitTransform = null;
            if (Physics.Raycast(ray, out RaycastHit raycastHit, 999f))
            {
                debugTransform.position = raycastHit.point;
                mouseWorldPosition = raycastHit.point;
                hitTransform = raycastHit.transform;
            }
           
            if (_inputs.aim)
            {
                followCamera.gameObject.SetActive(false);
                aimCamera.gameObject.SetActive(true);
                _thirdPersonController.SetSensitivity(aimSensitivity);

                Vector3 worldAimTarget = mouseWorldPosition;
                worldAimTarget.y = transform.position.y;
                Vector3 aimDirection = (worldAimTarget - transform.position).normalized;

                transform.forward = Vector3.Lerp(transform.forward, aimDirection, Time.deltaTime * 20f);
               
                _thirdPersonController.SetRotationOnMove(false);
                _thirdPersonController.SetSprintSpeedOnAim(aimSprintSpeed);
               
            }
            else
            {
                followCamera.gameObject.SetActive(true);
                aimCamera.gameObject.SetActive(false);
               
                _thirdPersonController.SetSensitivity(normalSensitivity);
                _thirdPersonController.SetRotationOnMove(true);
                _thirdPersonController.SetSprintSpeedOnAim(5.33f);
            }

            if (_inputs.shoot && _shooting.Value)
            {
                Debug.Log("Shooting");

                InvokeServerRpc(ShootProjectileServerRpc, mouseWorldPosition);
               
                _inputs.shoot = false;
            }
        }
    }

    [ClientRPC]
    private void ShootProjectileClientRpc(Vector3 mouseWorldPosition)
    {
        // ShootProjectileServerRpc(mouseWorldPosition); 
        // todo: handle spawned game object on clients also
    }

    [ServerRPC]
    private void ShootProjectileServerRpc(Vector3 mouseWorldPosition)
    {
        Vector3 aimDir = (mouseWorldPosition - spawnBulletPos.position).normalized;
        Instantiate(bulletTransform, spawnBulletPos.position, Quaternion.LookRotation(aimDir, Vector3.up));
        // go.GetComponent<NetworkedObject>().Spawn(); ??
    }
}

So basically this code works only on host, i see spawned bullet, but on client i can only spawn it and cannot see it, because its only on server, so how can I sync? this bullet with clients?

If you put a NetworkObject on the bullet and uncomment your last line, that should work.

There are other ways to do it, for example what I do is send a ClientRpc to the clients to also spawn bullets, but take into the network delay to spawn them further along their flight path so the hits sync up better. But that also depends on how you handle e.g. hit registration, so pick whatever works for you.

  • Instantiate(bulletTransform, spawnBulletPos.position, Quaternion.LookRotation(aimDir, Vector3.up));
  • // go.GetComponent().Spawn(); ??

This is what you need to do… your Instantiate call returns a game object… you need to save that … then get the network object and spawn it.

So

GameObject go = Instantiate(.......);
go.GetComponent<NetworkedObject>().Spawn();

You probably also want a network rigid body on your bullet, but it should work without it as well.