Only host is able to call serverrpc

Hello, im trying to make a gun script, i have a smoke effect and muzzleflasheffect functions that are being called and are also both serverrpc:

    [ServerRpc(RequireOwnership = false)]
    public void SmokeGameobjectServerRpc()
    {
        GameObject go = Instantiate(smokegobj, shootpoint.transform.position, shootpoint.transform.rotation);
        go.GetComponent<NetworkObject>().Spawn();



    }




    [ServerRpc(RequireOwnership = false)]
    public void MuzzleFlashGameobjectServerRpc()
    {
        GameObject go = Instantiate(muzzleflashGobj, shootpoint.transform.position, shootpoint.transform.rotation);
        go.GetComponent<NetworkObject>().Spawn();


    }

and i also have a raycast script:

    public void raycast_shoot()
    {
        RaycastHit hit;
        if (Physics.Raycast(shootpoint.transform.position, shootpoint.transform.TransformDirection(Vector3.forward), out hit, Mathf.Infinity))
        {
            Debug.DrawRay(shootpoint.transform.position, shootpoint.transform.TransformDirection(Vector3.forward) * hit.distance, Color.yellow);
            Debug.Log("Did Hit");
            GameObject go = Instantiate(hitEffect, hit.point, Quaternion.LookRotation(hit.normal));
            go.GetComponent<NetworkObject>().Spawn();
        }
        else
        {
            Debug.DrawRay(shootpoint.transform.position, shootpoint.transform.TransformDirection(Vector3.forward) * 1000, Color.white);
            Debug.Log("Did not Hit");
        }

    }

The problem with these functions are that they are called when the host executes them, but NOT when the client does, so the client and the host can see the host shoot, but the host and client can't see the client shoot.

help would be really appreciated


Are they not being called or just the effect doesn't work? Maybe because the RPC's are executed on the server so the shootpoint isn't the client's one.
Also, in your raycast script you are trying to spawn go but I think only the server is allowed to do that so the spawning should be in a serverRPC.


'so the shootpoint isnt the clients one'

they are being called with an event in an animation

what do you mean by 'so the shootpoint isn't the client's one'

Hi @cesar121321432
I think you are not correctly understand of the NGO principle.
You shared 2 ServerRpc methods but you didn't share where the exactly calling these methods?
And when/where is calling the "raycast_shoot()"? And which game object?
So you have a PlayerNetworkObject for each player and "raycast_shoot()" is calling from in the that script of NetworkObject?
Please share more specific and detailed information.

the 2 rpc methods are both being called with an event in a shoot animation

the raycast_shoot() method is also being called in the animation as an event, its being called on the gun game object

and this is the hierachy for the playercapsule:

the playercapsule object is the player prefab, the gun is attached with the inventory to the maincamera and the gun has arms with ik, the shootpoint is inside the gun prefab and is at the end of the barrel

i have a network object:
-on the playercapsule
-on all the effects

example of effect:

PlayerCapsule Player Prefab:

Here are the script for the makarov:

using System.Collections;
using System.Collections.Generic;
using TMPro;
using Unity.Mathematics;
using Unity.Netcode;
using UnityEngine;

public class Makarov : NetworkBehaviour
{
    public Animator anim;
    public AudioSource src;
    public AudioClip shoot_clip;

    public GameObject smokegobj;
    public Transform gun;
    public Vector3 gunaimPos;
    public quaternion pivot;
    public Transform player;
    public float AimSpeed = 5;

    public Transform shootpoint;
    public GameObject hitEffect;

    public GameObject muzzleflashGobj;
    // Start is called before the first frame update
    void Start()
    {
        if (!IsOwner) return;
        gunaimPos = new Vector3(0.117f, 0.018f, 0.083f);
        gameObject.GetComponent<NetworkObject>().Spawn();

    }


    // Update is called once per frame
    void Update()
    {
        if (!IsOwner) return;

        player.localRotation = Quaternion.Lerp(player.localRotation, pivot, AimSpeed * Time.deltaTime);
        gun.localPosition = Vector3.Slerp(transform.localPosition, gunaimPos, AimSpeed * Time.deltaTime);
        if (Input.GetMouseButtonDown(0))
        {

            playAnim();



        }
        if (Input.GetMouseButtonDown(1))

        {
            if (IsOwner)
            {
                gunaimPos = new Vector3(0.00400000019f, 0.209999993f, 0.166615874f);
                // gun.localPosition = new Vector3(0.002f, 0.134f, 0.083f);
            }
        }
        if (Input.GetMouseButtonUp(1))
        {
            if (IsOwner)
            {
                gunaimPos = new Vector3(0.117f, 0.018f, 0.083f);
                //gun.localPosition = new Vector3(0.117f, 0.018f, 0.083f);
            }
        }

    }

    public void playAnim() {
        anim.Play("Makarov_Shoot");
    }

    public void raycast_shoot()
    {
        RaycastHit hit;
        if (Physics.Raycast(shootpoint.transform.position, shootpoint.transform.TransformDirection(Vector3.forward), out hit, Mathf.Infinity))
        {
            Debug.DrawRay(shootpoint.transform.position, shootpoint.transform.TransformDirection(Vector3.forward) * hit.distance, Color.yellow);
            Debug.Log("Did Hit");
            GameObject go = Instantiate(hitEffect, hit.point, Quaternion.LookRotation(hit.normal));
            go.GetComponent<NetworkObject>().Spawn();
        }
        else
        {
            Debug.DrawRay(shootpoint.transform.position, shootpoint.transform.TransformDirection(Vector3.forward) * 1000, Color.white);
            Debug.Log("Did not Hit");
        }
      //  gameObject.GetComponent<NetworkObject>().Spawn();
    }

    public void shoot_sound()
    {


            src.PlayOneShot(shoot_clip);
            //gameObject.GetComponent<NetworkObject>().Spawn();


    }
    [ServerRpc(RequireOwnership = false)]
    public void SmokeGameobjectServerRpc()
    {
        GameObject go = Instantiate(smokegobj, shootpoint.transform.position, shootpoint.transform.rotation);
        go.GetComponent<NetworkObject>().Spawn();



    }




    [ServerRpc(RequireOwnership = false)]
    public void MuzzleFlashGameobjectServerRpc()
    {
        GameObject go = Instantiate(muzzleflashGobj, shootpoint.transform.position, shootpoint.transform.rotation);
        go.GetComponent<NetworkObject>().Spawn();


    }



}

Hope this is enough info...

Okay, these information are good.
But, why you are call "spawn" method in "Start Method" of "Makarov" script?
I think this isn't necessary because when PlayerCapsule is spawning "Makarov" will be also spawn. Because it is child object of PlayerCapsule.

 void Start()
    {
        if (!IsOwner) return;
        gunaimPos = new Vector3(0.117f, 0.018f, 0.083f);
        gameObject.GetComponent<NetworkObject>().Spawn();

    }

Actually I couldn't find the problem.
I create similar hierarchy on my test project and it's work.
I have a PlayerObject and added a child object then I try to trigger ServerRpc method and it works.
Actually you can't add "NetworkObject" object to the sub objects of Parent object who has also has "NetworkObject". Unity giving this error:
Spawning NetworkObjects with nested NetworkObjects is only supported for scene objects. Child NetworkObjects will not be spawned over the network!
Is "PlayerCapsule" scene object?

Would you add some log and share us please.

Thank you so much for helping!

the 'gameObject.GetComponent().Spawn();' method in start i didnt mean to put there so ill delete it.

what do you mean with scene object, do you mean Player Prefab, because it is.
or do you mean if it has an network object, because it does.

again thank you, i am experienced with unity but just not with netcode at all, so the help is great!

There are two types (Dynamic and In-Scene Placed) NetworkObjects.
You can look at this documentation page.
If I understood correctly, your PlayerCapsule is In-scene placed object. This means only one player can control this object at the same time.
I am curious of your PlayerCapsule controlling. If your PlayerCapsule is In-scene object, how do you move this object for each player?

And this page.

my player is spawed with the player prefab method in the networkmanager

here is the player script:

using System;
using Unity.Netcode;
using UnityEngine;

public class PlayerController : NetworkBehaviour
{

    //Assingables
    public Transform playerCam;
    public Transform orientation;

    //Other
    private Rigidbody rb;

    //Rotation and look
    private float xRotation;
    private float sensitivity = 50f;
    private float sensMultiplier = 1f;

    //Movement
    public float moveSpeed = 4500;
    public float maxSpeed = 20;
    public bool grounded;
    public LayerMask whatIsGround;

    public float counterMovement = 0.175f;
    private float threshold = 0.01f;
    public float maxSlopeAngle = 35f;

    //Crouch & Slide
    private Vector3 crouchScale = new Vector3(1, 0.5f, 1);
    private Vector3 playerScale;
    public float slideForce = 400;
    public float slideCounterMovement = 0.2f;

    //Jumping
    private bool readyToJump = true;
    private float jumpCooldown = 0.25f;
    public float jumpForce = 550f;

    //Input
    float x, y;
    bool jumping, sprinting, crouching;

    //Sliding
    private Vector3 normalVector = Vector3.up;
    private Vector3 wallNormalVector;

    void Awake()
    {
        rb = GetComponent<Rigidbody>();
    }

    void Start()
    {
        playerScale = transform.localScale;
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
    }


    private void FixedUpdate()
    {
        Movement();
    }
    public override void OnNetworkSpawn()
    {
        if (!IsOwner) { Destroy(this); }
    }
    private void Update()
    {
        MyInput();
        Look();
    }

    /// <summary>
    /// Find user input. Should put this in its own class but im lazy
    /// </summary>
    private void MyInput()
    {
        x = Input.GetAxisRaw("Horizontal");
        y = Input.GetAxisRaw("Vertical");
        jumping = Input.GetButton("Jump");
        crouching = Input.GetKey(KeyCode.LeftControl);

        //Crouching
        if (Input.GetKeyDown(KeyCode.LeftControl))
            StartCrouch();
        if (Input.GetKeyUp(KeyCode.LeftControl))
            StopCrouch();
    }

    private void StartCrouch()
    {
        transform.localScale = crouchScale;
        transform.position = new Vector3(transform.position.x, transform.position.y - 0.5f, transform.position.z);
        if (rb.velocity.magnitude > 0.5f)
        {
            if (grounded)
            {
                rb.AddForce(orientation.transform.forward * slideForce);
            }
        }
    }

    private void StopCrouch()
    {
        transform.localScale = playerScale;
        transform.position = new Vector3(transform.position.x, transform.position.y + 0.5f, transform.position.z);
    }

    private void Movement()
    {
        //Extra gravity
        rb.AddForce(Vector3.down * Time.deltaTime * 10);

        //Find actual velocity relative to where player is looking
        Vector2 mag = FindVelRelativeToLook();
        float xMag = mag.x, yMag = mag.y;

        //Counteract sliding and sloppy movement
        CounterMovement(x, y, mag);

        //If holding jump && ready to jump, then jump
        if (readyToJump && jumping) Jump();

        //Set max speed
        float maxSpeed = this.maxSpeed;

        //If sliding down a ramp, add force down so player stays grounded and also builds speed
        if (crouching && grounded && readyToJump)
        {
            rb.AddForce(Vector3.down * Time.deltaTime * 3000);
            return;
        }

        //If speed is larger than maxspeed, cancel out the input so you don't go over max speed
        if (x > 0 && xMag > maxSpeed) x = 0;
        if (x < 0 && xMag < -maxSpeed) x = 0;
        if (y > 0 && yMag > maxSpeed) y = 0;
        if (y < 0 && yMag < -maxSpeed) y = 0;

        //Some multipliers
        float multiplier = 1f, multiplierV = 1f;

        // Movement in air
        if (!grounded)
        {
            multiplier = 0.5f;
            multiplierV = 0.5f;
        }

        // Movement while sliding
        if (grounded && crouching) multiplierV = 0f;

        //Apply forces to move player
        rb.AddForce(orientation.transform.forward * y * moveSpeed * Time.deltaTime * multiplier * multiplierV);
        rb.AddForce(orientation.transform.right * x * moveSpeed * Time.deltaTime * multiplier);
    }

    private void Jump()
    {
        if (grounded && readyToJump)
        {
            readyToJump = false;

            //Add jump forces
            rb.AddForce(Vector2.up * jumpForce * 1.5f);
            rb.AddForce(normalVector * jumpForce * 0.5f);

            //If jumping while falling, reset y velocity.
            Vector3 vel = rb.velocity;
            if (rb.velocity.y < 0.5f)
                rb.velocity = new Vector3(vel.x, 0, vel.z);
            else if (rb.velocity.y > 0)
                rb.velocity = new Vector3(vel.x, vel.y / 2, vel.z);

            Invoke(nameof(ResetJump), jumpCooldown);
        }
    }

    private void ResetJump()
    {
        readyToJump = true;
    }

    private float desiredX;
    private void Look()
    {
        float mouseX = Input.GetAxis("Mouse X") * sensitivity * Time.fixedDeltaTime * sensMultiplier;
        float mouseY = Input.GetAxis("Mouse Y") * sensitivity * Time.fixedDeltaTime * sensMultiplier;

        //Find current look rotation
        Vector3 rot = playerCam.transform.localRotation.eulerAngles;
        desiredX = rot.y + mouseX;

        //Rotate, and also make sure we dont over- or under-rotate.
        xRotation -= mouseY;
        xRotation = Mathf.Clamp(xRotation, -90f, 90f);

        //Perform the rotations
        playerCam.transform.localRotation = Quaternion.Euler(xRotation, desiredX, 0);
        orientation.transform.localRotation = Quaternion.Euler(0, desiredX, 0);
    }

    private void CounterMovement(float x, float y, Vector2 mag)
    {
        if (!grounded || jumping) return;

        //Slow down sliding
        if (crouching)
        {
            rb.AddForce(moveSpeed * Time.deltaTime * -rb.velocity.normalized * slideCounterMovement);
            return;
        }

        //Counter movement
        if (Math.Abs(mag.x) > threshold && Math.Abs(x) < 0.05f || (mag.x < -threshold && x > 0) || (mag.x > threshold && x < 0))
        {
            rb.AddForce(moveSpeed * orientation.transform.right * Time.deltaTime * -mag.x * counterMovement);
        }
        if (Math.Abs(mag.y) > threshold && Math.Abs(y) < 0.05f || (mag.y < -threshold && y > 0) || (mag.y > threshold && y < 0))
        {
            rb.AddForce(moveSpeed * orientation.transform.forward * Time.deltaTime * -mag.y * counterMovement);
        }

        //Limit diagonal running. This will also cause a full stop if sliding fast and un-crouching, so not optimal.
        if (Mathf.Sqrt((Mathf.Pow(rb.velocity.x, 2) + Mathf.Pow(rb.velocity.z, 2))) > maxSpeed)
        {
            float fallspeed = rb.velocity.y;
            Vector3 n = rb.velocity.normalized * maxSpeed;
            rb.velocity = new Vector3(n.x, fallspeed, n.z);
        }
    }

    /// <summary>
    /// Find the velocity relative to where the player is looking
    /// Useful for vectors calculations regarding movement and limiting movement
    /// </summary>
    /// <returns></returns>
    public Vector2 FindVelRelativeToLook()
    {
        float lookAngle = orientation.transform.eulerAngles.y;
        float moveAngle = Mathf.Atan2(rb.velocity.x, rb.velocity.z) * Mathf.Rad2Deg;

        float u = Mathf.DeltaAngle(lookAngle, moveAngle);
        float v = 90 - u;

        float magnitue = rb.velocity.magnitude;
        float yMag = magnitue * Mathf.Cos(u * Mathf.Deg2Rad);
        float xMag = magnitue * Mathf.Cos(v * Mathf.Deg2Rad);

        return new Vector2(xMag, yMag);
    }

    private bool IsFloor(Vector3 v)
    {
        float angle = Vector3.Angle(Vector3.up, v);
        return angle < maxSlopeAngle;
    }

    private bool cancellingGrounded;

    /// <summary>
    /// Handle ground detection
    /// </summary>
    private void OnCollisionStay(Collision other)
    {
        //Make sure we are only checking for walkable layers
        int layer = other.gameObject.layer;
        if (whatIsGround != (whatIsGround | (1 << layer))) return;

        //Iterate through every collision in a physics update
        for (int i = 0; i < other.contactCount; i++)
        {
            Vector3 normal = other.contacts[i].normal;
            //FLOOR
            if (IsFloor(normal))
            {
                grounded = true;
                cancellingGrounded = false;
                normalVector = normal;
                CancelInvoke(nameof(StopGrounded));
            }
        }

        //Invoke ground/wall cancel, since we can't check normals with CollisionExit
        float delay = 3f;
        if (!cancellingGrounded)
        {
            cancellingGrounded = true;
            Invoke(nameof(StopGrounded), Time.deltaTime * delay);
        }
    }

    private void StopGrounded()
    {
        grounded = false;
    }

}

@cesar121321432 ,
I want to be clear to you. I think, you should start to read/learn beginning of the NGO because, PlayerController script has many wrong and unnecessary code.
For example:

  • Why OnNetworkSpawn method like this: if (!IsOwner) { Destroy(this); } If you do this you destroy other player's PlayerPrefab object. Actually, probably this line gives authority error.
  • You have to add "if (!IsOwner) return;" line to the "Movement()", "MyInput()" and "Look()" methods because, many "PlayerPrefab" objects will be in the scene.

Have a nice day.

im sorry but how does this apply to the question???