0

I'm trying to spawn different prefabs depending on the player platform. So I'm overriding the NetworkLobbyManager to spawn objects the way I want. So I create a Dictionnary that associates a connectionId to an index of a prefab and then I instantiate a prefab according to this index.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

public class LobbyManager : NetworkLobbyManager
{
    private Dictionary<int, int> m_currentPlayers;

    void Start()
    {
        m_currentPlayers = new Dictionary<int, int>();
    }

    void AddPlayer(NetworkConnection conn)
    {
        if (Application.platform == RuntimePlatform.WindowsEditor || Application.platform == RuntimePlatform.WindowsPlayer)
        {
            m_currentPlayers.Add(conn.connectionId, 0);
        }
        else if (Application.platform == RuntimePlatform.Android)
        {
            m_currentPlayers.Add(conn.connectionId, 1);
        }
    }

    public override GameObject OnLobbyServerCreateLobbyPlayer(NetworkConnection conn, short playerControllerId)
    {
        AddPlayer(conn);

        return base.OnLobbyServerCreateLobbyPlayer(conn, playerControllerId);
    }

    public override GameObject OnLobbyServerCreateGamePlayer(NetworkConnection conn, short playerControllerId)
    {
        GameObject go = Instantiate(spawnPrefabs[m_currentPlayers[conn.connectionId]]);
        NetworkServer.AddPlayerForConnection(conn, go, playerControllerId);

        return go;
    }
}

But with this code the spawn player on the clients is always the same as the host and I don't know why because it seems like I'm overriding the correct functions and I saw here http://abrgame.blogspot.fr/2016/01/using-unet-to-spawn-different-player.html a guy who used the same technique and that works for him...

Kalixio
  • 1
  • 1

1 Answers1

0

Your Problem

if (Application.platform == RuntimePlatform.WindowsEditor || Application.platform == RuntimePlatform.WindowsPlayer)
{
    m_currentPlayers.Add(conn.connectionId, 0);
}
else if (Application.platform == RuntimePlatform.Android)
{
    m_currentPlayers.Add(conn.connectionId, 1);
}

The NetworkLobbyManager component behaves differently when started as a client or a host, but ultimately, if i am correct, the host handles the player spawning. In your code that means, the component only looks at its own platform, not at the platforms of the connecting players.

Possible Solution

You need to pass the information about the connecting player's platform to the host. You can create a derived class of NetworkConnection that retrieves and carries the platform information, a derived class of NetworkClient which uses your custom NetworkConnectionclass, and ultimately adjust your own NetworkLobbyManager derived class to extract the platform information and use it.

//NetworkClient

public class MyNetworkClient: NetworkClient
{
    public MyNetworkClient() : base()
    {
        SetNetworkConnectionClass<MyNetworkConnection>();
    }
}

//NetworkConnection class

public class MyNetworkConnection : NetworkConnection
{
    private RuntimePlatform connectionPlatform;

    public MyNetworkConnection() : base()
    {
        connectionPlatform = Application.platform;
    }

    public RuntimePlatform ConnectionPlatform { get { return connectionPlatform; } }
}

// Suggested adjustment for your NetworkLobbyManagerClass

void AddPlayer(MyNetworkConnection conn)
{
    // I like switches, it's a question of taste imo
    switch(conn.ConnectionPlatform)
    {
        case RuntimePlatform.Android:
            m_currentPlayers.Add(conn.connectionId, 1);
            break;
        case RuntimePlatform.WindowsEditor:
        case RuntimePlatform.WindowsPlayer:
        default:
            m_currentPlayers.Add(conn.connectionId, 0);
    }
}

public override GameObject OnLobbyServerCreateLobbyPlayer(NetworkConnection conn, short playerControllerId)
{
    // Explicitely pass your custom class
    AddPlayer(conn as MyNetworkConnection);
    return base.OnLobbyServerCreateLobbyPlayer(conn, playerControllerId);
}

public override GameObject OnLobbyServerCreateGamePlayer(NetworkConnection conn, short playerControllerId)
{
    GameObject go = Instantiate(spawnPrefabs[m_currentPlayers[conn.connectionId]]);
    NetworkServer.AddPlayerForConnection(conn, go, playerControllerId);

    return go;
}

I'd like to hear from you whether it worked. :)

Edited: Since MyNetworkConnection inherits from NetworkConnection, it should be able to be passed as a NetworkConnection parameter. That means, you can leave your overriden methods as they are, however you need to explicitely pass your MyNetworkConnection class to your AddPlayer method.

Leon Willens
  • 356
  • 1
  • 16
  • Hello, thanks for your time, but visual is complaining about the overriding method OnLobbySerevrCreateLobbyPlayer because of the MyNetworkConnection parameter And also, what are the base() in MyNetworkClient ? – Kalixio May 11 '18 at 09:26
  • `base()` refers to the constructor of the inherited class. I have updated my answer, please review. – Leon Willens May 11 '18 at 10:45
  • I've updated according your modifications. It says "Object reference not set to an instance of an object LobbyManager.AddPlayer (.MyNetworkConnection conn) (at Assets/Scripts/LobbyManager.cs:42)" because it did not find "setNetworkConnectionClass(conn);" I replaced it by SetNetworkConnectionClass() so maybe it's that. – Kalixio May 11 '18 at 11:01
  • I also removed the "this()" because it was struggling on it in visual – Kalixio May 11 '18 at 11:03
  • Yeah, I spotted it. The method is called `SetNetworkConnectionClass()`, I had a typo. :( Also instead of `this()` `base()` should work. – Leon Willens May 11 '18 at 11:11
  • So I replaced it with SetNetworkConnectionClass() Is it good ? – Kalixio May 11 '18 at 11:13
  • You can do that, but you must pass your custom class as a parameter too (as written above): `SetNetworkConnectionClass(conn);` – Leon Willens May 11 '18 at 11:15
  • Yeah, but SetNetworkConnectionClass(conn); do not work be cause the SetNetworkConnectionClass needs to be something like SetNetworkConnectionClass() – Kalixio May 11 '18 at 11:17
  • Unity's documentation is at it again :') Still it should work, as my suggested `MyNetworkConnection` class pulls the platform directly from `Application.platform`. Did you test it? – Leon Willens May 11 '18 at 11:20
  • Yep, but it can't compile because of SetNetworkConnectionClass(conn); " No overload for method `SetNetworkConnectionClass' takes `1' arguments – Kalixio May 11 '18 at 11:22
  • I have updated my answer again, and adjusted some code based on your findings. – Leon Willens May 11 '18 at 11:22
  • I have updated according to your modifications. Everything compiles but fails here : `switch (conn.ConnectionPlatform)` ullReferenceException: Object reference not set to an instance of an object LobbyManager.AddPlayer (.MyNetworkConnection conn) (at Assets/Scripts/LobbyManager.cs:39) – Kalixio May 11 '18 at 11:27
  • Where do you keep your method to connect as a client? – Leon Willens May 11 '18 at 11:57
  • Wut ? I just have this component with the methods you gave. Sorry, it's the first time I'm working with the LobbyManager ^^ – Kalixio May 11 '18 at 11:59
  • Yes, but how do your players connect to the lobby? – Leon Willens May 11 '18 at 12:08
  • They use the GUI provided with NetworkManagerGUI So they just have to use LAN Host or LAN Client (with an ip address) to join a lobby – Kalixio May 11 '18 at 12:10
  • The standard NetworkManagerHUD won't cut it for your purpose, as it seems to use the standard `NetworkManager` component, which in turn creates a regular `NetworkClient` upon invoking `StartClient()`. Updating my answer. – Leon Willens May 12 '18 at 08:21