public void StartNetworked(int port, string address, string playerSessionId, MonoBehaviour parent, DemoSettingsClient settings)
    {
        var spawnPoint    = DemoSettings.GetSpawnPoint();
        var playerConfig  = DemoSettings.GetPlatformCharacterConfig();
        var recieveByGuid = new Dictionary <string, MessageHandler>();

        networkStream = NetworkApi.OpenOutbound(port, address, parent);
        networkStream.Recieve.Add((opCode, message) => {
            if (opCode == OpCode.PLAYER_ACCEPTED)
            {
                MessageHandler recieve = null;
                var acceptMsg          = (PlayerAcceptMessage)message;
                var isSelf             = acceptMsg.playerSessionId.Equals(playerSessionId);
                Debug.Log("client (" + playerSessionId + ")" + " accepts (" + acceptMsg.playerGuid + ") as self? " + isSelf);
                if (acceptMsg.playerSessionId.Equals(playerSessionId))
                {
                    var spawned    = GameObject.Instantiate(settings.playerPrefab, spawnPoint, Quaternion.identity);
                    var playerComp = spawned.GetComponent <PlayerCompClient>();
                    recieve        = playerComp.RegisterNetwork(networkStream.Send, playerConfig, acceptMsg.PlayerGuid, acceptMsg.trustDistance);
                }
                else
                {
                    var spawned    = GameObject.Instantiate(settings.otherPlayerPrefab, spawnPoint, Quaternion.identity);
                    var playerComp = spawned.GetComponent <OtherPlayerCompClient>();
                    recieve        = playerComp.RegisterNetwork(playerConfig, settings.interpolation);
                }
                recieveByGuid[acceptMsg.PlayerGuid] = recieve;
            }
            else
            {
                MessageHandler reciever = null;
                var found = recieveByGuid.TryGetValue(PlayerGuidUtil.Get(message), out reciever);
                if (found)
                {
                    reciever?.Invoke(opCode, message);
                }
            }
            return(1);
        });
        var joinMessage = new PlayerJoinMessage();

        joinMessage.playerSessionId = playerSessionId;
        networkStream.Send(OpCode.PLAYER_JOIN, joinMessage);
    }
    public async Task <int> StartNetworked(Func <string, bool> acceptPlayer, Action <string, int> handlePlayerExit, MonoBehaviour parent, DemoSettingsServer settings)
    {
        this.handlePlayerExit = handlePlayerExit;
        parent.StartCoroutine(Update());
        var spawnPoint = DemoSettings.GetSpawnPoint();

        var platformerConfig = DemoSettings.GetPlatformCharacterConfig();

        networkStream = await NetworkApi.AcceptInbound(parent, settings.port);

        networkStream.Recieve.Add((opCode, guid, message) => {
            if (opCode == OpCode.PLAYER_JOIN)
            {
                var joinMessage = (PlayerJoinMessage)message;
                acceptPlayer(joinMessage.playerSessionId);
                var onCancel = networkStream.Recieve.GetConnectionCancellation(guid);
                onCancel.Token.Register(() => {
                    lock (abandonedPlayers){
                        abandonedPlayers.Enqueue(guid);
                    }
                });
                playerGuids.Add(guid);
                var serverRep        = GameObject.Instantiate(settings.playerPrefab, spawnPoint, Quaternion.identity);
                var serverRepComp    = serverRep.GetComponent <PlayerCompServer>();
                var serverRepRecieve = serverRepComp.RegisterNetwork(guid, (toSendCode, toSendMessage) => {
                    playerGuids.ForEach((targetGuid) => {
                        try{
                            networkStream.Send(toSendCode, targetGuid, toSendMessage);
                        } catch (Exception e) {
                            Debug.Log("failed sending to player: " + e.Message);
                        }
                    });
                    return(1);
                }, platformerConfig, settings);
                ServerRepData repData   = new ServerRepData();
                repData.comp            = serverRepComp;
                repData.session         = joinMessage.playerSessionId;
                repData.recieve         = serverRepRecieve;
                repData.guid            = guid;
                serverReps[guid]        = repData;
                var acceptMsg           = new PlayerAcceptMessage();
                acceptMsg.trustDistance = settings.trustDistance;
                playerGuids.ForEach((existingPlayer) => {
                    acceptMsg.playerGuid         = guid;
                    var isSendingToNewlyAccepted = PlayerGuidUtil.IsFor(acceptMsg, existingPlayer);
                    acceptMsg.playerSessionId    = isSendingToNewlyAccepted ? joinMessage.playerSessionId : string.Empty;
                    networkStream.Send(OpCode.PLAYER_ACCEPTED, existingPlayer, acceptMsg);
                    if (!isSendingToNewlyAccepted)
                    {
                        acceptMsg.playerSessionId = string.Empty;
                        acceptMsg.playerGuid      = existingPlayer;
                        networkStream.Send(OpCode.PLAYER_ACCEPTED, guid, acceptMsg);
                    }
                });
            }
            else
            {
                if (serverReps.ContainsKey(guid))
                {
                    serverReps[guid].recieve(opCode, message);
                }
            }
            return(1);
        });
        return(1);
    }