[RESOLU][DB-RS] Téléportation d'un objet client via le serveur

Pour les scripts écrits en C#
Règles du forum
Merci de respecter la NOMENCLATURE suivante pour vos TITRES de messages :

Commencez par le niveau de vos scripts
DB = Débutant
MY = Moyen
CF = Confirmé

Puis le domaine d'application
-RS = Réseau
-AL = Algorithmie

Exemple :

[DB-RS] Mouvement perso multijoueur
Autodidactelife
Messages : 47
Inscription : 21 Fév 2018 23:04
Localisation : France

[RESOLU][DB-RS] Téléportation d'un objet client via le serveur

Message par Autodidactelife » 21 Fév 2018 23:41

Bonjour,

D'abord j'aimerais dire que je suis autodidacte et qu'il me manque surement pleins de notions, mais je sais encore faire une recherche google dont ici je ne trouve pas la réponse, je vais vous expliquer un peu plus en détails:

J'ai un soucis au niveau de la téléportation d'un objet, m'intéressant énormément à tout ce qui est failles et modifications du client je fais toujours des tests au cas où une personne arriverait à modifier ou détourner la fonction côté client, donc mon but est de faire tout ce qui est important niveau serveur.

J'ai actuellement un prototype ayant une inscription/connexion lié à une base de donnée, un personnage joueur avec local authority pour le joueur, des canvas qui jouent le rôle d'inventaire, liste des personnages connectés, chat. (Je suis à plus de 1000 lignes de programmation et aucun copier coller).

J'utilise donc une fonction dans le chat qui vérifie le grade du joueur qui l'exécute afin de téléporter un joueur (exemple: le mettre en "prison" afin de le punir). Malheureusement si je le fais uniquement côté serveur dès que le joueur bouge il ce téléporte à nouveau où il était, si dans le cas où je fais un ClientRpc, tout le monde voit bien le joueur être téléporter mais encore un mouvement (une synchronisation avec le serveur quoi) suffit pour être partir, donc le joueur peut aisément simuler où il est sans avoir aucune incidence niveau serveur.

En tant qu'application multijoueur je ne veux pas de failles, je sais que ce n'est pas facile de modifier les jeux Unity, mais en sois j'ai vu des logiciels assez efficace pour certains jeux et j'aimerais donc ne prendre aucun risque avec ça, je prend très au sérieux tout ce qui est failles et modification, j'ai même tester si nous pouvions lancer des Commands sur des gameobject qui ne sont pas en localauthority et j'ai eu ma réponse: ça ne marche pas (heureusement !).

Donc ma question pour la résumer:

Comment téléporter un joueur, sans passer par son client, d'une façon 100% sécurisé de tel façon que le serveur synchronise lui même le joueur avec la nouvelle position. Je ne pense pas que le joueur pourrait ensuite traverser les murs de la prison, dans le cas inverse je ferais une protection.

Mon jeu ce base énormément sur le déplacement, le conept est assez unique je veux que celui-ci soit parfaitement géré par le serveur et qu'un joueur mal intentionné ne puisse pas s'amuser à passer outre les sécurités et ce téléporter où il veut.

Je vous remercie pour avoir lu mon problème et je vous souhaite une bonne soirée/nuit.


Ps: J'ai essayer donc les transform.position côté serveur, les clientrpc qui transform.position, mon dernier choix serait de syncvar avec hook une variable contenant la position qui vérifie à chaque update que l'ancienne position et la nouvelle ne soit pas trop éloigné pour éviter la téléportation en plus de mettre correctement le joueur où il doit être. Mais si il y à une meilleur solution plus propre, ou si j'ai peut être mal compris quelque chose, j'en aimerais être informé ! Merci :)

Farstone
Messages : 187
Inscription : 04 Déc 2016 09:38

Re: [DB-RS] Téléportation d'un objet client via le serveur

Message par Farstone » 23 Fév 2018 06:32

Il faut mieux expliquer ton problème, comment tu informe les joueurs et le client en question de sa tp quand il est effectué côté serveur ? Je comprend le problème mais tu est trop vague dans t'es explications, poste un peu de code qu'ont comprennent, ou essaie de nous dire exactement comment ça marche. Ton problème a mon avis est juste une absence de serveur authoritative avec les info que tu donne. En gros, chaque action que le joueur fait au niveau du déplacement est simulé et vérifié par le serveur, ce qui rajoute du lag, qui peux ensuite être palier en développant un client prédiction, renseigne toi sur c'est sujets tu en apprendras plus. (Ne sous-estime pas l'autodidacte en passant, c'est l'avenir)

Autodidactelife
Messages : 47
Inscription : 21 Fév 2018 23:04
Localisation : France

Re: [DB-RS] Téléportation d'un objet client via le serveur

Message par Autodidactelife » 23 Fév 2018 14:50

Bonjour Twiixy, d'abord je te remercie pour ta réponse et ton intéressement à mon post,

Justement c'est la question ! Je vais essayer de détailler en code sans oublier de variable utile, donc voici ce que ça donnerait sans surplus:
Class ListJoueurs ainsi que la class listJoueurs (je viens de me rendre compte que c'est les mêmes noms --', bon pas grave heureusement que le C# tiens compte des MAJ).

Code : Tout sélectionner

using System.Collections.Generic;
using UnityEngine;

public class ListJoueurs : MonoBehaviour {

    public List<listJoueurs> list = new List<listJoueurs>(); // Liste des joueurs connectés
    public GameObject _prefabPseudo; // Prefab du visuel du pseudo à ajouté
   
    public void addPlayer(string _pseudo, GameObject perso, string stuff) { // Ajout d'un joueur dans la liste de connectés
        list.Add(new listJoueurs() { pseudo = _pseudo, personnage = perso, stuffJson = stuff }); // On y entre le pseudo, gameobject et son stuff
    }
    
    public void delPlayer(string pseudo) { //Retrait d'un joueur dans la liste des personnes connectés
        foreach (listJoueurs search in list) { // On cherche dans toute la liste des joueurs connectés
            if (pseudo == search.pseudo) { // Si le pseudo est identique à l'information reçu
                list.Remove(search); // On le supprime
                break;
            }
        }
    }

    public GameObject getPlayer(string _psd) {
        GameObject returnPlayer = null;
        foreach (listJoueurs _allPlay in list)  if (_allPlay.pseudo == _psd) return _allPlay.personnage;
        return returnPlayer;
    }
}

public class listJoueurs { // Class du listage des joueurs
    public string pseudo; // Pseudo du joueur
    public GameObject personnage; // GameObject du joueur
    public string stuffJson; // Stuff en JSON du joueur
    //public string amis;
    //public string ignore;
}

J'ai par la suite une bête Cmd que j'ai sur le GameObject joueur qui est exécuté par le client quand il envoie un message dans le chat, donc j'ai mis ma fonction entière sachant que "pseudo" n'est pas présent c'est simplement un string qui contient le pseudo du joueur (qu'il à rentrer dans un input avant la connexion au serveur tout un bordel ^^')

Code : Tout sélectionner

    [Command]
    public void CmdChat(string _txt) { // Envoie au serveur un message chat
        if (_txt.Length > 256) _txt.Substring(0, 255); // En cas de modification de la valeur max
		
		// Qui à envoyer la commande
        string _sndpsd = pseudo; 
        if (_accountType == 0) _sndpsd = "[" + pseudo + "]: "; else if (_accountType == 1) _sndpsd = "A[" + pseudo + "]: "; else if (_accountType == 2) _sndpsd = "M[" + pseudo + "]: "; else if (_accountType == 3) _sndpsd = "C[" + pseudo + "]: ";

        // Liste des commandes
        if (_txt.IndexOf("/") == 0 && _accountType > 0) {

            if (_txt.IndexOf("/say ") == 0) { // Commande /say accessible aux animateurs / modérateurs / créateurs
                RpcChat(_sndpsd, _txt.Replace("/say ", ""), new Color(0f, 125f / 255f, 0f, 1f)); // Mise d'un message de couleur verte
            } else if (_txt.IndexOf("/warn ") == 0 && _accountType > 1) { // Commande /warn accessible aux modérateurs / créateurs
                RpcChat(_sndpsd, _txt.Replace("/warn ", ""), new Color(1f, 0f, 0f, 1f)); // Mise d'un message de couleur rouge
            } else if (_txt.IndexOf("/tel ") == 0 && _accountType > 1) { // Commande /tel accessible aux modérateurs / créateurs
                string[] _splt = _txt.Split(new string[] { " " }, StringSplitOptions.None);
                GameObject player = _listJ.GetComponent<ListJoueurs>().getPlayer(_splt[1]);
                if (player != null) {
                    player.transform.position = new Vector3(float.Parse(_splt[2]), float.Parse(_splt[3]), float.Parse(_splt[4]));
                    RpcTele(_splt[1], new Vector3(float.Parse(_splt[2]), float.Parse(_splt[3]), float.Parse(_splt[4])));
                }
                // à changer
            }

        } else if (_txt.Length > 0) {
            RpcChat(_sndpsd, _txt, new Color(50f / 255f, 50f / 255f, 50f / 255f, 1f));
        }
    }
Pour finir mon RpcTele (le RpcChat n'est pas utile ici):

Code : Tout sélectionner

    [ClientRpc]
    void RpcTele(string _psd, Vector3 newPos) {
        if (pseudo == _psd) transform.position = newPos;
    }

Je sais que c'est moi qui n'a pas fait les choses correctement mais en général j'arrive à trouver la solution sauf que là j'ai dû passer à côté d'un truc important, donc je demandes de l'aide pour savoir quoi, en sois le soucis c'est qu'au final j'ai rien de plus que ces codes là, en gros le premier qui est le gameobject du joueur côté serveur le deuxième qui est exécuté par le serveur qu va vérifier si le gameobject possède les droits et faire l'action.

Alors ici j'ai un transform.position côté client et un rpc qui lui même fera exactement la même chose, mais dès que je retire le RpcTele sur un client et donc que je le génère et que je remet la fonction et que j'allume le serveur si je téléporte le joueur dès qu'il va bouger il va être remis où il était.

On part du principe où le client qui aurait était malhonnête à retirer la fonction RcpClient de son jeu par X ou Y façons (je sais pas si c'est facile mais tout ce que je sais c'est que c'est possible). Donc dans ce cas là j'aimerais que le client soit quand même téléporter et ne puisse rien faire :( Je sais que j'avais eu des bugs du genre et j'avais le client qui ce téléporter à l'autre bout de la map car il pensait le client qu'il était là bas et le serveur le faisais revenir où il devait être visuellement ça détruis une rétine (mais ce n'était pas en essayant ça)

Donc si je déplace le joueur côté serveur, il ne l'est jamais côté client :(

Merci en tout cas déjà pour ta réponse, je ne savais pas que le serveur vérifier quoi que ce sois vu mes tests j'avais pas l'impression, je vais me renseigner sur tout ça, le client prédiction je connaissais pas aussi, mais je vois totalement ce que c'est au niveaux de jeux auxquelles j'ai déjà tester ^^

Mais après c'est pas très important le lag, tant que le joueur est dans la seconde où il faut et qu'il ne peut pas ce téléporter le reste m'importe pas grand chose :/

Bonne après midi !

Farstone
Messages : 187
Inscription : 04 Déc 2016 09:38

Re: [DB-RS] Téléportation d'un objet client via le serveur

Message par Farstone » 23 Fév 2018 19:03

Dans un premier temps laisse moi te dire que tu réfléchie de la bonne façons, toujours éviter qu'un client qui retire un bout de code ou le change lui permette des choses improbable. Sinon je comprend mieux le problème, voici ce qui ce passe exactement pour que tu puisse situer le problème :

Le serveur reçois l'ordre de tp le joueur X a une position Y
Le serveur tp le joueur X côté serveur
Le serveur tp le joueur X a tout les client possédant la fonction Rpc en question
Les joueurs voient bien le joueurs être tp dans la prison à la position Y
Le joueur X qui na pas de Rpc n'est pas sensé être tp
Le joueur X se déplace et envoie au serveur ça nouvel position qui la synchronise à tout les clients automatiquement(NetworkTransform)
Les joueurs voient donc le client X être déplacé de la prison jusqu’à ça vrai position (celons le client X)

Le client X peux aussi ouvrir cheat-engine est augmenter la vitesse de déplacement sans que le serveur sans soucie

Il est là le problème, le NetworkTransform de Unet n'est pas authoritative, ce qui veux dire que le GO avec le NetworkTransform que le client X possède, envoie ça position au serveur (avec le send rate défini) qui se contente de l'actualiser chez les autres, et comme le client X n'a plus le Rpc pour être tp ben... il ne bouge pas. Mais comme il ne bouge pas, le NetworkTransform n'actualise pas ça position côté serveur pour économiser de la bande passante (ce qui explique qu'il est déplacé seulement quand il bouge).
Donc la c'est la galère, tu va devoir faire des recherches et suivre des tuto (ou pas) sur la façons de mettre en place un système de déplacement authoritative qui va permettre d’empêcher ce genre de problèmes et ajouter d'autres sécurité comme le speed-hack, jump-hack. En gros tu doit recrée ton propre NetworkTransform, ça peux faire peur mais le développement est assez logique et amusement, ça reste relativement court (moins de 300 lignes il me semble pour la base) ça te permettra d'avoir un meilleur contrôle de t'es déplacements en général, une meilleur sécurité, et une conscience tranquille .

Attention cependant, tu serras confronté à un autre problème durant le développement, étant donné que tout les déplacements seront validé par le serveur avant d'être envoyé au clients (y compris celui qui demande à bouger) tu va avoir un lag entre l'appui de ta touche et ton déplacement, et c'est la que viens le client prédiction dont je parlait dans mon précédant post, il permet de ce déplacer dans un premier temps sans le serveur pour ne pas avoir de lag (en gros le ping), après le ping le serveur va validé les déplacements comme à la base, mais il va tp le joueurs ou il devrait vraiment être si il fait des actions que le serveur ne peux pas faire (par exemple ce tp, ou speed-hack).
Le client-prédiction est uniquement pour le confort des joueurs, on voie très peux de jeu ne l'utilisant plus (de toutes façon avec des ping de 10 a 20ms c'est pas vraiment percevable)
Et là c'est le moment ou tu te dit, autant de travail pour résoudre un si petit problème :hehe:

Voila j’espère avoir été clair, normalement tu à tout les outils en main pour résoudre ton problème. Je ne peux malheuresement pas t'aider car je n'en suis pas encore là dans mon projet, mais j'ai tâté le terrain quand même. (je te conseille de regarder des exemples de server-authoritative utilisant UNET avant de te lancé tête baissé, j'en avait trouvé des sympas sur youtube, en anglais évidemment). Hésite pas si tu à d'autres questions sur le sujet, c'est toujours une bonne sources d'aide pour de futur lecteur :super:
Bonne journée et bonne chance pour ton projet !

EDIT : Voici un super site expliquant le concept en détails, et toutes les bonnes/mauvaises choses lié à cette méthode : http://www.gabrielgambetta.com/client-s ... cture.html
Dernière édition par Farstone le 02 Mars 2018 06:34, édité 1 fois.

Autodidactelife
Messages : 47
Inscription : 21 Fév 2018 23:04
Localisation : France

Re: [DB-RS] Téléportation d'un objet client via le serveur

Message par Autodidactelife » 23 Fév 2018 19:55

Je te remercie pour tes réponses claires !

Et pour l'utilisation de téléportation c'est ça, en sois je l'utiliserais pour les events (je ne vois pas trop l'utilité d'un joueur de pas vouloir être téléporté vu que c'est au bon vouloir), mais dans le cas de la prison c'était problématique !

Je vais me renseigner donc sur ça, j'avais des tutoriels payants sur Unity mais même ça ils n'en parlent pas, ça pousse plus loin les bases, mais sans aller trop loin :(

Donc je penses que le sujet peut être dit résolut, car j'ai la réponse, même si concrètement je n'ai pas encore vu ni tester, je sais maintenant où est le soucis et quoi faire ! :)

Merci encore pour avoir pris le temps de me répondre.
Je touches actuellement la fin de mon prototype j'ai hâte :D

Avatar de l’utilisateur
boubouk50
ModoGenereux
ModoGenereux
Messages : 6216
Inscription : 28 Avr 2014 11:57
Localisation : Saint-Didier-en-Bresse (71)

Re: [DB-RS] Téléportation d'un objet client via le serveur

Message par boubouk50 » 26 Fév 2018 10:26

Autodidactelife a écrit :
23 Fév 2018 19:55
Donc je penses que le sujet peut être dit résolut
Lorsque tu as résolu ton problème où du moins que la solution est trouvée, merci d'éditer le titre du premier message en ajoutant [RESOLU] en début de celui-ci. Je m'en suis occupé cette fois-ci.
"Ce n'est pas en améliorant la bougie, que l'on a inventé l'ampoule, c'est en marchant longtemps."
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation

Répondre

Revenir vers « (C#) CSharp »