Search Unity

How to send variables directly from one client/player to another

Discussion in 'Multiplayer' started by Zefalcon, Jan 30, 2018.

  1. Zefalcon

    Zefalcon

    Joined:
    Jun 17, 2016
    Posts:
    7
    I'm not sure if my question exactly matches my problem, but I'm not sure how else to phrase it. Some background before I get to the actual problem: I have a multiplayer networked applications where each player controls a neuron. They can set their own parameters by clicking on themselves, which pops open a window showing their current parameters that the user can type new values into and save. I also have a special class of user called an "instructor" that can change the parameters of any neuron through the same method and create neurons of their own (and change their parameters as well, of course).

    Originally players were the same as neurons, the instructor creates new neurons that have their own NetworkBehaviors and such, which generally screws up my code, but it's late enough in the process that it would be a pain to restructure, and honestly I've been able to avoid it thus far. But recently I had to force the settable parameters to not update on the server and all clients because it was causing issues with the way the instructor-spawned neurons decided if they lit up or not. Because of this, I now can't simply grab the parameters from the local copy to show in the window that pops up when a user tries to set their own (or in the case of an instructor, someone else's) parameters.

    So my question is: is there a way to specifically ask a client for their version of those parameters so I can show them in the popup window correctly when an instructor is asking for them (besides restructuring the entire codebase to avoid the problem entirely)? The methods I've tried so far haven't worked for me.

    Relevant code sections (this should be all):

    Code (CSharp):
    1. public class Controller : NetworkBehaviour {
    2. private float[] refractoryVariableHolder; //Temporary storage for refractory variables asked for from another Controller.
    3.  
    4. ...
    5.  
    6. public void PrepareRefractoryVariables() {
    7.         //Sets up refractory variables.
    8.         refractoryVariableHolder = new float[5];
    9.         CmdGetRefractoryVariables(gameObject);
    10.     }
    11.  
    12. [Command]
    13.     void CmdGetRefractoryVariables(GameObject neuron) {
    14.         TargetGetRefractoryVariables(neuron.GetComponent<Controller>().connectionToClient, neuron);  //TODO: Adjust for ISNs
    15.     }
    16.  
    17.     [TargetRpc]
    18.     void TargetGetRefractoryVariables(NetworkConnection connection, GameObject neuron) {
    19.         //Returns specific refractory variables from the source
    20.         float[] vars = new float[5];
    21.         vars[0] = GetThreshold();
    22.         vars[1] = GetHighThreshold();
    23.         vars[2] = GetAbsRefractoryPd();
    24.         vars[3] = GetRelRefractoryPd();
    25.         CmdReturnRefractoryVariables(vars[0], vars[1], vars[2], vars[3], neuron);
    26.     }
    27.  
    28.     [Command]
    29.     void CmdReturnRefractoryVariables(float thresh, float recovery, float absolute, float relative, GameObject neuron) {
    30.         float[] refractoryVariables = new float[] { thresh, recovery, absolute, relative, 5 };
    31.         neuron.GetComponent<Controller>().refractoryVariableHolder = refractoryVariables;
    32.         RpcReturnRefractoryVariables(thresh, recovery, absolute, relative, neuron);
    33.     }
    34.  
    35.     [ClientRpc]
    36.     void RpcReturnRefractoryVariables(float thresh, float recovery, float absolute, float relative, GameObject neuron) {
    37.         float[] refractoryVariables = new float[] { thresh, recovery, absolute, relative, 5 };
    38.         neuron.GetComponent<Controller>().refractoryVariableHolder = refractoryVariables;
    39.     }
    40.  
    41. public float[] GetRefractoryVariables() {
    42.         //Debug.Log("Get: " + refractoryVariableHolder[0]);
    43.         return refractoryVariableHolder;
    44.     }
    45. }
    Code (CSharp):
    1. public class UIManager : MonoBehaviour {
    2.  
    3. public void OpenSetNeuronParametersBox(GameObject neuron) {
    4.         setNeuronParameters.SetActive(true);
    5.         inDialogue = true;
    6.         neuronToSetRef = neuron;
    7.         Text message = GameObject.Find("EditingNeuronText").GetComponent<Text>();
    8.         message.text = "Currently editing " + neuron.name;
    9.  
    10.         //Set placeholders to correct values
    11.         neuron.GetComponent<Controller>().PrepareRefractoryVariables();
    12.         StartCoroutine("AwaitRefractoryVariables", neuron);
    13.     }
    14.  
    15.     public IEnumerator AwaitRefractoryVariables(GameObject neuron) {
    16.         //Wait for refractoryVariableHolder to be edited.
    17.         float[] refractoryVars = neuron.GetComponent<Controller>().GetRefractoryVariables();
    18.  
    19.         while (refractoryVars[4] == 0) {
    20.             yield return null;
    21.             refractoryVars = neuron.GetComponent<Controller>().GetRefractoryVariables();
    22.         }
    23.         SetNeuronParameterText(refractoryVars); //Sets textbox text to correct values
    24.     }
    25. }
    26.  
    If more code would help anyone solve my problem, just ask and I'll try not to overwhelm you.
     
  2. Zefalcon

    Zefalcon

    Joined:
    Jun 17, 2016
    Posts:
    7
    UPDATE: I was able to solve my issue without refactoring my code. I'm not sure which of these methods (or both combined) actually did the trick, but here's what I did, in case anyone has a vaguely similar issue.

    Instead of saving the parameters to a variable inside of the Controller class, I simply called the SetNeuronParameterText method from the asking client using a TargetRpc return method instead of the CmdReturnRefractoryVariables and Rpc versions. Secondly, for whatever reason, it seems like you can't call Cmd methods from within a TargetRpc, even if the script its attached to should have client authority, so I had to make simple methods to call from within the necessary TargetRpcs that took a NetworkBehavior (in this case Controller) and called the Cmd from there instead.