How to deal with cheaters and not rewrite all the code



    A few years ago, a prototype of the game War Robots appeared (then it was also called Walking War Robots). This was the first Pixonic experience in the tactical PvP genre, so many future problems were built into the code initially. But despite a number of difficulties (the popularity of the project was growing rapidly, a small team could not completely change the architecture of the game in a short time), we eventually managed to minimize the number of cheaters, as well as fix other shortcomings of the original code. I’ll tell you a little more.

    The very first implementation of WR did not use an authoritarian server - each of the clients independently controlled their health indicators and sent their changes over the network to other players. We used remote procedure call (RPC) to forward messages.




    Schematic illustration of sending a new health value using RPC when taking damage through the Photon Cloud Server and then delivering it to other players.

    This approach was easier to implement from an architectural point of view, since it did not require logic on the server, and the calculations were performed on clients. As a result, the team was able to quickly get a pilot version of the game and evaluate the interest of the audience.

    Of course, in the end, the question of fair play became acute. It is not possible to directly control whether the client actually records all incoming damage. And with the growth of the audience, this problem was expectedly becoming more relevant.

    "Kills"


    The problem of “immortal” players can be conditionally described in three situations:

    1. The player is having problems connecting to the network. As a result, he simply does not “see” his injuries and does not send an updated state. For the rest of the participants in the game, it looks as if the hit on the target was delayed, incomplete or completely absent for some period of time.
    2. The player intentionally cuts off his Internet connection (for example, putting the application in inactive mode) and ignores incoming damage.
    3. The player cheats in another way and becomes immortal.



    There are several ways to solve this problem.

    1. You can seek out and ban cheaters or automate their search by various criteria (for example, by average damage in battle). To do this, you need to build a comprehensive software defense, which, based on the player’s behavior and other aspects of the match, could recognize a dishonest game.

      But this is a rather time-consuming option, as it will be necessary to monitor the gameplay of each player, as well as form and test a set of rules by which cheaters will stand out from the crowd.
    2. Another popular solution is an authoritarian server. In this case, the entire logic of the match works on the server, and it fully controls the shooting and damage.

      We thought about different ways of implementing this approach, we also considered the option of launching Unity in batchmod, but in the end we abandoned the idea, since it required a complete redo of client-server interaction in the project.

    Then we began to look for another way out of the situation that would minimize the problem.

    What have we come to? ..

    Democracy




    We used the same base that was already in the prototype, but changed one key point - the server’s health was now controlled by the server based on all the data coming to it.

    Each of the clients sent damage indicators to the server not only on their own, but also on other players. Next, the server made a decision about the current state of health of clients, gaining a quorum of testimony and sent it to the players. Thus, we got a mixture between local damage counting and an authoritarian server.

    Immediately it is worth noting the limitations of this method. It does not work for 1 on 1 games. Absolutely. If two players have a difference in testimony, it is not clear which of them is telling the truth.

    The main plus - it was a relatively “cheap” solution, since we did not have to rewrite the network code globally and at the same time managed to solve the problem with cheaters.

    Algorithm





    In fact, the algorithm for dealing damage can conditionally be divided into 3 parts:

    1. Registration of damage by each client of all players and sending these indications to the server.
    2. Collection of damage indicators, aggregation, calculation of the victim’s current health and distribution of the final value to all participants in the match.
    3. Getting current health from the server.

    In more detail, this happens as follows: each of the clients monitors hits for each player and registers this damage on the server. An RPC message is sent to the server with information about the hit in the form:

    The message contains the ID of the victim, the ID of the damage, ID of the shot and the damage itself. It is worth noting that in War Robots each shell has a specific identifier that is synchronized between clients.

    The next step is the aggregation of damage indicators on the server. A quorum of size N is taken, after which client damage indicators are aggregated. Final damage is applied to the target and a new state of health is sent to all participants in the battle. Schematically, it looks like this:



    Thus, this is not an authoritarian server, but also not a simple local damage count on each player. As a result, one person cannot “drop” the entire system. He, of course, may try to correct the damage, but he will not be able to completely avoid it.

    Of course, this solution is not ideal. The main difficulty is the need to synchronize the ID of each shot (which is a separate issue). But here's what happened to players complaining about cheaters after introducing a new damage calculation system:


    Blue graph - the number of players complaining about cheaters .

    Of course, work on WR continues, but the main thing that we learned from this story is that you should not always rely on ready-made answers from textbooks. At each stage, from prototyping to maintaining the existing base of players, we proceeded from current tasks and needs.

    If everything was immediately done “right” a few years ago, some mistakes could have been avoided, but the game itself could have simply not fired, and resources would have been wasted.

    Also popular now: