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 StartLevelInfo(BeatmapDifficulty.Hard, GameplayModifiers.defaultModifiers, "Standard");
                            }

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

                            UpdateUI(roomInfo.roomState);
                        }
                    }
                    break;

                    case CommandType.SetLevelOptions:
                    {
                        if (roomInfo.roomState == RoomState.SelectingSong)
                        {
                            roomInfo.startLevelInfo = new StartLevelInfo(msg);

                            _playerManagementViewController.SetGameplayModifiers(roomInfo.startLevelInfo.modifiers);
                            _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;
                        }

                        StartLevelInfo levelInfo = new StartLevelInfo(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)
                        {
                            Logger.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
                                    Misc.Logger.Exception($"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)
                {
                    Logger.Exception($"Unable to parse packet! Packet={commandType}, DataLength={msg.LengthBytes}\nException: {e}");
                }
            }
        }
        private void PacketReceived(NetIncomingMessage msg)
        {
            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();
                        joined = true;
                        InGameOnlineController.Instance.needToSendUpdates = true;
                    }
                    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 (songToDownload != null)
                            {
                                songToDownload.songQueueState = SongQueueState.Error;
                            }

                            UpdateUI(roomInfo.roomState);
                        }
                    }
                    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;
                        }

                        lastSelectedSong = "";

                        Client.Instance.playerInfo.playerComboBlocks = 0;
                        Client.Instance.playerInfo.playerCutBlocks   = 0;
                        Client.Instance.playerInfo.playerEnergy      = 0f;
                        Client.Instance.playerInfo.playerScore       = 0;

                        byte     difficulty = msg.ReadByte();
                        SongInfo songInfo   = new SongInfo(msg);

                        MenuSceneSetupDataSO menuSceneSetupData = Resources.FindObjectsOfTypeAll <MenuSceneSetupDataSO>().FirstOrDefault();

                        if (menuSceneSetupData != null)
                        {
                            GameplayModifiers gameplayModifiers = new GameplayModifiers();

                            if (Config.Instance.SpectatorMode)
                            {
                                Client.Instance.playerInfo.playerState = PlayerState.Spectating;
                                gameplayModifiers.noFail = true;
                            }
                            else
                            {
                                Client.Instance.playerInfo.playerState = PlayerState.Game;
                                gameplayModifiers.noFail = roomInfo.noFail;
                            }

                            PlayerSpecificSettings playerSettings = Resources.FindObjectsOfTypeAll <PlayerDataModelSO>().FirstOrDefault().currentLocalPlayer.playerSpecificSettings;

                            roomInfo.roomState = RoomState.InGame;

                            Client.Instance.MessageReceived -= PacketReceived;

                            LevelSO            level             = _levelCollection.levels.First(x => x.levelID.StartsWith(songInfo.levelId));
                            IDifficultyBeatmap difficultyBeatmap = level.GetDifficultyBeatmap((BeatmapDifficulty)difficulty);

                            Logger.Info($"Starting song: name={level.songName}, levelId={level.levelID}, difficulty={(BeatmapDifficulty)difficulty}");

                            Client.Instance.MessageReceived -= PacketReceived;
                            menuSceneSetupData.StartStandardLevel(difficultyBeatmap, gameplayModifiers, playerSettings, null, null, (StandardLevelSceneSetupDataSO sender, LevelCompletionResults levelCompletionResults) => { InGameOnlineController.Instance.SongFinished(sender, levelCompletionResults, difficultyBeatmap, gameplayModifiers, false); });
                            return;
                        }
                        else
                        {
                            Logger.Error("SceneSetupData is null!");
                        }
                    }
                    break;

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

                    case CommandType.UpdatePlayerInfo:
                    {
                        if (roomInfo != null)
                        {
                            if (roomInfo.roomState != RoomState.SelectingSong)
                            {
                                float currentTime = msg.ReadFloat();
                                float 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
                                        Misc.Logger.Exception($"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;

                                case RoomState.Preparing:
                                    _roomManagementViewController.UpdatePlayerList(playerInfos);
                                    break;
                                }
                            }
                        }
                    }
                    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:
                    {
                        InGameOnlineController.Instance.needToSendUpdates = false;
                        if (msg.LengthBytes > 3)
                        {
                            string reason = msg.ReadString();

                            PopAllViewControllers(_roomNavigationController);
                            InGameOnlineController.Instance.DestroyAvatars();
                            PreviewPlayer.CrossfadeToDefault();
                            joined           = false;
                            lastSelectedSong = "";

                            _roomNavigationController.DisplayError(reason);
                        }
                        else
                        {
                            _roomNavigationController.DisplayError("ServerHub refused connection!");
                        }
                    }
                    break;
                    }
                }catch (Exception e)
                {
                    Logger.Exception("Unable to parse packet!");
                    if (msg != null)
                    {
                        Logger.Exception($"Packet={commandType}, DataLength={msg.LengthBytes}");
                    }
                    Logger.Exception(e.ToString());
                }
            }
        }
Ejemplo n.º 3
0
        public static IEnumerator DownloadAvatarCoroutine(string hash, Action <string> callback)
        {
            queuedAvatars.Add(hash);
            string          downloadUrl = "";
            string          avatarName  = "";
            UnityWebRequest www         = UnityWebRequest.Get("https://modelsaber.com/api/v1/avatar/get.php?filter=hash:" + hash);

            www.timeout = 10;

            yield return(www.SendWebRequest());

            if (www.isNetworkError || www.isHttpError)
            {
                Logger.Error(www.error);
                queuedAvatars.Remove(hash);
                callback?.Invoke(null);
                yield break;
            }
            else
            {
#if DEBUG
                Logger.Info("Received response from ModelSaber...");
#endif
                JSONNode node = JSON.Parse(www.downloadHandler.text);

                if (node.Count == 0)
                {
                    Logger.Error($"Avatar with hash {hash} doesn't exist on ModelSaber!");
                    cachedAvatars.Add(hash, null);
                    queuedAvatars.Remove(hash);
                    callback?.Invoke(null);
                    yield break;
                }

                downloadUrl = node[0]["download"].Value;
                avatarName  = downloadUrl.Substring(downloadUrl.LastIndexOf("/") + 1);
            }

            if (string.IsNullOrEmpty(downloadUrl))
            {
                queuedAvatars.Remove(hash);
                callback?.Invoke(null);
                yield break;
            }


            bool  timeout = false;
            float time    = 0f;
            UnityWebRequestAsyncOperation asyncRequest;

            try
            {
                www         = UnityWebRequest.Get(downloadUrl);
                www.timeout = 0;

                asyncRequest = www.SendWebRequest();
            }
            catch (Exception e)
            {
                Logger.Error(e);
                queuedAvatars.Remove(hash);
                callback?.Invoke(null);
                yield break;
            }

            while (!asyncRequest.isDone)
            {
                yield return(null);

                time += Time.deltaTime;

                if ((time >= 5f && asyncRequest.progress == 0f))
                {
                    www.Abort();
                    timeout = true;
                    Logger.Error("Connection timed out!");
                }

                //songInfo.downloadingProgress = asyncRequest.progress;
            }


            if (www.isNetworkError || www.isHttpError || timeout)
            {
                queuedAvatars.Remove(hash);
                Logger.Error("Unable to download avatar! " + (www.isNetworkError ? $"Network error: {www.error}" : (www.isHttpError ? $"HTTP error: {www.error}" : "Unknown error")));
                callback?.Invoke(null);
            }
            else
            {
#if DEBUG
                Logger.Info("Received response from ModelSaber...");
#endif
                string docPath          = "";
                string customAvatarPath = "";

                byte[] data = www.downloadHandler.data;

                try
                {
                    docPath          = Application.dataPath;
                    docPath          = docPath.Substring(0, docPath.Length - 5);
                    docPath          = docPath.Substring(0, docPath.LastIndexOf("/"));
                    customAvatarPath = docPath + "/CustomAvatars/" + avatarName;

                    File.WriteAllBytes(customAvatarPath, data);

                    CustomAvatar.CustomAvatar downloadedAvatar = CustomExtensions.CreateInstance <CustomAvatar.CustomAvatar>(customAvatarPath);

                    queuedAvatars.Remove(hash);
                    cachedAvatars.Add(hash, downloadedAvatar);

                    downloadedAvatar.Load((CustomAvatar.CustomAvatar avatar, CustomAvatar.AvatarLoadResult result) => { if (result == CustomAvatar.AvatarLoadResult.Completed)
                                                                                                                        {
                                                                                                                            callback?.Invoke(hash); avatarDownloaded?.Invoke(hash);
                                                                                                                        }
                                                                                                                        else
                                                                                                                        {
                                                                                                                            callback?.Invoke(null);
                                                                                                                        } });

                    Logger.Info("Downloaded avatar!");
                }
                catch (Exception e)
                {
                    Logger.Exception(e);
                    queuedAvatars.Remove(hash);
                    callback?.Invoke(null);
                    yield break;
                }
            }
        }
        public IEnumerator DownloadSongCoroutine(Song songInfo, string subFolder, Action callback, Action <float> progressChanged = null, CancellationTokenSource cancelToken = null)
        {
            songInfo.songQueueState = SongQueueState.Downloading;

            UnityWebRequest www;
            bool            timeout = false;
            float           time    = 0f;
            UnityWebRequestAsyncOperation asyncRequest;

            try
            {
                www = UnityWebRequest.Get(songInfo.downloadUrl);

                asyncRequest = www.SendWebRequest();
            }
            catch (Exception e)
            {
                Logger.Error(e);
                songInfo.songQueueState      = SongQueueState.Error;
                songInfo.downloadingProgress = 1f;

                yield break;
            }

            while ((!asyncRequest.isDone || songInfo.downloadingProgress != 1f) && songInfo.songQueueState != SongQueueState.Error)
            {
                yield return(null);

                time += Time.deltaTime;

                if ((time >= 5f && asyncRequest.progress == 0f) || songInfo.songQueueState == SongQueueState.Error)
                {
                    www.Abort();
                    timeout = true;
                    Logger.Error("Download aborted!");
                }

                songInfo.downloadingProgress = asyncRequest.progress;
                progressChanged?.Invoke(asyncRequest.progress);
            }


            if (www.isNetworkError || www.isHttpError || timeout || songInfo.songQueueState == SongQueueState.Error)
            {
                songInfo.songQueueState = SongQueueState.Error;
                Logger.Error("Unable to download song! " + (www.isNetworkError ? $"Network error: {www.error}" : (www.isHttpError ? $"HTTP error: {www.error}" : "Unknown error")));
            }
            else
            {
                Logger.Info("Received response from BeatSaver.com...");

                string docPath         = "";
                string customSongsPath = "";

                byte[] data = www.downloadHandler.data;

                Stream zipStream = null;

                try
                {
                    docPath         = Application.dataPath;
                    docPath         = docPath.Substring(0, docPath.Length - 5);
                    docPath         = docPath.Substring(0, docPath.LastIndexOf("/"));
                    customSongsPath = docPath + "/CustomSongs/" + subFolder + "/" + songInfo.id + "/";
                    if (!Directory.Exists(customSongsPath))
                    {
                        Directory.CreateDirectory(customSongsPath);
                    }
                    zipStream = new MemoryStream(data);
                    Logger.Info("Downloaded zip!");
                }
                catch (Exception e)
                {
                    Logger.Exception(e);
                    songInfo.songQueueState = SongQueueState.Error;
                    yield break;
                }

                yield return(new WaitWhile(() => _extractingZip)); //because extracting several songs at once sometimes hangs the game

                Task extract = ExtractZipAsync(songInfo, zipStream, customSongsPath);
                yield return(new WaitWhile(() => !extract.IsCompleted));

                songDownloaded?.Invoke(songInfo);
                callback?.Invoke();
            }
        }