unity-game-engineunity3d-mirror

Stop and Play Particle System on Networked Player in Unity using Mirror


I am trying to play and stop a particle system which is a child of a player prefab. So far I have gotten the host client's thrust particle effect to update across all clients but I haven't been able to figure out a non-host client. I would like it if every time a player presses the thruster button the game would display the thruster effect across all clients and when they stop the particle system stops and other clients would see it as well.

So far my code is as follows:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Mirror;

public class PlayerMovement : NetworkBehaviour
{
    public float thrustPower = 300f;
    Rigidbody2D m_playerRb;
    bool m_thrustOn = false;
    public ParticleSystem m_playerPs;

    [SyncVar(hook = nameof(SetThrusters))]
    bool m_thrusterState = false;

    private void Start()
    {
        m_playerRb = GetComponent<Rigidbody2D>();
        m_playerPs.Stop();

    }

    private void Update()
    {
        if (isLocalPlayer)
        {
            MovePlayer();
            m_thrusterState = m_thrustOn;
        }
    }

    private void FixedUpdate()
    {
        if (m_thrustOn)
        {
            m_playerRb.AddForce(gameObject.transform.up * thrustPower * Time.fixedDeltaTime, ForceMode2D.Force);
        }
    }

    private void SetThrusters(bool oldVal, bool newVal)
    {
        if (newVal) m_playerPs.Play();
        else if (newVal == false) m_playerPs.Stop();
    }

    

    private void MovePlayer()
    {
        m_thrustOn = Input.GetKey(KeyCode.W) ? true : false;

        float horizontalInput = Input.GetAxisRaw("Horizontal");

        transform.Rotate(new Vector3(0, 0, horizontalInput * -180 * Time.deltaTime));
    }
}

I cant really find anything online about Mirror in terms of particle systems. Let me know if you need any more info.

Thanks!


Solution

  • SyncVar always only go in the direction HOST -> CLIENT !


    For the other way round you would need to use a Command

    like e.g.

    [Command]
    void CmdSetSetThrusters(bool newVal)
    {
        // the hook would not be executed on the host => do it manually now
        SetThrusters(m_thrusterState, newVal);
    
        // set it on the host -> now via synVar automatically forwarded to others
        m_thrusterState = newVal;
    }
    

    And then you will have to add a check whether you are the host or not like e.g.

    if (isLocalPlayer)
    {
        MovePlayer();
    
        if(isServer)
        {
            // afaik this you still have to call manually for yourself
            // not sure here how SyncVar Hooks are handled on the host itself
            SetThrusters(m_thrusterState, m_thrustOn);
    
            // this is now synced to others
            m_thrusterState = m_thrustOn;
        }
        else
        {
            // if your not Host send the command
            CmdSetSetThrusters(m_thrustOn);
        }
    }
    

    Personally for this reason for me the SyncVar with Hooks was always a little bit confusing and suspect.

    You could as well simply implement both directions yourself using e.g.

    [Command]
    void CmdSetSetThrusters(bool newVal)
    {
        // set the value on yourself 
        SetThrusters(newVal);
    
        // Then directly forward it to all clients
        RpcSetThrusters(newVal);
    }
    
    [ClientRpc]
    private void RpcSetThrusters(bool newValue)
    {
        // set the value on all clients
        SetThrusters(newVal);
    }
    
    private void SetThrusters(bool newVal)
    {
        if (newVal)
        {
            m_playerPs.Play();
        }
        else 
        {
            m_playerPs.Stop();
        }
    
        // if you are the HOST forward to all clients
        if(isServer)
        {
            RpcSetThrusters(newVal);
        }
    }
    

    and then

    if (isLocalPlayer)
    {
        MovePlayer();
    
        if(isServer)
        {
            SetThrusters(m_thrusterState);
        }
        else
        {
            // if your not Host send the command
            CmdSetSetThrusters(m_thrustOn);
        }
    }