Example #1
0
        static int GetPreferredDifficulty(CustomSongInfo _song)
        {
            int difficulty = 0;

            foreach (CustomSongInfo.DifficultyLevel diff in _song.difficultyLevels)
            {
                if ((int)Enum.Parse(typeof(Difficulty), diff.difficulty) <= 3 && (int)Enum.Parse(typeof(Difficulty), diff.difficulty) >= difficulty)
                {
                    difficulty = (int)Enum.Parse(typeof(Difficulty), diff.difficulty);
                }
            }

            return(difficulty);
        }
        private static void DownloadSongs()
        {
            Settings.Instance.Server.Downloaded.GetDirectories().AsParallel().ForAll(dir => dir.Delete(true));

            Settings.Instance.AvailableSongs.Songs.ToList().AsParallel().ForAll(id =>
            {
                DownloadSongByID(id);
            });

            Logger.Instance.Log("All songs downloaded!");

            List <CustomSongInfo> _songs = SongLoader.RetrieveAllSongs();

            _songs.AsParallel().ForAll(song =>
            {
                ProcessSong(song);
            });

            if (Settings.Instance.AvailableSongs.SongOrder == Settings.SongOrder.List)
            {
                CustomSongInfo[] buffer = new CustomSongInfo[availableSongs.Count];
                availableSongs.CopyTo(buffer);
                availableSongs.Clear();

                foreach (string id in Settings.Instance.AvailableSongs.Songs)
                {
                    try
                    {
                        availableSongs.Add(buffer.First(x => x.beatSaverId == id));
                    }
                    catch (Exception)
                    {
                        Logger.Instance.Warning($"Can't find song with ID {id}");
                    }
                }

                var notSortedSongs = buffer.Except(availableSongs).ToList();
                if (notSortedSongs.Count > 0)
                {
                    Logger.Instance.Warning($"{notSortedSongs.Count} songs not sorted!");
                    availableSongs.AddRange(notSortedSongs);
                }
            }


            Logger.Instance.Log("Done!");
        }
        private static void ProcessSong(CustomSongInfo song)
        {
            try
            {
                Logger.Instance.Log($"Processing {song.songName} {song.songSubName}");

                if (song.difficultyLevels[0].audioPath.ToLower().EndsWith(".ogg"))
                {
                    string   pathToLoad      = $"{song.path}/{song.difficultyLevels[0].audioPath}";
                    string[] actualFileNames = Directory.GetFiles(song.path, "*.ogg", SearchOption.TopDirectoryOnly);

                    if (!File.Exists(pathToLoad))
                    {
                        pathToLoad = $"{song.path}/{actualFileNames[0]}";
                    }

                    using (VorbisReader vorbis = new VorbisReader(pathToLoad))
                    {
                        song.duration = vorbis.TotalTime;
                    }
                }
                else
                {
                    string   pathToLoad      = $"{song.path}/{song.difficultyLevels[0].audioPath}";
                    string[] actualFileNames = Directory.GetFiles(song.path, "*.wav", SearchOption.TopDirectoryOnly);

                    if (!File.Exists(pathToLoad))
                    {
                        pathToLoad = $"{song.path}/{actualFileNames[0]}";
                    }

                    using (AudioFileReader wave = new AudioFileReader(pathToLoad))
                    {
                        song.duration = wave.TotalTime;
                    }
                }

                availableSongs.Add(song);
            }
            catch (AggregateException e)
            {
                Logger.Instance.Error(e.Message);
                Logger.Instance.Warning("One common cause of this is incorrect case sensitivity in the song's json file in comparison to its actual song name.");
            }
        }
        static int GetPreferredDifficulty(CustomSongInfo _song)
        {
            int difficulty = 0;

            foreach (CustomSongInfo.DifficultyLevel diff in _song.difficultyLevels)
            {
                if ((int)Enum.Parse(typeof(Difficulty), diff.difficulty, true) <= (int)Settings.Instance.Server.PreferredDifficulty &&
                    (int)Enum.Parse(typeof(Difficulty), diff.difficulty, true) >= difficulty)
                {
                    difficulty = (int)Enum.Parse(typeof(Difficulty), diff.difficulty, true);
                }
            }

            if (difficulty == 0 && _song.difficultyLevels.Length > 0)
            {
                difficulty = (int)Enum.Parse(typeof(Difficulty), _song.difficultyLevels[0].difficulty, true);
            }

            return(difficulty);
        }
        void ServerLoop()
        {
            Stopwatch _timer = new Stopwatch();

            _timer.Start();
            int      _timerSeconds = 0;
            TimeSpan _lastTime     = new TimeSpan();

            float lobbyTimer = 0;
            float sendTimer  = 0;

            float sendTime = 1f / 20;

            int lobbyTime = Settings.Instance.Server.LobbyTime;

            TimeSpan deltaTime;

            while (ServerLoopThread.IsAlive)
            {
                deltaTime = (_timer.Elapsed - _lastTime);

                _lastTime = _timer.Elapsed;

                try
                {
                    switch (serverState)
                    {
                    case ServerState.Preparing:
                    case ServerState.Voting:
                    {
                        sendTimer  += (float)deltaTime.TotalSeconds;
                        lobbyTimer += (float)deltaTime.TotalSeconds;

                        if (clients.Count == 0)
                        {
                            lobbyTimer = 0;
                        }

                        if (Math.Ceiling(lobbyTimer) > _timerSeconds && _timerSeconds > -1)
                        {
                            _timerSeconds = Math.Ceiling(lobbyTimer);
                            SendToAllClients(
                                new ServerCommand(ServerCommandType.SetLobbyTimer,
                                                  Math.Max(lobbyTime - _timerSeconds, 0)));
                        }

                        if (sendTimer >= sendTime)
                        {
                            SendToAllClients(new ServerCommand(
                                                 ServerCommandType.SetPlayerInfos,
                                                 _playerInfos: (clients.Where(x => x != null && x.playerInfo != null)
                                                                .Select(x => JsonConvert.SerializeObject(x.playerInfo))).ToArray()
                                                 ));
                            sendTimer = 0f;
                        }


                        if (currentSongIndex == -1 && availableSongs.Count > 0)
                        {
                            switch (Settings.Instance.AvailableSongs.SongOrder)
                            {
                            case Settings.SongOrder.Voting: {
                                if (lobbyTimer >= lobbyTime / 2)
                                {
                                    if (clients.Any(x => x.votedFor != null))
                                    {
                                        string selectedLevelId = clients.Where(x => x.votedFor != null).Select(x => x.votedFor).GroupBy(v => v).OrderByDescending(g => g.Count()).First().Key.levelId;

                                        CustomSongInfo song = availableSongs.FirstOrDefault(x => x.levelId == selectedLevelId);

                                        if (song != null)
                                        {
                                            currentSongIndex = availableSongs.IndexOf(song);
                                        }
                                        else
                                        {
                                            currentSongIndex = lastSelectedSong + 1;
                                        }
                                    }
                                    else
                                    {
                                        currentSongIndex = lastSelectedSong + 1;
                                    }
                                }
                            }; break;

                            case Settings.SongOrder.Shuffle: {
                                Random rand = new Random();
                                currentSongIndex = rand.Next(availableSongs.Count);
                                if (currentSongIndex == lastSelectedSong)
                                {
                                    currentSongIndex = lastSelectedSong + 1;
                                }
                            }; break;

                            case Settings.SongOrder.List: {
                                currentSongIndex = lastSelectedSong + 1;
                            }; break;

                            case Settings.SongOrder.Manual:
                            {
                                serverState = ServerState.Preparing;
                                lobbyTimer  = 0;
                            }; break;
                            }

                            if (currentSongIndex >= availableSongs.Count)
                            {
                                currentSongIndex = 0;
                            }

                            if (currentSongIndex != -1)
                            {
                                serverState = ServerState.Preparing;
                                SendToAllClients(new ServerCommand(
                                                     ServerCommandType.SetSelectedSong,
                                                     _difficulty: GetPreferredDifficulty(availableSongs[currentSongIndex])), wss);
                                Logger.Instance.Log($"Next song is {availableSongs[currentSongIndex].songName} {availableSongs[currentSongIndex].songSubName}");
                            }
                        }

                        if (lobbyTimer >= lobbyTime)
                        {
                            if (availableSongs.Count > 0)
                            {
                                SendToAllClients(new ServerCommand(
                                                     ServerCommandType.StartSelectedSongLevel,
                                                     _difficulty: GetPreferredDifficulty(availableSongs[currentSongIndex])), wss);

                                serverState = ServerState.Playing;
                                Logger.Instance.Log("Starting song " + availableSongs[currentSongIndex].songName + " " +
                                                    availableSongs[currentSongIndex].songSubName + "...");
                            }
                            _timerSeconds = 0;
                            lobbyTimer    = 0;
                        }
                    };
                        break;

                    case ServerState.Playing:
                    {
                        sendTimer += (float)deltaTime.TotalSeconds;
                        playTime  += deltaTime;

                        if (sendTimer >= sendTime)
                        {
                            SendToAllClients(new ServerCommand(
                                                 ServerCommandType.SetPlayerInfos,
                                                 _playerInfos: (clients.Where(x => x.playerInfo != null)
                                                                .OrderByDescending(x => x.playerInfo.playerScore)
                                                                .Select(x => JsonConvert.SerializeObject(x.playerInfo))).ToArray(),
                                                 _selectedSongDuration: availableSongs[currentSongIndex].duration.TotalSeconds,
                                                 _selectedSongPlayTime: playTime.TotalSeconds), wss);
                            sendTimer = 0f;
                        }

                        if (playTime.TotalSeconds >= availableSongs[currentSongIndex].duration.TotalSeconds + 15f)
                        {
                            playTime         = new TimeSpan();
                            sendTimer        = 0f;
                            serverState      = ServerState.Voting;
                            lastSelectedSong = currentSongIndex;
                            currentSongIndex = -1;
                            Logger.Instance.Log("Returning to lobby...");

                            SendToAllClients(new ServerCommand(ServerCommandType.SetServerState));
                        }


                        if (clients.Count(x => x.state == ClientState.Playing) == 0 && playTime.TotalSeconds > 5 && playTime.TotalSeconds <= availableSongs[currentSongIndex].duration.TotalSeconds - 10f)
                        {
                            playTime         = new TimeSpan();
                            sendTimer        = 0f;
                            serverState      = ServerState.Voting;
                            lastSelectedSong = currentSongIndex;
                            currentSongIndex = -1;
                            Logger.Instance.Log("Returning to lobby (NO PLAYERS)...");

                            SendToAllClients(new ServerCommand(ServerCommandType.SetServerState));
                        }
                    };
                        break;
                    }

                    Console.Title = string.Format(TitleFormat, Settings.Instance.Server.ServerName, clients.Count);
                }catch (Exception e)
                {
                    Logger.Instance.Error($"Server loop exception: {e}");
                }
                Thread.Sleep(5);
            }
        }
        void ClientLoop()
        {
            int pingTimer = 0;

            Logger.Instance.Log("Client connected!");

            if (Misc.Settings.Instance.Server.MaxPlayers != 0)
            {
                if (Misc.Settings.Instance.Server.MaxPlayers < ServerMain.clients.Count)
                {
                    KickClient("Too many players");
                    return;
                }
            }

            while (_clientLoopThread.IsAlive)
            {
                try
                {
                    if (_client != null && _client.Connected)
                    {
                        clientIP = ((IPEndPoint)_client.Client.RemoteEndPoint).Address.ToString();

                        pingTimer++;
                        if (pingTimer > 180)
                        {
                            SendToClient(new ServerCommand(ServerCommandType.Ping));
                            pingTimer = 0;
                        }

                        string[] commands = ReceiveFromClient();

                        if (commands != null)
                        {
                            foreach (string data in commands)
                            {
                                ClientCommand command = JsonConvert.DeserializeObject <ClientCommand>(data);

                                Version clientVersion = new Version(command.version);

                                if (clientVersion.Major != ServerMain.serverVersion.Major || clientVersion.Minor != ServerMain.serverVersion.Minor || clientVersion.Build != ServerMain.serverVersion.Build)
                                {
                                    state = ClientState.UpdateRequired;
                                    SendToClient(new ServerCommand(ServerCommandType.UpdateRequired));
                                    DestroyClient();
                                }

                                if (state != ClientState.Playing && state != ClientState.Connected)
                                {
                                    state = ClientState.Connected;
                                }

                                switch (command.commandType)
                                {
                                case ClientCommandType.SetPlayerInfo:
                                {
                                    PlayerInfo receivedPlayerInfo =
                                        JsonConvert.DeserializeObject <PlayerInfo>(command.playerInfo);
                                    if (receivedPlayerInfo != null)
                                    {
                                        if (ServerMain.serverState == ServerState.Playing)
                                        {
                                            state = ClientState.Playing;
                                        }
                                        if (playerId == 0)
                                        {
                                            playerId = receivedPlayerInfo.playerId;
                                            if (!ServerMain.clients.Contains(this))
                                            {
                                                ServerMain.clients.Add(this);
                                                Logger.Instance.Log("New player: " + receivedPlayerInfo.playerName);
                                            }
                                        }
                                        else if (playerId != receivedPlayerInfo.playerId)
                                        {
                                            return;
                                        }

                                        if (playerName == null)
                                        {
                                            playerName = receivedPlayerInfo.playerName;
                                        }
                                        else if (playerName != receivedPlayerInfo.playerName)
                                        {
                                            return;
                                        }

                                        playerScore = receivedPlayerInfo.playerScore;

                                        playerInfo = receivedPlayerInfo;

                                        if (Misc.Settings.Instance.Access.Blacklist.Contains(receivedPlayerInfo.playerId.ToString()) || Misc.Settings.Instance.Access.Blacklist.Contains(clientIP))
                                        {
                                            KickClient();
                                            return;
                                        }

                                        if (Misc.Settings.Instance.Access.WhitelistEnabled && !Misc.Settings.Instance.Access.Whitelist.Contains(receivedPlayerInfo.playerId.ToString()) && !Misc.Settings.Instance.Access.Whitelist.Contains(clientIP))
                                        {
                                            KickClient();
                                            return;
                                        }
                                    }
                                }
                                    ;
                                    break;

                                case ClientCommandType.GetServerState:
                                {
                                    if (ServerMain.serverState != ServerState.Playing)
                                    {
                                        SendToClient(new ServerCommand(ServerCommandType.SetServerState));
                                    }
                                    else
                                    {
                                        SendToClient(new ServerCommand(
                                                         ServerCommandType.SetServerState,
                                                         _selectedSongDuration: ServerMain.availableSongs[ServerMain.currentSongIndex].duration.TotalSeconds,
                                                         _selectedSongPlayTime: ServerMain.playTime.TotalSeconds));
                                    }
                                }
                                    ;
                                    break;

                                case ClientCommandType.GetAvailableSongs:
                                {
                                    SendToClient(new ServerCommand(
                                                     ServerCommandType.DownloadSongs,
                                                     _songs: ServerMain.availableSongs.Select(x => x.levelId).ToArray()));
                                };
                                    break;

                                case ClientCommandType.VoteForSong:
                                {
                                    if (ServerMain.serverState == ServerState.Voting)
                                    {
                                        votedFor = ServerMain.availableSongs.FirstOrDefault(x => x.levelId.Substring(0, 32) == command.voteForLevelId.Substring(0, 32));
                                    }
                                };
                                    break;
                                }
                            }
                        }
                        while (sendQueue.Count != 0)
                        {
                            SendToClient(sendQueue.Dequeue());
                        }
                    }
                    else
                    {
                        if ((ServerMain.serverState == ServerState.Playing && ServerMain.playTime.TotalSeconds <= ServerMain.availableSongs[ServerMain.currentSongIndex].duration.TotalSeconds - 10f) || ServerMain.serverState != ServerState.Playing)
                        {
                            DestroyClient();
                            return;
                        }
                    }
                }catch (Exception e)
                {
                    Logger.Instance.Warning($"CLIENT EXCEPTION: {e}");
                }

                Thread.Sleep(8);
            }
        }