Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Executing functions on clients

Discussion in 'Scripting' started by Connor_13_, Jul 15, 2014.

  1. Connor_13_

    Connor_13_

    Joined:
    Mar 14, 2014
    Posts:
    40
    Is there a way to execute a function with or without an RPC call without any parameters and have it execute the same way on all clients as on the client sending the RPC call or otherwise?

    In other words, how can I pass all the information used in a function on one client to the other clients without using parameters?
     
  2. Deequation

    Deequation

    Joined:
    Jan 2, 2014
    Posts:
    16


    There are multiple ways of doing this, but considering you wrote with or without RPC, I am going to give you an example using the RPC method built in to the default (at the time of writing) network solution. If you are using another networking solution, you need to adjust and find the functions in their documentations. The goal of this is to show how to pass a function using the remote protocol call, from a client to all other clients.



    [01] Calling the function:


    The first thing you should note is a client can not communicate with another client directly. It has to go through the server, and then spread out to the rest of the clients. In this first example I will call a function from the client to the server, then have the server call a second function on everyone else - just to get you familiarized with passing the function. You should note that to use the networkView class you need to have a NetworkView-component on the game object.

    Code (CSharp):
    1. [Client.cs]
    2. ..
    3. void Awake ()
    4. {
    5.     networkView.RPC("Join", RPCMode.Server);
    6. }
    7.  
    8. [RPC] void Join ()
    9. {
    10. }
    11.  
    12. [RPC] void Hello ()
    13. {
    14.     Debug.Log("Hello");
    15. }
    16. ..
    17.  
    18. [Server.cs]
    19. ..
    20. [RPC] void Join ()
    21. {
    22.     networkView.RPC("Hello", RPCMode.All);
    23. }
    24.  
    25. [RPC] void Hello ()
    26. {
    27.     Debug.Log("Hello");
    28. }
    29. ..





    [02] Optimizing the target:


    Now the first method had two functions, so we avoided having to call the function twice on the sender. There's another way to do this, that are most likely what you want to do in your example. This has the drawback of calling it instantly on the client, and not letting the server handle any logic checks first. in this example I pass a string variable 'myName' to all other players, using a different RPCMode that calls the function through the server on everyone else except yourself.

    Code (CSharp):
    1. [Client.cs]
    2. ..
    3. void Awake ()
    4. {
    5.     networkView.RPC("NewPlayer", RPCMode.Others, myName);
    6. }
    7.  
    8. [RPC] void NewPlayer (string p_Name)
    9. {
    10.     Debug.Log("Player joined: " + p_Name);
    11. }
    12. ..




     
    Last edited: Jul 22, 2015
    Thoaril likes this.
  3. Connor_13_

    Connor_13_

    Joined:
    Mar 14, 2014
    Posts:
    40

    Thanks for the reply but I know basically how to use rpc calls. Let me explain ALOT more in depth...

    What I am actually trying to do is use unity networking to make the Bootcamp Unity demo have multiplayer functionality. I'm running into problems making the guns fire on all of the clients because I am not passing the booleans and other values for firing.

    The firing functions accesses variables and values from both other scripts and the game object the function is connected to. The functions have no parameters. What I want to know is if there is a way to send all of the information collected in the function to the other clients without adding parameters to the function itself.

    Again, is it possible to pass the values of variables used in an RPC function without using parameters? Can unity automatically collect the information from the client sending the call and then run an identical copy of the function, including all values, on the other clients instead of just running the function with values from the client receiving the call?
     
  4. Connor_13_

    Connor_13_

    Joined:
    Mar 14, 2014
    Posts:
    40
    Here is the Gun.js file I am working with...

    Code (JavaScript):
    1. #pragma strict
    2. #pragma implicit
    3. #pragma downcast
    4.  
    5. enum FireType
    6. {
    7.     RAYCAST,
    8.     PHYSIC_PROJECTILE,
    9. }
    10.  
    11. enum FireMode
    12. {
    13.     SEMI_AUTO,
    14.     FULL_AUTO,
    15.     BURST
    16. }
    17.  
    18. class Gun extends MonoBehaviour
    19. {
    20.     public var gunName : String;
    21.     public var bulletMark : GameObject;
    22.     public var projectilePrefab : GameObject;
    23.  
    24.     public var weaponTransformReference : Transform;
    25.  
    26.     public var hitLayer : LayerMask;
    27.  
    28.     public var woodParticle : GameObject;
    29.     public var metalParticle : GameObject;
    30.     public var concreteParticle : GameObject;
    31.     public var sandParticle : GameObject;
    32.     public var waterParticle : GameObject;
    33.  
    34.     //How many shots the gun can take in one second
    35.     public var fireRate : float;
    36.     public var useGravity : boolean;
    37.     private var fireType : FireType;
    38.     public var fireMode : FireMode;
    39.  
    40.     //Number of shoots to fire when on burst mode
    41.     public var burstRate : int;
    42.  
    43.     //Range of fire in meters
    44.     public var fireRange : float;
    45.  
    46.     //Speed of the projectile in m/s
    47.     public var projectileSpeed : float;
    48.  
    49.     public var clipSize : int;
    50.     public var totalClips : int;
    51.  
    52.     //Time to reload the weapon in seconds
    53.     public var reloadTime : float;
    54.     public var autoReload : boolean;
    55.     public var currentRounds : int;
    56.  
    57.     public var shootVolume : float = 0.4;
    58.     public var shootSound : AudioClip;
    59.     private var shootSoundSource : AudioSource;
    60.  
    61.     public var reloadSound : AudioClip;
    62.     private var reloadSoundSource : AudioSource;
    63.  
    64.     public var outOfAmmoSound : AudioClip;
    65.     private var outOfAmmoSoundSource : AudioSource;
    66.  
    67.     private var reloadTimer : float;
    68.  
    69.     @HideInInspector
    70.     public var freeToShoot : boolean;
    71.  
    72.     @HideInInspector
    73.     public var reloading : boolean;
    74.     private var lastShootTime : float;
    75.     private var shootDelay : float;
    76.     private var cBurst : int;
    77.  
    78.     @HideInInspector
    79.     public var fire : boolean;
    80.     public var hitParticles : GameObject;
    81.  
    82.     public var shotingEmitter : GunParticles;
    83.     private var shottingParticles : Transform;
    84.  
    85.     public var capsuleEmitter : ParticleEmitter[];
    86.  
    87.     public var shotLight : ShotLight;
    88.  
    89.     public var unlimited : boolean = true;
    90.  
    91.     private var timerToCreateDecal : float;
    92.  
    93.     public var pushPower : float = 3.0;
    94.  
    95.     public var soldierCamera : SoldierCamera;
    96.     private var cam : Camera;
    97.  
    98.     function OnDisable()
    99.     {
    100.         if(shotingEmitter != null)
    101.         {
    102.             shotingEmitter.ChangeState(false);
    103.         }
    104.      
    105.         if(capsuleEmitter != null)
    106.         {
    107.             for(var i : int = 0; i < capsuleEmitter.Length; i++)
    108.             {
    109.                 if (capsuleEmitter[i] != null)
    110.                     capsuleEmitter[i].emit = false;
    111.             }
    112.         }
    113.      
    114.         if(shotLight != null)
    115.         {
    116.             shotLight.enabled = false;
    117.         }
    118.     }
    119.  
    120.     function OnEnable()
    121.     {
    122.         cam = soldierCamera.camera;
    123.      
    124.         reloadTimer = 0.0;
    125.         reloading = false;
    126.         freeToShoot = true;
    127.         shootDelay = 1.0 / fireRate;
    128.      
    129.         cBurst = burstRate;
    130.      
    131.         totalClips--;
    132.         currentRounds = clipSize;
    133.      
    134.         if(projectilePrefab != null)
    135.         {
    136.             fireType = FireType.PHYSIC_PROJECTILE;
    137.         }
    138.      
    139.         if(shotLight != null)
    140.         {
    141.             shotLight.enabled = false;
    142.         }
    143.      
    144.         shottingParticles = null;
    145.         if(shotingEmitter != null)
    146.         {
    147.             for(var i : int = 0; i < shotingEmitter.transform.childCount; i++)
    148.             {
    149.                 if(shotingEmitter.transform.GetChild(i).name == "bullet_trace")
    150.                 {
    151.                     shottingParticles = shotingEmitter.transform.GetChild(i);
    152.                     break;
    153.                 }
    154.             }
    155.         }
    156.     }
    157.  
    158.     @RPC
    159.     function ShotTheTarget()
    160.     {
    161.         if(fire && !reloading)
    162.         {
    163.             Debug.LogError("fire && !reloading");
    164.             if(currentRounds > 0)
    165.             {
    166.                 Debug.LogError("current rounds > 0");
    167.                 if(Time.time > lastShootTime && freeToShoot && cBurst > 0)
    168.                 {
    169.                     Debug.LogError("blah, blah");
    170.  
    171.                     lastShootTime = Time.time + shootDelay;
    172.          
    173.                     switch(fireMode)
    174.                     {
    175.                         case FireMode.SEMI_AUTO:
    176.                             freeToShoot = false;
    177.                             break;
    178.                         case FireMode.BURST:
    179.                             cBurst--;
    180.                             break;
    181.                     }
    182.                  
    183.                     if(capsuleEmitter != null)
    184.                     {
    185.                         for(var i : int = 0; i < capsuleEmitter.Length; i++)
    186.                         {
    187.                             capsuleEmitter[i].Emit();
    188.                         }
    189.                     }
    190.  
    191.                     PlayShootSound();
    192.                  
    193.                     if(shotingEmitter != null)
    194.                     {
    195.                         shotingEmitter.ChangeState(true);
    196.                      
    197.                     }
    198.                  
    199.                     if(shotLight != null)
    200.                     {
    201.                         shotLight.enabled = true;
    202.                     }
    203.                  
    204.                     switch(fireType)
    205.                     {
    206.                         case FireType.RAYCAST:
    207.                             TrainingStatistics.shootsFired++;
    208.                             CheckRaycastHit();
    209.                             break;
    210.                         case FireType.PHYSIC_PROJECTILE:
    211.                             TrainingStatistics.grenadeFired++;
    212.                             LaunchProjectile();
    213.                             break;
    214.                     }
    215.                  
    216.                     currentRounds--;
    217.                  
    218.                     if(currentRounds <= 0)
    219.                     {
    220.                         Reload();
    221.                     }
    222.                 }
    223.             }
    224.             else if(autoReload && freeToShoot)
    225.             {
    226.                 Debug.LogError("autoreload and free to shoot");
    227.  
    228.                 if(shotingEmitter != null)
    229.                 {
    230.                     shotingEmitter.ChangeState(false);
    231.                 }
    232.              
    233.                 if(shotLight != null)
    234.                 {
    235.                     shotLight.enabled = false;
    236.                 }
    237.              
    238.                 if(!reloading)
    239.                 {
    240.                     Reload();
    241.                 }
    242.             }
    243.         }
    244.         else
    245.         {
    246.             Debug.LogError("else");
    247.  
    248.             if(shotingEmitter != null)
    249.             {
    250.                 shotingEmitter.ChangeState(false);
    251.             }
    252.          
    253.             if(shotLight != null)
    254.             {
    255.                 shotLight.enabled = false;
    256.             }
    257.         }
    258.     }
    259.  
    260.     function LaunchProjectile()
    261.     {
    262.         //Get the launch position (weapon related)
    263.         var camRay : Ray = cam.ScreenPointToRay(new Vector3(Screen.width * 0.5, Screen.height * 0.6, 0));
    264.      
    265.         var startPosition : Vector3;
    266.      
    267.         if(weaponTransformReference != null)
    268.         {
    269.             startPosition = weaponTransformReference.position;
    270.         }
    271.         else
    272.         {
    273.             startPosition = cam.ScreenToWorldPoint(new Vector3 (Screen.width * 0.5, Screen.height * 0.5, 0.5));
    274.         }
    275.      
    276.         var projectile : GameObject = GameObject.Instantiate(projectilePrefab, startPosition, Quaternion.identity);
    277.      
    278.         var grenadeObj : Grenade = projectile.GetComponent("Grenade") as Grenade;
    279.         grenadeObj.soldierCamera = soldierCamera;
    280.      
    281.         projectile.transform.rotation = Quaternion.LookRotation(camRay.direction);
    282.      
    283.         var projectileRigidbody : Rigidbody = projectile.rigidbody;
    284.      
    285.         if(projectile.rigidbody == null)
    286.         {
    287.             projectileRigidbody = projectile.AddComponent("Rigidbody");  
    288.         }
    289.         projectileRigidbody.useGravity = useGravity;
    290.      
    291.         var hit : RaycastHit;
    292.         var camRay2 : Ray = cam.ScreenPointToRay(new Vector3(Screen.width * 0.5, Screen.height * 0.55, 0));
    293.      
    294.         if(Physics.Raycast(camRay2.origin, camRay2.direction, hit, fireRange, hitLayer))
    295.         {
    296.             projectileRigidbody.velocity = (hit.point - weaponTransformReference.position).normalized * projectileSpeed;
    297.         }
    298.         else
    299.         {
    300.             projectileRigidbody.velocity = (cam.ScreenToWorldPoint(new Vector3(Screen.width * 0.5, Screen.height * 0.55, 40)) - weaponTransformReference.position).normalized * projectileSpeed;
    301.         }
    302.     }
    303.  
    304.     function CheckRaycastHit()
    305.     {
    306.         var hit : RaycastHit;
    307.         var glassHit : RaycastHit;
    308.         var camRay : Ray;
    309.         var origin : Vector3;
    310.         var glassOrigin : Vector3;
    311.         var dir : Vector3;
    312.         var glassDir : Vector3;
    313.      
    314.         if(weaponTransformReference == null)
    315.         {
    316.             camRay = cam.ScreenPointToRay(new Vector3(Screen.width * 0.5, Screen.height * 0.5, 0));
    317.             origin = camRay.origin;
    318.             dir = camRay.direction;
    319.             origin += dir * 0.1;
    320.         }
    321.         else
    322.         {
    323.             camRay = cam.ScreenPointToRay(new Vector3(Screen.width * 0.5, Screen.height * 0.5, 0));
    324.            
    325.             origin = weaponTransformReference.position + (weaponTransformReference.right * 0.2);
    326.          
    327.             if(Physics.Raycast(camRay.origin + camRay.direction * 0.1, camRay.direction, hit, fireRange, hitLayer))
    328.             {
    329.                 dir = (hit.point - origin).normalized;
    330.              
    331.                 if(hit.collider.tag == "glass")
    332.                 {
    333.                     glassOrigin = hit.point + dir * 0.05;
    334.                  
    335.                     if(Physics.Raycast(glassOrigin, camRay.direction, glassHit, fireRange - hit.distance, hitLayer))
    336.                     {
    337.                         glassDir = glassHit.point - glassOrigin;
    338.                     }
    339.                 }
    340.             }
    341.             else
    342.             {
    343.                 dir = weaponTransformReference.forward;
    344.             }
    345.         }
    346.      
    347.         if(shottingParticles != null)
    348.         {
    349.             shottingParticles.rotation = Quaternion.FromToRotation(Vector3.forward, (cam.ScreenToWorldPoint(new Vector3(Screen.width * 0.5, Screen.height * 0.5, cam.farClipPlane)) - weaponTransformReference.position).normalized);
    350.         }
    351.      
    352.         if(Physics.Raycast(origin, dir, hit, fireRange, hitLayer))
    353.         {
    354.             hit.collider.gameObject.SendMessage("Hit", hit, SendMessageOptions.DontRequireReceiver);
    355.             GenerateGraphicStuff(hit);
    356.          
    357.             if(hit.collider.tag == "glass")
    358.             {
    359.                 if(Physics.Raycast(glassOrigin, glassDir, glassHit, fireRange - hit.distance, hitLayer))
    360.                 {
    361.                     glassHit.collider.gameObject.SendMessage("Hit", glassHit, SendMessageOptions.DontRequireReceiver);
    362.                     GenerateGraphicStuff(glassHit);
    363.                 }
    364.             }
    365.         }
    366.     }
    367.  
    368.     function GenerateGraphicStuff(hit : RaycastHit)
    369.     {
    370.         var hitType : HitType;
    371.      
    372.         var body : Rigidbody = hit.collider.rigidbody;
    373.         if(body == null)
    374.         {
    375.             if(hit.collider.transform.parent != null)
    376.             {
    377.                 body = hit.collider.transform.parent.rigidbody;
    378.             }
    379.         }
    380.      
    381.         if(body != null)
    382.         {
    383.             if(body.gameObject.layer != 10 && !body.gameObject.name.ToLower().Contains("door"))
    384.             {
    385.                 body.isKinematic = false;
    386.             }
    387.      
    388.             if(!body.isKinematic)
    389.             {
    390.                     var direction : Vector3 = hit.collider.transform.position - weaponTransformReference.position;
    391.                 body.AddForceAtPosition(direction.normalized * pushPower, hit.point, ForceMode.Impulse);
    392.             }
    393.         }
    394.      
    395.         var go : GameObject;
    396.      
    397.         var delta : float = -0.02;
    398.         var hitUpDir : Vector3 = hit.normal;
    399.         var hitPoint : Vector3 = hit.point + hit.normal * delta;
    400.      
    401.         switch(hit.collider.tag)
    402.         {
    403.             case "wood":
    404.                 hitType = HitType.WOOD;
    405.                 go = GameObject.Instantiate(woodParticle, hitPoint, Quaternion.FromToRotation(Vector3.up, hitUpDir)) as GameObject;
    406.                 break;
    407.             case "metal":
    408.                 hitType = HitType.METAL;
    409.                 go = GameObject.Instantiate(metalParticle, hitPoint, Quaternion.FromToRotation(Vector3.up, hitUpDir)) as GameObject;
    410.                 break;
    411.             case "car":
    412.                 hitType = HitType.METAL;
    413.                 go = GameObject.Instantiate(metalParticle, hitPoint, Quaternion.FromToRotation(Vector3.up, hitUpDir)) as GameObject;
    414.                 break;
    415.             case "concrete":
    416.                 hitType = HitType.CONCRETE;
    417.                 go = GameObject.Instantiate(concreteParticle, hitPoint, Quaternion.FromToRotation(Vector3.up, hitUpDir)) as GameObject;
    418.                 break;
    419.             case "dirt":
    420.                 hitType = HitType.CONCRETE;
    421.                 go = GameObject.Instantiate(sandParticle, hitPoint, Quaternion.FromToRotation(Vector3.up, hitUpDir)) as GameObject;
    422.                 break;
    423.             case "sand":
    424.                 hitType = HitType.CONCRETE;
    425.                 go = GameObject.Instantiate(sandParticle, hitPoint, Quaternion.FromToRotation(Vector3.up, hitUpDir)) as GameObject;
    426.                 break;
    427.             case "water":
    428.                 go = GameObject.Instantiate(waterParticle, hitPoint, Quaternion.FromToRotation(Vector3.up, hitUpDir)) as GameObject;
    429.                 break;
    430.             default:
    431.                 return;
    432.         }
    433.      
    434.         go.layer = hit.collider.gameObject.layer;
    435.      
    436.         if(hit.collider.renderer == null) return;
    437.      
    438.         if(timerToCreateDecal < 0.0 && hit.collider.tag != "water")
    439.         {
    440.             go = GameObject.Instantiate(bulletMark, hit.point, Quaternion.FromToRotation(Vector3.forward, -hit.normal));
    441.             var bm : BulletMarks = go.GetComponent("BulletMarks");
    442.             bm.GenerateDecal(hitType, hit.collider.gameObject);
    443.             timerToCreateDecal = 0.02;
    444.         }
    445.     }
    446.  
    447.     function Update()
    448.     {
    449.         timerToCreateDecal -= Time.deltaTime;
    450.      
    451.         if(Input.GetButtonDown("Fire1") && currentRounds == 0 && !reloading && freeToShoot)
    452.         {
    453.             networkView.RPC("PlayOutOfAmmoSound", RPCMode.All);
    454.             //PlayOutOfAmmoSound();
    455.         }
    456.      
    457.         if(Input.GetButtonUp("Fire1"))
    458.         {
    459.             freeToShoot = true;
    460.             cBurst = burstRate;
    461.         }
    462.         networkView.RPC("HandleReloading", RPCMode.All);
    463.         //HandleReloading();
    464.         networkView.RPC("ShotTheTarget", RPCMode.All);
    465.         //ShotTheTarget();
    466.     }
    467.  
    468.     @RPC
    469.     function HandleReloading()
    470.     {
    471.         if(Input.GetKeyDown(KeyCode.R) && !reloading)
    472.         {
    473.             Reload();
    474.         }
    475.      
    476.         if(reloading)
    477.         {
    478.             reloadTimer -= Time.deltaTime;
    479.          
    480.             if(reloadTimer <= 0.0)
    481.             {
    482.                 reloading = false;
    483.                 if(!unlimited)
    484.                 {
    485.                     totalClips--;
    486.                 }
    487.                 currentRounds = clipSize;
    488.             }
    489.         }
    490.     }
    491.  
    492.     function Reload()
    493.     {
    494.         if(totalClips > 0 && currentRounds < clipSize)
    495.         {
    496.             PlayReloadSound();
    497.             reloading = true;
    498.             reloadTimer = reloadTime;
    499.         }
    500.     }
    501.  
    502.     //---------------AUDIO METHODS--------
    503.     @RPC
    504.     function PlayOutOfAmmoSound()
    505.     {
    506.         audio.PlayOneShot(outOfAmmoSound, 1.5);
    507.     }
    508.  
    509.     @RPC
    510.     function PlayReloadSound()
    511.     {
    512.         audio.PlayOneShot(reloadSound, 1.5);
    513.     }
    514.  
    515.     @RPC
    516.     function PlayShootSound()
    517.     {
    518.         audio.PlayOneShot(shootSound);
    519.     }
    520. }

    I did various tests, one of which was conclusive in some way (using the Debug.LogError lines).

    I had a client and server running on the same machine. I'll start with what happened on the client. "else" printed continuously unless the fire button was pressed in which case "fire && !reloading" printed. Then "current rounds > 0" printed then "blah, blah" printed. The gun had successfully fired. During all of this and through all of the RPC calls, the server continued to show only "else". I concluded that this meant that the variables included in the function were not being passed. They must be passed as parameters.

    I want to know if there is any way to send variables that are simply included in a function (like the Gun.js script) to the other clients without using parameters.

    I know this may not be possible, and that is an acceptable answer. If it is not possible, I would appreciate some help rewritting the above Gun.js script.

    Thanks

    (sorry I wasn't good at explaining this before)