Creating an Abstract Network Class - Best Approach?

Hey Everyone!

I’m working on a multiplayer game with a few of my friends, and we are in the middle of an overhaul on our architecture, including networking. We aren’t confident in what networking API we ultimately want to use, so for flexibility I’m trying to create abstract classes for all our networking needs that can have concrete versions implemented for each API (Unity internal, uLink, Photon, etc). The main allure here is that the rest of our code base won’t have to worry about the underlying networking implementation, and can just generically use the abstract class.

The issue I’m mainly facing is dealing with the varying object types each API uses. The example below clearly illustrates the problem.

Lets say I have an abstract class called “InitNetwork” and I want it to force concrete implementations to deal with a common network event, such as when a player connects:

public abstract class InitNetwork : MonoBehaviour {

    public abstract void OnPlayerConnected(Object networkPlayer);

}

Now, every networking API has a different version of Unity’s NetworkPlayer object, so at the abstract class level I’ve used Object as the parameter. The plan is to pass the NetworkPlayer variant in in the concrete implementation and cast it. Now, this abstract version of the event won’t actually be called, so each concrete class has to also implement its “native” version of the event, like so:

public class UnityInitNetwork: InitNetwork{

    List<NetworkPlayer> connectedPlayers; // initialized somewhere

	void OnPlayerConnected(NetworkPlayer networkPlayer){
		OnPlayerConnected(networkPlayer);
	}
	
	public override void OnPlayerConnected (Object networkPlayer){
		connectedPlayers.Add(((NetworkPlayer) networkPlayer));
	}
}

So, I’m catching the native event, and passing the NetworkPlayer parameter into the overridden OnPlayerConnected method.

Now, we run into the issue: UnityEngine.Object will not cast to UnityEngine.NetworkPlayer (Error: “Cannot convert type ‘UnityEngine.Object’ to type ‘UnityEngine.NetworkPlayer’”). This surprised me; I though you could cast an Object to pretty much anything as long as you knew the proper type.

Does anyone know how to overcome this casting issue, or perhaps know a better way to approach creating an abstract networking class?

Well, with a bit of hunting I’ve found the solution to the casting error that lets this abstract network class structure live on.

As the question below explains, not all Unity objects derive from UnityEngine.Object – but they do all derive from System.Object.

Thus, the solution is to replace “Object” with “System.Object”.

The reason you can not convert NetworkPlayer to Object is because NetworkPlayer does not inherit from Object, as told ( rather not told) in the documentation. Check e.g. GameObject, Transform, or any other random class and it’ll tell you what it inherits from, if any.

As to abstracting your networking logic, you should create interfaces for all behavior you need from your network. If creating an interface for networking, you could have something like (Assuming you develop your game in Unity, and the networking API will change.)

public interface INetworking{
    void DisconnectFromServer();
    void ConnectToServer(string ip, int port);
}

Now, you’ll need a class for each different networking API you will use, and each class must implement this interface. If you first develop on Unity’s own networking, and then move to SmartFox you’ll end up with these two classes:

public class UnityNetworking : INetworking{
    void DisconnectFromServer(){
        Network.Disconnect();
    }

    void ConnectToServer(string ip, int port){ 
        Network.Connect(ip, port);
    }
} 

public class SmartFoxNetworking : INetworking{
    void DisconnectFromServer(){
        //However you disconnect from a photon server.
    }

    void ConnectToServer(string ip, int port){ 
        //However you connect to a Photon server 
    }
}

You choose the correct implementation depending on which API you use.(Also called the Strategy Pattern.) Using interfaces allows you to have both types of servers, because you can let the player choose which server he wants to connect using e.g. a drop down menu. Basically like this:

public class NetworkModule : MonoBehaviour{

    INetworking currentServerImplementation;

    void OnGUI(){
        if(currentServerImplementation == null){
            // show the drop down menu
            ChooseNetworkServer(/*result of drop down menu*/);
        }else{
            if(GUILayout.Button("Connect"))
                currentServerImplementation.ConnectToServer(ip, port);
        }
    }

    void ChooseNetworkServer(string server)
    if (server.Equals("Unity")){
        currentServerImplementation = new UnityNetworking();
    }
    if (server.Equals("Photon")){
        currentServerImplementation = new PhotonNetworking();
    }
}