NetworkedMultiplayerEnet client fails to connect to server
Asked Answered
L

1

0

I'm at the end of my rope here, I'm trying to create a client-server architecture using the NetworkedMultiplayerEnet API from the high level multiplayer section in the docs with mono by using this post from Ryan Forrester as a guide: https://ryanforrester.ca/godot/2020/02/02/godot-mono-high-level-multiplayer-example-3-2/
Despite following a similar structure (the only parts I think I modified being related to specific implementation) I manage to host a server and connect to it through a client in Ryan's example, yet I cannot even trigger a single network related signal in my own project.
The project compiles and runs normally up until the point where I attempt to call an RPC, at which point the program fails and throws the following error:

'E 0:00:06.906   rpcp: Trying to call an RPC via a network peer which is not connected.
  <C++ Error>Condition "network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED" is true.
  <C++ Source>  core/io/multiplayer_api.cpp:625 @ rpcp()
  <Traceback>:0 @ System.Object Godot.NativeCalls.godot_icall_3_686(IntPtr , IntPtr , Int32 , System.String , System.Object[] )()
                Node.cs:1699 @ System.Object Godot.Node.RpcId(Int32 , System.String , System.Object[] )()
                RegisterButton.cs:98 @ void RegisterButton._on_RegisterButton_pressed()()
'

Here's the relevant code:

using Godot;
using System;
using System.Collections.Generic;

public class Lobby : Control
{
    private readonly int DEFAULT_PORT = 4321;
    private readonly int MAX_PLAYERS = 30;
    private readonly string ADDRESS = "localhost";
    
    public string playerName { get ; set ;}
    private Dictionary<int, string> players = new Dictionary<int, string>();
    
    public override void _Ready()
    {
        GetTree().Connect("network_peer_connected", this, nameof(PlayerConnected));
        GetTree().Connect("network_peer_disconnected", this, nameof(PlayerConnected));
        GetTree().Connect("connected_to_server", this, nameof(ConnectedToServer));
        GetTree().Connect("connection_failed", this, nameof(ConnectionFailed));
        GetTree().Connect("server_disconnected", this, nameof(ServerDisconnected));
    }

    public bool HostLobby()
    {
        var peer = new NetworkedMultiplayerENet();
        var result = peer.CreateServer(DEFAULT_PORT, MAX_PLAYERS);
        if (result == 0)
        { 
            GetTree().NetworkPeer = peer;
            GD.Print($"Hosting server at {ADDRESS}:{DEFAULT_PORT}.");
            return true;
        }
        else
        {
            return false;
        }
    }

    
    public bool IsHosting()
    {
        if(GetTree().NetworkPeer != null) 
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    
    public void JoinGame()
    {
        GD.Print($"Joining lobby with address {ADDRESS}:{DEFAULT_PORT}");

        var clientPeer = new NetworkedMultiplayerENet();
        var result = clientPeer.CreateClient(ADDRESS, DEFAULT_PORT);

        GetTree().NetworkPeer = clientPeer;
    }
    
    public void LeaveGame()
    {
        GD.Print("Leaving current game");

        players.Clear();

        GetNode(GetTree().GetNetworkUniqueId().ToString()).QueueFree();

        Rpc(nameof(RemovePlayer), GetTree().GetNetworkUniqueId());

        ((NetworkedMultiplayerENet)GetTree().NetworkPeer).CloseConnection();
        GetTree().NetworkPeer = null;
    }

    private void PlayerConnected(int peerId)
    {
        GD.Print($"player {peerId} has connected.");
        Rpc(nameof(RegisterPlayer), playerName);
    }

    private void PlayerDisconnected(int peerId)
    {
        GD.Print("Player disconnected");
        RemovePlayer(peerId);
    }

    private void ConnectedToServer()
    {
        GD.Print("Successfully connected to the server");
    }

    private void ConnectionFailed()
    {
        GetTree().NetworkPeer = null;

        GD.Print("Failed to connect.");
    }

    private void ServerDisconnected()
    {
        GD.Print($"Disconnected from the server");
    }

    [Remote]
    private void RegisterPlayer(string playerName)
    {
        var peerId = GetTree().GetRpcSenderId();

        players.Add(peerId, playerName);

        GD.Print($"player {playerName} added with peer ID {peerId}");
    }

    [Remote]
    private void RemovePlayer(int peerId)
        {

        if (players.ContainsKey(peerId))
        {
            players.Remove(peerId);
        }
    }
}

The HostLobby() and JoinGame() methods are called through two other classes, which are instanced in the server or client as necessary:

using Godot;
using System;

public class ServerLobby : Lobby
{
    public override void _Ready()
    {
        if(!IsHosting())
        {
            if(!HostLobby())
            {
                GD.Print("Failed to start server, shutting down");
                GetTree().Quit();
                return;
            }
        }
    }
} 
using Godot;
using System;

public class ClientLobby : Lobby
{
    public override void _Ready()
    {
        JoinGame();
    }
}

Thanks for your help in advance, and I apologize for any glaring flaws or defects I may have missed.

Lovelace answered 27/10, 2022 at 2:54 Comment(0)
L
0

Well, I figured it out
As it turns out I had TOTALLY forgotten that nodes need to have the same path relative to /root/.. for RPCs to work.
In order to fix this I completely scrapped inheritance and moved all relevant operations to an autoload singleton, now everything works as expected.

using Godot;
using System;
using System.Collections.Generic;

public class NetworkUtilities : Node
{
    private readonly int DEFAULT_PORT = 4321;
    private readonly int MAX_PLAYERS = 30;
    private readonly string ADDRESS = "localhost";
    
    public string playerName { get ; set ;}
    private Dictionary<int, string> players = new Dictionary<int, string>();
    
    public override void _Ready()
    {
        GetTree().Connect("network_peer_connected", this, nameof(PlayerConnected));
        GetTree().Connect("network_peer_disconnected", this, nameof(PlayerConnected));
        GetTree().Connect("connected_to_server", this, nameof(ConnectedToServer));
        GetTree().Connect("connection_failed", this, nameof(ConnectionFailed));
        GetTree().Connect("server_disconnected", this, nameof(ServerDisconnected));
    }
    
    public bool HostLobby()
    {
        var peer = new NetworkedMultiplayerENet();
        var result = peer.CreateServer(DEFAULT_PORT, MAX_PLAYERS);
        if (result == 0)
        { 
            GetTree().NetworkPeer = peer;
            GD.Print($"Hosting server at {ADDRESS}:{DEFAULT_PORT}.");
            return true;
        }
        else
        {
            return false;
        }
    }
    
        public bool IsHosting()
    {
        if(GetTree().NetworkPeer != null) 
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    
    public void JoinGame()
    {
        GD.Print($"Joining lobby with address {ADDRESS}:{DEFAULT_PORT}");

        var clientPeer = new NetworkedMultiplayerENet();
        var result = clientPeer.CreateClient(ADDRESS, DEFAULT_PORT);

        GetTree().NetworkPeer = clientPeer;
    }
    
    public void LeaveGame()
    {
        GD.Print("Leaving current game");

        players.Clear();

        Rpc(nameof(RemovePlayer), GetTree().GetNetworkUniqueId());

        ((NetworkedMultiplayerENet)GetTree().NetworkPeer).CloseConnection();
        GetTree().NetworkPeer = null;
    }

    private void PlayerConnected(int peerId)
    {
        GD.Print($"player no.{peerId} has connected.");
        Rpc(nameof(RegisterPlayer), playerName);
    }

    private void PlayerDisconnected(int peerId)
    {
        GD.Print("Player disconnected");
        RemovePlayer(peerId);
    }

    private void ConnectedToServer()
    {
        GD.Print("Successfully connected to the server");
    }

    private void ConnectionFailed()
    {
        GetTree().NetworkPeer = null;

        GD.Print("Failed to connect.");
    }

    private void ServerDisconnected()
    {
        GD.Print($"Disconnected from the server");
    }

    [Remote]
    private void RegisterPlayer(string playerName)
    {
        var peerId = GetTree().GetRpcSenderId();

        players.Add(peerId, playerName);

        GD.Print($"player {playerName} added with peer ID {peerId}");
    }

    [Remote]
    private void RemovePlayer(int peerId)
        {

        if (players.ContainsKey(peerId))
        {
            players.Remove(peerId);
            GD.Print($"Player no. {peerId} has disconnected.");
        }
    }
Lovelace answered 27/10, 2022 at 16:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.