DoubleDeez / MDFramework

A multiplayer C# game framework for Godot 3.4 Mono.
https://discord.gg/UH49eHK
MIT License
76 stars 13 forks source link

Duplicated nodes on client #7

Closed Beider closed 4 years ago

Beider commented 4 years ago

So I am still not sure why this is happening and I am currently trying to figure it out.

I have the following piece of code to spawn a player character for each player when they join my game. (The first part just sets the name after joining)

    private void OnPlayerJoined(int PeerId)
    {
        // Set our name
        if (!MDStatics.IsNetworkActive() || _session.GetPlayerInfo(PeerId).IsNetworkMaster())
        {
            _session.GetPlayerInfo(PeerId).PlayerName = _txtPlayerName.Text;
        }
        if (_session.IsMaster())
        {
            PlayerSpawnPoint point = (PlayerSpawnPoint)GetTree().GetNodesInGroup(ManagerBase.GROUP_SPAWN_POINT)[0];
            this.SpawnNetworkedNode("res://Scenes/Characters/PlayerCharacters/Elf/PlayerElf.tscn", "Player" + PeerId, PeerId, point.GetGlobalSpawnPosition().To3D());
        }
    }

As you can see in the screenshot below a second node appears on the client with a suffix of @38, this causes a bunch of errors to be thrown on the server as the MDReplicator tries to replicate the values of this node as well. Which of course does not exist on the server.

NetworkInstanceProblem NetworkInstanceProblem2

Beider commented 4 years ago

So I tracked it down to this method

    private void ServerOnPeerConnected(int PeerId)
    {
        MDLog.Info(LOG_CAT, "Peer [ID: {0}] connected", PeerId);
        OnPlayerJoined_Internal(PeerId);
        BroadcastNewPlayerJoined(PeerId);
        SendConnectionDataToClient(PeerId);
        SynchronizeNetworkedNodes(PeerId);
        Replicator.OnPlayerJoined(PeerId);
    }

Since I spawn the player on the join event it is created and then replicated again during SynchronizeNetworkedNodes.

I solved it by deferring the call to spawn the player, so now it looks like this.

    private void OnPlayerJoined(int PeerId)
    {
        // Set our name
        if (!MDStatics.IsNetworkActive() || _session.GetPlayerInfo(PeerId).IsNetworkMaster())
        {
            _session.GetPlayerInfo(PeerId).PlayerName = _txtPlayerName.Text;
        }
        if (_session.IsMaster())
        {
            CallDeferred(nameof(SpawnPlayer), PeerId);
        }
    }

    private void SpawnPlayer(int PeerId)
    {
        PlayerSpawnPoint point = (PlayerSpawnPoint)GetTree().GetNodesInGroup(ManagerBase.GROUP_SPAWN_POINT)[0];
        this.SpawnNetworkedNode("res://Scenes/Characters/PlayerCharacters/Elf/PlayerElf.tscn", "Player" + PeerId, PeerId, point.GetGlobalSpawnPosition().To3D());
    }

This fixes it however I don't know if this is something that perhaps should be rethought anyway, as I am sure others who use the framework will make the same mistake. Perhaps move the player joined event later or split it into two. One before synch and one after?