somethinglikegames.de

My personal Blog about Game Development as a single person in part time


Categories

After we were able to gather first experiences with the MultiplayerSynchronizer in the article about Scene Replication, we want to continue to make our experiences with it in this article. In addition to the synchronization interval, the MultiplayerSynchronizer has other configuration options that can be used to do interesting things.

In this article we want to deal with the topic of Interest Management. In network games, this means that the respective game clients only receive the information about the other players that the player really needs to be able to perceive everything in his environment. This tries to keep the network communication per connected GameClient / player as small as possible. As a side effect, this reduces the risk of wallhacks etc. in competitive games, since the GameClient ideally only receives and processes the information that the player can perceive (see or hear). Basically, it is based on the fact that every game character has (at least) one Area of Interest (AoI). When something happens within this area, for example another game character moves within the area, the GameClient is informed about it, so that it can also display this movement. You could also work with multiple AoI to represent different aspects of it, e.g. if the player can see further than hear, you could use a separate AoI for each sense.

On the subject of Interest Management, a Godot Proposal worth reading was published in February 2022, which Fabio Alessandrelli then also implemented in the context of Godot 4 by integrating it into the MultiplayerSynchronizer. The corresponding pull request with concrete implementation can be found here. But let’s have a look at a concrete example for a better understanding of the whole topic.

We’ll start with the example project from the article on Scene Replication. If you don’t have it anymore, you can find it in the associated Github repository. I thought we extend the project so that the game character inside the Player scene gets an AoI in the form of an Area3D with associated CollisionShape3D. As shape we take a CylinderShape3D with a radius of 5m, so that our player character has a circular AoI with 5m radius. This should allow us to notice the effect very well in our example.

The player scene incl. 3D view

The player scene incl. 3D view

Configuration of the ServerSynchronizer

Configuration of the ServerSynchronizer

Before we look at the associated source code, we need to do some more preliminary work. The idea is that the Area3D is our AoI. This means that all game characters that “collide” with our AoI are of interest, all others are of no interest to us. So for the implementation we have to link the body_entered and body_exited signals of our Area3D with our player script.

Additionally we have to activate Interest Management in the MultiplayerSynchronizer. For this we set the property public_visibility of the synchronizer to false. This can be done either script-based or by unchecking the appropriate box via the Inspector, as I did here in the accompanying screenshot. Now visibility settings that can be made via the set_visibility_for() function are also taken into account by the Synchronizer.

As can be seen in the source code snippet below, we use our linked signals of Area3D to turn on/off the visibility of the respective game characters for the own GameClient. Here we benefit from the fact that we have named the respective game characters with the networkID of the GameClient. Here in this example project we do not check if the colliding Node3D objects are really other game characters for the sake of simplicity. Normally this would have to be evaluated or better CollisionLayer and CollisionMask would have to be configured in such a way that collisions can only be triggered by other game figures or their actions.

The Player scene must of course be extended in both the WorldServer and the GameClient. Strictly speaking, it is sufficient to set only the public_visibility property of the ServerSynchronizer to false in the GameClient, since we do the collision detection with the Area of Interest exclusively on the server. Therefore the following script extension is only necessary in the WorldServer.
47func _on_area_3d_body_entered(body: Node3D) -> void:
48	synchronizer.set_visibility_for(str(body.name).to_int(), true)
49
50
51func _on_area_3d_body_exited(body: Node3D) -> void:
52	synchronizer.set_visibility_for(str(body.name).to_int(), false)

Once these changes are made, nothing should stand in the way of the test run. I hope that I have not forgotten anything and that it was understandable so far. I find the Godot implementation of Interest Management quite elegant, as it is not only functional, but gives the developers the freedom to determine themselves what their visibility criteria are for the respective Area of Interest. You don’t have to work with collisions, as in this example, you are completely free or, to quote German politicians, “open to technology” 😉.

With this technology it should even be possible to develop a system that works similar to the layering in World of Warcraft Classic. Since there are often many more players in certain areas at the start of an addon than a few weeks after the launch, players are assigned to certain layers and then only see players and NPC / monsters of the same layer. Groups are of course merged on one layer, so that you can also see and play with your own group members.

Of course the finished project is available in the usual Github repository for your own use.