Kehom / GodotAddonPack

A collection of pure GDScript addons for Godot
http://kehomsforge.com
MIT License
183 stars 15 forks source link

Network: null NetPlayerNode on server when client calls network.notify_ready #3

Closed croxis closed 4 years ago

croxis commented 4 years ago

In case it is relevant: Because I am exporting to HTML5 for the client I replaced enet with websocket (would love webrtc instead but I have yet to figure out how to get that bundle of joy implemented, but I digress.)

Client calls network.join_server() at the end of the ready function of the initial scene. Client listens for "join_accepted" before calling network.notify_ready() But no snapshots propagate to client, regular godot rpc calls do work however.

Relevant code snips from gameworld.gd

func _on_server_join() -> void:
    if (!network.has_authority()):
        debug("Notifying server that I am ready")
        network.notify_ready()

# Called when the node enters the scene tree for the first time.
func _ready():
    var is_client: bool = false

    if OS.get_name() == 'HTML5':
        is_client = true
    if Array(OS.get_cmdline_args()).has("-c"):
        is_client = true

    if is_client:
        print("Debug Gameworld: Is_client")
        _setup_network_input()
        network.connect("join_accepted", self, "_on_server_join")
        network.join_server('127.0.0.1', gamestate.server_info.port)
        var lobbyUI = load("res://lobby.tscn")
        var lobby_node = lobbyUI.instance()
        $HUD.add_child(lobby_node)
    else:
        print("Debug Gameworld: Is_server")
        network.create_server(gamestate.server_info.port, gamestate.server_info.name, gamestate.server_info.max_players)
        $HUD/PanelServerInfo.hide()    

    # Spawn the ship
    if (!get_tree().is_network_server()):
        #rpc_id(1, "spawn_player_ship", gamestate.ship_name)
        print('Debug Gameworld: I am a client attempting to call server spawning player info')

In network.gd I threw in some debug print statements. The remote_player dict is empty so nothing is set to ready.

# Server will only send snapshot data to a client when this function is called
# by that peer.
remote func server_client_is_ready() -> void:
    assert(has_authority())
    # Retrieve the unique ID of the player that called this
    var pid: int = get_tree().get_rpc_sender_id()
    var player: NetPlayerNode = player_data.remote_player.get(pid)
    print("Debug Network: server_client_is_ready " + str(pid) + " " + str(player_data.remote_player) + " " + str(player))
    if (player):       
        player.set_ready(true)
        print("player ready")
Kehom commented 4 years ago

OK, are you saying you replaced

var net: NetworkedMultiplayerENet = NetworkedMultiplayerENet.new()

with

var net: WebSocketClient = WebSocketClient.new()

for client and

var net: WebSocketServer = WebSocketServer.new()

for servers? If this is the case, I honestly have absolutely no idea what to expect other than not work at all, even if the documentation say that web sockets are compatible with the high-level multiplayer. The remote player container relies on the player registration system, which relies on events (signals) emitted by the networking system (which in this case is ENet). If the container is empty, maybe one of those two things became broken after the transition from ENet to WebSocket.

Another thing that I want to point out is that I did provide the network.has_authority() exactly to quickly test if server or client. Basically, if this function returns true then it is safe to assume the code is running on the server OR on a single player (no networking was initialized). With the transition to web sockets it's also important to verify if this check is returning the expected value.

Lastly, the client doesn't have to explicitly request the server to spawn a node. As part of the server's "new player event handling", it can spawn the node and the replication system will take care of spawning it on the client. Again, this is true based on the ENet testing and I have no idea what must be changed to make it work with WebSockets.

croxis commented 4 years ago

I got it to work! I threw in a one second timer delay on the client between receiving join_accepted and network.notify_ready. My ship showed up on the client! I haven't been able to figure out why the server needs extra time between sending join_accepted and notify_ready, my guess is godot's websocket implementation.

Thanks for the heads up about the new player even system. My cognitive load is over capacity trying to wrap my head around all the concepts!

Kehom commented 4 years ago

Glad to hear you got it working!