Security / RPC

Hey.

I’m thinking about my game and his network system. I read many articles about network and the fact we have to be careful with the players who cheat. I’m not used to code network games so I have 2 questions:

  • RPC: I don’t know how to ask my question so I’m just gonna show you an example. On an GameObject (Character), I have 2 components :

  • PlayerController : handle inputs and is enable only for ONE character (OUR character)

public class PlayerController : MonoBehaviour {
    private MyCharacterController _character;
    Spell spell = new Fireball();

    void Awake() {
        _character = GetComponent<MyCharacterController>();
    }

    void Update() {
        if (Input.GetKeyDown(KeyCode.UpArrow)) {
            // change the character position
        } else if (Input.GetKeyDown(KeyCode.DownArrow)) {
            // change character position
        } else if (Input.GetKeyDown(KeyCode.A)) {
            if (_character.mana >= spell.cost) {
                 // Launch a Fireball to the target
                 // Spell.spellName is needed to know which spell is being cast
                 // target.photonView.viewID is needed to know who is targeted
                 _character.photonView.RPC("spellCast", PhotonTargets.All, spell.spellName, target.photonView.viewID);
             }
        }
    }
}
  • CharacterController : contains all data relative to a character (Health, Mana, whatever…) and all functions which will call an animation or an effect.
public class MyCharacterController : MonoBehaviour {
    public float health;
    public float mana;
    public float speedMovement;

    [RPC]
    public void spellCast(string spellName, int targetViewId) {
        Character target = getTargetByViewId(targetViewId);
        Spell spell = getSpellByName(spellName);

        // Apply effects of the spell
        spell.effects();

        target.takeDamage(spell.damages);
    }

    public void takeDamage(int damages) {
        // do some maths and check (is the player dying ?)

        // the change the character life
        setHealth(health - damages);
    }

    public void setHealth(int newHealth) {
        health = newHealth;
    }
}

When you connect to my game, the game creates a “Character” for you. For each other players in the game, It’ll create a “Character” and disablePlayerController” (because there should be only one PlayerController).
Now, let’s say I wanna cast a spell ; through my PlayerController, I’m gonna check if everything is OK (have I enough mana ? is the spell in cooldown ? etc.) and if so, I’ll callcastSpell” of “CharacterController” which is a RPC function. Every player is gonna call this function.
Okay, now here is my problem: when I call this function, castSpell will… cast the spell wanted by ALL player. So everybody is gonna call spell.effects which creates a Fireball G.O. (but it is NOT instantiate with Photon.Instantiate). And I’m not really sure if this is a good idea. But it works. However, the real “problem” is when I’m gonna apply the damages : I have NO idea how to do that… Currently, you can see that everybody is gonna call “target.takeDamages(…)” ; so it shouldn’t be a problem, all of them will have the target life updated (it works)… But I’m pretty sure this is not the good way… I was thinking about changing setHealth to a RPC function… but If I do that, I’ll have to change everything (cause everyone will call setHealth so this is stupid… or maybe should I check if photonView.isMine returns true ?).

I don’t know If I’m clear (maybe my english, I don’t even know how to explain that in my mother tongue :smile:). I don’t want you to code something, I wanna know the way of how to refreshing data and applying animations/effects through the network.

  • Security: as you can see above, I don’t check what the player is sending (HE checks if he has enough mana to cast his spell)… I read somewhere that it should be interesting to have a “fake” player (launched by the server) who creates the game (so he is the MasterClient) and all RPC have to go through him… But I’m not sure if it is efficient… I mean, If I do that, when a player call a RPC function, he has to send his request to the MasterClient, then the MasterClient check if it is OK and finally, the MasterClient sends to all players the request… Instead of doing:

  • Client → Server → Clients

It does:

  • Client → Server → MasterClient → Server → Clients

… Maybe i didn’t understand what they were saying. Lol.
Maybe I have a solution, but I want to be sure this is safe: when the player launches the game, the server is gonna check all the files inside the game directory… so if someone tried to change a file or add a file, the server is gonna say “No”. Good or bad solution ? :smile:

Thank you and If you need any information, feel free to ask me your questions!! I really want to understand all that stuff :slight_smile:

Sbizz.

watch thread :slight_smile:

About the security, I checked on internet what I can / have to do and I found what I was talking about ; “Authoritative Server” on google will lead you. I found a tutorial and I’m trying to change all my network system I already have. Once this will be done, I think I’ll have to change the way I use RPC functions.

All clients have to go through a “fake” client as I said ; when a client uses photonView.RPC(“function”), the target must be this “fake” client (the easiest thing I found it’s to connect the “fake” client first so he’s considered as the Master Client of the game ; you just have to send client’s RPC to him). The M.C. will do some check and if everything is OK he’s going to update HIS data. You just have to synchronize your clients with the M.C. (using OnPhotonSerializeView). The only thing to keep in mind is : your clients send actions they wanna do to the M.C. (“I want to move forward”), the M.C. receives the action, checks if the client can move forward and updates the GameObejct which represents the client’s GameObject. The hardest thing with an Authoritative server is to split server and client side… because you’re in the same scene, with the same GameObject and the same components ; but depending on which side you are (sender / receiver), you have to either disable some components or check if it’s the client requesting or the server…

Check this tutorial, it’s a bit hard if you already done something but from scratch it’s really easy to get it : Authoritative server networking. There are 3 parts!

If I solve my first problem, I’ll update this thread :wink:

You cannot create an authoritative server with PUN.

You can however let the master client control damage and such. Still possible to hack the game though.

Let me give a very simple example.
Lets say you cast a fireball. You will spawn it locally and check for impact locally (no Photon instantiate).
We will let the masterclient update health and everyone else will just disable the fireball locally on hit.

//Instantiate RPC, call this on all others and locally.

[RPC]
private void CreateFireball(vector3 direction, vector3 position)
{
             //Do your instaniate magic in here
}

//Check for impact in update for example and call this when it hits locally - NOW IMPORTANT. Update health if //you are master client, else disable it locally.

private void Impact(int damage)
{
         if(PhotonNetwork.isMasterClient)
         {
                 photonView.RPC("UpdateHealth", PhotonTargets.All, health - damage);
          }

         Fireball.SetActive(false);
}

//Health RPC update, controlled by the master client
[RPC]
private void UpdateHealth(int newHealth)
{
          health = newHealth;
}

I’m doing an authoritative server with PUN and it works fine.

About your first message: why it still possible to hack the game ? I mean, the Master Client will be on a server so… nobody can access to it.

For your example, I don’t understand why you’re creating your fireball locally. It should be created on the server (with Photon so all clients will synchronize the new GameObject).

Maybe I missed something…

If you think you are creating an authoritative server with PUN you need to read up on how it all works a bit more. An authoritative server means that the server makes all important decisions, NOT the master client who is just another player. With PUN you don’t have access to your own server.

I will control the fireball locally because you dont have enough messages to control stuff like that over the network. You got a limit of 500 msgs per second. Lets say you update the fireball 10 times per second with four players then that one fireball alone is 40 msgs per second. Now you also need messages for each player, so you will quickly hit the limit.

And it is all possible to hack, because the masterclient can hack everything, he is just a player like everyone else.

The thing is that my Master Client will be launched on the server by an executable. That’s why I can do an authoritative server with PUN. It is not controlled by a player… (and it will be launched with the flag -batchmode, so there will be no rendering). It’s just a trick to do an authoritative server with PUN.

Anyway, this is not really a problem, the way I do my game is “like” an authoritative server, so If I need to remove PUN to change it by something else, I’ll be able to do it easily because it’s structured as an authoritative server. I guess… D:

This is something good to know :o Where did you see this limit ? Can it be modified ? This limit only appears with PUN ? Even without a fireball, handling player movement is also a problem… no ? My game must handle 30 players D:

Well yes of cause you can run a master client on a server. Kind of a weird solution but possible.
The msgs limit is presented under both PUN and Photon Realtime on their website.

30 People will never happen with PUN. Then you need to go with their server solution: Multiplayer Game Development Made Easy | Photon Engine.

The thing with their server solution is that you need to implement all physics, pathfinding and such server side yourself. You cannot use Unity stuff.

But why not go with something else then? Like: https://www.assetstore.unity3d.com/en/#!/content/18358 forexample.