Closed lbragile closed 6 months ago
@Faless any chance you can have a look?
Please provide a proper minimum reproduction project, not just code:
.godot
folder in the archive (but keep project.godot
).Please try convert the code to GDScript as well, it'll help getting this tested faster
Without a project we can't know things like spawners and other very important network details 🙂
Like #85883 , the err print is a side effect of #82777 which no longer use NodePaths for indexing (and soon won't keep the path cache lingering indefinitely).
The problem is that, the first RPC from a node, needs to "simplify" the path.
This means:
The problem is that when the sender received the "path simplify ack" message, the node is gone because it was queue_freed, hence the error.
I don't think there's much we can do tbh, beside using a spawner in the project, or simply ignoring the error.
Got it, thank you for the detailed explanation!
AFAICT the plan is to fix this in v4.3, so I will just ignore the error for now.
@Faless I ended up implementing a spawner for the "pellets" as follows:
This works well and eliminates the above issue I was facing. I can now replicate despawning pellets on all peers using the spawner!
However, I am running into a strange error that I cannot wrap my head around since it only pops up in a specific situation (which appears unrelated). I am hoping the following can sufficiently explain:
When a client connects, a Player
is spawned on the server:
// Game.cs
[Rpc(MultiplayerApi.RpcMode.AnyPeer)]
private void SpawnPlayer(string playerName)
{
var peerId = Multiplayer.GetRemoteSenderId();
var player = _playerScene.Instantiate<Player>();
player.Name = $"{playerName}-{peerId}";
player.SetPeerId(peerId);
_playerContainer.AddChild(player, true);
}
and then an initial SubPlayer
is spawned in the Player
's respective container:
// Player.cs
public override void _Ready()
{
base._Ready();
var subPlayerContainer = GetNode("SubPlayerContainer");
var subPlayerScene = ResourceLoader.Load<PackedScene>("res://Scenes/SubPlayer.tscn");
var subPlayer = subPlayerScene.Instantiate<SubPlayer>();
subPlayer.Init();
subPlayerContainer.AddChild(subPlayer, true);
subPlayer.Owner = this;
}
Again, this shows up well on both server & client. That is, upon connection I see the same replicated Player
on both.
This also works with multiple client connections. For example, if I connect with 2 clients, I see both Players
replicated correctly on each peer. Eating pellets also works correctly and replicates the "despawned" pellets across all peers.
However, when I join with client A and eat a single pellet with it, then join with client B, I don't see client B on all peers!
Instead I get the following error (ff-*
is the Player
):
What I cannot understand:
why does the pellet's
QueueFree
impact the SubPlayerSpawner "visibility" when a subsequent client joins?
I am also not able to debug this with breakpoints since I haven't figured out a way to do so with VSCode for multiple client Godot Engine instances.
The interesting thing is that the pellet despawning (and corresponding synchronized properties based on this event) is correctly replicated on all peers.
This does not happen if I don't eat a pellet or eat 2+ pellets on client A before joining with client B. In such cases, again everything works as expected with respect to the multiplayer replication.
For reference, my updated pellet script (no longer using RPC call due to spawner):
using Godot;
namespace AgarioCloneServer.Scripts.Entities;
public partial class Food : Area2D
{
public override void _Ready()
{
base._Ready();
AddToGroup("Pellet");
BodyEntered += OnBodyEntered;
}
private void OnBodyEntered(Node2D body)
{
if (body is not SubPlayer subPlayer)
{
return;
}
subPlayer.ScoreManager.IncreaseScore(100.0f);
QueueFree();
}
}
I came across this post which appears to be related, but I don't think that the proposed solution applies in my case.
Any ideas would be greatly appreciated as this is a blocker for my project.
Feel free to re-open this issue if it is indeed a bug.
If my understanding is correct, this https://github.com/godotengine/godot/pull/71534#issue-1535726185 appears to suggest that nested spawners replicate scenes on the _enter_tree()
method (instead of on _ready()
). Wouldn't this cause the above to happen frequently?
I also found this comment:
// If we are a nested spawn, we need to wait until the parent is ready.
It is found in the following method:
void SceneReplicationInterface::_node_ready(const ObjectID &p_oid)
Shouldn't a node only be ready when it's children are ready (ref)?
Called when the node is "ready", i.e. when both the node and its children have entered the scene tree. If the node has children, their _ready callbacks get triggered first, and the parent node will receive the ready notification afterwards.
@lbragile may I ask how you "despawning" objects , because I'm facing same issue on 4.3-dev5 I'm just queue_free
on collision
Tested versions
Godot Engine v4.2.stable.mono.official.46dc27791
System information
Windows 10 - Vulkan API 1.3.242 - Forward+ - Using Vulkan Device #0: NVIDIA - NVIDIA GeForce GTX 1650
Issue description
Similar issue is outlined here.
However, I am not sure how to implement the potential resolution:
I have a server & client project for an Agario Clone. When the player node overlaps with a "pellet" (food) on the server I use an RPC to delete the node on the client. I am not using a MultiplayerSpawner due to the fact that the pellets spawn on the server before clients connect and are "synced" to each client via another RPC call.
Server (before client joins):
Server (after client joins):
In the RPC functions, I use
QueueFree
to remove the nodes from both the server and client, respectively. The nodes get removed from both sides, however I see the following error (only on the server):Steps to reproduce
Minimal reproduction project (MRP)