我对Unity Netcode还是个新手,我一直在网上看一些视频并阅读文档。
我正在尝试创建自己的大厅系统,为此,我尝试保留一个NetworkList变量,该变量包含每个玩家的用户名列表,只是为了显示已经加入服务器的玩家列表。
我的问题是,当要向列表添加主机的用户名本身时,我无法调用应该更新列表的ServerRpc方法。
这是脚本的一部分,该脚本应保存NetworkList变量并相应地管理更新UI中的列表。
public class PlayersListManager : NetworkBehaviour
{
[SerializeField] RectTransform playersListTransform;
[SerializeField] GameObject playerNamePrefab;
public NetworkList<FixedString32Bytes> playerUsernamesList;
private void Awake()
{
playerUsernamesList = new NetworkList<FixedString32Bytes>();
playerUsernamesList.OnListChanged += OnPlayersListUpdate;
}
[ServerRpc(RequireOwnership = false)]
public void AddNewPlayer_ServerRpc(string newUsername)
{
Debug.Log("AddNewPlayer_ServerRpc");
playerUsernamesList.Add(new FixedString32Bytes(newUsername));
}
[...]
}
这是一个播放器对象,它应该发送ServerRpc,以便使服务器将其用户名添加到NetworkList中。
public class NetworkPlayer : NetworkBehaviour
{
[SerializeField] private string _username; //DEBUG ONLY
public string Username { get; private set; }
private MainMenuInteraction mainMenuInteraction;
private PlayersListManager playersListManager;
public override void OnNetworkSpawn()
{
base.OnNetworkSpawn();
mainMenuInteraction = FindObjectOfType<MainMenuInteraction>();
playersListManager = FindObjectOfType<PlayersListManager>();
if (IsLocalPlayer)
{
Username = mainMenuInteraction.GetUsernameText();
_username = Username;
playersListManager.AddNewPlayer_ServerRpc(Username);
}
}
[...]
}
基本上发生的事情是,玩家首先被要求选择它的用户名,然后他可以创建/加入一个房间,一旦他连接上NetworkPlayer将在服务器上产生。一旦NetworkPlayer产生,它从本地InputText获取文本,并更新其用户名(这里我添加了一个private _username字符串,只是为了让它在编辑器上序列化,并检查发生了什么). variale Username被正确地更新为正确的用户名,然后是播放器列表管理器.添加新播放器_服务器Rpc(用户名);应该是从主机的客户端调用,然后在服务器上执行,但是什么都没有发生!我添加了Debug.log(“AddNewPlayer_ServerRpc”)这一行;在ServerRpc方法中检查它是否被执行过,但没有执行。
一个“有趣”的事情是,ServerRpc可以从任何其他客户机(不是主机)正确调用。
阅读了ServerRpc文档后,我明白了这并没有什么错,因为Host同时充当客户端和服务器,所以Host应该能够调用和执行ServerRpc本身。
1条答案
按热度按时间nhaq1z211#
经过一整天尽可能多的测试,我发现了问题并解决了它,所以我在这里写下答案,以便让遇到类似问题的每个人都知道如何解决这个问题。
通过添加一个按钮,该按钮在每次单击时调用ServerRpc(用于递增一个简单的int),我已经设法了解了发生了什么。由于该按钮成功递增了int,我了解到问题可能是
OnNetworkSpawn()
调用ServerRpc太早了,因为OnNetworkSpawn位于播放器NetworkObject
内部,播放器在主机启动时由NetworkManager
生成。为了确保服务器准备好运行任何ServerRpc,我实现了一个协程来检查ServerRpc是否实际运行。
我的网络播放器变成这样:
其中
mainMenuInteraction.CheckIfServerReady_ServerRpc();
简单为其中
ServerReady
是初始化为假的简单bool:这样,主机的(仅主机的)NetworkPlayer脚本在spawn上将等待此ServerReady设置为true,然后再调用实际的
AddNewPlayer_ServerRpc
。