UNET:自动托管服务器或作为客户端加入

UNET: Automatically hosting server or joining as client

我试图避免手动确定 运行 unity 游戏的当前实例是主机还是客户端。有没有办法检测现有的游戏,如果有加入它们,如果没有启动主机?

请注意,玩家不了解网络内容,因此我不能指望他们启动自己的主机或选择现有主机进行连接。

我尝试使用 NetworkDiscovery 组件,如下所示:

public class TestPlayerSetup : NetworkDiscovery {

  private float timeToWait = 1f;
  private float timeWaited = 0f;

  private bool hostDiscovered = false;

  void Start () {
    NetworkManager.singleton.networkAddress = "localhost";
    NetworkManager.singleton.networkPort = 7777;

    Initialize ();
    StartAsClient ();
  }


  void Update() {

    if (timeWaited < timeToWait) {
      timeWaited += Time.deltaTime;
      return;
    }

    if (!hostDiscovered) {
      NetworkServer.Reset ();
      NetworkManager.singleton.StartHost ();
      StartAsServer ();
      hostDiscovered = true;
    }
  }

  public override void OnReceivedBroadcast(string fromAddress, string data){
    Debug.Log ("received broadcast");
    NetworkManager.singleton.StartClient();
    hostDiscovered = true;
    setPlayerColor ();
  }

}

但是您似乎无法在启动客户端后启动 NetworkDiscovery 服务器。

The above code returns that error (StartAsServer fails because there is already a client running)

OnReceivedBroadcast 函数中删除 NetworkManager.singleton.StartClient(); 函数。每次调用 OnReceivedBroadcast 时都会尝试启动客户端。

至于自动连接服务器,不要那样做。相反,向玩家显示可用服务器列表,他们的工作就是选择一个。将您的代码分为服务器和客户端代码。

首先忽略OnReceivedBroadcast函数中的字符串fromAddress参数。不要使用那个。

在服务器上做什么:

在您的服务器代码上,创建一个简单的 class 来保存服务器的 ip 和端口号。使用Unity的将class序列化后保存到NetworkDiscovery.broadcastData。您现在可以调用 StartAsServer();.

在客户端做什么:

创建一个 List 保存那个 class 保存服务器的 ip 和端口。使用第二个参数 (string data) 在 OnReceivedBroadcast 函数中填充此 List。由于它是一个字符串,您必须使用 将其转换回 class。如果 ip 和端口不在 List 中,则仅将其添加到列表中。

就是这样。然后玩家可以从包含服务器 ip 和端口的 List 选择连接到哪个服务器。

我通过在 运行 作为客户端时没有发现主机时删除 NetworkDiscovery 组件,并添加一个新的组件来启动主机来使其工作:

private float timeToWait = 1f;
private float timeWaited = 0f;
private NetworkDiscovery serverNetwork;
private TestPlayerClient clientNetwork;
private bool serverStarted = false;
private bool hostDiscovered = false;

void Start () {
  NetworkManager.singleton.networkAddress = "localhost";
  NetworkManager.singleton.networkPort = 7777;

  clientNetwork = gameObject.AddComponent<TestPlayerClient> ();
}

void Update() {

  if (timeWaited < timeToWait) {
    timeWaited += Time.deltaTime;
    return;
  }

  hostDiscovered = clientNetwork.hostDiscovered;
  if(clientNetwork != null && !hostDiscovered) {
    clientNetwork.StopBroadcast ();
    Destroy (clientNetwork);
    return;
  }

  if (!hostDiscovered && !serverStarted) {
    NetworkManager.singleton.StartHost ();
    serverNetwork = gameObject.AddComponent<NetworkDiscovery> ();
    serverNetwork.Initialize ();
    serverNetwork.StartAsServer ();
    serverStarted = true;
  }
}

TestPlayerClient代码:

public class TestPlayerClient : NetworkDiscovery {

  public bool hostDiscovered {
    get;
    private set;
  }

    void Start () {
    Initialize ();
    StartAsClient ();
    Debug.Log ("trying client");
    hostDiscovered = false;
    }

  public override void OnReceivedBroadcast(string fromAddress, string data){
    Debug.Log ("broadcast received, starting client");
    StopBroadcast ();
    NetworkManager.singleton.StartClient();
    hostDiscovered = true;
  }

}