public void SongStart(SongList.SongData song)
 {
     this.initialiseStateManagers();
     this.songCalculator = new SongLengthCalculator();
     this.songData       = song;
     this.songPlaying    = true;
 }
    private void EvaluateDifficulties(SongList.SongData songData)
    {
        var expertCues = SongCues.GetCues(songData, KataConfig.Difficulty.Expert);

        if (expertCues.Length > 0 && expertCues != null)
        {
            this.expert = new CalculatedDifficulty(expertCues, songData);
        }
        var advancedCues = SongCues.GetCues(songData, KataConfig.Difficulty.Hard);

        if (advancedCues.Length > 0 && advancedCues != null)
        {
            this.advanced = new CalculatedDifficulty(advancedCues, songData);
        }
        var standardCues = SongCues.GetCues(songData, KataConfig.Difficulty.Normal);

        if (standardCues.Length > 0 && standardCues != null)
        {
            this.standard = new CalculatedDifficulty(standardCues, songData);
        }
        var beginnerCues = SongCues.GetCues(songData, KataConfig.Difficulty.Easy);

        if (beginnerCues.Length > 0 && beginnerCues != null)
        {
            this.beginner = new CalculatedDifficulty(beginnerCues, songData);
        }
    }
예제 #3
0
        public static void SelectRandomSong()
        {
            if (currentSongsFull.Count == 0)
            {
                return;
            }

            if (currentSongs.Count == 0)
            {
                recentlySelected.Clear();
                FillSongList();
            }

            int songCount = currentSongs.Count;

            System.Random rand   = new System.Random();
            int           idx    = rand.Next(0, songCount);
            string        songID = currentSongs[idx];

            SongList.SongData data = SongList.I.GetSong(songID);
            if (data != null)
            {
                // remove from the random songs list
                currentSongs.RemoveAt(idx);
                if (recentlySelected.Count > historySize)
                {
                    recentlySelected.RemoveAt(0);
                }
                recentlySelected.Add(songID);

                SongDataHolder.I.songData = data;
                MenuState.I.GoToLaunchPage();
            }
        }
        private static SongList.SongData SearchSong(QueryData data, out bool foundExactMatch)
        {
            SongList.SongData song = null;
            bool foundAny          = false;
            bool foundBetter       = false;

            foundExactMatch = false;

            for (int i = 0; i < SongList.I.songs.Count; i++)
            {
                SongList.SongData currentSong = SongList.I.songs[i];
                if ((data.Artist == null || currentSong.artist.ToLowerInvariant().Replace(" ", "").Contains(data.Artist)) &&
                    (data.Mapper == null || currentSong.author.ToLowerInvariant().Replace(" ", "").Contains(data.Mapper)) &&
                    (currentSong.title.ToLowerInvariant().Contains(data.Title) ||
                     currentSong.songID.ToLowerInvariant().Contains(data.Title.Replace(" ", ""))))
                {
                    if (LookForMatch(data.Title, currentSong.title, ref foundAny, ref foundBetter, ref foundExactMatch))
                    {
                        song = currentSong;
                        if (foundExactMatch)
                        {
                            break;
                        }
                    }
                }
            }
            return(song);
        }
예제 #5
0
        public static void SelectRandomSong()
        {
            SongSelect select = GameObject.FindObjectOfType <SongSelect>();

            if (select == null)
            {
                return;
            }
            List <SongSelectItem> songs = select.GetSongButtons();

            if (songs.Count == 0)
            {
                return;
            }

            int songCount = songs.Count;

            System.Random rand = new System.Random();
            int           idx  = rand.Next(0, songCount);

            SongList.SongData data = songs[idx].mSongData;
            if (data != null)
            {
                SongDataHolder.I.songData = data;
                MenuState.I.GoToLaunchPage();
            }
        }
예제 #6
0
 public DifficultyCalculator(SongList.SongData songData)
 {
     if (songData == null)
     {
         return;
     }
     this.songID = songData.songID;
     EvaluateDifficulties(songData);
 }
 public void EvaluateCues(SongCues.Cue[] cues, SongList.SongData songData)
 {
     this.length = AudioDriver.TickSpanToMs(songData, cues[0].tick, cues[cues.Length - 1].tick);
     SplitCues(cues);
     CalculateSpacing();
     CalculateDensity();
     CalculateReadability();
     difficultyRating = ((spacing + readability) / length) * 500f + (length / 100000f * lengthMultiplier);
 }
예제 #8
0
 public static int GetFirstTick()
 {
     if (cachedFirstTick == 0)
     {
         SongList.SongData     songData = SongDataHolder.I.songData;
         KataConfig.Difficulty diff     = KataConfig.I.GetDifficulty();
         cachedFirstTick = SongCues.GetCues(songData, diff)[0].tick;
     }
     return(cachedFirstTick);
 }
        public static IEnumerator ChangeNamesDS(DifficultySelect __instance)
        {
            yield return(new WaitForSeconds(0.05f));

            SongList.SongData song = SongDataHolder.I.songData;

            ChangeSpecificDifficulty(ref song, __instance.expert.label, difficultyNameToTag["Expert"]);
            ChangeSpecificDifficulty(ref song, __instance.hard.label, difficultyNameToTag["Advanced"]);
            ChangeSpecificDifficulty(ref song, __instance.normal.label, difficultyNameToTag["Moderate"]);
            ChangeSpecificDifficulty(ref song, __instance.easy.label, difficultyNameToTag["Beginner"]);
        }
        public static IEnumerator ChangeNamesLP(LaunchPanel __instance)
        {
            yield return(new WaitForSeconds(0.05f));

            SongList.SongData song = SongDataHolder.I.songData;

            ChangeSpecificDifficulty(ref song, __instance.expert.GetComponentInChildren <TextMeshPro>(), difficultyNameToTag["Expert"]);
            ChangeSpecificDifficulty(ref song, __instance.hard.GetComponentInChildren <TextMeshPro>(), difficultyNameToTag["Advanced"]);
            ChangeSpecificDifficulty(ref song, __instance.normal.GetComponentInChildren <TextMeshPro>(), difficultyNameToTag["Moderate"]);
            ChangeSpecificDifficulty(ref song, __instance.easy.GetComponentInChildren <TextMeshPro>(), difficultyNameToTag["Beginner"]);
        }
예제 #11
0
 private static void Postfix(SongSelectItem __instance)
 {
     SongList.SongData currentSong = SongDataHolder.I.songData;
     AudicaRPC.Presence.state          = currentSong.artist;
     AudicaRPC.Presence.details        = currentSong.title;
     AudicaRPC.Presence.startTimestamp = default(long);
     AudicaRPC.Presence.largeImageKey  = "audica_main";
     AudicaRPC.Presence.largeImageText = "Audica";
     AudicaRPC.Presence.smallImageKey  = "expert";
     AudicaRPC.Presence.smallImageText = "Expert difficulty";
     DiscordRpc.UpdatePresence(AudicaRPC.Presence);
 }
예제 #12
0
        public static void UpdateUiInfo(SongList.SongData data)
        {
            songInfo.text        = Utility.RemoveFormatting($"{data.artist} - {data.title}");
            mapperInfo.text      = data.author;
            difficultyLabel.text = kataConfig.mDifficulty.ToString();

            var scoreKeeper = ScoreKeeper.I;

            scoreText.text = scoreKeeper.GetScore().ToString("N0", CultureInfo.CreateSpecificCulture("en-US"));
            comboText.text = scoreKeeper.mStreak > 1 ? scoreKeeper.mStreak.ToString() + " Streak!" : "";

            int aimAssistPercent = (int)(PlayerPreferences.I.AimAssistAmount.mVal * 100f);

            aimAssistLabel.text = aimAssistPercent != 100 ? $"{aimAssistPercent}% AA" : "";
            ModifierText.text   = Utility.GetModText();
        }
예제 #13
0
        private string GetSongName(string song)
        {
            string fileName = song + ".audica";

            if (PlaylistManager.internalSongList.Any(s => Path.GetFileName(s.zipPath) == fileName))
            {
                SongList.SongData _song = PlaylistManager.internalSongList.First(s => Path.GetFileName(s.zipPath) == fileName);
                SetSongDownloaded(song, true);
                return(_song.title + " - " + _song.author);
            }
            else
            {
                SetSongDownloaded(song, false);
                return(song);
            }
        }
예제 #14
0
        public static void OnSelect(IntPtr @this)
        {
            AudicaRPC.SongSelectItem_OnSelect.InvokeOriginal(@this);
            MelonModLogger.Log("Song Selected!");

            SongList.SongData currentSong = SongDataHolder.I.songData;

            Presence.state          = currentSong.artist;
            Presence.details        = currentSong.title;
            Presence.startTimestamp = default(long);
            Presence.largeImageKey  = "audica_main";
            Presence.largeImageText = "Audica";
            Presence.smallImageKey  = "expert";
            Presence.smallImageText = "Expert difficulty";
            DiscordRpc.UpdatePresence(Presence);
        }
        private static void ChangeSpecificDifficulty(ref SongList.SongData song, TextMeshPro label, string difficultyTag)
        {
            bool hasCustom = SongDataLoader.AllSongData[song.songID].HasCustomData();

            if (hasCustom && SongDataLoader.AllSongData[song.songID].SongHasCustomDataKey(difficultyTag))
            {
                string text = SongDataLoader.AllSongData[song.songID].GetCustomData <string>(difficultyTag);
                if (text.Length > 0)
                {
                    label.SetText(text);
                }
            }
            else
            {
                label.SetText(difficultyTagToName[difficultyTag]);
            }
        }
        public static void ProcessQueue()
        {
            bool addedAny = false;

            MelonLogger.Log(requestQueue.Count + " in queue.");

            if (requestQueue.Count != 0)
            {
                foreach (string str in requestQueue)
                {
                    QueryData         data   = new QueryData(str);
                    SongList.SongData result = SearchSong(data, out bool foundExactMatch);

                    if ((!hasCompatibleSongBrowser || foundExactMatch) && result != null)
                    {
                        // if we have web search we want to make sure we prioritize exact matches
                        // over partial local ones
                        MelonLogger.Log("Result: " + result.songID);
                        if (!requestList.Contains(result.songID))
                        {
                            requestList.Add(result.songID);
                            addedAny = true;
                        }
                    }
                    else if (hasCompatibleSongBrowser)
                    {
                        StartWebSearch(data);
                    }
                    else
                    {
                        MelonLogger.Log($"Found no match for \"{str}\"");
                    }
                }
                requestQueue.Clear();
            }

            if (addedAny && MenuState.GetState() == MenuState.State.SongPage)
            {
                RequestUI.UpdateFilter();
            }

            RequestUI.UpdateButtonText();
        }
예제 #17
0
        private static void Postfix(AudioDriver __instance)
        {
            if (!Config.Enabled)
            {
                return;
            }
            SongCues.Cue[]    cues = SongCues.I.GetCues();
            SongList.SongData song = SongList.I.GetSong(SongDataHolder.I.songData.songID);
            SongList.SongData.TempoChange[] tempos = song.tempos;

            for (int i = 0; i < tempos.Length; i++)
            {
                float timingWindowMs = 200 * Mathf.Lerp(0.07f, 1.0f, percent);

                float ticks     = timingWindowMs / (60000 / (tempos[i].tempo * 480));
                float halfTicks = ticks / 2;

                for (int j = 0; j < cues.Length; j++)
                {
                    if (cues[j].behavior != Target.TargetBehavior.Chain && cues[j].behavior != Target.TargetBehavior.Dodge && cues[j].behavior != Target.TargetBehavior.Melee)
                    {
                        void UpdateTarget(SongCues.Cue cue)
                        {
                            cue.slopAfterTicks  = halfTicks;
                            cue.slopBeforeTicks = halfTicks;
                        }

                        if (cues[j].tick >= tempos[i].tick)
                        {
                            if (tempos.Length >= tempos.Length + 1 && cues[j].tick < tempos[i + 1].tick)
                            {
                                UpdateTarget(cues[j]);
                            }
                            else if (tempos.Length < tempos.Length + 1)
                            {
                                UpdateTarget(cues[j]);
                            }
                        }
                    }
                }
            }
        }
예제 #18
0
        public static void Search()
        {
            searchResult.Clear();
            searchInProgress = false;

            if (query == null)
            {
                return;
            }

            for (int i = 0; i < SongList.I.songs.Count; i++)
            {
                SongList.SongData currentSong = SongList.I.songs[i];
                bool isCustom = Utility.IsCustomSong(currentSong.songID);

                if ((mapType == MapType.CustomsOnly && !isCustom) ||
                    (mapType == MapType.OfficialOnly && isCustom))
                {
                    continue;
                }

                if (currentSong.songID == "tutorial")
                {
                    continue; // never return the tutorial as result
                }
                string cleanQuery = CleanForSearch(query);

                if (CleanForSearch(currentSong.artist).Contains(cleanQuery) ||
                    CleanForSearch(currentSong.title).Contains(cleanQuery) ||
                    CleanForSearch(currentSong.songID).Contains(cleanQuery) ||
                    currentSong.author != null && CleanForSearch(currentSong.author).Contains(cleanQuery) ||
                    CleanForSearch(currentSong.artist).Replace(" ", "").Contains(cleanQuery) ||
                    CleanForSearch(currentSong.title).Replace(" ", "").Contains(cleanQuery))
                {
                    searchResult.Add(currentSong.songID);
                }
            }
        }
예제 #19
0
        private void Precalc()
        {
            this.song = SongDataHolder.I.songData;

            UnhollowerBaseLib.Il2CppReferenceArray <SongCues.Cue> cues = AudicaGameStateManager.songCues.mCues.cues;
            SongCues.Cue endCue  = cues[cues.Length - 1];
            float        endTick = endCue.tick + endCue.tickLength;

            this.songLengthMs = 0;

            for (int i = 0; i < song.tempos.Length; i++)
            {
                float startChunkTick = song.tempos[i].tick;
                float endChunkTick   = endTick;

                // if it's NOT the last tempo change, grab the tick from the next one instead.
                if (i != song.tempos.Length - 1)
                {
                    endChunkTick = song.tempos[i + 1].tick;
                }

                // complete chunk length in ticks
                float chunkTickLength = endChunkTick - startChunkTick;

                // ms accumulator
                float chunkMilliseconds = GetTicksMillisconds(chunkTickLength, song.tempos[i].tempo);
                this.songLengthMs += chunkMilliseconds;

                // cache
                ChunkCache chunk = new ChunkCache();
                chunk.startTick = startChunkTick;
                chunk.endTick   = endChunkTick;
                chunk.lengthMs  = chunkMilliseconds;
                this.chunkCache.Add(chunk);
            }
        }
 public CalculatedDifficulty(SongCues.Cue[] cues, SongList.SongData songData)
 {
     EvaluateCues(cues, songData);
 }
 public DifficultyCalculator(SongList.SongData songData)
 {
     this.songID = songData.songID;
     EvaluateDifficulties(songData);
 }
예제 #22
0
        //The process to update a LeaderboardRow
        public static void UpdateLeaderboardRow(LeaderboardRow leaderboardRow)
        {
            //DoWork function is really intensive so it's called only when absolutely required
            //This function will calculate the total max possible score for either OST or with extras
            void DoWork(bool e)
            {
                Il2CppSystem.Collections.Generic.List <SongList.SongData> songs = SongList.I.songs;

                int totalMaxScore = 0;

                for (int i = 0; i < songs.Count; i++)
                {
                    SongList.SongData song = songs[i];
                    if (e)
                    {
                        if (song.dlc | song.unlockable)
                        {
                            totalMaxScore += starThresholds.GetMaxRawScore(song.songID, KataConfig.Difficulty.Expert);
                        }
                    }
                    if (song.dlc == false && song.unlockable == false && song.extrasSong == false)
                    {
                        totalMaxScore += starThresholds.GetMaxRawScore(song.songID, KataConfig.Difficulty.Expert);
                    }
                }
                if (e)
                {
                    extrasMaxTotalScore = totalMaxScore;
                }
                else
                {
                    ostMaxTotalScore = totalMaxScore;
                }
            }

            float score = Convert.ToSingle(leaderboardRow.mData.score.Split('.')[0]);
            float percentage;

            if (menuState != MenuState.State.MainPage)
            {
                percentage = GetScorePercentage(selectedSong, score, KataConfig.Difficulty.Expert);
            }
            else
            {
                LeaderboardDisplay leaderboardDisplay = UnityEngine.Object.FindObjectOfType <LeaderboardDisplay>();
                bool extras = leaderboardDisplay.extrasButton.IsChecked.Invoke();
                DoWork(extras);

                if (extras)
                {
                    if (extrasMaxTotalScore == 0)
                    {
                        DoWork(extras);
                    }
                    percentage = (score / extrasMaxTotalScore) * 100;
                }
                else
                {
                    if (ostMaxTotalScore == 0)
                    {
                        DoWork(extras);
                    }
                    percentage = (score / ostMaxTotalScore) * 100;
                }
            }

            //Make pretty-ish strings
            leaderboardRow.username.text = "<size=" + leaderboardUsernameSize + ">" + leaderboardRow.username.text + "</size>";
            string scoreString      = "<size=" + leaderboardHighScoreSize + ">" + String.Format("{0:n0}", score).Replace(",", " ") + "</size>";
            string percentageString = "<size=" + leaderboardPercentSize + "> (" + String.Format("{0:0.00}", percentage) + "%)</size>";

            //Update label
            if (leaderboardRow.score.text.Contains("<color=yellow>"))
            {
                leaderboardRow.score.text = "<color=" + leaderboardUserColor + ">" + scoreString + percentageString + "</color>";
            }
            else
            {
                leaderboardRow.score.text = scoreString + percentageString;
            }

            if (leaderboardRow.rank.text.Contains("<color=yellow>"))
            {
                leaderboardRow.rank.text = leaderboardRow.rank.text.Replace("<color=yellow>", "<color=" + leaderboardUserColor + ">");
            }

            if (leaderboardRow.username.text.Contains("<color=yellow>"))
            {
                leaderboardRow.username.text = leaderboardRow.username.text.Replace("<color=yellow>", "<color=" + leaderboardUserColor + ">");
            }
        }
        private static void ProcessWebSearchResult(string query, APISongList response)
        {
            QueryData data            = webSearchQueryData[query];
            bool      addedLocalMatch = false;

            if (response.song_count > 0)
            {
                Song bestMatch   = null;
                bool foundAny    = false;
                bool foundBetter = false;
                bool foundExact  = false;
                foreach (Song s in response.songs)
                {
                    if ((data.Artist == null || s.artist.ToLowerInvariant().Replace(" ", "").Contains(data.Artist)) &&
                        (data.Mapper == null || s.author.ToLowerInvariant().Replace(" ", "").Contains(data.Mapper)) &&
                        (s.title.ToLowerInvariant().Contains(data.Title) ||
                         s.song_id.ToLowerInvariant().Contains(data.Title.Replace(" ", ""))))
                    {
                        if (LookForMatch(data.Title, s.title, ref foundAny, ref foundBetter, ref foundExact))
                        {
                            bestMatch = s;
                            if (foundExact)
                            {
                                break;
                            }
                        }
                    }
                }
                if (bestMatch != null)
                {
                    // check if we already have that file downloaded
                    QueryData         matchData = new QueryData($"{bestMatch.title} -artist {bestMatch.artist} -mapper {bestMatch.author}");
                    SongList.SongData s         = SearchSong(matchData, out bool isExactMatch);
                    if (isExactMatch)
                    {
                        MelonLogger.Log("Result: " + s.songID);
                        if (!requestList.Contains(s.songID))
                        {
                            requestList.Add(s.songID);
                            addedLocalMatch = true;
                        }
                    }
                    else if (!missingSongs.ContainsKey(bestMatch.song_id))
                    {
                        missingSongs.Add(bestMatch.song_id, bestMatch);
                        MelonLogger.Log("Result (missing): " + bestMatch.song_id);
                    }
                }
                else
                {
                    MelonLogger.Log($"Found no match for \"{data.FullQuery}\"");
                }
            }
            else
            {
                // check if we have a local match (can happen if
                // this particular map hasn't been uploaded or was taken down)
                SongList.SongData s = SearchSong(data, out bool _);
                if (s != null)
                {
                    MelonLogger.Log("Result: " + s.songID);
                    if (!requestList.Contains(s.songID))
                    {
                        requestList.Add(s.songID);
                        addedLocalMatch = true;
                    }
                }
                else
                {
                    MelonLogger.Log($"Found no match for \"{data.FullQuery}\"");
                }
            }

            if (addedLocalMatch && MenuState.GetState() == MenuState.State.SongPage)
            {
                RequestUI.UpdateFilter();
            }

            webSearchQueryData.Remove(query);
            if (GetActiveWebSearchCount() == 0)
            {
                RequestUI.UpdateButtonText();
            }
        }