Example #1
0
        ////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Build cell
        /// </summary>
        /// <param name="p_TableView">Table view instance</param>
        /// <param name="p_Index">Cell index</param>
        /// <returns></returns>
        public HMUI.TableCell CellForIdx(HMUI.TableView p_TableView, int p_Index)
        {
            LevelListTableCell l_Cell = GetTableCell();

            TextMeshProUGUI l_Text    = l_Cell.GetField <TextMeshProUGUI, LevelListTableCell>("_songNameText");
            TextMeshProUGUI l_SubText = l_Cell.GetField <TextMeshProUGUI, LevelListTableCell>("_songAuthorText");

            l_Cell.GetField <UnityEngine.UI.Image, LevelListTableCell>("_favoritesBadgeImage").gameObject.SetActive(false);

            var l_HoverHint = l_Cell.gameObject.GetComponent <HMUI.HoverHint>();

            if (l_HoverHint == null || !l_HoverHint)
            {
                l_HoverHint = l_Cell.gameObject.AddComponent <HMUI.HoverHint>();
                l_HoverHint.SetField("_hoverHintController", UnityEngine.Resources.FindObjectsOfTypeAll <HMUI.HoverHintController>().First());
            }

            if (l_Cell.gameObject.GetComponent <LocalizedHoverHint>())
            {
                UnityEngine.GameObject.Destroy(l_Cell.gameObject.GetComponent <LocalizedHoverHint>());
            }

            var l_SongEntry = Data[p_Index];

            l_SongEntry.Init();

            if ((l_SongEntry.BeatSaver_Map != null && !l_SongEntry.BeatSaver_Map.Partial) || l_SongEntry.CustomLevel != null)
            {
                var l_HaveSong = l_SongEntry.CustomLevel != null && SongCore.Loader.CustomLevels.ContainsKey(l_SongEntry.CustomLevel.customLevelPath);

                string l_MapName       = "";
                string l_MapAuthor     = "";
                string l_MapSongAuthor = "";
                float  l_Duration      = 0f;
                float  l_BPM           = 0f;

                if (l_SongEntry.CustomLevel != null)
                {
                    l_MapName       = l_SongEntry.CustomLevel.songName;
                    l_MapAuthor     = l_SongEntry.CustomLevel.levelAuthorName;
                    l_MapSongAuthor = l_SongEntry.CustomLevel.songAuthorName;
                    l_BPM           = l_SongEntry.CustomLevel.beatsPerMinute;
                    l_Duration      = l_SongEntry.CustomLevel.songDuration;
                }
                else
                {
                    var l_FirstDiff = l_SongEntry.BeatSaver_Map.Metadata.Characteristics.First().Difficulties.Where(x => x.Value.HasValue).LastOrDefault();

                    l_MapName       = l_SongEntry.BeatSaver_Map.Name;
                    l_MapAuthor     = l_SongEntry.BeatSaver_Map.Metadata.LevelAuthorName;
                    l_MapSongAuthor = l_SongEntry.BeatSaver_Map.Metadata.SongAuthorName;
                    l_BPM           = l_SongEntry.BeatSaver_Map.Metadata.BPM;
                    l_Duration      = l_FirstDiff.Value.Value.Length;
                }

                string l_Title    = l_SongEntry.TitlePrefix + (l_SongEntry.TitlePrefix.Length != 0 ? " " : "") + (l_HaveSong ? "<#7F7F7F>" : "") + l_MapName;
                string l_SubTitle = l_MapAuthor + " [" + l_MapSongAuthor + "]";

                if (l_Title.Length > (28 + (l_HaveSong ? "<#7F7F7F>".Length : 0)))
                {
                    l_Title = l_Title.Substring(0, 28 + (l_HaveSong ? "<#7F7F7F>".Length : 0)) + "...";
                }
                if (l_SubTitle.Length > 28)
                {
                    l_SubTitle = l_SubTitle.Substring(0, 28) + "...";
                }

                l_Text.text    = l_Title;
                l_SubText.text = l_SubTitle;

                var l_BPMText = l_Cell.GetField <TextMeshProUGUI, LevelListTableCell>("_songBpmText");
                l_BPMText.gameObject.SetActive(true);
                l_BPMText.text = ((int)l_BPM).ToString();

                var l_DurationText = l_Cell.GetField <TextMeshProUGUI, LevelListTableCell>("_songDurationText");
                l_DurationText.gameObject.SetActive(true);
                l_DurationText.text = l_Duration >= 0.0 ? $"{Math.Floor((double)l_Duration / 60):N0}:{Math.Floor((double)l_Duration % 60):00}" : "--";

                l_Cell.transform.Find("BpmIcon").gameObject.SetActive(true);

                if (l_SongEntry.Cover != null)
                {
                    l_Cell.GetField <UnityEngine.UI.Image, LevelListTableCell>("_coverImage").sprite = l_SongEntry.Cover;
                }
                else if (CoverCache.TryGetValue(l_SongEntry.GetLevelHash(), out var l_Cover))
                {
                    l_SongEntry.Cover = l_Cover;
                    l_Cell.GetField <UnityEngine.UI.Image, LevelListTableCell>("_coverImage").sprite = l_SongEntry.Cover;

                    OnCoverFetched?.Invoke(l_Cell.idx, l_SongEntry);
                }
                else
                {
                    l_Cell.GetField <UnityEngine.UI.Image, LevelListTableCell>("_coverImage").sprite = m_DefaultCover;

                    if (l_HaveSong)
                    {
                        var l_CoverTask = l_SongEntry.CustomLevel.GetCoverImageAsync(CancellationToken.None);
                        _ = l_CoverTask.ContinueWith(p_CoverTaskResult =>
                        {
                            if (l_Cell.idx >= Data.Count || l_SongEntry != Data[l_Cell.idx])
                            {
                                return;
                            }

                            Unity.MainThreadInvoker.Enqueue(() =>
                            {
                                /// Update infos
                                l_SongEntry.Cover = p_CoverTaskResult.Result;

                                /// Cache cover
                                if (!CoverCache.ContainsKey(l_SongEntry.GetLevelHash()))
                                {
                                    CoverCache.Add(l_SongEntry.GetLevelHash(), l_SongEntry.Cover);
                                }

                                if (l_Cell.idx < Data.Count && l_SongEntry == Data[l_Cell.idx])
                                {
                                    l_Cell.GetField <UnityEngine.UI.Image, LevelListTableCell>("_coverImage").sprite = l_SongEntry.Cover;
                                    l_Cell.RefreshVisuals();

                                    OnCoverFetched?.Invoke(l_Cell.idx, l_SongEntry);
                                }
                            });
                        });
                    }
                    else if (l_SongEntry.BeatSaver_Map != null)
                    {
                        /// Fetch cover
                        var l_CoverTask = l_SongEntry.BeatSaver_Map.FetchCoverImage();
                        _ = l_CoverTask.ContinueWith(p_CoverTaskResult =>
                        {
                            if (l_Cell.idx >= Data.Count || l_SongEntry != Data[l_Cell.idx])
                            {
                                return;
                            }

                            Unity.MainThreadInvoker.Enqueue(() =>
                            {
                                var l_Texture = Unity.Texture2D.CreateFromRaw(p_CoverTaskResult.Result);
                                if (l_Texture != null)
                                {
                                    l_SongEntry.Cover = UnityEngine.Sprite.Create(l_Texture, new UnityEngine.Rect(0, 0, l_Texture.width, l_Texture.height), new UnityEngine.Vector2(0.5f, 0.5f), 100);

                                    /// Cache cover
                                    if (!CoverCache.ContainsKey(l_SongEntry.GetLevelHash()))
                                    {
                                        CoverCache.Add(l_SongEntry.GetLevelHash(), l_SongEntry.Cover);
                                    }

                                    if (l_Cell.idx < Data.Count && l_SongEntry == Data[l_Cell.idx])
                                    {
                                        l_Cell.GetField <UnityEngine.UI.Image, LevelListTableCell>("_coverImage").sprite = l_SongEntry.Cover;
                                        l_Cell.RefreshVisuals();

                                        OnCoverFetched?.Invoke(l_Cell.idx, l_SongEntry);
                                    }
                                }
                            });
                        });
                    }
                }
            }
            else if (l_SongEntry.BeatSaver_Map != null && l_SongEntry.BeatSaver_Map.Partial)
            {
                l_Text.text    = "Loading from BeatSaver...";
                l_SubText.text = "";

                l_Cell.GetField <TextMeshProUGUI, LevelListTableCell>("_songBpmText").gameObject.SetActive(false);
                l_Cell.GetField <TextMeshProUGUI, LevelListTableCell>("_songDurationText").gameObject.SetActive(false);
                l_Cell.transform.Find("BpmIcon").gameObject.SetActive(false);

                l_Cell.GetField <UnityEngine.UI.Image, LevelListTableCell>("_coverImage").sprite = m_DefaultCover;
            }
            else
            {
                l_Text.text    = "<#FF0000>Invalid song";
                l_SubText.text = l_SongEntry.CustomLevel != null?l_SongEntry.CustomLevel.levelID.Replace("custom_level_", "") : "";

                l_Cell.GetField <TextMeshProUGUI, LevelListTableCell>("_songBpmText").gameObject.SetActive(false);
                l_Cell.GetField <TextMeshProUGUI, LevelListTableCell>("_songDurationText").gameObject.SetActive(false);
                l_Cell.transform.Find("BpmIcon").gameObject.SetActive(false);

                l_Cell.GetField <UnityEngine.UI.Image, LevelListTableCell>("_coverImage").sprite = m_DefaultCover;
            }

            if (!string.IsNullOrEmpty(l_SongEntry.HoverHint))
            {
                var l_HoverHintText = l_SongEntry.HoverHint;
                if (l_SongEntry.HoverHintTimeArg.HasValue && l_HoverHintText.Contains("$$time$$"))
                {
                    var l_Replace = "";
                    var l_Elapsed = Misc.Time.UnixTimeNow() - Misc.Time.ToUnixTime(l_SongEntry.HoverHintTimeArg.Value);
                    if (l_Elapsed < (60 * 60))
                    {
                        l_Replace = Math.Max(1, l_Elapsed / 60).ToString() + " minute(s) ago";
                    }
                    else if (l_Elapsed < (60 * 60 * 24))
                    {
                        l_Replace = Math.Max(1, l_Elapsed / (60 * 60)).ToString() + " hour(s) ago";
                    }
                    else
                    {
                        l_Replace = Math.Max(1, l_Elapsed / (60 * 60 * 24)).ToString() + " day(s) ago";
                    }

                    l_HoverHintText = l_HoverHintText.Replace("$$time$$", l_Replace);
                }

                l_HoverHint.enabled = true;
                l_HoverHint.text    = l_HoverHintText;
            }
            else
            {
                l_HoverHint.enabled = false;
            }

            return(l_Cell);
        }