Search Unity

Question about local authority

Discussion in 'Multiplayer' started by shiva-js, Jun 16, 2015.

  1. shiva-js

    shiva-js

    Joined:
    Oct 5, 2011
    Posts:
    31
    Consider how a game like Battlefield might exist if implemented with UNet. When a client joins a server and spawns, a 'player' object is created for them. This object would have local authority so that the client's inputs apply immediately.

    So far so good. My query revolves around how player-controlled vehicles fit into the puzzle. As far as I can tell, I cannot make the vehicle local player authoritative when the player hops in. How then will the vehicle controls be applied to the vehicle in a responsive way? Will I need to store my own 'the player is controlling me' variable on the vehicle while it is being controlled in order to ignore data coming back from the server?

    I'm not concerned about being able to solve this issue, I'm more curious to hear what the best practice is for situations like this.
     
  2. Sbizz

    Sbizz

    Joined:
    Oct 2, 2014
    Posts:
    250
    When you check "Local Authority" on a GameObject, it is applied on the current gameObject and his children.

    So, you could change the vehicle's parent in order to become a player's child. That's way, you have the authority on the vehicle.
     
  3. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    Yes, this is a use case that doesn't have an obvious solution in this version of UNet.

    There is NetworkServer.ReplacePlayerForConnection() that allows you to switch the player object for a connection at runtime. You could also route vehicle controls through the player object.
     
  4. Carpe-Denius

    Carpe-Denius

    Joined:
    May 17, 2013
    Posts:
    842
    If I route vehicle controls through the player, wouldn't that mean that I have to put EVERY method for controls onto the player (one for a bike, one for cars, one for cars with horns) which seems pretty ugly or use a method where every input I have will be sent over the network, causing too much traffic?

    Because if my player sends a drive()-message to the car which in turn should send it to the server, I will get an error message that it's not my own player...

    It wouldn't work if you have two GameObjects with receiving inputs, say your character for shooting and the drivable car, because only one gameobject could be assigned as player.
     
    Last edited: Jun 16, 2015
  5. Sbizz

    Sbizz

    Joined:
    Oct 2, 2014
    Posts:
    250
    Or you can have one script which handles every moves for a vehicle, let's say AVehicle and your player just have to get the component AVehicle from the gameObject. Then you can have several classes which inherit from AVehicle and implement the abstract functions like "MoveForward", "Shoot" (does nothing is can not shoot), "Jump", whatever.
     
  6. Carpe-Denius

    Carpe-Denius

    Joined:
    May 17, 2013
    Posts:
    842
    Thats what I meant with "put every control on the player object". I have to differ between vehicles, air, foot and every other type of input with a switch on the player instead of letting the object handle input
     
  7. Sbizz

    Sbizz

    Joined:
    Oct 2, 2014
    Posts:
    250
    Okay, let's say you have a class named "Player" : this is your player. When it presses "Z", it calls "MoveForward()", when it presses S : "MoveBack()", etc.
    You could have a property called "Vehicle" type of "AVehicle". So, in MoveForward of Player, you could do that :

    Code (CSharp):
    1. if (this.Vehicle == null) {
    2. // Move player forward
    3. } else {
    4. this.Vehicle.MoveForward();
    5. }
    AVehicle could have several abstract functions (similar to Player's) and on your vehicle object, you'll have to attach the right script. It's a grounded vehicle ? Car : AVehicle. A plane ? Plane : AVehicle, etc.

    So in my case, Player handles his movements or it calls the functions of the vehicle.. so yes, you have to switch between Player Movements and AVehicle Movements, but the way of the object moves is inside the attached script (Car, Plane, etc).
     
  8. Carpe-Denius

    Carpe-Denius

    Joined:
    May 17, 2013
    Posts:
    842
    Yes, I did understand you. But I have several different types of input-receiving objects (car, plane, chopper, crane, radio, door-systems...). I think I will take an interface with PlayerInput(float), PlayerInput(float, float), until 6 or 7 floats. That way I only have 7 different methods to check. Or maybe I will find something better since f1 to f7 are not very clear names.

    Edit: maybe I can add the component (craneInputReceiver) to the playerobject and disable it completely when needed. Otherwise I would get lost in ifs and switches
     
  9. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Just create a series of classes to handle control schemes and switch them out when the player enters/exists a vehicle.

    Code (csharp):
    1.  
    2. public abstract class ControlScheme
    3. {
    4.     Player player;
    5.  
    6.     public ControlScheme(Player player)
    7.     {
    8.         this.player = player;
    9.     }
    10.  
    11.     public virtual void HandleInput() { }
    12. }
    13.  
    14. public class PlayerControl : ControlScheme { }
    15. public class VehicleControl : ControlScheme { }
    16.  
    Code (csharp):
    1.  
    2. public class Player : NetworkBehaviour
    3. {
    4.     ControlScheme controlScheme;
    5.  
    6.     void Awake()
    7.     {
    8.         controlScheme = new PlayerControl(this);
    9.     }
    10.  
    11.     void Update()
    12.     {
    13.         controlScheme.HandleInput();
    14.     }
    15.  
    16.     void EnterVehicle()
    17.     {
    18.         controlScheme = new VehicleControl(this);
    19.     }
    20. }
    21.  
     
  10. Carpe-Denius

    Carpe-Denius

    Joined:
    May 17, 2013
    Posts:
    842
    Thats cleaner than switching components, thank you.
    Edit: does that even work? I can't use commands in the control scheme since it is no NetworkBehaviour, so I still have to send every axis via network, even if this control scheme just uses 2.
     
    Last edited: Jun 17, 2015
  11. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    You've got a NetworkBehaviour wrapper in Player already so you could route Commands through that if need be. Not sure why you'd send axis information over the network anyway though...
     
  12. Carpe-Denius

    Carpe-Denius

    Joined:
    May 17, 2013
    Posts:
    842
    At the moment I have a player, a script which handles Input and a receiver (simplified: car.move(speed,steering), train.move(speed) or plane.Move(speed, leftRight, UpDown)).
    That works, with all the different combinations I have (car with horns, plane with movable wheels..).

    If I want to put networking inbetween , I'll get:
    player.Update() -> handles input, sends it to
    player.CmdReceiveCar(float, float) -> sends it to
    Car

    That way I have to have all three input schemes in player.Update() and all three commands in the player object (plus all the other commands, like Honk or MoveWheelsUp, MoveWheelsDown, fire onboard weapon)

    If I put it in a second monobehaviour and activate that, it would probably work.
    If I put it in your ControlScheme, I will have:

    ControlScheme.Update() handles Input, sends floats to
    Player -> sends commands to
    Player.CmdReceiveCar -> sends floats back to
    ControlScheme to handle them and send them to
    Car

    This seems unneccessary complicated and I didn't get any combinations to work yet.
    I somehow think I should delete everything and start over, now knowing which object can send stuff and which can't ;)
     
    Last edited: Jun 18, 2015
  13. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Shouldn't the local player just be handling input? It seems to make more sense to just sync position and rotation (which I believe NetworkTransform should just do for you).
     
  14. Carpe-Denius

    Carpe-Denius

    Joined:
    May 17, 2013
    Posts:
    842
    Sadly that doesn't work.
    If I let the player move his car, the position gets overwritten by the NetworkTransform since the car wasn't moved on the server.
    That was my very first thought how to handle it, but if I move the car locally, I'll either get an error that I can only change my own playerObject or the car just won't move.
    I couldn't find a "NetworkIdentity.SetOwner" method either.

    Edit: well, turns out, commands won't work on added monobehaviours and SyncVars won't work from player to server, not even on the player object.
    Adding the car as a player object seems to be the only possibility left. It works and has the benefit of direct reaction to your input, but it makes it more vunerable to cheats.
     
    Last edited: Jun 19, 2015