public void Init(OnlinePlayerController newOwner)
        {
            BeatmapObjectCallbackController original = FindObjectsOfType <BeatmapObjectCallbackController>().First(x => !(x is OnlineBeatmapCallbackController));

            foreach (FieldInfo info in original.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic).Where(x => !x.Name.ToLower().Contains("event")))
            {
                info.SetValue(this, info.GetValue(original));
            }

            owner = newOwner;

            _beatmapObjectDataCallbackCacheList = new List <BeatmapObjectData>();
            _beatmapObjectCallbackData          = new List <BeatmapObjectCallbackData>();

            _beatmapDataModel = new GameObject("CustomBeatmapDataModel").AddComponent <BeatmapDataModel>();
            if (BS_Utils.Plugin.LevelData.IsSet)
            {
                LevelOptionsInfo   levelInfo   = owner.playerInfo.updateInfo.playerLevelOptions;
                IDifficultyBeatmap diffBeatmap = BS_Utils.Plugin.LevelData.GameplayCoreSceneSetupData.difficultyBeatmap.level.beatmapLevelData.difficultyBeatmapSets.First(x => x.beatmapCharacteristic.serializedName == owner.playerInfo.updateInfo.playerLevelOptions.characteristicName).difficultyBeatmaps.First(x => x.difficulty == owner.playerInfo.updateInfo.playerLevelOptions.difficulty);
                BeatmapData        data        = diffBeatmap.beatmapData;

                _beatmapDataModel.beatmapData = BeatDataTransformHelper.CreateTransformedBeatmapData(data, levelInfo.modifiers.ToGameplayModifiers(), PracticeSettings.defaultPracticeSettings, PlayerSpecificSettings.defaultSettings);
                HandleBeatmapDataModelDidChangeBeatmapData();

                Plugin.log.Info($"Set custom BeatmapDataModel for difficulty {levelInfo.difficulty}");
            }
        }
Beispiel #2
0
 private void UpdateLevelOptions()
 {
     if (_playerManagementViewController != null)
     {
         if (Client.Instance.isHost)
         {
             if (roomInfo.roomState == RoomState.Preparing && _difficultySelectionViewController != null)
             {
                 LevelOptionsInfo info = new LevelOptionsInfo(_difficultySelectionViewController.selectedDifficulty, _playerManagementViewController.modifiers, _difficultySelectionViewController.selectedCharacteristic.serializedName);
                 Client.Instance.SetLevelOptions(info);
                 roomInfo.startLevelInfo = info;
                 Client.Instance.playerInfo.playerLevelOptions = info;
             }
             else
             {
                 LevelOptionsInfo info = new LevelOptionsInfo(BeatmapDifficulty.Hard, _playerManagementViewController.modifiers, "Standard");
                 Client.Instance.SetLevelOptions(info);
                 roomInfo.startLevelInfo = info;
                 Client.Instance.playerInfo.playerLevelOptions = info;
             }
         }
         else
         {
             if (roomInfo.roomState == RoomState.Preparing && _difficultySelectionViewController != null)
             {
                 Client.Instance.playerInfo.playerLevelOptions = new LevelOptionsInfo(_difficultySelectionViewController.selectedDifficulty, _playerManagementViewController.modifiers, _difficultySelectionViewController.selectedCharacteristic.serializedName);
             }
             else
             {
                 Client.Instance.playerInfo.playerLevelOptions = new LevelOptionsInfo(BeatmapDifficulty.Hard, _playerManagementViewController.modifiers, "Standard");
             }
         }
     }
 }
Beispiel #3
0
        public virtual void StartLevel(PlayerInfo sender, LevelOptionsInfo options, SongInfo song)
        {
            if (sender.Equals(roomHost))
            {
                selectedSong   = song;
                startLevelInfo = options;

                SongWithOptions songWithDifficulty = new SongWithOptions(selectedSong, startLevelInfo);

                NetOutgoingMessage outMsg = HubListener.ListenerServer.CreateMessage();

                outMsg.Write((byte)CommandType.StartLevel);
                startLevelInfo.AddToMessage(outMsg);
                selectedSong.AddToMessage(outMsg);

                BroadcastPacket(outMsg, NetDeliveryMethod.ReliableOrdered, 0);
                BroadcastWebSocket(CommandType.StartLevel, songWithDifficulty);

                roomState      = RoomState.InGame;
                _songStartTime = DateTime.Now;
                _readyPlayers.Clear();
            }
            else
            {
                Logger.Instance.Warning($"{sender.playerName}({sender.playerId}) tried to start the level, but he is not the host");
            }
        }
Beispiel #4
0
        public override void Start()
        {
            try
            {
                if (BS_Utils.Plugin.LevelData.IsSet)
                {
                    LevelOptionsInfo   levelInfo   = owner.playerInfo.updateInfo.playerLevelOptions;
                    IDifficultyBeatmap diffBeatmap = BS_Utils.Plugin.LevelData.GameplayCoreSceneSetupData.difficultyBeatmap.level.beatmapLevelData.difficultyBeatmapSets.First(x => x.beatmapCharacteristic.serializedName == owner.playerInfo.updateInfo.playerLevelOptions.characteristicName).difficultyBeatmaps.First(x => x.difficulty == owner.playerInfo.updateInfo.playerLevelOptions.difficulty);

                    _beatsPerMinute        = diffBeatmap.level.beatsPerMinute;
                    _noteLinesCount        = diffBeatmap.beatmapData.beatmapLinesData.Length;
                    _noteJumpMovementSpeed = diffBeatmap.noteJumpMovementSpeed;
                    _disappearingArrows    = levelInfo.modifiers.disappearingArrows;
                    _ghostNotes            = levelInfo.modifiers.ghostNotes;
                    float num = 60f / _beatsPerMinute;
                    _moveDistance = _moveSpeed * num * _moveDurationInBeats;
                    while (_noteJumpMovementSpeed * num * _halfJumpDurationInBeats > _maxHalfJumpDistance)
                    {
                        _halfJumpDurationInBeats /= 2f;
                    }
                    _halfJumpDurationInBeats += diffBeatmap.noteJumpStartBeatOffset;
                    if (_halfJumpDurationInBeats < 1f)
                    {
                        _halfJumpDurationInBeats = 1f;
                    }
                    _jumpDistance   = _noteJumpMovementSpeed * num * _halfJumpDurationInBeats * 2f;
                    _spawnAheadTime = _moveDistance / _moveSpeed + _jumpDistance * 0.5f / _noteJumpMovementSpeed;
                }
            }
            catch (Exception e)
            {
                Plugin.log.Warn("Unable to update beatmap data! Exception: " + e);
            }

            if (_beatmapObjectCallbackController != null)
            {
                if (_beatmapObjectCallbackId != -1)
                {
                    _beatmapObjectCallbackController.RemoveBeatmapObjectCallback(_beatmapObjectCallbackId);
                }
                _beatmapObjectCallbackId = _beatmapObjectCallbackController.AddBeatmapObjectCallback(new BeatmapObjectCallbackController.BeatmapObjectCallback(HandleBeatmapObjectCallback), _spawnAheadTime);

                if (_eventCallbackId != -1)
                {
                    _beatmapObjectCallbackController.RemoveBeatmapEventCallback(_eventCallbackId);
                }
                _beatmapObjectCallbackController.callbacksForThisFrameWereProcessedEvent += HandleCallbacksForThisFrameWereProcessed;
            }

            NoteCutEffectSpawner cutEffectSpawner = FindObjectOfType <NoteCutEffectSpawner>();

            (this as BeatmapObjectSpawnController).noteWasCutEvent += (sender, controller, cutInfo) => { if (cutInfo.allIsOK)
                                                                                                         {
                                                                                                             cutEffectSpawner.HandleNoteWasCutEvent(sender, controller, cutInfo);
                                                                                                         }
            };
        }
        public void SetLevelOptions(LevelOptionsInfo info)
        {
            if (connected && networkClient != null)
            {
                NetOutgoingMessage outMsg = networkClient.CreateMessage();
                outMsg.Write((byte)CommandType.SetLevelOptions);
                info.AddToMessage(outMsg);

                networkClient.SendMessage(outMsg, NetDeliveryMethod.ReliableOrdered, 0);
                Plugin.log.Debug("Updating level options: Selected modifiers: " + string.Join(", ", Resources.FindObjectsOfTypeAll <GameplayModifiersModelSO>().First().GetModifierParams(info.modifiers.ToGameplayModifiers()).Select(x => Polyglot.Localization.Get(x.modifierNameLocalizationKey))));
            }
        }
        public override void Start()
        {
            try
            {
                if (BS_Utils.Plugin.LevelData.IsSet)
                {
                    LevelOptionsInfo   levelInfo   = owner.playerInfo.updateInfo.playerLevelOptions;
                    IDifficultyBeatmap diffBeatmap = BS_Utils.Plugin.LevelData.GameplayCoreSceneSetupData.difficultyBeatmap.level.beatmapLevelData.difficultyBeatmapSets.First(x => x.beatmapCharacteristic.serializedName == owner.playerInfo.updateInfo.playerLevelOptions.characteristicName).difficultyBeatmaps.First(x => x.difficulty == owner.playerInfo.updateInfo.playerLevelOptions.difficulty);

                    _disappearingArrows = levelInfo.modifiers.disappearingArrows;
                    _ghostNotes         = levelInfo.modifiers.ghostNotes;

                    var movementSpeed = diffBeatmap.noteJumpMovementSpeed;

                    if (movementSpeed <= 0f)
                    {
                        movementSpeed = diffBeatmap.difficulty.NoteJumpMovementSpeed();
                    }

                    //TODO: Implement Fast Notes modifier in level options

                    /*
                     * if (levelInfo.modifiers.ToGameplayModifiers().fastNotes)
                     * {
                     *  movementSpeed = 20f;
                     * }
                     */
                    _initData = new InitData(diffBeatmap.level.beatsPerMinute, diffBeatmap.beatmapData.beatmapLinesData.Length, movementSpeed, diffBeatmap.noteJumpStartBeatOffset, _disappearingArrows, _ghostNotes, _initData.jumpOffsetY);
                }
            }
            catch (Exception e)
            {
                Plugin.log.Warn("Unable to update beatmap data! Exception: " + e);
            }

            _variableBPMProcessor.SetBPM(_initData.beatsPerMinute);
            _beatmapObjectSpawnMovementData.Init(_initData.noteLinesCount, _initData.noteJumpMovementSpeed, _initData.beatsPerMinute, _initData.noteJumpStartBeatOffset, _initData.jumpOffsetY, transform.position + transform.right * owner.avatarOffset, transform.right, transform.forward);
            _beatmapCallbackItemDataList = new BeatmapCallbackItemDataList(new BeatmapCallbackItemDataList.SpawnNoteCallback(SpawnNote), new BeatmapCallbackItemDataList.SpawnObstacleCallback(SpawnObstacle), new BeatmapCallbackItemDataList.ProcessBeatmapEventCallback(ProcessEarlyBeatmapEventData), new BeatmapCallbackItemDataList.ProcessBeatmapEventCallback(ProcessLateBeatmapEventData), new Action(EarlyEventsWereProcessed), new BeatmapCallbackItemDataList.GetRelativeNoteOffsetCallback(_beatmapObjectSpawnMovementData.Get2DNoteOffset));
            _jumpOffsetY        = _initData.jumpOffsetY;
            _disappearingArrows = _initData.disappearingArrows;
            _ghostNotes         = _initData.ghostNotes;
            if (_beatmapObjectCallbackData != null)
            {
                _beatmapObjectCallbackController.RemoveBeatmapObjectCallback(_beatmapObjectCallbackData);
            }
            _beatmapObjectCallbackData = _beatmapObjectCallbackController.AddBeatmapObjectCallback(new BeatmapObjectCallbackController.BeatmapObjectCallback(HandleBeatmapObjectCallback), _beatmapObjectSpawnMovementData.spawnAheadTime);
            if (_beatmapEventCallbackData != null)
            {
                _beatmapObjectCallbackController.RemoveBeatmapEventCallback(_beatmapEventCallbackData);
            }
            _beatmapEventCallbackData = _beatmapObjectCallbackController.AddBeatmapEventCallback(new BeatmapObjectCallbackController.BeatmapEventCallback(HandleBeatmapEventCallback), _beatmapObjectSpawnMovementData.spawnAheadTime);
            _beatmapObjectCallbackController.callbacksForThisFrameWereProcessedEvent += HandleCallbacksForThisFrameWereProcessed;
        }
Beispiel #7
0
        public void Init(OnlinePlayerController newOwner, OnlineBeatmapCallbackController callbackController, OnlineAudioTimeController syncController)
        {
            BeatmapObjectSpawnController original = FindObjectsOfType <BeatmapObjectSpawnController>().First(x => !x.name.StartsWith("Online"));

            foreach (FieldInfo info in original.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Default).Where(x => !x.Name.ToLower().Contains("event")))
            {
                info.SetValue(this, info.GetValue(original));
            }

            owner = newOwner;

            try
            {
                if (BS_Utils.Plugin.LevelData.IsSet)
                {
                    LevelOptionsInfo   levelInfo   = owner.PlayerInfo.playerLevelOptions;
                    IDifficultyBeatmap diffBeatmap = BS_Utils.Plugin.LevelData.GameplayCoreSceneSetupData.difficultyBeatmap.level.beatmapLevelData.difficultyBeatmapSets.First(x => x.beatmapCharacteristic.serializedName == owner.PlayerInfo.playerLevelOptions.characteristicName).difficultyBeatmaps.First(x => x.difficulty == owner.PlayerInfo.playerLevelOptions.difficulty);

                    Init(diffBeatmap.level.beatsPerMinute, diffBeatmap.beatmapData.beatmapLinesData.Length, diffBeatmap.noteJumpMovementSpeed, diffBeatmap.noteJumpStartBeatOffset, levelInfo.modifiers.disappearingArrows, levelInfo.modifiers.ghostNotes);
                }
            }catch (Exception e)
            {
                Plugin.log.Warn("Unable to update beatmap data! Exception: " + e);
            }

            onlineCallbackController         = callbackController;
            _beatmapObjectCallbackController = onlineCallbackController;
            onlineSyncController             = syncController;

            if (onlineCallbackController != null)
            {
                _beatmapObjectCallbackId = onlineCallbackController.AddBeatmapObjectCallback(new BeatmapObjectCallbackController.BeatmapObjectCallback(BeatmapObjectSpawnCallback), _spawnAheadTime);
            }

            _localPlayer         = FindObjectsOfType <PlayerController>().First(x => !(x is OnlinePlayerController));
            _localSyncController = FindObjectsOfType <AudioTimeSyncController>().First(x => !(x is OnlineAudioTimeController));

            NoteCutEffectSpawner cutEffectSpawner = FindObjectOfType <NoteCutEffectSpawner>();

            (this as BeatmapObjectSpawnController).noteWasCutEvent += (sender, controller, cutInfo) => { if (cutInfo.allIsOK)
                                                                                                         {
                                                                                                             cutEffectSpawner.HandleNoteWasCutEvent(sender, controller, cutInfo);
                                                                                                         }
            };

            _activeNotes     = new List <NoteController>();
            _activeObstacles = new List <ObstacleController>();
        }
Beispiel #8
0
        public override void Start()
        {
            _spawningStartTime = _initData.spawningStartTime;
            if (BS_Utils.Plugin.LevelData.IsSet)
            {
                Plugin.log.Debug($"Level data is set, trying to match BeatmapDatamodel for selected difficulty...");

                LevelOptionsInfo   levelInfo   = owner.playerInfo.updateInfo.playerLevelOptions;
                IDifficultyBeatmap diffBeatmap = BS_Utils.Plugin.LevelData.GameplayCoreSceneSetupData.difficultyBeatmap.level.beatmapLevelData.difficultyBeatmapSets.First(x => x.beatmapCharacteristic.serializedName == owner.playerInfo.updateInfo.playerLevelOptions.characteristicName).difficultyBeatmaps.First(x => x.difficulty == owner.playerInfo.updateInfo.playerLevelOptions.difficulty);
                BeatmapData        data        = diffBeatmap.beatmapData;

                SetNewBeatmapData(BeatDataTransformHelper.CreateTransformedBeatmapData(data, levelInfo.modifiers.ToGameplayModifiers(), PracticeSettings.defaultPracticeSettings, PlayerSpecificSettings.defaultSettings));

                Plugin.log.Debug($"Set custom BeatmapDataModel for difficulty {levelInfo.difficulty}");
            }
            else
            {
                Plugin.log.Warn($"Level data is not set! Unable to set BeatmapDataModel for other players!");
                SetNewBeatmapData(_initData.beatmapData);
            }
        }
Beispiel #9
0
 private void UpdateLevelOptions()
 {
     try
     {
         if (_playerManagementViewController != null && roomInfo != null)
         {
             if (Client.Instance.isHost)
             {
                 if (roomInfo.roomState == RoomState.Preparing && _difficultySelectionViewController != null)
                 {
                     LevelOptionsInfo info = new LevelOptionsInfo(_difficultySelectionViewController.selectedDifficulty, _playerManagementViewController.modifiers, _difficultySelectionViewController.selectedCharacteristic.serializedName);
                     Client.Instance.SetLevelOptions(info);
                     roomInfo.startLevelInfo = info;
                     Client.Instance.playerInfo.updateInfo.playerLevelOptions = info;
                 }
                 else
                 {
                     LevelOptionsInfo info = new LevelOptionsInfo(BeatmapDifficulty.Hard, _playerManagementViewController.modifiers, "Standard");
                     Client.Instance.SetLevelOptions(info);
                     roomInfo.startLevelInfo = info;
                     Client.Instance.playerInfo.updateInfo.playerLevelOptions = info;
                 }
             }
             else
             {
                 if (roomInfo.roomState == RoomState.Preparing && _difficultySelectionViewController != null)
                 {
                     Client.Instance.playerInfo.updateInfo.playerLevelOptions = new LevelOptionsInfo(_difficultySelectionViewController.selectedDifficulty, _playerManagementViewController.modifiers, _difficultySelectionViewController.selectedCharacteristic.serializedName);
                 }
                 else
                 {
                     Client.Instance.playerInfo.updateInfo.playerLevelOptions = new LevelOptionsInfo(BeatmapDifficulty.Hard, _playerManagementViewController.modifiers, "Standard");
                 }
             }
         }
     }catch (Exception e)
     {
         Plugin.log.Critical($"Unable to update level options! Exception: {e}");
     }
 }
Beispiel #10
0
        public virtual void SetLevelOptions(PlayerInfo sender, LevelOptionsInfo info)
        {
            if (sender.Equals(roomHost))
            {
                startLevelInfo = info;

                NetOutgoingMessage outMsg = HubListener.ListenerServer.CreateMessage();

                outMsg.Write((byte)CommandType.SetLevelOptions);
                startLevelInfo.AddToMessage(outMsg);

                BroadcastPacket(outMsg, NetDeliveryMethod.ReliableOrdered, 0, new List <Client>()
                {
                    roomClients.First(x => x.playerInfo.Equals(sender))
                });
                BroadcastWebSocket(CommandType.SetLevelOptions, startLevelInfo);
            }
            else
            {
                Logger.Instance.Warning($"{sender.playerName}({sender.playerId}) tried to change level options, but he is not the host");
            }
        }
Beispiel #11
0
        public void Update()
        {
            if (_receivedMessages.Count > 0)
            {
                networkClient.Recycle(_receivedMessages);
                _receivedMessages.Clear();
            }

            if (networkClient.ReadMessages(_receivedMessages) > 0)
            {
                for (int i = _receivedMessages.Count - 1; i >= 0; i--)
                {
                    if (_receivedMessages[i].MessageType == NetIncomingMessageType.Data && _receivedMessages[i].PeekByte() == (byte)CommandType.UpdatePlayerInfo)
                    {
                        if (_packets > 150)
                        {
                            _averagePacketTime = 0f;
                            _packets           = 0;
                        }

                        if (Time.realtimeSinceStartup - _lastPacketTime < 0.2f)
                        {
                            _averagePacketTime += Time.realtimeSinceStartup - _lastPacketTime;
                            _packets++;

                            if (_averagePacketTime != 0f && _packets != 0)
                            {
                                tickrate = 1f / (_averagePacketTime / _packets);
                            }
                        }
                        else
                        {
                            _averagePacketTime = 0f;
                            _packets           = 0;
                        }
                        _lastPacketTime = Time.realtimeSinceStartup;

                        MessageReceived?.Invoke(_receivedMessages[i]);
                        _receivedMessages[i].Position = 0;

                        break;
                    }
                }

                if (Config.Instance.SpectatorMode)
                {
                    for (int i = 0; i < _receivedMessages.Count; i++)
                    {
                        _receivedMessages[i].Position = 0;
                        if (_receivedMessages[i].MessageType == NetIncomingMessageType.Data && _receivedMessages[i].PeekByte() == (byte)CommandType.GetPlayerUpdates)
                        {
                            PlayerInfoUpdateReceived?.Invoke(_receivedMessages[i]);
                            _receivedMessages[i].Position = 0;
                        }
                    }
                }

                foreach (NetIncomingMessage msg in _receivedMessages)
                {
                    switch (msg.MessageType)
                    {
                    case NetIncomingMessageType.StatusChanged:
                    {
                        NetConnectionStatus status = (NetConnectionStatus)msg.ReadByte();

                        if (status == NetConnectionStatus.Connected && !connected)
                        {
                            connected = true;
                            ConnectedToServerHub?.Invoke();
                        }
                        else if (status == NetConnectionStatus.Disconnected && connected)
                        {
#if DEBUG
                            Plugin.log.Info("Disconnecting...");
#endif
                            Disconnect();

                            MessageReceived?.Invoke(null);
                        }
                        else if (status == NetConnectionStatus.Disconnected && !connected)
                        {
                            Plugin.log.Error("ServerHub refused connection! Reason: " + msg.ReadString());
                        }
                    }
                    break;

                    case NetIncomingMessageType.Data:
                    {
                        CommandType commandType = (CommandType)msg.PeekByte();

                        switch (commandType)
                        {
                        case CommandType.Disconnect:
                        {
#if DEBUG
                            Plugin.log.Info("Disconnecting...");
#endif
                            Disconnect();

                            MessageReceived?.Invoke(msg);
                        }
                        break;

                        case CommandType.SendEventMessage:
                        {
                            string header = msg.ReadString();
                            string data   = msg.ReadString();

#if DEBUG
                            Plugin.log.Info($"Received event message! Header=\"{header}\", Data=\"{data}\"");
#endif

                            foreach (Action <string, string> nextDel in EventMessageReceived.GetInvocationList())
                            {
                                try
                                {
                                    nextDel?.Invoke(header, data);
                                }
                                catch (Exception e)
                                {
                                    if (nextDel != null)
                                    {
                                        Plugin.log.Error($"Exception in {nextDel.Target.GetType()}.{nextDel.Method.Name} on event message received event: {e}");
                                    }
                                    else
                                    {
                                        Plugin.log.Error($"Exception in {nextDel.Target.GetType()}.{nextDel.Method.Name} on event message received event: {e}");
                                    }
                                }
                            }
                        }
                        break;

                        case CommandType.JoinRoom:
                        {
                            msg.Position = 8;
                            if (msg.PeekByte() == 0 && ClientJoinedRoom != null)
                            {
                                foreach (Action nextDel in ClientJoinedRoom.GetInvocationList())
                                {
                                    try
                                    {
                                        nextDel?.Invoke();
                                    }
                                    catch (Exception e)
                                    {
                                        if (nextDel != null)
                                        {
                                            Plugin.log.Error($"Exception in {nextDel.Target.GetType()}.{nextDel.Method.Name} on client joined room event: {e}");
                                        }
                                        else
                                        {
                                            Plugin.log.Error($"Exception on client joined room event: {e}");
                                        }
                                    }
                                }
                            }

                            MessageReceived?.Invoke(msg);
                        }
                        break;

                        case CommandType.StartLevel:
                        {
#if DEBUG
                            startNewDump = true;
                            packetsBuffer.Clear();
                            msg.Position = 8;
                            LevelOptionsInfo levelInfo = new LevelOptionsInfo(msg);
                            SongInfo         songInfo  = new SongInfo(msg);
                            List <byte>      buffer    = new List <byte>();
                            buffer.AddRange(levelInfo.ToBytes());
                            buffer.AddRange(HexConverter.ConvertHexToBytesX(songInfo.hash));

                            Plugin.log.Info("LevelID: " + songInfo.levelId + ", Bytes: " + BitConverter.ToString(buffer.ToArray()));

                            packetsBuffer.Enqueue(buffer.ToArray());
                            msg.Position = 0;
#endif
                            if (playerInfo != null && playerInfo.updateInfo.playerState == PlayerState.Room && ClientLevelStarted != null)
                            {
                                foreach (Action nextDel in ClientLevelStarted.GetInvocationList())
                                {
                                    try
                                    {
                                        nextDel?.Invoke();
                                    }
                                    catch (Exception e)
                                    {
                                        if (nextDel != null)
                                        {
                                            Plugin.log.Error($"Exception in {nextDel.Target.GetType()}.{nextDel.Method.Name} on client level started event: {e}");
                                        }
                                        else
                                        {
                                            Plugin.log.Error($"Exception on client level started event: {e}");
                                        }
                                    }
                                }
                            }

                            MessageReceived?.Invoke(msg);
                        }
                        break;

                        case CommandType.UpdatePlayerInfo:
                            break;

                        default:
                        {
                            MessageReceived?.Invoke(msg);
                        }
                        break;
                        }
                    };
                        break;

                    case NetIncomingMessageType.WarningMessage:
                        Plugin.log.Warn(msg.ReadString());
                        break;

                    case NetIncomingMessageType.ErrorMessage:
                        Plugin.log.Error(msg.ReadString());
                        break;

#if DEBUG
                    case NetIncomingMessageType.VerboseDebugMessage:
                    case NetIncomingMessageType.DebugMessage:
                        Plugin.log.Info(msg.ReadString());
                        break;

                    default:
                        Plugin.log.Info("Unhandled message type: " + msg.MessageType);
                        break;
#endif
                    }
                }

                networkClient.Recycle(_receivedMessages);
                _receivedMessages.Clear();
            }

            if (connected && networkClient.ConnectionsCount == 0)
            {
#if DEBUG
                Plugin.log.Info("Connection lost! Disconnecting...");
#endif
                Disconnect();

                MessageReceived?.Invoke(null);
            }

            if ((Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) && Input.GetKeyDown(KeyCode.F1))
            {
                GarbageCollector.GCMode = GarbageCollector.GCMode == GarbageCollector.Mode.Enabled ? GarbageCollector.Mode.Disabled : GarbageCollector.Mode.Enabled;
                Plugin.log.Notice($"Garbage collector {GarbageCollector.GCMode.ToString()}!");
            }
        }
Beispiel #12
0
        private void PacketReceived(NetIncomingMessage msg)
        {
            if (msg == null)
            {
                DisconnectCommandReceived(null);
                return;
            }
            msg.Position = 0;

            CommandType commandType = (CommandType)msg.ReadByte();

            if (!joined)
            {
                if (commandType == CommandType.JoinRoom)
                {
                    switch (msg.ReadByte())
                    {
                    case 0:
                    {
                        Client.Instance.playerInfo.updateInfo.playerState = PlayerState.DownloadingSongs;
                        Client.Instance.RequestRoomInfo();
                        roomInfoRequestTime = Time.time;
                        Client.Instance.SendPlayerInfo(true);
                        Client.Instance.inRoom = true;
                        joined = true;
                        InGameOnlineController.Instance.needToSendUpdates = true;
                        if (Config.Instance.EnableVoiceChat)
                        {
                            InGameOnlineController.Instance.VoiceChatStartRecording();
                        }
                    }
                    break;

                    case 1:
                    {
                        _roomNavigationController.DisplayError("Unable to join room!\nRoom not found");
                    }
                    break;

                    case 2:
                    {
                        _roomNavigationController.DisplayError("Unable to join room!\nIncorrect password");
                    }
                    break;

                    case 3:
                    {
                        _roomNavigationController.DisplayError("Unable to join room!\nToo much players");
                    }
                    break;

                    default:
                    {
                        _roomNavigationController.DisplayError("Unable to join room!\nUnknown error");
                    }
                    break;
                    }
                }
            }
            else
            {
                try
                {
                    if (roomInfo == null && commandType != CommandType.GetRoomInfo)
                    {
                        if (Time.time - roomInfoRequestTime < 1.5f)
                        {
                            return;
                        }
                        else
                        {
                            throw new ArgumentNullException("RoomInfo is null! Need to wait for it to arrive...");
                        }
                    }

                    switch (commandType)
                    {
                    case CommandType.GetRoomInfo:
                    {
                        roomInfo = new RoomInfo(msg);

                        Client.Instance.playerInfo.updateInfo.playerState = PlayerState.Room;

                        Client.Instance.isHost = Client.Instance.playerInfo.Equals(roomInfo.roomHost);

                        UpdateUI(roomInfo.roomState);
                    }
                    break;

                    case CommandType.SetSelectedSong:
                    {
                        if (msg.LengthBytes < 16)
                        {
                            roomInfo.roomState    = RoomState.SelectingSong;
                            roomInfo.selectedSong = null;

                            PreviewPlayer.CrossfadeToDefault();

                            UpdateUI(roomInfo.roomState);

                            if (songToDownload != null)
                            {
                                songToDownload.songQueueState = SongQueueState.Error;
                                Client.Instance.playerInfo.updateInfo.playerState = PlayerState.Room;
                            }
                        }
                        else
                        {
                            roomInfo.roomState = RoomState.Preparing;
                            SongInfo selectedSong = new SongInfo(msg);
                            roomInfo.selectedSong = selectedSong;

                            if (roomInfo.startLevelInfo == null)
                            {
                                roomInfo.startLevelInfo = new LevelOptionsInfo(BeatmapDifficulty.Hard, GameplayModifiers.defaultModifiers, "Standard");
                            }

                            if (songToDownload != null)
                            {
                                songToDownload.songQueueState = SongQueueState.Error;
                            }

                            UpdateUI(roomInfo.roomState);
                        }
                    }
                    break;

                    case CommandType.SetLevelOptions:
                    {
                        roomInfo.startLevelInfo = new LevelOptionsInfo(msg);

                        _playerManagementViewController.SetGameplayModifiers(roomInfo.startLevelInfo.modifiers.ToGameplayModifiers());

                        if (roomInfo.roomState == RoomState.Preparing)
                        {
                            _difficultySelectionViewController.SetBeatmapCharacteristic(_beatmapCharacteristics.First(x => x.serializedName == roomInfo.startLevelInfo.characteristicName));

                            if (!roomInfo.perPlayerDifficulty)
                            {
                                _difficultySelectionViewController.SetBeatmapDifficulty(roomInfo.startLevelInfo.difficulty);
                            }
                        }
                    }
                    break;

                    case CommandType.GetRandomSongInfo:
                    {
                        SongInfo random = new SongInfo(SongCore.Loader.CustomBeatmapLevelPackCollectionSO.beatmapLevelPacks.SelectMany(x => x.beatmapLevelCollection.beatmapLevels).ToArray().Random());

                        Client.Instance.SetSelectedSong(random);
                    }
                    break;

                    case CommandType.TransferHost:
                    {
                        roomInfo.roomHost      = new PlayerInfo(msg);
                        Client.Instance.isHost = Client.Instance.playerInfo.Equals(roomInfo.roomHost);

                        if (Client.Instance.playerInfo.updateInfo.playerState == PlayerState.DownloadingSongs)
                        {
                            return;
                        }

                        UpdateUI(roomInfo.roomState);
                    }
                    break;

                    case CommandType.StartLevel:
                    {
                        if (Client.Instance.playerInfo.updateInfo.playerState == PlayerState.DownloadingSongs)
                        {
                            return;
                        }

                        LevelOptionsInfo levelInfo = new LevelOptionsInfo(msg);

                        BeatmapCharacteristicSO characteristic = _beatmapCharacteristics.First(x => x.serializedName == levelInfo.characteristicName);

                        SongInfo             songInfo = new SongInfo(msg);
                        IPreviewBeatmapLevel level    = SongCore.Loader.CustomBeatmapLevelPackCollectionSO.beatmapLevelPacks.SelectMany(x => x.beatmapLevelCollection.beatmapLevels).FirstOrDefault(x => x.levelID.StartsWith(songInfo.levelId));

                        if (level == null)
                        {
                            Plugin.log.Error("Unable to start level! Level is null! LevelID=" + songInfo.levelId);
                        }
                        else
                        {
                            LoadBeatmapLevelAsync(level,
                                                  (status, success, beatmapLevel) =>
                                {
                                    if (roomInfo.perPlayerDifficulty && _difficultySelectionViewController != null)
                                    {
                                        StartLevel(beatmapLevel, characteristic, _difficultySelectionViewController.selectedDifficulty, levelInfo.modifiers.ToGameplayModifiers());
                                    }
                                    else
                                    {
                                        StartLevel(beatmapLevel, characteristic, levelInfo.difficulty, levelInfo.modifiers.ToGameplayModifiers());
                                    }
                                });
                        }
                    }
                    break;

                    case CommandType.LeaveRoom:
                    {
                        LeaveRoom();
                    }
                    break;

                    case CommandType.UpdatePlayerInfo:
                    {
                        if (roomInfo != null)
                        {
                            currentTime = msg.ReadFloat();
                            totalTime   = msg.ReadFloat();

                            if (roomInfo.roomState == RoomState.InGame || roomInfo.roomState == RoomState.Results)
                            {
                                UpdateLeaderboard(currentTime, totalTime, roomInfo.roomState == RoomState.Results);
                            }

                            _playerManagementViewController.UpdatePlayerList(roomInfo.roomState);
                        }
                    }
                    break;

                    case CommandType.PlayerReady:
                    {
                        int playersReady = msg.ReadInt32();
                        int playersTotal = msg.ReadInt32();

                        if (roomInfo.roomState == RoomState.Preparing && _difficultySelectionViewController != null)
                        {
                            _difficultySelectionViewController.SetPlayersReady(playersReady, playersTotal);
                        }
                    }
                    break;

                    case CommandType.Disconnect:
                    {
                        DisconnectCommandReceived(msg);
                    }
                    break;
                    }
                }catch (Exception e)
                {
                    Plugin.log.Error($"Unable to parse packet! Packet={commandType}, DataLength={msg.LengthBytes}\nException: {e}");
                }
            }
        }
        public void Init(OnlinePlayerController newOwner, OnlineBeatmapCallbackController callbackController, OnlineAudioTimeController syncController)
        {
            BeatmapObjectSpawnController original = FindObjectsOfType <BeatmapObjectSpawnController>().First(x => !(x is OnlineBeatmapSpawnController));

            foreach (FieldInfo info in original.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic).Where(x => !x.Name.ToLower().Contains("event")))
            {
                info.SetValue(this, info.GetValue(original));
            }

            owner = newOwner;


            try
            {
                if (BS_Utils.Plugin.LevelData.IsSet)
                {
                    LevelOptionsInfo   levelInfo   = owner.playerInfo.updateInfo.playerLevelOptions;
                    IDifficultyBeatmap diffBeatmap = BS_Utils.Plugin.LevelData.GameplayCoreSceneSetupData.difficultyBeatmap.level.beatmapLevelData.difficultyBeatmapSets.First(x => x.beatmapCharacteristic.serializedName == owner.playerInfo.updateInfo.playerLevelOptions.characteristicName).difficultyBeatmaps.First(x => x.difficulty == owner.playerInfo.updateInfo.playerLevelOptions.difficulty);

                    _beatsPerMinute        = diffBeatmap.level.beatsPerMinute;
                    _noteLinesCount        = (float)diffBeatmap.beatmapData.beatmapLinesData.Length;
                    _noteJumpMovementSpeed = diffBeatmap.noteJumpMovementSpeed;
                    _disappearingArrows    = levelInfo.modifiers.disappearingArrows;
                    _ghostNotes            = levelInfo.modifiers.ghostNotes;
                    float num = 60f / _beatsPerMinute;
                    _moveDistance = _moveSpeed * num * _moveDurationInBeats;
                    while (_noteJumpMovementSpeed * num * _halfJumpDurationInBeats > _maxHalfJumpDistance)
                    {
                        _halfJumpDurationInBeats /= 2f;
                    }
                    _halfJumpDurationInBeats += diffBeatmap.noteJumpStartBeatOffset;
                    if (_halfJumpDurationInBeats < 1f)
                    {
                        _halfJumpDurationInBeats = 1f;
                    }
                    _jumpDistance   = _noteJumpMovementSpeed * num * _halfJumpDurationInBeats * 2f;
                    _spawnAheadTime = _moveDistance / _moveSpeed + _jumpDistance * 0.5f / _noteJumpMovementSpeed;
                }
            }catch (Exception e)
            {
                Plugin.log.Warn("Unable to update beatmap data! Exception: " + e);
            }

            _beatmapObjectCallbackController = callbackController;
            onlineSyncController             = syncController;

            if (_beatmapObjectCallbackId != -1)
            {
                _beatmapObjectCallbackController.RemoveBeatmapObjectCallback(_beatmapObjectCallbackId);
            }

            if (_beatmapObjectCallbackController != null)
            {
                _beatmapObjectCallbackId = _beatmapObjectCallbackController.AddBeatmapObjectCallback(new BeatmapObjectCallbackController.BeatmapObjectCallback(BeatmapObjectSpawnCallback), _spawnAheadTime);
            }

            _localPlayer         = FindObjectsOfType <PlayerController>().First(x => !(x is OnlinePlayerController));
            _localSyncController = FindObjectsOfType <AudioTimeSyncController>().First(x => !(x is OnlineAudioTimeController));

            NoteCutEffectSpawner cutEffectSpawner = FindObjectOfType <NoteCutEffectSpawner>();

            (this as BeatmapObjectSpawnController).noteWasCutEvent += (sender, controller, cutInfo) => { if (cutInfo.allIsOK)
                                                                                                         {
                                                                                                             cutEffectSpawner.HandleNoteWasCutEvent(sender, controller, cutInfo);
                                                                                                         }
            };

            _activeNotes     = new List <NoteController>();
            _activeObstacles = new List <ObstacleController>();
        }
 public SongWithOptions(SongInfo songInfo, LevelOptionsInfo optionsInfo)
 {
     song    = songInfo;
     options = optionsInfo;
 }
Beispiel #15
0
        private void PacketReceived(NetIncomingMessage msg)
        {
            if (msg == null)
            {
                DisconnectCommandReceived(null);
                return;
            }

            CommandType commandType = (CommandType)msg.ReadByte();

            if (!joined)
            {
                if (commandType == CommandType.JoinRoom)
                {
                    switch (msg.ReadByte())
                    {
                    case 0:
                    {
                        Client.Instance.playerInfo.playerState = PlayerState.DownloadingSongs;
                        Client.Instance.RequestRoomInfo();
                        Client.Instance.SendPlayerInfo();
                        Client.Instance.inRoom = true;
                        joined = true;
                        InGameOnlineController.Instance.needToSendUpdates = true;
                        if (Config.Instance.EnableVoiceChat)
                        {
                            InGameOnlineController.Instance.VoiceChatStartRecording();
                        }
                    }
                    break;

                    case 1:
                    {
                        _roomNavigationController.DisplayError("Unable to join room!\nRoom not found");
                    }
                    break;

                    case 2:
                    {
                        _roomNavigationController.DisplayError("Unable to join room!\nIncorrect password");
                    }
                    break;

                    case 3:
                    {
                        _roomNavigationController.DisplayError("Unable to join room!\nToo much players");
                    }
                    break;

                    default:
                    {
                        _roomNavigationController.DisplayError("Unable to join room!\nUnknown error");
                    }
                    break;
                    }
                }
            }
            else
            {
                try
                {
                    switch (commandType)
                    {
                    case CommandType.GetRoomInfo:
                    {
                        Client.Instance.playerInfo.playerState = PlayerState.Room;

                        roomInfo = new RoomInfo(msg);

                        Client.Instance.isHost = Client.Instance.playerInfo.Equals(roomInfo.roomHost);

                        UpdateUI(roomInfo.roomState);
                    }
                    break;

                    case CommandType.SetSelectedSong:
                    {
                        if (msg.LengthBytes < 16)
                        {
                            roomInfo.roomState    = RoomState.SelectingSong;
                            roomInfo.selectedSong = null;

                            PreviewPlayer.CrossfadeToDefault();

                            UpdateUI(roomInfo.roomState);

                            if (songToDownload != null)
                            {
                                songToDownload.songQueueState          = SongQueueState.Error;
                                Client.Instance.playerInfo.playerState = PlayerState.Room;
                            }
                        }
                        else
                        {
                            roomInfo.roomState = RoomState.Preparing;
                            SongInfo selectedSong = new SongInfo(msg);
                            roomInfo.selectedSong = selectedSong;

                            if (roomInfo.startLevelInfo == null)
                            {
                                roomInfo.startLevelInfo = new LevelOptionsInfo(BeatmapDifficulty.Hard, GameplayModifiers.defaultModifiers, "Standard");
                            }

                            if (songToDownload != null)
                            {
                                songToDownload.songQueueState = SongQueueState.Error;
                            }

                            UpdateUI(roomInfo.roomState);
                        }
                    }
                    break;

                    case CommandType.SetLevelOptions:
                    {
                        roomInfo.startLevelInfo = new LevelOptionsInfo(msg);

                        _playerManagementViewController.SetGameplayModifiers(roomInfo.startLevelInfo.modifiers);

                        if (roomInfo.roomState == RoomState.SelectingSong)
                        {
                            _difficultySelectionViewController.SetBeatmapCharacteristic(_beatmapCharacteristics.First(x => x.serializedName == roomInfo.startLevelInfo.characteristicName));

                            if (!roomInfo.perPlayerDifficulty)
                            {
                                _difficultySelectionViewController.SetBeatmapDifficulty(roomInfo.startLevelInfo.difficulty);
                            }
                        }
                    }
                    break;

                    case CommandType.GetRandomSongInfo:
                    {
                        SongInfo random = new SongInfo(SongLoader.CustomBeatmapLevelPackCollectionSO.beatmapLevelPacks.SelectMany(x => x.beatmapLevelCollection.beatmapLevels).ToArray().Random() as BeatmapLevelSO);

                        Client.Instance.SetSelectedSong(random);
                    }
                    break;

                    case CommandType.TransferHost:
                    {
                        roomInfo.roomHost      = new PlayerInfo(msg);
                        Client.Instance.isHost = Client.Instance.playerInfo.Equals(roomInfo.roomHost);

                        if (Client.Instance.playerInfo.playerState == PlayerState.DownloadingSongs)
                        {
                            return;
                        }

                        UpdateUI(roomInfo.roomState);
                    }
                    break;

                    case CommandType.StartLevel:
                    {
                        if (Client.Instance.playerInfo.playerState == PlayerState.DownloadingSongs)
                        {
                            return;
                        }

                        LevelOptionsInfo levelInfo = new LevelOptionsInfo(msg);

                        BeatmapCharacteristicSO characteristic = _beatmapCharacteristics.First(x => x.serializedName == levelInfo.characteristicName);

                        SongInfo       songInfo = new SongInfo(msg);
                        BeatmapLevelSO level    = SongLoader.CustomBeatmapLevelPackCollectionSO.beatmapLevelPacks.SelectMany(x => x.beatmapLevelCollection.beatmapLevels).FirstOrDefault(x => x.levelID.StartsWith(songInfo.levelId)) as BeatmapLevelSO;

                        if (level == null)
                        {
                            Plugin.log.Error("Unable to start level! Level is null! LevelID=" + songInfo.levelId);
                        }

                        if (roomInfo.perPlayerDifficulty && _difficultySelectionViewController != null)
                        {
                            StartLevel(level, characteristic, _difficultySelectionViewController.selectedDifficulty, levelInfo.modifiers);
                        }
                        else
                        {
                            StartLevel(level, characteristic, levelInfo.difficulty, levelInfo.modifiers);
                        }
                    }
                    break;

                    case CommandType.LeaveRoom:
                    {
                        LeaveRoom();
                    }
                    break;

                    case CommandType.UpdatePlayerInfo:
                    {
                        if (roomInfo != null)
                        {
                            currentTime = msg.ReadFloat();
                            totalTime   = msg.ReadFloat();

                            int playersCount = msg.ReadInt32();

                            List <PlayerInfo> playerInfos = new List <PlayerInfo>();
                            for (int j = 0; j < playersCount; j++)
                            {
                                try
                                {
                                    playerInfos.Add(new PlayerInfo(msg));
                                }
                                catch (Exception e)
                                {
#if DEBUG
                                    Plugin.log.Critical($"Unable to parse PlayerInfo! Excpetion: {e}");
#endif
                                }
                            }

                            switch (roomInfo.roomState)
                            {
                            case RoomState.InGame:
                                playerInfos = playerInfos.Where(x => x.playerScore > 0 && x.playerState == PlayerState.Game).ToList();
                                UpdateLeaderboard(playerInfos, currentTime, totalTime, false);
                                break;

                            case RoomState.Results:
                                playerInfos = playerInfos.Where(x => x.playerScore > 0 && (x.playerState == PlayerState.Game || x.playerState == PlayerState.Room)).ToList();
                                UpdateLeaderboard(playerInfos, currentTime, totalTime, true);
                                break;
                            }

                            _playerManagementViewController.UpdatePlayerList(playerInfos, roomInfo.roomState);
                        }
                    }
                    break;

                    case CommandType.PlayerReady:
                    {
                        int playersReady = msg.ReadInt32();
                        int playersTotal = msg.ReadInt32();

                        if (roomInfo.roomState == RoomState.Preparing && _difficultySelectionViewController != null)
                        {
                            _difficultySelectionViewController.SetPlayersReady(playersReady, playersTotal);
                        }
                    }
                    break;

                    case CommandType.Disconnect:
                    {
                        DisconnectCommandReceived(msg);
                    }
                    break;
                    }
                }catch (Exception e)
                {
                    Plugin.log.Error($"Unable to parse packet! Packet={commandType}, DataLength={msg.LengthBytes}\nException: {e}");
                }
            }
        }
Beispiel #16
0
        private static void HubLoop(object sender, HighResolutionTimerElapsedEventArgs e)
        {
            if (_ticksLength.Count > 30)
            {
                _ticksLength.RemoveAt(0);
            }
            _ticksLength.Add(DateTime.UtcNow.Subtract(_lastTick).Ticks / (float)TimeSpan.TicksPerMillisecond);
            _lastTick = DateTime.UtcNow;
            List <RoomInfo> roomsList = RoomsController.GetRoomInfosList();

            string titleBuffer = $"ServerHub v{Assembly.GetEntryAssembly().GetName().Version}: {roomsList.Count} rooms, {hubClients.Count} clients in lobby, {roomsList.Select(x => x.players).Sum() + hubClients.Count} clients total {(Settings.Instance.Server.ShowTickrateInTitle ? $", {Tickrate.ToString("0.0")} tickrate" : "")}";

            if (_currentTitle != titleBuffer)
            {
                _currentTitle = titleBuffer;
                Console.Title = _currentTitle;
            }

            List <Client> allClients = hubClients.Concat(RoomsController.GetRoomsList().SelectMany(x => x.roomClients)).Concat(RadioController.radioChannels.SelectMany(x => x.radioClients)).ToList();

            NetIncomingMessage msg;

            while (ListenerServer.ReadMessage(out msg))
            {
                try
                {
                    Program.networkBytesInNow += msg.LengthBytes;

                    switch (msg.MessageType)
                    {
                    case NetIncomingMessageType.ConnectionApproval:
                    {
                        byte[] versionBytes = msg.PeekBytes(4);
                        byte[] version      = msg.ReadBytes(4);

                        if (version[0] == 0 && version[1] == 0)
                        {
                            uint versionUint       = BitConverter.ToUInt32(version, 0);
                            uint serverVersionUint = ((uint)Assembly.GetEntryAssembly().GetName().Version.Major).ConcatUInts((uint)Assembly.GetEntryAssembly().GetName().Version.Minor).ConcatUInts((uint)Assembly.GetEntryAssembly().GetName().Version.Build).ConcatUInts((uint)Assembly.GetEntryAssembly().GetName().Version.Revision);
                            msg.SenderConnection.Deny($"Version mismatch!\nServer:{serverVersionUint}\nClient:{versionUint}");
                            Logger.Instance.Log($"Client version v{versionUint} tried to connect");
                            break;
                        }

                        byte[] serverVersion = new byte[4] {
                            (byte)Assembly.GetEntryAssembly().GetName().Version.Major, (byte)Assembly.GetEntryAssembly().GetName().Version.Minor, (byte)Assembly.GetEntryAssembly().GetName().Version.Build, (byte)Assembly.GetEntryAssembly().GetName().Version.Revision
                        };

                        if (version[0] != serverVersion[0] || version[1] != serverVersion[1] || version[2] != serverVersion[2])
                        {
                            msg.SenderConnection.Deny($"Version mismatch|{string.Join('.', serverVersion)}|{string.Join('.', version)}");
                            Logger.Instance.Log($"Client version v{string.Join('.', version)} tried to connect");
                            break;
                        }

                        PlayerInfo playerInfo = new PlayerInfo(msg);

                        if (Settings.Instance.Access.WhitelistEnabled)
                        {
                            if (!IsWhitelisted(msg.SenderConnection.RemoteEndPoint, playerInfo))
                            {
                                msg.SenderConnection.Deny("You are not whitelisted on this ServerHub!");
                                Logger.Instance.Warning($"Client {playerInfo.playerName}({playerInfo.playerId})@{msg.SenderConnection.RemoteEndPoint.Address} is not whitelisted!");
                                break;
                            }
                        }

                        if (IsBlacklisted(msg.SenderConnection.RemoteEndPoint, playerInfo))
                        {
                            msg.SenderConnection.Deny("You are banned on this ServerHub!");
                            Logger.Instance.Warning($"Client {playerInfo.playerName}({playerInfo.playerId})@{msg.SenderConnection.RemoteEndPoint.Address} is banned!");
                            break;
                        }

                        NetOutgoingMessage outMsg = ListenerServer.CreateMessage();
                        outMsg.Write(serverVersion);
                        outMsg.Write(Settings.Instance.Server.ServerHubName);

                        msg.SenderConnection.Approve(outMsg);

                        Client client = new Client(msg.SenderConnection, playerInfo);
                        client.playerInfo.updateInfo.playerState = PlayerState.Lobby;

                        client.ClientDisconnected += ClientDisconnected;

                        hubClients.Add(client);
                        allClients.Add(client);
                        Logger.Instance.Log($"{playerInfo.playerName} connected!");
                    };
                        break;

                    case NetIncomingMessageType.Data:
                    {
                        Client client = allClients.FirstOrDefault(x => x.playerConnection.RemoteEndPoint.Equals(msg.SenderEndPoint));

                        switch ((CommandType)msg.ReadByte())
                        {
                        case CommandType.Disconnect:
                        {
                            if (client != null)
                            {
                                allClients.Remove(client);
                                ClientDisconnected(client);
                            }
                        }
                        break;

                        case CommandType.UpdatePlayerInfo:
                        {
                            if (client != null)
                            {
                                if (msg.PeekByte() == 1 || !client.lastUpdateIsFull)
                                {
                                    client.UpdatePlayerInfo(msg);
                                }

                                if (Settings.Instance.Misc.PlayerColors.ContainsKey(client.playerInfo.playerId))
                                {
                                    client.playerInfo.updateInfo.playerNameColor = Settings.Instance.Misc.PlayerColors[client.playerInfo.playerId];
                                }
                            }
                        }
                        break;

                        case CommandType.UpdateVoIPData:
                        {
                            if (!Settings.Instance.Server.AllowVoiceChat)
                            {
                                return;
                            }

                            if (client != null)
                            {
                                UnityVOIP.VoipFragment data = new UnityVOIP.VoipFragment(msg);
                                if (data.playerId == client.playerInfo.playerId)
                                {
                                    client.playerVoIPQueue.Enqueue(data);
                                }
                            }
                        }
                        break;

                        case CommandType.JoinRoom:
                        {
                            if (client != null)
                            {
                                uint roomId = msg.ReadUInt32();

                                BaseRoom room = RoomsController.GetRoomsList().FirstOrDefault(x => x.roomId == roomId);

                                if (room != null)
                                {
                                    if (room.roomSettings.UsePassword)
                                    {
                                        if (RoomsController.ClientJoined(client, roomId, msg.ReadString()))
                                        {
                                            if (hubClients.Contains(client))
                                            {
                                                hubClients.Remove(client);
                                            }
                                            client.joinedRoomID = roomId;
                                        }
                                    }
                                    else
                                    {
                                        if (RoomsController.ClientJoined(client, roomId, ""))
                                        {
                                            if (hubClients.Contains(client))
                                            {
                                                hubClients.Remove(client);
                                            }
                                            client.joinedRoomID = roomId;
                                        }
                                    }
                                }
                                else
                                {
                                    RoomsController.ClientJoined(client, roomId, "");
                                }
                            }
                        }
                        break;

                        case CommandType.LeaveRoom:
                        {
                            if (client != null)
                            {
                                RoomsController.ClientLeftRoom(client);
                                client.joinedRoomID = 0;
                                client.playerInfo.updateInfo.playerState = PlayerState.Lobby;
                                if (!hubClients.Contains(client))
                                {
                                    hubClients.Add(client);
                                }
                            }
                        }
                        break;

                        case CommandType.GetRooms:
                        {
                            NetOutgoingMessage outMsg = ListenerServer.CreateMessage();
                            outMsg.Write((byte)CommandType.GetRooms);
                            RoomsController.AddRoomListToMessage(outMsg);

                            msg.SenderConnection.SendMessage(outMsg, NetDeliveryMethod.ReliableOrdered, 0);
                            Program.networkBytesOutNow += outMsg.LengthBytes;
                        }
                        break;

                        case CommandType.CreateRoom:
                        {
                            if (client != null)
                            {
                                uint roomId = RoomsController.CreateRoom(new RoomSettings(msg), client.playerInfo);

                                NetOutgoingMessage outMsg = ListenerServer.CreateMessage(5);
                                outMsg.Write((byte)CommandType.CreateRoom);
                                outMsg.Write(roomId);

                                msg.SenderConnection.SendMessage(outMsg, NetDeliveryMethod.ReliableOrdered, 0);
                                Program.networkBytesOutNow += outMsg.LengthBytes;
                            }
                        }
                        break;

                        case CommandType.GetRoomInfo:
                        {
                            if (client != null)
                            {
#if DEBUG
                                Logger.Instance.Log("GetRoomInfo: Client room=" + client.joinedRoomID);
#endif
                                if (client.joinedRoomID != 0)
                                {
                                    BaseRoom joinedRoom = RoomsController.GetRoomsList().FirstOrDefault(x => x.roomId == client.joinedRoomID);
                                    if (joinedRoom != null)
                                    {
                                        NetOutgoingMessage outMsg = ListenerServer.CreateMessage();

                                        outMsg.Write((byte)CommandType.GetRoomInfo);

                                        joinedRoom.GetRoomInfo().AddToMessage(outMsg);

                                        msg.SenderConnection.SendMessage(outMsg, NetDeliveryMethod.ReliableOrdered, 0);
                                        Program.networkBytesOutNow += outMsg.LengthBytes;
                                    }
                                }
                            }
                        }
                        break;

                        case CommandType.SetSelectedSong:
                        {
                            if (client != null && client.joinedRoomID != 0)
                            {
                                BaseRoom joinedRoom = RoomsController.GetRoomsList().FirstOrDefault(x => x.roomId == client.joinedRoomID);
                                if (joinedRoom != null)
                                {
                                    if (msg.LengthBytes < 16)
                                    {
                                        joinedRoom.SetSelectedSong(client.playerInfo, null);
                                    }
                                    else
                                    {
                                        joinedRoom.SetSelectedSong(client.playerInfo, new SongInfo(msg));
                                    }
                                }
                            }
                        }
                        break;

                        case CommandType.SetLevelOptions:
                        {
                            if (client != null && client.joinedRoomID != 0)
                            {
                                BaseRoom joinedRoom = RoomsController.GetRoomsList().FirstOrDefault(x => x.roomId == client.joinedRoomID);
                                if (joinedRoom != null)
                                {
                                    joinedRoom.SetLevelOptions(client.playerInfo, new LevelOptionsInfo(msg));
                                }
                            }
                        }
                        break;

                        case CommandType.StartLevel:
                        {
#if DEBUG
                            Logger.Instance.Log("Received command StartLevel");
#endif

                            if (client != null && client.joinedRoomID != 0)
                            {
                                BaseRoom joinedRoom = RoomsController.GetRoomsList().FirstOrDefault(x => x.roomId == client.joinedRoomID);
                                if (joinedRoom != null)
                                {
                                    LevelOptionsInfo options = new LevelOptionsInfo(msg);
                                    SongInfo         song    = new SongInfo(msg);
                                    song.songDuration += 2.5f;
                                    joinedRoom.StartLevel(client.playerInfo, options, song);
                                }
                            }
                        }
                        break;

                        case CommandType.DestroyRoom:
                        {
                            if (client != null && client.joinedRoomID != 0)
                            {
                                BaseRoom joinedRoom = RoomsController.GetRoomsList().FirstOrDefault(x => x.roomId == client.joinedRoomID);
                                if (joinedRoom != null)
                                {
                                    joinedRoom.DestroyRoom(client.playerInfo);
                                }
                            }
                        }
                        break;

                        case CommandType.TransferHost:
                        {
                            if (client != null && client.joinedRoomID != 0)
                            {
                                BaseRoom joinedRoom = RoomsController.GetRoomsList().FirstOrDefault(x => x.roomId == client.joinedRoomID);
                                if (joinedRoom != null)
                                {
                                    joinedRoom.TransferHost(client.playerInfo, new PlayerInfo(msg));
                                }
                            }
                        }
                        break;

                        case CommandType.PlayerReady:
                        {
                            if (client != null && client.joinedRoomID != 0)
                            {
                                BaseRoom joinedRoom = RoomsController.GetRoomsList().FirstOrDefault(x => x.roomId == client.joinedRoomID);
                                if (joinedRoom != null)
                                {
                                    joinedRoom.ReadyStateChanged(client.playerInfo, msg.ReadBoolean());
                                }
                            }
                        }
                        break;

                        case CommandType.SendEventMessage:
                        {
                            if (client != null && client.joinedRoomID != 0 && Settings.Instance.Server.AllowEventMessages)
                            {
                                BaseRoom joinedRoom = RoomsController.GetRoomsList().FirstOrDefault(x => x.roomId == client.joinedRoomID);
                                if (joinedRoom != null)
                                {
                                    string header = msg.ReadString();
                                    string data   = msg.ReadString();

                                    joinedRoom.BroadcastEventMessage(header, data, new List <Client>()
                                            {
                                                client
                                            });
                                    joinedRoom.BroadcastWebSocket(CommandType.SendEventMessage, new EventMessage(header, data));

                                    EventMessageReceived?.Invoke(client, header, data);
#if DEBUG
                                    Logger.Instance.Log($"Received event message! Header=\"{header}\", Data=\"{data}\"");
#endif
                                }
                            }
                        }
                        break;

                        case CommandType.GetChannelInfo:
                        {
                            if (Settings.Instance.Radio.EnableRadio && RadioController.radioStarted)
                            {
                                int channelId = msg.ReadInt32();

                                NetOutgoingMessage outMsg = ListenerServer.CreateMessage();
                                outMsg.Write((byte)CommandType.GetChannelInfo);

                                if (RadioController.radioChannels.Count > channelId)
                                {
                                    RadioController.radioChannels[channelId].channelInfo.AddToMessage(outMsg);
                                }
                                else
                                {
                                    new ChannelInfo()
                                    {
                                        channelId = -1, currentSong = new SongInfo()
                                        {
                                            levelId = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
                                        }
                                    }.AddToMessage(outMsg);
                                }

                                msg.SenderConnection.SendMessage(outMsg, NetDeliveryMethod.ReliableOrdered, 0);
                                Program.networkBytesOutNow += outMsg.LengthBytes;
                            }
                        }
                        break;

                        case CommandType.JoinChannel:
                        {
                            int channelId = msg.ReadInt32();

                            NetOutgoingMessage outMsg = ListenerServer.CreateMessage();
                            outMsg.Write((byte)CommandType.JoinChannel);

                            if (RadioController.ClientJoinedChannel(client, channelId))
                            {
                                outMsg.Write((byte)0);
                                hubClients.Remove(client);
                            }
                            else
                            {
                                outMsg.Write((byte)1);
                            }

                            msg.SenderConnection.SendMessage(outMsg, NetDeliveryMethod.ReliableOrdered, 0);
                            Program.networkBytesOutNow += outMsg.LengthBytes;
                        }
                        break;

                        case CommandType.GetSongDuration:
                        {
                            foreach (RadioChannel channel in RadioController.radioChannels)
                            {
                                if (channel.radioClients.Contains(client) && channel.requestingSongDuration)
                                {
                                    SongInfo info = new SongInfo(msg);
                                    if (info.levelId == channel.channelInfo.currentSong.levelId)
                                    {
                                        channel.songDurationResponses.TryAdd(client, info.songDuration);
                                    }
                                }
                            }
                        }
                        break;

                        case CommandType.LeaveChannel:
                        {
                            if (RadioController.radioStarted && client != null)
                            {
                                RadioController.ClientLeftChannel(client);
                            }
                        }; break;
                        }
                    };
                        break;



                    case NetIncomingMessageType.WarningMessage:
                        Logger.Instance.Warning(msg.ReadString());
                        break;

                    case NetIncomingMessageType.ErrorMessage:
                        Logger.Instance.Error(msg.ReadString());
                        break;

                    case NetIncomingMessageType.StatusChanged:
                    {
                        NetConnectionStatus status = (NetConnectionStatus)msg.ReadByte();

                        Client client = allClients.FirstOrDefault(x => x.playerConnection.RemoteEndPoint.Equals(msg.SenderEndPoint));

                        if (client != null)
                        {
                            if (status == NetConnectionStatus.Disconnected)
                            {
                                allClients.Remove(client);
                                ClientDisconnected(client);
                            }
                        }
                    }
                    break;

#if DEBUG
                    case NetIncomingMessageType.VerboseDebugMessage:
                    case NetIncomingMessageType.DebugMessage:
                        Logger.Instance.Log(msg.ReadString());
                        break;

                    default:
                        Logger.Instance.Log("Unhandled message type: " + msg.MessageType);
                        break;
#endif
                    }
                }catch (Exception ex)
                {
                    Logger.Instance.Log($"Exception on message received: {ex}");
                }
                ListenerServer.Recycle(msg);
            }
        }
Beispiel #17
0
        public void Update()
        {
            if (networkClient.ReadMessages(_receivedMessages) > 0)
            {
                try
                {
                    if (_receivedMessages.Any(x => x.PeekByte() != (byte)CommandType.UpdateVoIPData))
                    {
                        float packetTime = (float)DateTime.UtcNow.Subtract(_lastPacketTime).TotalMilliseconds;
                        if (packetTime > 2f)
                        {
                            _averagePacketTimes.Add(packetTime);

                            if (_averagePacketTimes.Count > 150)
                            {
                                _averagePacketTimes.RemoveAt(0);
                            }

                            tickrate = (float)Math.Round(1000f / _averagePacketTimes.Where(x => x > 2f).Average(), 2);
                        }
                        _lastPacketTime = DateTime.UtcNow;
                    }

                    try
                    {
                        if (Config.Instance.SpectatorMode)
                        {
                            foreach (var lastPlayerHistoryUpdates in _receivedMessages.Where(x => x.MessageType == NetIncomingMessageType.Data && x.PeekByte() == (byte)CommandType.GetPlayerUpdates))
                            {
                                foreach (Action <NetIncomingMessage> nextDel in PlayerInfoUpdateReceived.GetInvocationList())
                                {
                                    try
                                    {
                                        lastPlayerHistoryUpdates.Position = 0;
                                        nextDel?.Invoke(lastPlayerHistoryUpdates);
                                    }
                                    catch (Exception e)
                                    {
                                        if (nextDel != null)
                                        {
                                            Plugin.log.Error($"Exception in {nextDel.Target.GetType()}.{nextDel.Method.Name} on update received event: {e}");
                                        }
                                        else
                                        {
                                            Plugin.log.Error($"Exception on update received event: {e}");
                                        }
                                    }
                                }
                                lastPlayerHistoryUpdates.Position = 0;
                            }
                        }
                    }catch (Exception e)
                    {
                        Plugin.log.Error("Unable to parse GetPlayerUpdates message! Exception: " + e);
                    }

                    try
                    {
                        NetIncomingMessage lastUpdate = _receivedMessages.LastOrDefault(x => x.MessageType == NetIncomingMessageType.Data && x.PeekByte() == (byte)CommandType.UpdatePlayerInfo);

                        if (lastUpdate != null)
                        {
                            _receivedMessages.RemoveAll(x => x.MessageType == NetIncomingMessageType.Data && x.PeekByte() == (byte)CommandType.UpdatePlayerInfo);

                            foreach (Action <NetIncomingMessage> nextDel in MessageReceived.GetInvocationList())
                            {
                                try
                                {
                                    lastUpdate.Position = 0;
                                    nextDel?.Invoke(lastUpdate);
                                }
                                catch (Exception e)
                                {
                                    if (nextDel != null)
                                    {
                                        Plugin.log.Error($"Exception in {nextDel.Target.GetType()}.{nextDel.Method.Name} on update received event: {e}");
                                    }
                                    else
                                    {
                                        Plugin.log.Error($"Exception on update received event: {e}");
                                    }
                                }
                            }
                            lastUpdate.Position = 0;
                        }
                    }catch (Exception e)
                    {
                        Plugin.log.Error("Unable to parse UpdatePlayerInfo message! Exception: " + e);
                    }

                    foreach (NetIncomingMessage msg in _receivedMessages)
                    {
                        switch (msg.MessageType)
                        {
                        case NetIncomingMessageType.StatusChanged:
                        {
                            NetConnectionStatus status = (NetConnectionStatus)msg.ReadByte();

                            if (status == NetConnectionStatus.Connected && !connected)
                            {
                                connected = true;
                                ConnectedToServerHub?.Invoke();
                            }
                            else if (status == NetConnectionStatus.Disconnected && connected)
                            {
#if DEBUG
                                Plugin.log.Info("Disconnecting...");
#endif
                                Disconnect();

                                foreach (Action <NetIncomingMessage> nextDel in MessageReceived.GetInvocationList())
                                {
                                    try
                                    {
                                        nextDel?.Invoke(null);
                                    }
                                    catch (Exception e)
                                    {
                                        if (nextDel != null)
                                        {
                                            Plugin.log.Error($"Exception in {nextDel.Target.GetType()}.{nextDel.Method.Name} on message received event: {e}");
                                        }
                                        else
                                        {
                                            Plugin.log.Error($"Exception on message received event: {e}");
                                        }
                                    }
                                }
                            }
                            else if (status == NetConnectionStatus.Disconnected && !connected)
                            {
                                Plugin.log.Error("ServerHub refused connection! Reason: " + msg.ReadString());
                            }
                        }
                        break;

                        case NetIncomingMessageType.Data:
                        {
                            CommandType commandType = (CommandType)msg.PeekByte();

                            if (commandType == CommandType.Disconnect)
                            {
#if DEBUG
                                Plugin.log.Info("Disconnecting...");
#endif
                                Disconnect();

                                foreach (Action <NetIncomingMessage> nextDel in MessageReceived.GetInvocationList())
                                {
                                    try
                                    {
                                        msg.Position = 0;
                                        nextDel?.Invoke(msg);
                                    }
                                    catch (Exception e)
                                    {
                                        if (nextDel != null)
                                        {
                                            Plugin.log.Error($"Exception in {nextDel.Target.GetType()}.{nextDel.Method.Name} on message received event: {e}");
                                        }
                                        else
                                        {
                                            Plugin.log.Error($"Exception on message received event: {e}");
                                        }
                                    }
                                }

                                return;
                            }
                            else if (commandType == CommandType.SendEventMessage)
                            {
                                string header = msg.ReadString();
                                string data   = msg.ReadString();

#if DEBUG
                                Plugin.log.Info($"Received event message! Header=\"{header}\", Data=\"{data}\"");
#endif
                                foreach (Action <string, string> nextDel in EventMessageReceived.GetInvocationList())
                                {
                                    try
                                    {
                                        nextDel?.Invoke(header, data);
                                    }
                                    catch (Exception e)
                                    {
                                        if (nextDel != null)
                                        {
                                            Plugin.log.Error($"Exception in {nextDel.Target.GetType()}.{nextDel.Method.Name} on event message received event: {e}");
                                        }
                                        else
                                        {
                                            Plugin.log.Error($"Exception in {nextDel.Target.GetType()}.{nextDel.Method.Name} on event message received event: {e}");
                                        }
                                    }
                                }
                            }
                            else
                            {
                                if (MessageReceived != null)
                                {
                                    foreach (Action <NetIncomingMessage> nextDel in MessageReceived.GetInvocationList())
                                    {
                                        try
                                        {
                                            msg.Position = 0;
                                            nextDel?.Invoke(msg);
                                        }
                                        catch (Exception e)
                                        {
                                            if (nextDel != null)
                                            {
                                                Plugin.log.Error($"Exception in {nextDel.Target.GetType()}.{nextDel.Method.Name} on message received event: {e}");
                                            }
                                            else
                                            {
                                                Plugin.log.Error($"Exception on message received event: {e}");
                                            }
                                        }
                                    }
                                }
                            }


                            if (commandType == CommandType.JoinRoom)
                            {
                                msg.Position = 8;
                                if (msg.PeekByte() == 0 && ClientJoinedRoom != null)
                                {
                                    foreach (Action nextDel in ClientJoinedRoom.GetInvocationList())
                                    {
                                        try
                                        {
                                            nextDel?.Invoke();
                                        }
                                        catch (Exception e)
                                        {
                                            if (nextDel != null)
                                            {
                                                Plugin.log.Error($"Exception in {nextDel.Target.GetType()}.{nextDel.Method.Name} on client joined room event: {e}");
                                            }
                                            else
                                            {
                                                Plugin.log.Error($"Exception on client joined room event: {e}");
                                            }
                                        }
                                    }
                                }
                            }
                            else if (commandType == CommandType.StartLevel)
                            {
#if DEBUG
                                startNewDump = true;
                                packetsBuffer.Clear();
                                msg.Position = 8;
                                LevelOptionsInfo levelInfo = new LevelOptionsInfo(msg);
                                SongInfo         songInfo  = new SongInfo(msg);
                                List <byte>      buffer    = new List <byte>();
                                buffer.AddRange(levelInfo.ToBytes());
                                buffer.AddRange(HexConverter.ConvertHexToBytesX(songInfo.levelId));

                                Plugin.log.Info("LevelID: " + songInfo.levelId + ", Bytes: " + BitConverter.ToString(buffer.ToArray()));

                                packetsBuffer.Enqueue(buffer.ToArray());
                                msg.Position = 0;
#endif
                                if (playerInfo.playerState == PlayerState.Room)
                                {
                                    foreach (Action nextDel in ClientLevelStarted.GetInvocationList())
                                    {
                                        try
                                        {
                                            nextDel?.Invoke();
                                        }
                                        catch (Exception e)
                                        {
                                            if (nextDel != null)
                                            {
                                                Plugin.log.Error($"Exception in {nextDel.Target.GetType()}.{nextDel.Method.Name} on client level started event: {e}");
                                            }
                                            else
                                            {
                                                Plugin.log.Error($"Exception on client level started event: {e}");
                                            }
                                        }
                                    }
                                }
                            }
                        };
                            break;

                        case NetIncomingMessageType.WarningMessage:
                            Plugin.log.Warn(msg.ReadString());
                            break;

                        case NetIncomingMessageType.ErrorMessage:
                            Plugin.log.Error(msg.ReadString());
                            break;

#if DEBUG
                        case NetIncomingMessageType.VerboseDebugMessage:
                        case NetIncomingMessageType.DebugMessage:
                            Plugin.log.Info(msg.ReadString());
                            break;

                        default:
                            Plugin.log.Info("Unhandled message type: " + msg.MessageType);
                            break;
#endif
                        }
                        networkClient.Recycle(msg);
                    }
                }catch (Exception e)
                {
#if DEBUG
                    Plugin.log.Critical($"Exception on message received event: {e}");
#endif
                }
                _receivedMessages.Clear();
            }

            if (connected && networkClient.ConnectionsCount == 0)
            {
#if DEBUG
                Plugin.log.Info("Connection lost! Disconnecting...");
#endif
                Disconnect();

                foreach (Action <NetIncomingMessage> nextDel in MessageReceived.GetInvocationList())
                {
                    try
                    {
                        nextDel.Invoke(null);
                    }
                    catch (Exception e)
                    {
                        if (nextDel != null)
                        {
                            Plugin.log.Error($"Exception in {nextDel.Target.GetType()}.{nextDel.Method.Name} on message received event: {e}");
                        }
                        else
                        {
                            Plugin.log.Error($"Exception on message received event: {e}");
                        }
                    }
                }
            }
        }
Beispiel #18
0
        private void MessageReceived(NetIncomingMessage msg)
        {
            if (msg == null)
            {
                InGameOnlineController.Instance.needToSendUpdates = false;

                PopAllViewControllers();
                InGameOnlineController.Instance.DestroyPlayerControllers();
                PreviewPlayer.CrossfadeToDefault();
                joined = false;

                _radioNavController.DisplayError("Lost connection to the ServerHub!");
                return;
            }
            msg.Position = 0;

            CommandType commandType = (CommandType)msg.ReadByte();

            if (!joined)
            {
                if (commandType == CommandType.JoinChannel)
                {
                    switch (msg.ReadByte())
                    {
                    case 0:
                    {
                        Client.Instance.playerInfo.updateInfo.playerState = PlayerState.Room;
                        Client.Instance.RequestChannelInfo(channelId);
                        Client.Instance.SendPlayerInfo(true);
                        joined = true;
                        InGameOnlineController.Instance.needToSendUpdates = true;
                    }
                    break;

                    case 1:
                    {
                        _radioNavController.DisplayError("Unable to join channel!\nChannel not found");
                    }
                    break;

                    default:
                    {
                        _radioNavController.DisplayError("Unable to join channel!\nUnknown error");
                    }
                    break;
                    }
                }
            }
            else
            {
                try
                {
                    switch (commandType)
                    {
                    case CommandType.GetChannelInfo:
                    {
                        channelInfo      = new ChannelInfo(msg);
                        channelInfo.ip   = ip;
                        channelInfo.port = port;

                        UpdateUI(channelInfo.state);
                    }
                    break;

                    case CommandType.SetSelectedSong:
                    {
                        if (msg.LengthBytes > 16)
                        {
                            SongInfo song = new SongInfo(msg);
                            channelInfo.currentSong = song;
                            channelInfo.state       = ChannelState.NextSong;

                            UpdateUI(channelInfo.state);
                        }
                    }
                    break;

                    case CommandType.GetSongDuration:
                    {
                        SongInfo             requestedSong = new SongInfo(msg);
                        IPreviewBeatmapLevel level         = SongCore.Loader.CustomBeatmapLevelPackCollectionSO.beatmapLevelPacks.SelectMany(x => x.beatmapLevelCollection.beatmapLevels).FirstOrDefault(x => x.levelID.StartsWith(channelInfo.currentSong.levelId));

                        if (level != null)
                        {
                            LoadBeatmapLevelAsync(level,
                                                  (success, beatmapLevel) =>
                                {
                                    Client.Instance.SendSongDuration(new SongInfo(beatmapLevel));
                                });
                        }
                    }
                    break;

                    case CommandType.StartLevel:
                    {
                        if (Client.Instance.playerInfo.updateInfo.playerState == PlayerState.DownloadingSongs)
                        {
                            return;
                        }

                        if (nextSongSkipped)
                        {
                            nextSongSkipped   = false;
                            channelInfo.state = ChannelState.InGame;
                            UpdateUI(channelInfo.state);
                            return;
                        }

                        LevelOptionsInfo levelInfo = new LevelOptionsInfo(msg);

                        BeatmapCharacteristicSO characteristic = _beatmapCharacteristics.First(x => x.serializedName == levelInfo.characteristicName);

                        SongInfo             songInfo = new SongInfo(msg);
                        IPreviewBeatmapLevel level    = SongCore.Loader.CustomBeatmapLevelPackCollectionSO.beatmapLevelPacks.SelectMany(x => x.beatmapLevelCollection.beatmapLevels).FirstOrDefault(x => x.levelID.StartsWith(songInfo.levelId));

                        if (level == null)
                        {
                            Plugin.log.Error("Unable to start level! Level is null! LevelID=" + songInfo.levelId);
                            return;
                        }

                        LoadBeatmapLevelAsync(level,
                                              (success, beatmapLevel) =>
                            {
                                StartLevel(beatmapLevel, characteristic, levelInfo.difficulty, levelInfo.modifiers.ToGameplayModifiers());
                            });
                    }
                    break;

                    case CommandType.LeaveRoom:
                    {
                        LeaveChannel();
                    }
                    break;

                    case CommandType.UpdatePlayerInfo:
                    {
                        if (channelInfo != null)
                        {
                            currentTime = msg.ReadFloat();
                            totalTime   = msg.ReadFloat();

                            switch (channelInfo.state)
                            {
                            case ChannelState.InGame:
                                UpdateInGameScreen();
                                break;

                            case ChannelState.NextSong:
                                UpdateNextSongScreen();
                                break;

                            case ChannelState.Results:
                                UpdateResultsScreen();
                                break;
                            }
                        }
                    }
                    break;

                    case CommandType.Disconnect:
                    {
                        InGameOnlineController.Instance.needToSendUpdates = false;

                        if (msg.LengthBytes > 3)
                        {
                            string reason = msg.ReadString();

                            PopAllViewControllers();
                            InGameOnlineController.Instance.DestroyPlayerControllers();
                            PreviewPlayer.CrossfadeToDefault();
                            joined = false;

                            _radioNavController.DisplayError(reason);
                        }
                        else
                        {
                            _radioNavController.DisplayError("ServerHub refused connection!");
                        }
                    }
                    break;
                    }
                }
                catch (Exception e)
                {
                    Plugin.log.Error($"Unable to parse packet! Packet={commandType}, DataLength={msg.LengthBytes}\nException: {e}");
                }
            }
        }
        private void MessageReceived(NetIncomingMessage msg)
        {
            if (msg == null)
            {
                InGameOnlineController.Instance.needToSendUpdates = false;

                PopAllViewControllers();
                InGameOnlineController.Instance.DestroyPlayerControllers();
                PreviewPlayer.CrossfadeToDefault();
                joined = false;

                _radioNavController.DisplayError("Lost connection to the ServerHub!");
                return;
            }

            CommandType commandType = (CommandType)msg.ReadByte();

            if (!joined)
            {
                if (commandType == CommandType.JoinChannel)
                {
                    switch (msg.ReadByte())
                    {
                    case 0:
                    {
                        Client.Instance.playerInfo.playerState = PlayerState.Room;
                        Client.Instance.RequestChannelInfo(channelId);
                        Client.Instance.SendPlayerInfo();
                        joined = true;
                        InGameOnlineController.Instance.needToSendUpdates = true;
                    }
                    break;

                    case 1:
                    {
                        _radioNavController.DisplayError("Unable to join channel!\nChannel not found");
                    }
                    break;

                    default:
                    {
                        _radioNavController.DisplayError("Unable to join channel!\nUnknown error");
                    }
                    break;
                    }
                }
            }
            else
            {
                try
                {
                    switch (commandType)
                    {
                    case CommandType.GetChannelInfo:
                    {
                        channelInfo      = new ChannelInfo(msg);
                        channelInfo.ip   = ip;
                        channelInfo.port = port;

                        UpdateUI(channelInfo.state);
                    }
                    break;

                    case CommandType.SetSelectedSong:
                    {
                        if (msg.LengthBytes > 16)
                        {
                            SongInfo song = new SongInfo(msg);
                            channelInfo.currentSong = song;
                            channelInfo.state       = ChannelState.NextSong;

                            UpdateUI(channelInfo.state);
                        }
                    }
                    break;

                    case CommandType.GetSongDuration:
                    {
                        SongInfo       requestedSong = new SongInfo(msg);
                        BeatmapLevelSO level         = SongLoader.CustomBeatmapLevelPackCollectionSO.beatmapLevelPacks.SelectMany(x => x.beatmapLevelCollection.beatmapLevels).FirstOrDefault(x => x.levelID.StartsWith(channelInfo.currentSong.levelId)) as BeatmapLevelSO;

                        if (level != null)
                        {
                            SongLoader.Instance.LoadAudioClipForLevel((CustomLevel)level,
                                                                      (loadedLevel) =>
                                {
                                    Client.Instance.SendSongDuration(new SongInfo(loadedLevel));
                                });
                        }
                    }
                    break;

                    case CommandType.StartLevel:
                    {
                        if (Client.Instance.playerInfo.playerState == PlayerState.DownloadingSongs)
                        {
                            return;
                        }

                        if (nextSongSkipped)
                        {
                            nextSongSkipped   = false;
                            channelInfo.state = ChannelState.InGame;
                            UpdateUI(channelInfo.state);
                            return;
                        }

                        LevelOptionsInfo levelInfo = new LevelOptionsInfo(msg);

                        BeatmapCharacteristicSO characteristic = _beatmapCharacteristics.First(x => x.serializedName == levelInfo.characteristicName);

                        SongInfo       songInfo = new SongInfo(msg);
                        BeatmapLevelSO level    = SongLoader.CustomBeatmapLevelPackCollectionSO.beatmapLevelPacks.SelectMany(x => x.beatmapLevelCollection.beatmapLevels).FirstOrDefault(x => x.levelID.StartsWith(songInfo.levelId)) as BeatmapLevelSO;

                        if (level == null)
                        {
                            Plugin.log.Error("Unable to start level! Level is null! LevelID=" + songInfo.levelId);
                            return;
                        }

                        SongLoader.Instance.LoadAudioClipForLevel((CustomLevel)level,
                                                                  (levelLoaded) =>
                            {
                                try
                                {
                                    BS_Utils.Gameplay.Gamemode.NextLevelIsIsolated("Beat Saber Multiplayer");
                                }
                                catch
                                {
                                }

                                StartLevel(levelLoaded, characteristic, levelInfo.difficulty, levelInfo.modifiers);
                            });
                    }
                    break;

                    case CommandType.LeaveRoom:
                    {
                        LeaveChannel();
                    }
                    break;

                    case CommandType.UpdatePlayerInfo:
                    {
                        if (channelInfo != null)
                        {
                            currentTime = msg.ReadFloat();
                            totalTime   = msg.ReadFloat();

                            switch (channelInfo.state)
                            {
                            case ChannelState.InGame:
                                UpdateInGameScreen();
                                break;

                            case ChannelState.NextSong:
                                UpdateNextSongScreen();
                                break;

                            case ChannelState.Results:
                            {
                                UpdateResultsScreen();

                                int playersCount = msg.ReadInt32();

                                List <PlayerInfo> playerInfos = new List <PlayerInfo>();

                                try
                                {
                                    for (int j = 0; j < playersCount; j++)
                                    {
                                        playerInfos.Add(new PlayerInfo(msg));
                                    }
                                }
                                catch (Exception e)
                                {
#if DEBUG
                                    Plugin.log.Critical($"Unable to parse PlayerInfo! Excpetion: {e}");
#endif
                                    return;
                                }

                                playerInfos = playerInfos.Where(x => x.playerScore > 0 && (x.playerState == PlayerState.Game || x.playerState == PlayerState.Room)).ToList();
                            }
                            break;
                            }
                        }
                    }
                    break;

                    case CommandType.Disconnect:
                    {
                        InGameOnlineController.Instance.needToSendUpdates = false;

                        if (msg.LengthBytes > 3)
                        {
                            string reason = msg.ReadString();

                            PopAllViewControllers();
                            InGameOnlineController.Instance.DestroyPlayerControllers();
                            PreviewPlayer.CrossfadeToDefault();
                            joined = false;

                            _radioNavController.DisplayError(reason);
                        }
                        else
                        {
                            _radioNavController.DisplayError("ServerHub refused connection!");
                        }
                    }
                    break;
                    }
                }
                catch (Exception e)
                {
                    Plugin.log.Error($"Unable to parse packet! Packet={commandType}, DataLength={msg.LengthBytes}\nException: {e}");
                }
            }
        }