예제 #1
0
        public static string GetHashFromID(string id)
        {
            if (OstHelper.IsOst(id))
            {
                return(id);
            }

            Logger.Debug($"Getting hash for {id} from {beatSaverUrl}");


            HttpClientHandler httpClientHandler = new HttpClientHandler();

            httpClientHandler.AllowAutoRedirect = false;

            using (var client = new HttpClient(httpClientHandler))
            {
                client.DefaultRequestHeaders.Add("user-agent", SharedConstructs.Name);

                var response = client.GetAsync($"{beatSaverDownloadByKeyUrl}{id}");
                response.Wait();

                var result     = response.Result.Headers.Location.ToString();
                var startIndex = result.LastIndexOf("/") + 1;
                var length     = result.LastIndexOf(".") - startIndex;

                return(result.Substring(startIndex, length));
            }
        }
예제 #2
0
 public static string GetHashFromLevelId(string levelId)
 {
     if (OstHelper.IsOst(levelId))
     {
         return(levelId);
     }
     return(Collections.hashForLevelID(levelId).ToLower());
 }
예제 #3
0
        private void MockClient_PlaySong(Beatmap map)
        {
            if (OstHelper.IsOst(map.LevelId))
            {
                return;
            }

            var match = State.Matches.First(x => x.Players.Contains(Self));

            otherPlayersInMatch = match.Players.Select(x => x.Id).Union(new Guid[] { match.Leader.Id }).ToArray();

            currentlyPlayingMap  = map;
            currentlyPlayingSong = new DownloadedSong(HashFromLevelId(map.LevelId));
            currentMaxScore      = currentlyPlayingSong.GetMaxScore(currentlyPlayingMap.Characteristic.SerializedName, currentlyPlayingMap.Difficulty);

            /*using (var libVLC = new LibVLC())
             * {
             *  var media = new Media(libVLC, currentlyPlayingSong.GetAudioPath(), FromType.FromPath);
             *  await media.Parse();
             *
             *  songTimer = new Timer();
             *  songTimer.AutoReset = false;
             *  songTimer.Interval = media.Duration;
             *  songTimer.Elapsed += SongTimer_Elapsed;
             *
             *  noteTimer = new Timer();
             *  noteTimer.AutoReset = false;
             *  noteTimer.Interval = 500;
             *  noteTimer.Elapsed += NoteTimer_Elapsed;
             *
             *  noteTimer.Start();
             *  songTimer.Start();
             * }*/

            songTimer           = new Timer();
            songTimer.AutoReset = false;
            songTimer.Interval  = 60 * 3 * 1000;
            songTimer.Elapsed  += SongTimer_Elapsed;

            noteTimer           = new Timer();
            noteTimer.AutoReset = false;
            noteTimer.Interval  = 500;
            noteTimer.Elapsed  += NoteTimer_Elapsed;

            noteTimer.Start();
            songTimer.Start();

            (Self as Player).PlayState = Player.PlayStates.InGame;
            var playerUpdated = new Event();

            playerUpdated.Type          = Event.EventType.PlayerUpdated;
            playerUpdated.ChangedObject = Self;
            Send(new Packet(playerUpdated));
        }
예제 #4
0
        public SongListItem(GameplayParameters parameters)
        {
            this.parameters   = parameters;
            cancellationToken = new CancellationTokenSource();

            if (OstHelper.IsOst(parameters.Beatmap.LevelId) || SongUtils.masterLevelList.Any(x => x.levelID == parameters.Beatmap.LevelId))
            {
                downloadState = DownloadState.Complete;
                level         = SongUtils.masterLevelList.First(x => x.levelID == parameters.Beatmap.LevelId);
            }
            else
            {
                SongDownloader.DownloadSong(parameters.Beatmap.LevelId, true, OnSongDownloaded, OnDownloadProgress);
            }
        }
        public DownloadedSong(string songHash)
        {
            Hash = songHash;

            if (!OstHelper.IsOst(Hash))
            {
                _infoPath       = GetInfoPath();
                Characteristics = GetBeatmapCharacteristics();
                Name            = GetSongName();
            }
            else
            {
                Name            = OstHelper.GetOstSongNameFromLevelId(Hash);
                Characteristics = new string[] { "Standard", "OneSaber", "NoArrows", "90Degree", "360Degree" };
            }
        }
        protected override void Client_PacketReceived(Packet packet)
        {
            base.Client_PacketReceived(packet);

            if (packet.Type == PacketType.PlaySong)
            {
                PlaySong playSong = packet.SpecificPacket as PlaySong;

                var desiredLevel          = SongUtils.masterLevelList.First(x => x.levelID == playSong.GameplayParameters.Beatmap.LevelId);
                var desiredCharacteristic = desiredLevel.previewDifficultyBeatmapSets.FirstOrDefault(x => x.beatmapCharacteristic.serializedName == playSong.GameplayParameters.Beatmap.Characteristic.SerializedName).beatmapCharacteristic ?? desiredLevel.previewDifficultyBeatmapSets.First().beatmapCharacteristic;
                var desiredDifficulty     = (BeatmapDifficulty)playSong.GameplayParameters.Beatmap.Difficulty;

                var playerData     = Resources.FindObjectsOfTypeAll <PlayerDataModel>().First().playerData;
                var playerSettings = playerData.playerSpecificSettings;

                //Override defaults if we have forced options enabled
                if (playSong.GameplayParameters.PlayerSettings.Options != PlayerOptions.None)
                {
                    playerSettings = new PlayerSpecificSettings(
                        playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.StaticLights),
                        playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.LeftHanded),
                        playSong.GameplayParameters.PlayerSettings.PlayerHeight,
                        playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.AutoPlayerHeight),
                        playSong.GameplayParameters.PlayerSettings.SfxVolume,
                        playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.ReduceDebris),
                        playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.NoHud),
                        playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.NoFailEffects),
                        playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.AdvancedHud),
                        playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.AutoRestart),
                        playSong.GameplayParameters.PlayerSettings.SaberTrailIntensity,
                        playSong.GameplayParameters.PlayerSettings.NoteJumpStartBeatOffset,
                        playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.HideNoteSpawnEffect),
                        playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.AdaptiveSfx)
                        );
                }

                var songSpeed = GameplayModifiers.SongSpeed.Normal;
                if (playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.SlowSong))
                {
                    songSpeed = GameplayModifiers.SongSpeed.Slower;
                }
                if (playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.FastSong))
                {
                    songSpeed = GameplayModifiers.SongSpeed.Faster;
                }

                var gameplayModifiers = new GameplayModifiers(
                    playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.DemoNoFail),
                    playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.DemoNoObstacles),
                    playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.BatteryEnergy) ? GameplayModifiers.EnergyType.Battery : GameplayModifiers.EnergyType.Bar,
                    playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.NoFail),
                    playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.InstaFail),
                    playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.FailOnClash),
                    playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.NoObstacles) ? GameplayModifiers.EnabledObstacleType.NoObstacles : GameplayModifiers.EnabledObstacleType.All,
                    playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.NoBombs),
                    playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.FastNotes),
                    playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.StrictAngles),
                    playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.DisappearingArrows),
                    songSpeed,
                    playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.NoArrows),
                    playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.GhostNotes)
                    );

                var colorScheme = playerData.colorSchemesSettings.overrideDefaultColors ? playerData.colorSchemesSettings.GetSelectedColorScheme() : null;

                //Disable score submission if nofail is on. This is specifically for Hidden Sabers, though it may stay longer
                if (playSong.DisableScoresaberSubmission)
                {
                    BS_Utils.Gameplay.ScoreSubmission.DisableSubmission(SharedConstructs.Name);
                }
                if (playSong.ShowNormalNotesOnStream)
                {
                    var customNotes = IPA.Loader.PluginManager.GetPluginFromId("CustomNotes");
                    if (customNotes != null)
                    {
                        EnableHMDOnly();
                    }
                }

                PlaySong?.Invoke(desiredLevel, desiredCharacteristic, desiredDifficulty, gameplayModifiers, playerSettings, playerData.overrideEnvironmentSettings, colorScheme, playSong.FloatingScoreboard, playSong.StreamSync, playSong.DisablePause, playSong.DisableFail);
            }
            else if (packet.Type == PacketType.Command)
            {
                Command command = packet.SpecificPacket as Command;
                if (command.CommandType == Command.CommandTypes.ReturnToMenu)
                {
                    if (SyncHandler.Instance != null)
                    {
                        ScreenOverlay.Instance.Clear();
                    }
                    if ((Self as Player).PlayState == Player.PlayStates.InGame)
                    {
                        PlayerUtils.ReturnToMenu();
                    }
                }
                else if (command.CommandType == Command.CommandTypes.ScreenOverlay_ShowPng)
                {
                    ScreenOverlay.Instance.ShowPng();
                }
                else if (command.CommandType == Command.CommandTypes.DelayTest_Finish)
                {
                    UnityMainThreadDispatcher.Instance().Enqueue(() => {
                        ScreenOverlay.Instance.Clear();
                        SyncHandler.Instance.Resume();
                        SyncHandler.Destroy();
                    });
                }
            }
            else if (packet.Type == PacketType.LoadSong)
            {
                LoadSong loadSong = packet.SpecificPacket as LoadSong;

                Action <IBeatmapLevel> SongLoaded = (loadedLevel) =>
                {
                    //Send updated download status
                    (Self as Player).DownloadState = Player.DownloadStates.Downloaded;

                    var playerUpdate = new Event();
                    playerUpdate.Type          = Event.EventType.PlayerUpdated;
                    playerUpdate.ChangedObject = Self;
                    Send(new Packet(playerUpdate));

                    //Notify any listeners of the client that a song has been loaded
                    LoadedSong?.Invoke(loadedLevel);
                };

                if (OstHelper.IsOst(loadSong.LevelId))
                {
                    SongLoaded?.Invoke(SongUtils.masterLevelList.First(x => x.levelID == loadSong.LevelId) as BeatmapLevelSO);
                }
                else
                {
                    if (SongUtils.masterLevelList.Any(x => x.levelID == loadSong.LevelId))
                    {
                        SongUtils.LoadSong(loadSong.LevelId, SongLoaded);
                    }
                    else
                    {
                        Action <string, bool> loadSongAction = (hash, succeeded) =>
                        {
                            if (succeeded)
                            {
                                SongUtils.LoadSong(loadSong.LevelId, SongLoaded);
                            }
                            else
                            {
                                (Self as Player).DownloadState = Player.DownloadStates.DownloadError;

                                var playerUpdated = new Event();
                                playerUpdated.Type          = Event.EventType.PlayerUpdated;
                                playerUpdated.ChangedObject = Self;

                                Send(new Packet(playerUpdated));
                            }
                        };

                        (Self as Player).DownloadState = Player.DownloadStates.Downloading;

                        var playerUpdate = new Event();
                        playerUpdate.Type          = Event.EventType.PlayerUpdated;
                        playerUpdate.ChangedObject = Self;
                        Send(new Packet(playerUpdate));

                        SongDownloader.DownloadSong(loadSong.LevelId, songDownloaded: loadSongAction, downloadProgressChanged: (hash, progress) => Logger.Debug($"DOWNLOAD PROGRESS ({hash}): {progress}"), customHostUrl: loadSong.CustomHostUrl);
                    }
                }
            }
            else if (packet.Type == PacketType.File)
            {
                File file = packet.SpecificPacket as File;
                if (file.Intent == File.Intentions.SetPngToShowWhenTriggered)
                {
                    var pngBytes = file.Compressed ? CompressionUtils.Decompress(file.Data) : file.Data;
                    ScreenOverlay.Instance.SetPngBytes(pngBytes);
                }
                else if (file.Intent == File.Intentions.ShowPngImmediately)
                {
                    var pngBytes = file.Compressed ? CompressionUtils.Decompress(file.Data) : file.Data;
                    ScreenOverlay.Instance.SetPngBytes(pngBytes);
                    ScreenOverlay.Instance.ShowPng();
                }

                Send(packet.From, new Packet(new Acknowledgement()
                {
                    PacketId = packet.Id,
                    Type     = Acknowledgement.AcknowledgementType.FileDownloaded
                }));
            }
        }
        public async Task AddSongAsync([Remainder] string paramString = null)
        {
            if (IsAdmin())
            {
                var eventId = paramString.ParseArgs("eventId");
                var songId  = paramString.ParseArgs("song");

                if (string.IsNullOrEmpty(eventId) || string.IsNullOrEmpty(songId))
                {
                    await ReplyAsync(embed : ("Usage: `addSong -eventId \"[event id]\" -song [song link]`\n" +
                                              "To find event ids, please run `listEvents`\n" +
                                              "Optional parameters: `-difficulty [difficulty]`, `-characteristic [characteristic]` (example: `-characteristic onesaber`), `-[modifier]` (example: `-nofail`)").ErrorEmbed());

                    return;
                }

                //Parse the difficulty input, either as an int or a string
                BeatmapDifficulty difficulty = BeatmapDifficulty.ExpertPlus;

                string difficultyArg = paramString.ParseArgs("difficulty");
                if (difficultyArg != null)
                {
                    //If the enum conversion doesn't succeed, try it as an int
                    if (!Enum.TryParse(difficultyArg, true, out difficulty))
                    {
                        await ReplyAsync(embed : "Could not parse difficulty parameter".ErrorEmbed());

                        return;
                    }
                }

                string characteristic = paramString.ParseArgs("characteristic");
                characteristic = characteristic ?? "Standard";

                GameOptions   gameOptions   = GameOptions.None;
                PlayerOptions playerOptions = PlayerOptions.None;

                //Load up the GameOptions and PlayerOptions
                foreach (GameOptions o in Enum.GetValues(typeof(GameOptions)))
                {
                    if (paramString.ParseArgs(o.ToString()) == "true")
                    {
                        gameOptions = (gameOptions | o);
                    }
                }

                foreach (PlayerOptions o in Enum.GetValues(typeof(PlayerOptions)))
                {
                    if (paramString.ParseArgs(o.ToString()) == "true")
                    {
                        playerOptions = (playerOptions | o);
                    }
                }

                //Sanitize input
                if (songId.StartsWith("https://beatsaver.com/") || songId.StartsWith("https://bsaber.com/"))
                {
                    //Strip off the trailing slash if there is one
                    if (songId.EndsWith("/"))
                    {
                        songId = songId.Substring(0, songId.Length - 1);
                    }

                    //Strip off the beginning of the url to leave the id
                    songId = songId.Substring(songId.LastIndexOf("/") + 1);
                }

                if (songId.Contains("&"))
                {
                    songId = songId.Substring(0, songId.IndexOf("&"));
                }

                var server = ServerService.GetServer();
                if (server == null)
                {
                    await ReplyAsync(embed : "The Server is not running, so we can't can't add songs to it".ErrorEmbed());
                }
                else
                {
                    //Get the hash for the song
                    var hash       = BeatSaverDownloader.GetHashFromID(songId);
                    var knownPairs = await HostScraper.ScrapeHosts(server.State.KnownHosts, $"{server.CoreServer.Address}:{server.CoreServer.Port}", 0);

                    var targetPair  = knownPairs.FirstOrDefault(x => x.Value.Events.Any(y => y.EventId.ToString() == eventId));
                    var targetEvent = targetPair.Value.Events.FirstOrDefault(x => x.EventId.ToString() == eventId);
                    var songPool    = targetEvent.QualifierMaps.ToList();

                    if (OstHelper.IsOst(hash))
                    {
                        if (!SongExists(songPool, hash, characteristic, (int)difficulty, (int)gameOptions, (int)playerOptions))
                        {
                            GameplayParameters parameters = new GameplayParameters
                            {
                                Beatmap = new Beatmap
                                {
                                    Name           = OstHelper.GetOstSongNameFromLevelId(hash),
                                    LevelId        = hash,
                                    Characteristic = new Characteristic
                                    {
                                        SerializedName = characteristic
                                    },
                                    Difficulty = difficulty
                                },
                                GameplayModifiers = new GameplayModifiers
                                {
                                    Options = gameOptions
                                },
                                PlayerSettings = new PlayerSpecificSettings
                                {
                                    Options = playerOptions
                                }
                            };

                            songPool.Add(parameters);
                            targetEvent.QualifierMaps = songPool.ToArray();

                            var response = await server.SendUpdateQualifierEvent(targetPair.Key, targetEvent);

                            if (response.Type == Response.ResponseType.Success)
                            {
                                await ReplyAsync(embed : ($"Added: {parameters.Beatmap.Name} ({difficulty}) ({characteristic})" +
                                                          $"{(gameOptions != GameOptions.None ? $" with game options: ({gameOptions})" : "")}" +
                                                          $"{(playerOptions != PlayerOptions.None ? $" with player options: ({playerOptions})" : "!")}").SuccessEmbed());
                            }
                            else if (response.Type == Response.ResponseType.Fail)
                            {
                                await ReplyAsync(embed : response.Message.ErrorEmbed());
                            }
                        }
                        else
                        {
                            await ReplyAsync(embed : "Song is already active in the database".ErrorEmbed());
                        }
                    }
                    else
                    {
                        BeatSaverDownloader.DownloadSong(hash, async(songPath) =>
                        {
                            if (songPath != null)
                            {
                                DownloadedSong song = new DownloadedSong(hash);
                                string songName     = song.Name;

                                if (!song.GetBeatmapDifficulties(characteristic).Contains(difficulty))
                                {
                                    BeatmapDifficulty nextBestDifficulty = song.GetClosestDifficultyPreferLower(difficulty);

                                    if (SongExists(songPool, hash, characteristic, (int)nextBestDifficulty, (int)gameOptions, (int)playerOptions))
                                    {
                                        await ReplyAsync(embed: $"{songName} doesn't have {difficulty}, and {nextBestDifficulty} is already in the event".ErrorEmbed());
                                    }
                                    else
                                    {
                                        GameplayParameters parameters = new GameplayParameters
                                        {
                                            Beatmap = new Beatmap
                                            {
                                                Name           = songName,
                                                LevelId        = $"custom_level_{hash.ToUpper()}",
                                                Characteristic = new Characteristic
                                                {
                                                    SerializedName = characteristic
                                                },
                                                Difficulty = nextBestDifficulty
                                            },
                                            GameplayModifiers = new GameplayModifiers
                                            {
                                                Options = gameOptions
                                            },
                                            PlayerSettings = new PlayerSpecificSettings
                                            {
                                                Options = playerOptions
                                            }
                                        };

                                        songPool.Add(parameters);
                                        targetEvent.QualifierMaps = songPool.ToArray();

                                        var response = await server.SendUpdateQualifierEvent(targetPair.Key, targetEvent);
                                        if (response.Type == Response.ResponseType.Success)
                                        {
                                            await ReplyAsync(embed: ($"{songName} doesn't have {difficulty}, using {nextBestDifficulty} instead.\n" +
                                                                     $"Added to the song list" +
                                                                     $"{(gameOptions != GameOptions.None ? $" with game options: ({gameOptions})" : "")}" +
                                                                     $"{(playerOptions != PlayerOptions.None ? $" with player options: ({playerOptions})" : "!")}").SuccessEmbed());
                                        }
                                        else if (response.Type == Response.ResponseType.Fail)
                                        {
                                            await ReplyAsync(embed: response.Message.ErrorEmbed());
                                        }
                                    }
                                }
                                else
                                {
                                    GameplayParameters parameters = new GameplayParameters
                                    {
                                        Beatmap = new Beatmap
                                        {
                                            Name           = songName,
                                            LevelId        = $"custom_level_{hash.ToUpper()}",
                                            Characteristic = new Characteristic
                                            {
                                                SerializedName = characteristic
                                            },
                                            Difficulty = difficulty
                                        },
                                        GameplayModifiers = new GameplayModifiers
                                        {
                                            Options = gameOptions
                                        },
                                        PlayerSettings = new PlayerSpecificSettings
                                        {
                                            Options = playerOptions
                                        }
                                    };

                                    songPool.Add(parameters);
                                    targetEvent.QualifierMaps = songPool.ToArray();

                                    var response = await server.SendUpdateQualifierEvent(targetPair.Key, targetEvent);
                                    if (response.Type == Response.ResponseType.Success)
                                    {
                                        await ReplyAsync(embed: ($"{songName} ({difficulty}) ({characteristic}) downloaded and added to song list" +
                                                                 $"{(gameOptions != GameOptions.None ? $" with game options: ({gameOptions})" : "")}" +
                                                                 $"{(playerOptions != PlayerOptions.None ? $" with player options: ({playerOptions})" : "!")}").SuccessEmbed());
                                    }
                                    else if (response.Type == Response.ResponseType.Fail)
                                    {
                                        await ReplyAsync(embed: response.Message.ErrorEmbed());
                                    }
                                }
                            }
                            else
                            {
                                await ReplyAsync(embed: "Could not download song.".ErrorEmbed());
                            }
                        });
                    }
                }
            }
            else
            {
                await ReplyAsync(embed : "You do not have sufficient permissions to use this command".ErrorEmbed());
            }
        }
예제 #8
0
        public async Task AddSongAsync([Remainder] string paramString = null)
        {
            if (IsAdmin())
            {
                var eventId = paramString.ParseArgs("赛事");
                var songId  = paramString.ParseArgs("歌曲");

                if (string.IsNullOrEmpty(eventId) || string.IsNullOrEmpty(songId))
                {
                    await ReplyAsync(embed : ("用法: `添加歌曲 -赛事 \"[赛事ID]\" -歌曲 [链接/key]`\n" +
                                              "赛事ID可以通过`赛事列表`命令查找\n" +
                                              "可选参数: `-难度 [Easy/Normal/Hard/Expert/ExpertPlus]`, `-谱型 [例如: onesaber]`, `-[修改项]` (例如: 不死模式为 `-nofail`)").ErrorEmbed());

                    return;
                }

                //Parse the difficulty input, either as an int or a string
                BeatmapDifficulty difficulty = BeatmapDifficulty.ExpertPlus;

                string difficultyArg = paramString.ParseArgs("难度");
                if (difficultyArg != null)
                {
                    //If the enum conversion doesn't succeed, try it as an int
                    if (!Enum.TryParse(difficultyArg, true, out difficulty))
                    {
                        await ReplyAsync(embed : "请检查难度参数".ErrorEmbed());

                        return;
                    }
                }

                string characteristic = paramString.ParseArgs("谱型");
                characteristic = characteristic ?? "Standard";

                GameOptions   gameOptions   = GameOptions.None;
                PlayerOptions playerOptions = PlayerOptions.None;

                //Load up the GameOptions and PlayerOptions
                foreach (GameOptions o in Enum.GetValues(typeof(GameOptions)))
                {
                    if (paramString.ParseArgs(o.ToString()) == "true")
                    {
                        gameOptions = (gameOptions | o);
                    }
                }

                foreach (PlayerOptions o in Enum.GetValues(typeof(PlayerOptions)))
                {
                    if (paramString.ParseArgs(o.ToString()) == "true")
                    {
                        playerOptions = (playerOptions | o);
                    }
                }

                //Sanitize input
                if (songId.StartsWith("https://beatsaver.com/") || songId.StartsWith("https://bsaber.com/"))
                {
                    //Strip off the trailing slash if there is one
                    if (songId.EndsWith("/"))
                    {
                        songId = songId.Substring(0, songId.Length - 1);
                    }

                    //Strip off the beginning of the url to leave the id
                    songId = songId.Substring(songId.LastIndexOf("/") + 1);
                }

                if (songId.Contains("&"))
                {
                    songId = songId.Substring(0, songId.IndexOf("&"));
                }

                var server = ServerService.GetServer();
                if (server == null)
                {
                    await ReplyAsync(embed : "服务器不在线,所以不能添加歌曲".ErrorEmbed());
                }
                else
                {
                    //Get the hash for the song
                    var hash       = BeatSaverDownloader.GetHashFromID(songId);
                    var knownPairs = await HostScraper.ScrapeHosts(server.State.KnownHosts, $"{server.CoreServer.Address}:{server.CoreServer.Port}", 0);

                    var targetPair  = knownPairs.FirstOrDefault(x => x.Value.Events.Any(y => y.EventId.ToString() == eventId));
                    var targetEvent = targetPair.Value.Events.FirstOrDefault(x => x.EventId.ToString() == eventId);
                    var songPool    = targetEvent.QualifierMaps.ToList();

                    if (OstHelper.IsOst(hash))
                    {
                        if (!SongExists(songPool, hash, characteristic, (int)difficulty, (int)gameOptions, (int)playerOptions))
                        {
                            GameplayParameters parameters = new GameplayParameters
                            {
                                Beatmap = new Beatmap
                                {
                                    Name           = OstHelper.GetOstSongNameFromLevelId(hash),
                                    LevelId        = hash,
                                    Characteristic = new Characteristic
                                    {
                                        SerializedName = characteristic
                                    },
                                    Difficulty = difficulty
                                },
                                GameplayModifiers = new GameplayModifiers
                                {
                                    Options = gameOptions
                                },
                                PlayerSettings = new PlayerSpecificSettings
                                {
                                    Options = playerOptions
                                }
                            };

                            songPool.Add(parameters);
                            targetEvent.QualifierMaps = songPool.ToArray();

                            var response = await server.SendUpdateQualifierEvent(targetPair.Key, targetEvent);

                            if (response.Type == Response.ResponseType.Success)
                            {
                                await ReplyAsync(embed : ($"已添加: {parameters.Beatmap.Name} ({difficulty}) ({characteristic})" +
                                                          $"{(gameOptions != GameOptions.None ? $" 附加游戏参数: ({gameOptions})" : "")}" +
                                                          $"{(playerOptions != PlayerOptions.None ? $" 附加玩家参数: ({playerOptions})" : "!")}").SuccessEmbed());
                            }
                            else if (response.Type == Response.ResponseType.Fail)
                            {
                                await ReplyAsync(embed : response.Message.ErrorEmbed());
                            }
                        }
                        else
                        {
                            await ReplyAsync(embed : "歌曲已存在于数据库".ErrorEmbed());
                        }
                    }
                    else
                    {
                        var songInfo = await BeatSaverDownloader.GetSongInfo(songId);

                        string songName = songInfo.Name;

                        if (!songInfo.HasDifficulty(characteristic, difficulty))
                        {
                            BeatmapDifficulty nextBestDifficulty = songInfo.GetClosestDifficultyPreferLower(characteristic, difficulty);

                            if (SongExists(songPool, hash, characteristic, (int)nextBestDifficulty, (int)gameOptions, (int)playerOptions))
                            {
                                await ReplyAsync(embed : $"{songName} 不存在 {difficulty} 难度, 而且 {nextBestDifficulty} 已存在于赛事".ErrorEmbed());
                            }
                            else
                            {
                                GameplayParameters parameters = new GameplayParameters
                                {
                                    Beatmap = new Beatmap
                                    {
                                        Name           = songName,
                                        LevelId        = $"custom_level_{hash.ToUpper()}",
                                        Characteristic = new Characteristic
                                        {
                                            SerializedName = characteristic
                                        },
                                        Difficulty = nextBestDifficulty
                                    },
                                    GameplayModifiers = new GameplayModifiers
                                    {
                                        Options = gameOptions
                                    },
                                    PlayerSettings = new PlayerSpecificSettings
                                    {
                                        Options = playerOptions
                                    }
                                };

                                songPool.Add(parameters);
                                targetEvent.QualifierMaps = songPool.ToArray();

                                var response = await server.SendUpdateQualifierEvent(targetPair.Key, targetEvent);

                                if (response.Type == Response.ResponseType.Success)
                                {
                                    await ReplyAsync(embed : ($"{songName} 不存在 {difficulty} 难度, 使用 {nextBestDifficulty} 难度代替。\n" +
                                                              $"已添加至歌曲列表" +
                                                              $"{(gameOptions != GameOptions.None ? $" 附加游戏参数: ({gameOptions})" : "")}" +
                                                              $"{(playerOptions != PlayerOptions.None ? $" 附加玩家参数: ({playerOptions})" : "!")}").SuccessEmbed());
                                }
                                else if (response.Type == Response.ResponseType.Fail)
                                {
                                    await ReplyAsync(embed : response.Message.ErrorEmbed());
                                }
                            }
                        }
                        else
                        {
                            GameplayParameters parameters = new GameplayParameters
                            {
                                Beatmap = new Beatmap
                                {
                                    Name           = songName,
                                    LevelId        = $"custom_level_{hash.ToUpper()}",
                                    Characteristic = new Characteristic
                                    {
                                        SerializedName = characteristic
                                    },
                                    Difficulty = difficulty
                                },
                                GameplayModifiers = new GameplayModifiers
                                {
                                    Options = gameOptions
                                },
                                PlayerSettings = new PlayerSpecificSettings
                                {
                                    Options = playerOptions
                                }
                            };

                            songPool.Add(parameters);
                            targetEvent.QualifierMaps = songPool.ToArray();

                            var response = await server.SendUpdateQualifierEvent(targetPair.Key, targetEvent);

                            if (response.Type == Response.ResponseType.Success)
                            {
                                await ReplyAsync(embed : ($"{songName} ({difficulty}) ({characteristic}) 已下载并添加至歌曲列表" +
                                                          $"{(gameOptions != GameOptions.None ? $" 附加游戏参数: ({gameOptions})" : "")}" +
                                                          $"{(playerOptions != PlayerOptions.None ? $" 附加玩家参数: ({playerOptions})" : "!")}").SuccessEmbed());
                            }
                            else if (response.Type == Response.ResponseType.Fail)
                            {
                                await ReplyAsync(embed : response.Message.ErrorEmbed());
                            }
                        }
                    }
                }
            }
            else
            {
                await ReplyAsync(embed : "你没有足够的权限使用该命令".ErrorEmbed());
            }
        }
예제 #9
0
        public static void StartHttpServer()
        {
            var route_config = new List <Route>()
            {
                new Route {
                    Name     = "Score Receiver",
                    UrlRegex = @"^/submit/$",
                    Method   = "POST",
                    Callable = (HttpRequest request) => {
                        try
                        {
                            //Get JSON object from request content
                            JSONNode node = JSON.Parse(WebUtility.UrlDecode(request.Content));

                            //Get Score object from JSON
                            Score s = Score.FromString(node["pb"]);

                            if (RSA.SignScore(Convert.ToUInt64(s.UserId), s.SongHash, s.Difficulty, s.Characteristic, s.FullCombo, s.Score_, s.PlayerOptions, s.GameOptions) == s.Signed &&
                                Song.Exists(s.SongHash, (LevelDifficulty)s.Difficulty, s.Characteristic, true) &&
                                !new Song(s.SongHash, (LevelDifficulty)s.Difficulty, s.Characteristic).Old&&
                                Player.Exists(s.UserId) &&
                                Player.IsRegistered(s.UserId))
                            {
                                Logger.Info($"RECEIVED VALID SCORE: {s.Score_} FOR {new Player(s.UserId).DiscordName} {s.SongHash} {s.Difficulty} {s.Characteristic}");
                            }
                            else
                            {
                                Logger.Error($"RECEIVED INVALID SCORE {s.Score_} FROM {new Player(s.UserId).DiscordName} FOR {s.UserId} {s.SongHash} {s.Difficulty} {s.Characteristic}");
                                return(new HttpResponse()
                                {
                                    ReasonPhrase = "Bad Request",
                                    StatusCode = "400"
                                });
                            }

#if BEATKHANA
                            PostToBeatKhana(s.UserId, s.SongHash, s.Score_.ToString(), new EventServer.BeatSaver.Song(s.SongHash).GetMaxScore(s.Characteristic, (LevelDifficulty)s.Difficulty).ToString());
#endif

                            Database.Score oldScore = null;
                            if (Database.Score.Exists(s.SongHash, s.UserId, (LevelDifficulty)s.Difficulty, s.Characteristic))
                            {
                                oldScore = new Database.Score(s.SongHash, s.UserId, (LevelDifficulty)s.Difficulty, s.Characteristic);
                            }

                            if (oldScore == null ^ (oldScore != null && oldScore.GetScore() < s.Score_))
                            {
                                Player player = new Player(s.UserId);

                                long oldScoreNumber = oldScore == null ? 0 : oldScore.GetScore();
                                oldScore?.SetOld();

                                //Player stats
                                if (oldScoreNumber > 0)
                                {
                                    player.IncrementPersonalBestsBeaten();
                                }
                                else
                                {
                                    player.IncrementSongsPlayed();
                                }
                                player.IncrementSongsPlayed();
                                player.TotalScore += s.Score_ - oldScoreNumber; //Increment total score only by the amount the score has increased

                                Database.Score newScore = new Database.Score(s.SongHash, s.UserId, (LevelDifficulty)s.Difficulty, s.Characteristic);
                                newScore.SetScore(s.Score_, s.FullCombo);

                                //Only send message if player is registered
                                if (Player.Exists(s.UserId))
                                {
                                    CommunityBot.SendToScoreChannel($"User \"{player.DiscordMention}\" has scored {s.Score_} on {new Song(s.SongHash, (LevelDifficulty)s.Difficulty, s.Characteristic).SongName} ({(LevelDifficulty)s.Difficulty}) ({s.Characteristic})!");
                                }
                            }

                            return(new HttpResponse()
                            {
                                ReasonPhrase = "OK",
                                StatusCode = "200"
                            });
                        }
                        catch (Exception e)
                        {
                            Logger.Error($"{e}");
                        }

                        return(new HttpResponse()
                        {
                            ReasonPhrase = "Bad Request",
                            StatusCode = "400"
                        });
                    }
                },
                new Route {
                    Name     = "Rank Receiver",
                    UrlRegex = @"^/requestrank/$",
                    Method   = "POST",
                    Callable = (HttpRequest request) => {
                        try
                        {
                            //Get JSON object from request content
                            JSONNode node = JSON.Parse(WebUtility.UrlDecode(request.Content));

                            //Get Score object from JSON
                            RankRequest r = RankRequest.FromString(node["pb"]);

                            if (RSA.SignRankRequest(Convert.ToUInt64(r.UserId), r.RequestedTeamId, r.InitialAssignment) == r.Signed &&
                                Player.Exists(r.UserId) &&
                                Player.IsRegistered(r.UserId) &&
                                Team.Exists(r.RequestedTeamId))
                            {
                                Logger.Info($"RECEIVED VALID RANK REQUEST: {r.RequestedTeamId} FOR {r.UserId} {r.RequestedTeamId} {r.InitialAssignment}");

                                var player = new Player(r.UserId);
                                var team   = new Team(r.RequestedTeamId);

                                //The rank up system will ignore requets where the player doesn't have the required tokens,
                                //or is requesting a rank higher than the one above their current rank (if it's not an inital rank assignment)
                                if (r.InitialAssignment && player.Team == "-1")
                                {
                                    CommunityBot.ChangeTeam(player, team);
                                }
                                else if (player.Team != "gold")
                                {
                                    var oldTeam  = new Team(player.Team);
                                    var nextTeam = new Team(oldTeam.NextPromotion);
                                    if (player.Tokens >= nextTeam.RequiredTokens)
                                    {
                                        CommunityBot.ChangeTeam(player, nextTeam);
                                    }
                                }
                                else if (player.Team == "gold" && player.Tokens >= new Team("blue").RequiredTokens)   //Player is submitting for Blue
                                {
                                    new Vote(player.UserId, r.OstScoreInfo);
                                }
                                else
                                {
                                    return(new HttpResponse()
                                    {
                                        ReasonPhrase = "Bad Request",
                                        StatusCode = "400"
                                    });
                                }

                                return(new HttpResponse()
                                {
                                    ReasonPhrase = "OK",
                                    StatusCode = "200"
                                });
                            }
                            else
                            {
                                Logger.Warning($"RECEIVED INVALID RANK REQUEST {r.RequestedTeamId} FROM {r.UserId}");
                            }
                        }
                        catch (Exception e)
                        {
                            Logger.Error($"{e}");
                        }

                        return(new HttpResponse()
                        {
                            ReasonPhrase = "Bad Request",
                            StatusCode = "400"
                        });
                    }
                },
                new Route {
                    Name     = "Song Getter",
                    UrlRegex = @"^/songs/",
                    Method   = "GET",
                    Callable = (HttpRequest request) => {
                        string[] requestData = request.Path.Substring(1).Split('/');
                        string   userId      = requestData[1];
                        userId = Regex.Replace(userId, "[^a-zA-Z0-9- ]", "");

                        //If the userid is null, we'll give them e+ everything. It's likely the leaderboard site
                        if (!string.IsNullOrEmpty(userId) && (!Player.Exists(userId) || !Player.IsRegistered(userId)))
                        {
                            return(new HttpResponse()
                            {
                                ReasonPhrase = "Bad Request",
                                StatusCode = "400"
                            });
                        }

                        JSONNode             json  = new JSONObject();
                        List <SongConstruct> songs = GetActiveSongs();

                        songs.ForEach(x => {
                            //If the request doesn't include a player id, we can't be sure which difficulty the player is supposed to play, so we'll just leave
                            //the difficulty set to Auto because it's probably the website asking
                            if (x.Difficulty == LevelDifficulty.Auto && !string.IsNullOrEmpty(userId))
                            {
                                if (OstHelper.IsOst(x.SongHash))
                                {
                                    x.Difficulty = new Player(userId).GetPreferredDifficulty(OstHelper.IsOst(x.SongHash));
                                }
                                else
                                {
                                    var preferredDifficulty = new Player(userId).GetPreferredDifficulty(OstHelper.IsOst(x.SongHash));
                                    x.Difficulty            = new BeatSaver.Song(x.SongHash).GetClosestDifficultyPreferLower(preferredDifficulty);
                                }
                            }

                            var item               = new JSONObject();
                            item["songName"]       = x.Name;
                            item["songHash"]       = x.SongHash;
                            item["difficulty"]     = (int)x.Difficulty;
                            item["gameOptions"]    = (int)x.GameOptions;
                            item["playerOptions"]  = (int)x.PlayerOptions;
                            item["characteristic"] = x.Characteristic;
                            json.Add(x.SongHash + (int)x.Difficulty, item);
                        });

                        return(new HttpResponse()
                        {
                            ContentAsUTF8 = json.ToString(),
                            ReasonPhrase = "OK",
                            StatusCode = "200"
                        });
                    }
                },
                new Route {
                    Name     = "Team Getter",
                    UrlRegex = @"^/teams/",
                    Method   = "GET",
                    Callable = (HttpRequest request) => {
                        string source = request.Path.Substring(request.Path.LastIndexOf("/") + 1);
                        if (!string.IsNullOrEmpty(source))
                        {
                            Logger.Success("Team Request from Duo's Site");
                        }

                        JSONNode    json  = new JSONObject();
                        List <Team> teams = GetAllTeams();

                        foreach (var team in teams)
                        {
                            var item = new JSONObject();
                            item["captainId"]      = team.Captain;
                            item["teamName"]       = team.TeamName;
                            item["color"]          = team.Color;
                            item["requiredTokens"] = team.RequiredTokens;
                            item["nextPromotion"]  = team.NextPromotion;
                            json.Add(team.TeamId, item);
                        }

                        return(new HttpResponse()
                        {
                            ContentAsUTF8 = json.ToString(),
                            ReasonPhrase = "OK",
                            StatusCode = "200"
                        });
                    }
                },
                new Route {
                    Name     = "Player Stats Getter",
                    UrlRegex = @"^/playerstats/",
                    Method   = "GET",
                    Callable = (HttpRequest request) => {
                        string userId = request.Path.Substring(request.Path.LastIndexOf("/") + 1);
                        userId = Regex.Replace(userId, "[^a-zA-Z0-9]", "");

                        if (!(userId.Length == 17 || userId.Length == 16 || userId.Length == 15)) //17 = vive, 16 = oculus, 15 = sfkwww
                        {
                            Logger.Error($"Invalid id size: {userId.Length}");
                            return(new HttpResponse()
                            {
                                ReasonPhrase = "Bad Request",
                                StatusCode = "400"
                            });
                        }

                        JSONNode json = new JSONObject();

                        if (Player.Exists(userId) && Player.IsRegistered(userId))
                        {
#if QUALIFIER
                            var isRegistered = true;
                            if (userId != "76561198063268251")
                            {
                                var registrationCheck = IsPlayerRegisteredInBSWC(userId);
                                registrationCheck.Wait();
                                isRegistered = registrationCheck.Result;
                            }
#else
                            var isRegistered = true;
#endif

                            if ((Config.ServerFlags.HasFlag(ServerFlags.Teams) && new Player(userId).Team == "-1") || !isRegistered)
                            {
                                json["message"] = "Please be sure you're assigned to a team before playing";
                            }
                            else
                            {
                                Player player = new Player(userId);
                                json["version"]        = VersionCode;
                                json["team"]           = player.Team;
                                json["tokens"]         = player.Tokens;
                                json["serverSettings"] = (int)Config.ServerFlags;
                            }
                        }
                        else if (Player.Exists(userId) && !Player.IsRegistered(userId))
                        {
                            json["message"] = "You have been banned from this event.";
                        }
                        else
                        {
                            json["message"] = "Please register with the bot before playing. Check #plugin-information for more info. Sorry for the inconvenience.";
                        }

                        return(new HttpResponse()
                        {
                            ContentAsUTF8 = json.ToString(),
                            ReasonPhrase = "OK",
                            StatusCode = "200"
                        });
                    }
                },
                new Route {
                    Name     = "Song Leaderboard Getter",
                    UrlRegex = @"^/leaderboards/",
                    Method   = "GET",
                    Callable = (HttpRequest request) => {
                        string[] requestData = request.Path.Substring(1).Split('/');
                        string   songHash    = requestData[1];
                        JSONNode json        = new JSONObject();

#if HIDDENNOTES
                        return(new HttpResponse()
                        {
                            ContentAsUTF8 = json.ToString(),
                            ReasonPhrase = "OK",
                            StatusCode = "200"
                        });
#endif

                        if (songHash == "all")
                        {
                            int    take   = 10;
                            string teamId = "-1";

                            if (requestData.Length > 2)
                            {
                                take = Convert.ToInt32(requestData[2]);
                            }
                            if (requestData.Length > 3)
                            {
                                teamId = requestData[3];
                            }

                            List <SongConstruct> songs = GetAllScores(teamId);
                            songs.ToList().ForEach(x =>
                            {
                                JSONNode songNode          = new JSONObject();
                                songNode["levelId"]        = x.SongHash;
                                songNode["songName"]       = x.Name;
                                songNode["difficulty"]     = (int)x.Difficulty;
                                songNode["characteristic"] = x.Characteristic;
                                songNode["scores"]         = new JSONObject();

                                int place = 1;
                                x.Scores.Take(take).ToList().ForEach(y =>
                                {
                                    JSONNode scoreNode     = new JSONObject();
                                    scoreNode["score"]     = y.Score;
                                    scoreNode["player"]    = new Player(y.UserId).DiscordName;
                                    scoreNode["place"]     = place;
                                    scoreNode["fullCombo"] = y.FullCombo ? "true" : "false";
                                    scoreNode["userId"]    = y.UserId;
                                    scoreNode["team"]      = y.TeamId;
                                    songNode["scores"].Add(Convert.ToString(place++), scoreNode);
                                });

                                json.Add(x.SongHash + ":" + (int)x.Difficulty, songNode);
                            });
                        }
                        else
                        {
                            int    take           = 10;
                            int    difficulty     = Convert.ToInt32(requestData[2]);
                            string characteristic = requestData[3];
                            string teamId         = requestData[4];
                            if (requestData.Length > 5)
                            {
                                take = Convert.ToInt32(requestData[5]);
                            }

                            songHash = Regex.Replace(songHash, "[^a-zA-Z0-9- ]", "");
                            teamId   = Regex.Replace(teamId, "[^a-zA-Z0-9- ]", "");

                            SongConstruct songConstruct = new SongConstruct()
                            {
                                SongHash       = songHash,
                                Difficulty     = (LevelDifficulty)difficulty,
                                Characteristic = characteristic
                            };

                            if (!Song.Exists(songHash, (LevelDifficulty)difficulty, characteristic, true))
                            {
                                Logger.Error($"Song doesn't exist for leaderboards: {songHash}");
                                return(new HttpResponse()
                                {
                                    ReasonPhrase = "Bad Request",
                                    StatusCode = "400"
                                });
                            }

                            List <ScoreConstruct> scores = GetScoresForSong(songConstruct, teamId);

                            int place = 1;
                            scores.Take(take).ToList().ForEach(x =>
                            {
                                JSONNode node     = new JSONObject();
                                node["score"]     = x.Score;
                                node["player"]    = new Player(x.UserId).DiscordName;
                                node["place"]     = place;
                                node["fullCombo"] = x.FullCombo ? "true" : "false";
                                node["userId"]    = x.UserId;
                                node["team"]      = x.TeamId;
                                json.Add(Convert.ToString(place++), node);
                            });
                        }

                        return(new HttpResponse()
                        {
                            ContentAsUTF8 = json.ToString(),
                            ReasonPhrase = "OK",
                            StatusCode = "200"
                        });
                    }
                }
            };

            Logger.Info($"HTTP Server listening on {Dns.GetHostName()}");

#if (TEAMSABER)
            int port = 3707;
#elif (DISCORDCOMMUNITY)
            int port = 3703;
#elif (TRUEACCURACY)
            int port = 3711;
#elif (ASIAVR)
            int port = 3709;
#elif (QUALIFIER)
            int port = 3713;
#elif (BTH)
            int port = 3715;
#elif (FENCINGQUALIFIER)
            int port = 3717;
#elif (BEATKHANA)
            int port = 3719;
#elif (HIDDENNOTES)
            int port = 3721;
#elif BETA
            int port = 3704; //My vhost is set up to direct to 3708 when the /api-beta/ route is followed
#endif
            HttpServer httpServer = new HttpServer(port, route_config);
            httpServer.Listen();
        }
예제 #10
0
        //GET the songs from the server, then start the Download coroutine to download and display them
        //TODO: Time complexity here is a mess.
        private static IEnumerator GetSongs(SongListViewController slvc, string userId, Action <List <Song> > songsGottenCallback = null)
        {
            UnityWebRequest www = UnityWebRequest.Get($"{discordCommunityApi}/songs/{userId}/");

            Logger.Debug($"REQUESTING SONGS: {discordCommunityApi}/songs/{userId}/");

            www.timeout = 30;
            yield return(www.SendWebRequest());

            if (www.isNetworkError || www.isHttpError)
            {
                Logger.Error($"Error getting songs: {www.error}");
                slvc.ErrorHappened($"Error getting songs: {www.error}");
            }
            else
            {
                List <Song> songs = new List <Song>();
                try
                {
                    //Get the list of songs to download, and map out the song ids to the corresponding gamemodes
                    var node = JSON.Parse(www.downloadHandler.text);
                    foreach (var id in node)
                    {
                        var newSong = new Song()
                        {
                            Hash           = id.Value["songHash"],
                            SongName       = id.Value["songName"],
                            GameOptions    = (GameOptions)Convert.ToInt32(id.Value["gameOptions"].ToString()),
                            PlayerOptions  = (PlayerOptions)Convert.ToInt32(id.Value["playerOptions"].ToString()),
                            Difficulty     = (LevelDifficulty)Convert.ToInt32(id.Value["difficulty"].ToString()),
                            Characteristic = id.Value["characteristic"]
                        };

                        Logger.Debug($"ADDING SONG: {newSong.SongName} {newSong.Difficulty} {newSong.Characteristic}");
                        songs.Add(newSong);
                    }
                }
                catch (Exception e)
                {
                    Logger.Error($"Error parsing getsong data: {e}");
                    slvc.ErrorHappened($"Error parsing getsong data: {e}");
                    yield break;
                }

                //If we got songs, filter them as neccessary then download any we don't have
                List <Song> availableSongs = new List <Song>();

                //Filter out songs we already have and OSTS
                IEnumerable <Song> osts        = songs.Where(x => OstHelper.IsOst(x.Hash));
                IEnumerable <Song> alreadyHave = songs.Where(x => Collections.songWithHashPresent(x.Hash.ToUpper()));

                //Loads a level from a song instance, populates the Beatmap property and adds to the available list
                Action <Song> loadLevel = (song) =>
                {
                    if (Collections.songWithHashPresent(song.Hash.ToUpper()))
                    {
                        var levelId = Collections.levelIDsForHash(song.Hash).First();

                        var customPreview = Loader.CustomLevelsCollection.beatmapLevels.First(x => x.levelID == levelId) as CustomPreviewBeatmapLevel;

                        song.PreviewBeatmap = customPreview;

                        //TODO: Figure out proper async-ness here

                        /*var beatmapLevelResult = Task.Run(async () => await SongUtils.GetLevelFromPreview(customPreview));
                         * beatmapLevelResult.Wait();
                         *
                         * //TODO: add characteristic name field to the song data stored in the server
                         * song.Beatmap = SongUtils.GetClosestDifficultyPreferLower(beatmapLevelResult.Result?.beatmapLevel, (BeatmapDifficulty)song.Difficulty);
                         * availableSongs.Add(song);*/
                    }
                    else
                    {
                        slvc.ErrorHappened($"Could not load level {song.SongName}");
                    }
                };

                //Load the preview levels for what we have
                foreach (Song song in osts)
                {
                    foreach (IBeatmapLevelPack pack in Loader.BeatmapLevelsModelSO.allLoadedBeatmapLevelPackCollection.beatmapLevelPacks)
                    {
                        var foundLevel = pack.beatmapLevelCollection.beatmapLevels.FirstOrDefault(y => y.levelID.ToLower() == song.Hash.ToLower());
                        if (foundLevel != null)
                        {
                            song.PreviewBeatmap = foundLevel;
                        }
                    }
                }

                foreach (Song song in alreadyHave)
                {
                    loadLevel(song);
                }

                //Of what we already have, add the Levels to the availableSongs list
                availableSongs.AddRange(alreadyHave);
                availableSongs.AddRange(osts);

                //Remove what we already have from the download queue
                songs.RemoveAll(x => availableSongs.Contains(x)); //Don't redownload

                //Download the things we don't have, or if we have everything, show the menu
                if (songs.Count > 0)
                {
                    List <IEnumerator> downloadCoroutines = new List <IEnumerator>();
                    songs.ForEach(x =>
                    {
                        downloadCoroutines.Add(DownloadSongs(x.Hash, slvc));
                    });

                    //Wait for the all downloads to finish
                    yield return(SharedCoroutineStarter.instance.StartCoroutine(new ParallelCoroutine().ExecuteCoroutines(downloadCoroutines.ToArray())));

                    Action <Loader, Dictionary <string, CustomPreviewBeatmapLevel> > songsLoaded =
                        (_, __) =>
                    {
                        //Now that they're refreshed, we can populate their beatmaps and add them to the available list
                        songs.ForEach(x => loadLevel(x));
                        songsGottenCallback?.Invoke(availableSongs.Union(songs).ToList());
                    };

                    Loader.SongsLoadedEvent -= songsLoaded;
                    Loader.SongsLoadedEvent += songsLoaded;
                    Loader.Instance.RefreshSongs(false);
                }
                else
                {
                    songsGottenCallback?.Invoke(availableSongs);
                }
            }
        }
예제 #11
0
        public async Task AddSongAsync(string songId, [Remainder] string paramString = null)
        {
            if (IsAdmin())
            {
                //Parse the difficulty input, either as an int or a string
                BeatmapDifficulty difficulty = BeatmapDifficulty.ExpertPlus;

                string difficultyArg = ParseArgs(paramString, "difficulty");
                if (difficultyArg != null)
                {
                    //If the enum conversion doesn't succeed, try it as an int
                    if (!Enum.TryParse(difficultyArg, true, out difficulty))
                    {
                        await ReplyAsync("Could not parse difficulty parameter.\n" +
                                         "Usage: addSong [songId] [difficulty]");

                        return;
                    }
                }

                string characteristic = ParseArgs(paramString, "characteristic");
                characteristic = characteristic ?? "Standard";

                GameOptions   gameOptions   = GameOptions.None;
                PlayerOptions playerOptions = PlayerOptions.None;

                //Load up the GameOptions and PlayerOptions
                foreach (GameOptions o in Enum.GetValues(typeof(GameOptions)))
                {
                    if (ParseArgs(paramString, o.ToString()) == "true")
                    {
                        gameOptions = (gameOptions | o);
                    }
                }

                foreach (PlayerOptions o in Enum.GetValues(typeof(PlayerOptions)))
                {
                    if (ParseArgs(paramString, o.ToString()) == "true")
                    {
                        playerOptions = (playerOptions | o);
                    }
                }

                //Sanitize input
                if (songId.StartsWith("https://beatsaver.com/") || songId.StartsWith("https://bsaber.com/"))
                {
                    //Strip off the trailing slash if there is one
                    if (songId.EndsWith("/"))
                    {
                        songId = songId.Substring(0, songId.Length - 1);
                    }

                    //Strip off the beginning of the url to leave the id
                    songId = songId.Substring(songId.LastIndexOf("/") + 1);
                }

                if (songId.Contains("&"))
                {
                    songId = songId.Substring(0, songId.IndexOf("&"));
                }

                //Get the hash for the song
                var hash = BeatSaverDownloader.GetHashFromID(songId);

                if (OstHelper.IsOst(hash))
                {
                    //if (!Song.Exists(hash, parsedDifficulty, characteristicArg, true))
                    if (!SongExists(Context.Guild.Id, hash, characteristic, (int)difficulty, (int)gameOptions, (int)playerOptions))
                    {
                        Song song = new Song
                        {
                            Name              = OstHelper.GetOstSongNameFromLevelId(hash),
                            GuildId           = Context.Guild.Id,
                            LevelId           = hash,
                            Characteristic    = characteristic,
                            BeatmapDifficulty = (int)difficulty,
                            GameOptions       = (int)gameOptions,
                            PlayerOptions     = (int)playerOptions
                        };
                        await ReplyAsync($"Added: {song.Name} ({difficulty}) ({characteristic})" +
                                         $"{(gameOptions != GameOptions.None ? $" with game options: ({gameOptions.ToString()})" : "")}" +
                                         $"{(playerOptions != PlayerOptions.None ? $" with player options: ({playerOptions.ToString()})" : "!")}");
                    }
                    else
                    {
                        await ReplyAsync("Song is already active in the database");
                    }
                }
                else
                {
                    BeatSaverDownloader.DownloadSong(hash, async(songPath) =>
                    {
                        if (songPath != null)
                        {
                            DownloadedSong song = new DownloadedSong(hash);
                            string songName     = song.Name;

                            if (!song.GetBeatmapDifficulties(characteristic).Contains(difficulty))
                            {
                                BeatmapDifficulty nextBestDifficulty = song.GetClosestDifficultyPreferLower(difficulty);

                                if (SongExists(Context.Guild.Id, hash, characteristic, (int)nextBestDifficulty, (int)gameOptions, (int)playerOptions))
                                {
                                    await ReplyAsync($"{songName} doesn't have {difficulty}, and {nextBestDifficulty} is already in the database.\n" +
                                                     $"Song not added.");
                                }

                                else
                                {
                                    Song databaseSong = new Song
                                    {
                                        Name              = OstHelper.GetOstSongNameFromLevelId(hash),
                                        GuildId           = Context.Guild.Id,
                                        LevelId           = hash,
                                        Characteristic    = characteristic,
                                        BeatmapDifficulty = (int)nextBestDifficulty,
                                        GameOptions       = (int)gameOptions,
                                        PlayerOptions     = (int)playerOptions
                                    };
                                    await ReplyAsync($"{songName} doesn't have {difficulty}, using {nextBestDifficulty} instead.\n" +
                                                     $"Added to the song list" +
                                                     $"{(gameOptions != GameOptions.None ? $" with game options: ({gameOptions})" : "")}" +
                                                     $"{(playerOptions != PlayerOptions.None ? $" with player options: ({playerOptions})" : "!")}");
                                }
                            }
                            else
                            {
                                Song databaseSong = new Song
                                {
                                    Name              = OstHelper.GetOstSongNameFromLevelId(hash),
                                    GuildId           = Context.Guild.Id,
                                    LevelId           = hash,
                                    Characteristic    = characteristic,
                                    BeatmapDifficulty = (int)difficulty,
                                    GameOptions       = (int)gameOptions,
                                    PlayerOptions     = (int)playerOptions
                                };
                                await ReplyAsync($"{songName} ({difficulty}) ({characteristic}) downloaded and added to song list" +
                                                 $"{(gameOptions != GameOptions.None ? $" with game options: ({gameOptions})" : "")}" +
                                                 $"{(playerOptions != PlayerOptions.None ? $" with player options: ({playerOptions})" : "!")}");
                            }
                        }
                        else
                        {
                            await ReplyAsync("Could not download song.");
                        }
                    });
                }
            }
        }
예제 #12
0
        protected override void Client_PacketRecieved(Packet packet)
        {
            base.Client_PacketRecieved(packet);

            if (packet.Type == PacketType.PlaySong)
            {
                PlaySong playSong = packet.SpecificPacket as PlaySong;

                var desiredLevel          = SongUtils.masterLevelList.First(x => x.levelID == playSong.Beatmap.LevelId);
                var desiredCharacteristic = desiredLevel.previewDifficultyBeatmapSets.FirstOrDefault(x => x.beatmapCharacteristic.serializedName == playSong.Beatmap.Characteristic.SerializedName).beatmapCharacteristic ?? desiredLevel.previewDifficultyBeatmapSets.First().beatmapCharacteristic;
                var desiredDifficulty     = (BeatmapDifficulty)playSong.Beatmap.Difficulty;

                var playerData     = Resources.FindObjectsOfTypeAll <PlayerDataModel>().First().playerData;
                var playerSettings = playerData.playerSpecificSettings;

                //Override defaults if we have forced options enabled
                if (playSong.PlayerSettings.Options != PlayerOptions.None)
                {
                    playerSettings                = new PlayerSpecificSettings();
                    playerSettings.leftHanded     = playSong.PlayerSettings.Options.HasFlag(PlayerOptions.LeftHanded);
                    playerSettings.staticLights   = playSong.PlayerSettings.Options.HasFlag(PlayerOptions.StaticLights);
                    playerSettings.noTextsAndHuds = playSong.PlayerSettings.Options.HasFlag(PlayerOptions.NoHud);
                    playerSettings.advancedHud    = playSong.PlayerSettings.Options.HasFlag(PlayerOptions.AdvancedHud);
                    playerSettings.reduceDebris   = playSong.PlayerSettings.Options.HasFlag(PlayerOptions.ReduceDebris);
                }

                var gameplayModifiers = new GameplayModifiers();
                gameplayModifiers.batteryEnergy      = playSong.GameplayModifiers.Options.HasFlag(GameOptions.BatteryEnergy);
                gameplayModifiers.disappearingArrows = playSong.GameplayModifiers.Options.HasFlag(GameOptions.DisappearingArrows);
                gameplayModifiers.failOnSaberClash   = playSong.GameplayModifiers.Options.HasFlag(GameOptions.FailOnClash);
                gameplayModifiers.fastNotes          = playSong.GameplayModifiers.Options.HasFlag(GameOptions.FastNotes);
                gameplayModifiers.ghostNotes         = playSong.GameplayModifiers.Options.HasFlag(GameOptions.GhostNotes);
                gameplayModifiers.instaFail          = playSong.GameplayModifiers.Options.HasFlag(GameOptions.InstaFail);
                gameplayModifiers.noBombs            = playSong.GameplayModifiers.Options.HasFlag(GameOptions.NoBombs);
                gameplayModifiers.noFail             = playSong.GameplayModifiers.Options.HasFlag(GameOptions.NoFail);
                gameplayModifiers.noObstacles        = playSong.GameplayModifiers.Options.HasFlag(GameOptions.NoObstacles);
                gameplayModifiers.noArrows           = playSong.GameplayModifiers.Options.HasFlag(GameOptions.NoArrows);

                if (playSong.GameplayModifiers.Options.HasFlag(GameOptions.SlowSong))
                {
                    gameplayModifiers.songSpeed = GameplayModifiers.SongSpeed.Slower;
                }
                if (playSong.GameplayModifiers.Options.HasFlag(GameOptions.FastSong))
                {
                    gameplayModifiers.songSpeed = GameplayModifiers.SongSpeed.Faster;
                }

                var colorScheme = playerData.colorSchemesSettings.overrideDefaultColors ? playerData.colorSchemesSettings.GetSelectedColorScheme() : null;

                PlaySong?.Invoke(desiredLevel, desiredCharacteristic, desiredDifficulty, gameplayModifiers, playerSettings, playerData.overrideEnvironmentSettings, colorScheme, playSong.FloatingScoreboard, playSong.StreamSync, playSong.DisablePause, playSong.DisableFail);
            }
            else if (packet.Type == PacketType.Command)
            {
                Command command = packet.SpecificPacket as Command;
                if (command.CommandType == Command.CommandTypes.ReturnToMenu)
                {
                    if (SyncHandler.Instance != null)
                    {
                        ScreenOverlay.Instance.Clear();
                    }
                    if ((Self as Player).PlayState == Player.PlayStates.InGame)
                    {
                        PlayerUtils.ReturnToMenu();
                    }
                }
                else if (command.CommandType == Command.CommandTypes.ScreenOverlay_ShowPng)
                {
                    ScreenOverlay.Instance.ShowPng();
                }
                else if (command.CommandType == Command.CommandTypes.DelayTest_Finish)
                {
                    UnityMainThreadDispatcher.Instance().Enqueue(() => {
                        ScreenOverlay.Instance.Clear();
                        SyncHandler.Instance.Resume();
                        SyncHandler.Destroy();
                    });
                }
            }
            else if (packet.Type == PacketType.LoadSong)
            {
                LoadSong loadSong = packet.SpecificPacket as LoadSong;

                Action <IBeatmapLevel> SongLoaded = (loadedLevel) =>
                {
                    //Send updated download status
                    (Self as Player).DownloadState = Player.DownloadStates.Downloaded;

                    var playerUpdate = new Event();
                    playerUpdate.Type          = Event.EventType.PlayerUpdated;
                    playerUpdate.ChangedObject = Self;
                    Send(new Packet(playerUpdate));

                    //Notify any listeners of the client that a song has been loaded
                    LoadedSong?.Invoke(loadedLevel);

                    Logger.Debug($"SENT DOWNLOADED SIGNAL {(playerUpdate.ChangedObject as Player).DownloadState}");
                };

                if (OstHelper.IsOst(loadSong.LevelId))
                {
                    SongLoaded?.Invoke(SongUtils.masterLevelList.First(x => x.levelID == loadSong.LevelId) as BeatmapLevelSO);
                }
                else
                {
                    if (SongUtils.masterLevelList.Any(x => x.levelID == loadSong.LevelId))
                    {
                        SongUtils.LoadSong(loadSong.LevelId, SongLoaded);
                    }
                    else
                    {
                        Action <bool> loadSongAction = (succeeded) =>
                        {
                            if (succeeded)
                            {
                                SongUtils.LoadSong(loadSong.LevelId, SongLoaded);
                            }
                            else
                            {
                                (Self as Player).DownloadState = Player.DownloadStates.DownloadError;

                                var playerUpdated = new Event();
                                playerUpdated.Type          = Event.EventType.PlayerUpdated;
                                playerUpdated.ChangedObject = Self;

                                Send(new Packet(playerUpdated));

                                Logger.Debug($"SENT DOWNLOADED SIGNAL {(playerUpdated.ChangedObject as Player).DownloadState}");
                            }
                        };

                        (Self as Player).DownloadState = Player.DownloadStates.Downloading;

                        var playerUpdate = new Event();
                        playerUpdate.Type          = Event.EventType.PlayerUpdated;
                        playerUpdate.ChangedObject = Self;
                        Send(new Packet(playerUpdate));

                        Logger.Debug($"SENT DOWNLOAD SIGNAL {(playerUpdate.ChangedObject as Player).DownloadState}");

                        SongDownloader.DownloadSong(loadSong.LevelId, songDownloaded: loadSongAction, downloadProgressChanged: (progress) => Logger.Debug($"DOWNLOAD PROGRESS: {progress}"));
                    }
                }
            }
            else if (packet.Type == PacketType.File)
            {
                File file = packet.SpecificPacket as File;
                if (file.Intention == File.Intentions.SetPngToShowWhenTriggered)
                {
                    var pngBytes = file.Compressed ? CompressionUtils.Decompress(file.Data) : file.Data;
                    ScreenOverlay.Instance.SetPngBytes(pngBytes);
                }
                else if (file.Intention == File.Intentions.ShowPngImmediately)
                {
                    var pngBytes = file.Compressed ? CompressionUtils.Decompress(file.Data) : file.Data;
                    ScreenOverlay.Instance.SetPngBytes(pngBytes);
                    ScreenOverlay.Instance.ShowPng();
                }

                Send(packet.From, new Packet(new Acknowledgement()
                {
                    PacketId = packet.Id,
                    Type     = Acknowledgement.AcknowledgementType.FileDownloaded
                }));
            }
        }
예제 #13
0
        private void MockClient_PlaySong(Beatmap map)
        {
            if (OstHelper.IsOst(map.LevelId))
            {
                return;
            }

            var match = State.Matches.First(x => x.Players.Any(p => p.Id == Self.Id && p.Name == Self.Name));

            otherPlayersInMatch = match.Players.Select(x => x.Id).Union(new string[] { match.LeaderCase == Match.LeaderOneofCase.Coordinator ? match.Coordinator.Id : match.Player.Id }).Select(s => Guid.TryParse(s, out var g) ? g : Guid.Empty).ToArray();

            currentlyPlayingMap  = map;
            currentlyPlayingSong = new DownloadedSong(HashFromLevelId(map.LevelId));
            currentMaxScore      = 0;
            notesElapsed         = 0;

            /*using (var libVLC = new LibVLC())
             * {
             *  var media = new Media(libVLC, currentlyPlayingSong.GetAudioPath(), FromType.FromPath);
             *  await media.Parse();
             *
             *  songTimer = new Timer();
             *  songTimer.AutoReset = false;
             *  songTimer.Interval = media.Duration;
             *  songTimer.Elapsed += SongTimer_Elapsed;
             *
             *  noteTimer = new Timer();
             *  noteTimer.AutoReset = false;
             *  noteTimer.Interval = 500;
             *  noteTimer.Elapsed += NoteTimer_Elapsed;
             *
             *  noteTimer.Start();
             *  songTimer.Start();
             * }*/

            songTimer           = new Timer();
            songTimer.AutoReset = false;
            songTimer.Interval  = 60 * 3 * 1000;
            songTimer.Elapsed  += SongTimer_Elapsed;

            noteTimer           = new Timer();
            noteTimer.AutoReset = false;
            noteTimer.Interval  = 500;
            noteTimer.Elapsed  += NoteTimer_Elapsed;

            noteTimer.Start();
            songTimer.Start();

            var selfPlayer = SelfObject as Player;

            selfPlayer.PlayState = Player.Types.PlayStates.InGame;

            selfPlayer.Score        = 0;
            selfPlayer.Combo        = 0;
            selfPlayer.Accuracy     = 0;
            selfPlayer.SongPosition = 0;
            multiplier = 1;

            var playerUpdated = new Event
            {
                Type          = Event.Types.EventType.PlayerUpdated,
                ChangedObject = Google.Protobuf.WellKnownTypes.Any.Pack(selfPlayer)
            };

            Send(new Packet(playerUpdated));
        }
예제 #14
0
        public async Task LeaderboardsAsync()
        {
            if (!IsAdmin())
            {
                return;
            }

            string finalMessage = "Leaderboard:\n\n";

            if (Config.ServerFlags.HasFlag(ServerFlags.Teams))
            {
                foreach (var team in GetAllTeams())
                {
                    finalMessage += $"({team.TeamName})\n\n";

                    foreach (var song in GetAllScores(teamId: team.TeamId))
                    {
                        if (song.Scores.Count > 0) //Don't print if no one submitted scores
                        {
                            finalMessage += $"{song.Name} ({song.Scores.First().Difficulty}):\n";

                            int place = 1;
                            foreach (var score in song.Scores)
                            {
                                //Incredibly inefficient to open a song info file every time, but only the score structure is guaranteed to hold the real difficutly,
                                //seeing as auto difficulty is what would be represented in the songconstruct
                                string percentage = "???%";
                                if (!OstHelper.IsOst(song.SongHash))
                                {
                                    var maxScore = new BeatSaver.Song(song.SongHash).GetMaxScore(score.Characteristic, score.Difficulty);
                                    percentage = ((double)score.Score / maxScore).ToString("P", CultureInfo.InvariantCulture);
                                }

                                finalMessage += place + ": " + new Player(score.UserId).DiscordName + " - " + score.Score + $" ({percentage})" + (score.FullCombo ? " (Full Combo)" : "");
                                if (Config.ServerFlags.HasFlag(ServerFlags.Tokens))
                                {
                                    if (place == 1)
                                    {
                                        finalMessage += " (+3 Tokens)";
                                    }
                                    else if (place == 2)
                                    {
                                        finalMessage += " (+2 Tokens)";
                                    }
                                    else if (place == 3)
                                    {
                                        finalMessage += " (+1 Token)";
                                    }
                                }
                                finalMessage += "\n";
                                place++;
                            }
                            finalMessage += "\n";
                        }
                    }
                    finalMessage += "\n";
                }
            }
            else
            {
                List <SongConstruct> songs = GetActiveSongs(true);

                songs.ForEach(x =>
                {
                    string hash = x.SongHash;

                    if (x.Scores.Count > 0) //Don't print if no one submitted scores
                    {
                        var song      = new Song(hash, x.Difficulty, x.Characteristic);
                        finalMessage += song.SongName + ":\n";

                        int place = 1;
                        foreach (ScoreConstruct item in x.Scores)
                        {
                            //Incredibly inefficient to open a song info file every time, but only the score structure is guaranteed to hold the real difficutly,
                            //seeing as auto difficulty is what would be represented in the songconstruct
                            string percentage = "???%";
                            if (!OstHelper.IsOst(hash))
                            {
                                var maxScore = new BeatSaver.Song(hash).GetMaxScore(item.Characteristic, item.Difficulty);
                                percentage   = ((double)item.Score / maxScore).ToString("P", CultureInfo.InvariantCulture);
                            }

                            finalMessage += place + ": " + new Player(item.UserId).DiscordName + " - " + item.Score + $" ({percentage})" + (item.FullCombo ? " (Full Combo)" : "");
                            finalMessage += "\n";
                            place++;
                        }
                        finalMessage += "\n";
                    }
                });
            }

            //Deal with long messages
            if (finalMessage.Length > 2000)
            {
                for (int i = 0; finalMessage.Length > 2000; i++)
                {
                    await ReplyAsync(finalMessage.Substring(0, finalMessage.Length > 2000 ? 2000 : finalMessage.Length));

                    finalMessage = finalMessage.Substring(2000);
                }
            }
            await ReplyAsync(finalMessage);
        }