Browse Source

Merge pull request #3720 from Meriipu/master_highlevel

high-level networking: remove bad practice; bomber demo more explicit
Rémi Verschelde 5 years ago
parent
commit
c7d18873d5
1 changed files with 49 additions and 12 deletions
  1. 49 12
      tutorials/networking/high_level_multiplayer.rst

+ 49 - 12
tutorials/networking/high_level_multiplayer.rst

@@ -291,7 +291,8 @@ every peer and RPC will work great! Here is an example:
             get_node("/root/world/players").add_child(player)
             get_node("/root/world/players").add_child(player)
 
 
         # Tell server (remember, server is always ID=1) that this peer is done pre-configuring.
         # Tell server (remember, server is always ID=1) that this peer is done pre-configuring.
-        rpc_id(1, "done_preconfiguring", selfPeerID)
+        # The server can call get_tree().get_rpc_sender_id() to find out who said they were done.
+        rpc_id(1, "done_preconfiguring")
 
 
 
 
 .. note:: Depending on when you execute pre_configure_game(), you may need to change any calls to ``add_child()``
 .. note:: Depending on when you execute pre_configure_game(), you may need to change any calls to ``add_child()``
@@ -314,7 +315,8 @@ When the server gets the OK from all the peers, it can tell them to start, as fo
 ::
 ::
 
 
     var players_done = []
     var players_done = []
-    remote func done_preconfiguring(who):
+    remote func done_preconfiguring():
+        var who = get_tree().get_rpc_sender_id()
         # Here are some checks you can do, for example
         # Here are some checks you can do, for example
         assert(get_tree().is_network_server())
         assert(get_tree().is_network_server())
         assert(who in player_info) # Exists
         assert(who in player_info) # Exists
@@ -326,8 +328,10 @@ When the server gets the OK from all the peers, it can tell them to start, as fo
             rpc("post_configure_game")
             rpc("post_configure_game")
 
 
     remote func post_configure_game():
     remote func post_configure_game():
-        get_tree().set_pause(false)
-        # Game starts now!
+        # Only the server is allowed to tell a client to unpause
+        if 1 == get_tree().get_rpc_sender_id():
+            get_tree().set_pause(false)
+            # Game starts now!
 
 
 Synchronizing the game
 Synchronizing the game
 ----------------------
 ----------------------
@@ -403,19 +407,43 @@ Example player code:
             return # Already stunned
             return # Already stunned
 
 
         rpc("stun")
         rpc("stun")
-        stun() # Stun myself, could have used remotesync keyword too.
+        
+        # Stun this player instance for myself as well; could instead have used
+        # the remotesync keyword above (in place of puppet) to achieve this.
+        stun()
 
 
-In the above example, a bomb explodes somewhere (likely managed by whoever is master). The bomb knows the bodies in the area, so it checks them
-and checks that they contain an ``exploded`` function.
+In the above example, a bomb explodes somewhere (likely managed by whoever is the master of this bomb-node, e.g. the host).
+The bomb knows the bodies (player nodes) in the area, so it checks that they contain an ``exploded`` method before calling it.
 
 
-If they do, the bomb calls ``exploded`` on it. However, the ``exploded`` method in the player has a ``master`` keyword. This means that only the player
-who is master for that instance will actually get the function.
+Recall that each peer has a complete set of instances of player nodes, one instance for each peer (including itself and the host).
+Each peer has set itself as the master of the instance corresponding to itself, and it has set a different peer as the master for
+each of the other instances.
 
 
-This instance, then, calls the ``stun`` method in the same instances of that same player (but in different peers), and only those which are set as puppet,
-making the player look stunned in all the peers (as well as the current, master one).
+Now, going back to the call to the ``exploded`` method, the bomb on the host has called it remotely on all bodies in the area
+that have the method. However, this method is in a player node and has a ``master`` keyword.
+
+The ``master`` keyword on the ``exploded`` method in the player node means two things for how this call is made.
+Firstly, from the perspective of the calling peer (the host), the calling peer will only attempt to remotely call the
+method on the peer that it has set as the network master of the player node in question.
+Secondly, from the perspective of the peer the host is sending the call to, the peer will only accept the call if it
+set itself as the network master of the player node with the method being called (which has the ``master`` keyword).
+This works well as long as all peers agree on who is the master of what.
+
+The above setup means that only the peer who owns the affected body will be responsible for telling all the other peers that its body
+was stunned, after being remotely instructed to do so by the host's bomb.
+The owning peer therefore (still in the ``exploded`` method) tells all the other peers that its player node was stunned.
+The peer does this by remotely calling the ``stun`` method on all instances of that player node (on the other peers).
+Because the ``stun`` method has the ``puppet`` keyword, only peers who did not set themselves as the network master of the node will
+call it (in other words, those peers are set as puppets for that node by virtue of not being the network master of it).
+
+The result of this call to ``stun`` is to make the player look stunned on the screen of all the peers, including the current
+network master peer (due to the local call to ``stun`` after ``rpc("stun")``).
+
+The master of the bomb (the host) repeats the above steps for each of the bodies in the area, such that all the instances of
+any player in the bomb area get stunned on the screens of all the peers.
 
 
 Note that you could also send the ``stun()`` message only to a specific player by using ``rpc_id(<id>, "exploded", bomb_owner)``.
 Note that you could also send the ``stun()`` message only to a specific player by using ``rpc_id(<id>, "exploded", bomb_owner)``.
-This may not make much sense for an area-of-effect case like the bomb, but in other cases, like single target damage.
+This may not make much sense for an area-of-effect case like the bomb, but might in other cases, like single target damage.
 
 
 ::
 ::
 
 
@@ -434,3 +462,12 @@ a dedicated server with no GPU available. See
     server. You'll have to modify them so the server isn't considered to be a
     server. You'll have to modify them so the server isn't considered to be a
     player. You'll also have to modify the game starting mechanism so that the
     player. You'll also have to modify the game starting mechanism so that the
     first player who joins can start the game.
     first player who joins can start the game.
+
+.. note::
+
+    The bomberman example here is largely for illustrational purposes, and does not
+    do anything on the host-side to handle the case where a peer uses a custom client
+    to cheat by for example refusing to to stun itself. In the current implementation
+    such cheating is perfectly possible because each client is the network master of
+    its own player, and the network master of a player is the one which decides whether
+    to call the I-was-stunned method (``stun``) on all of the other peers and itself.