private void OnModeSelection(FreePlayMode mode) { if (mode == FreePlayMode.Solo) { Logger.log.Debug("Selected solo free play mode"); _freePlayFlowCoordinator = FindObjectOfType <SoloFreePlayFlowCoordinator>(); (_freePlayFlowCoordinator as SoloFreePlayFlowCoordinator).didFinishEvent += OnFreePlayFlowCoordinatorFinished; PrepareLevelPackSelectedEvent(); if (!SongBrowserTweaks.ModLoaded) { UnityCoroutineHelper.StartDelayedAction(SelectSavedLevelPack); } else if (!SongBrowserTweaks.Initialized) { StartCoroutine(GetSongBrowserButtons()); } } else if (mode == FreePlayMode.Party) { Logger.log.Debug("Selected party free play mode"); _freePlayFlowCoordinator = FindObjectOfType <PartyFreePlayFlowCoordinator>(); (_freePlayFlowCoordinator as PartyFreePlayFlowCoordinator).didFinishEvent += OnFreePlayFlowCoordinatorFinished; PrepareLevelPackSelectedEvent(); if (!SongBrowserTweaks.ModLoaded) { UnityCoroutineHelper.StartDelayedAction(SelectSavedLevelPack); } else if (!SongBrowserTweaks.Initialized) { StartCoroutine(GetSongBrowserButtons()); } } else if (mode == FreePlayMode.Campaign) { Logger.log.Debug("Selected campaign play mode"); _freePlayFlowCoordinator = FindObjectOfType <CampaignFlowCoordinator>(); (_freePlayFlowCoordinator as CampaignFlowCoordinator).didFinishEvent += OnFreePlayFlowCoordinatorFinished; } // UIState in SongBrowser is always reset to Main, so we need to disable the filter button SongBrowserTweaks.DisableOtherFiltersButton(); }
public void HideScreen(bool immediately = false) { if (!_floatingScreen.gameObject.activeSelf) { return; } if (immediately) { _floatingScreen.transform.localScale = new Vector3(HiddenScale, HiddenScale, _floatingScreen.transform.localScale.z); (_floatingScreen.transform as RectTransform).sizeDelta = new Vector2(DefaultXSize, DefaultYSize); _floatingScreen.gameObject.SetActive(false); } else { _revealAnimation = UnityCoroutineHelper.Start(RevealAnimationCoroutine(HiddenScale, true)); } }
public static void OnHandleUnresolvedException(object sender, UnhandledExceptionEventArgs args) { if (args == null || args.ExceptionObject == null) { return; } var exception = args.ExceptionObject as Exception; if (exception != null) { Debug.Log("Unhandled exception: " + exception.ToString()); #if UNITY_IOS && !UNITY_EDITOR TrackErrorWithAttachments(exception); #else lock (_unhandledExceptions) { _unhandledExceptions.Enqueue(exception); } UnityCoroutineHelper.StartCoroutine(SendUnhandledExceptionReports); #endif } }
public static void OnHandleUnresolvedException(object sender, UnhandledExceptionEventArgs args) { if (args == null || args.ExceptionObject == null) { return; } var exception = args.ExceptionObject as Exception; if (exception != null) { Debug.Log("Unhandled exception: " + exception.ToString()); #if UNITY_ANDROID lock (_unhandledExceptions) { _unhandledExceptions.Enqueue(exception); } UnityCoroutineHelper.StartCoroutine(SendUnhandledExceptionReports); #else var exceptionWrapper = CreateWrapperException(exception); CrashesInternal.TrackException(exceptionWrapper.GetRawObject()); #endif } }
public void ShowScreen(bool immediately = false) { if (_floatingScreen.gameObject.activeSelf) { return; } if (immediately) { _floatingScreen.transform.localScale = new Vector3(DefaultScale, DefaultScale, _floatingScreen.transform.localScale.z); (_floatingScreen.transform as RectTransform).sizeDelta = new Vector2(DefaultXSize, DefaultYSize); _outlineImage.color = OutlineColour; _iconImage.color = Color.white; _text.color = Color.white; _floatingScreen.gameObject.SetActive(true); } else { _floatingScreen.gameObject.SetActive(true); _revealAnimation = UnityCoroutineHelper.Start(RevealAnimationCoroutine(DefaultScale)); } }
private void LevelPackSelected(LevelFilteringNavigationController navController, IAnnotatedBeatmapLevelCollection levelPack, GameObject noDataInfoPrefab, BeatmapCharacteristicSO preferredCharacteristic) { // ignore the first select event that's fired immediately after the user select the free play mode // this is done so we can select the saved last pack later // when the saved pack is selected, it will then call this function again for sorting/storing if (_isSelectingInitialLevelPack) { _lastPack = levelPack; _isSelectingInitialLevelPack = false; if (levelPack is IBeatmapLevelPack beatmapLevelPack) { Logger.log.Debug($"Storing '{beatmapLevelPack.packName}' (id = '{beatmapLevelPack.packID}') level pack as initial pack"); } else { Logger.log.Debug($"Storing '{levelPack.collectionName}' level collection as initial pack"); } return; } // in ConfirmDeleteButtonClicked, the call to SongCore.Loader.Instance.DeleteSong will reload the level packs // which causes the custom level pack to be re-selected. but, if filters are applied or level pack is sorted, // we want to reshow our own filtered/sorted level pack and not reset our UI, so we don't have to handle this event // this code is kinda smelly tbh, but can't do anything about it unless there are changes to SongCore else if (_isDeletingSongInModOwnedLevelPack) { return; } // when SongBrowser is enabled, we only need to store the pack for the WordPredictionEngine when using the search feature else if (SongBrowserTweaks.Initialized) { _lastPack = levelPack; SongBrowserTweaks.DisableOtherFiltersButton(); return; } if (levelPack.collectionName != FilteredLevelsLevelPack.CollectionName) { _lastPack = levelPack; // store level pack to PluginConfig var tabBarVC = LevelFilteringNavigationController.GetPrivateField <TabBarViewController>("_tabBarViewController"); var tabBarItems = tabBarVC.GetPrivateField <TabBarViewController.TabBarItem[]>("_items"); string lastLevelPackString = tabBarItems[tabBarVC.selectedCellNumber].title + PluginConfig.LastLevelPackIDSeparator; if (levelPack is IBeatmapLevelPack beatmapLevelPack) { lastLevelPackString += beatmapLevelPack.packID; Logger.log.Debug($"Storing '{beatmapLevelPack.packName}' (id = '{beatmapLevelPack.packID}') level pack as last pack"); } else { lastLevelPackString += levelPack.collectionName; Logger.log.Debug($"Storing '{levelPack.collectionName}' level collection as last pack"); } PluginConfig.LastLevelPackID = lastLevelPackString; // reapply sort mode if (!SongSortModule.IsDefaultSort) { _sortedLevelsLevelPack.SetupFromLevelCollection(levelPack); // since the level selection navigation controller shows a level pack using the same event that calls this function // and it technically isn't a guarantee that this function will run after it is set, // delay setting our level pack UnityCoroutineHelper.StartDelayedAction(() => LevelSelectionNavigationController.SetData( _sortedLevelsLevelPack, true, LevelSelectionNavigationController.GetPrivateField <bool>("_showPlayerStatsInDetailView"), LevelSelectionNavigationController.GetPrivateField <bool>("_showPracticeButtonInDetailView"))); } } // SongBrowser can now apply filters to OST levels and switch between different level packs // so our old behaviour of cancelling the filters is no longer needed // that being said, without SongBrowser, we are still going to cancel filters upon switching level packs // because i'd rather the player have to go into the FilterViewController, // so that it can check if all the beatmap details have been loaded if (FilterList.AnyApplied) { Logger.log.Debug("Another level pack has been selected, unapplying filters"); } UnapplyFilters(); if (_uiAdditions != null) { UnityCoroutineHelper.StartDelayedAction(_uiAdditions.RefreshPageButtons); } }
private void SelectSavedLevelPack() { string lastLevelPackString = PluginConfig.LastLevelPackID; int separatorPos = lastLevelPackString.IndexOf(PluginConfig.LastLevelPackIDSeparator); if (separatorPos < 0 || separatorPos + PluginConfig.LastLevelPackIDSeparator.Length >= lastLevelPackString.Length) { goto OnError; } string lastLevelPackCollectionTitle = lastLevelPackString.Substring(0, separatorPos); string lastLevelPackID = lastLevelPackString.Substring(separatorPos + PluginConfig.LastLevelPackIDSeparator.Length); TabBarViewController tabBarVC = LevelFilteringNavigationController.GetPrivateField <TabBarViewController>("_tabBarViewController"); TabBarViewController.TabBarItem[] tabBarItems = tabBarVC.GetPrivateField <TabBarViewController.TabBarItem[]>("_items"); if (tabBarItems == null) { goto OnError; } var item = tabBarItems.FirstOrDefault(x => x.title == lastLevelPackCollectionTitle); if (item == null) { goto OnError; } int itemIndex = Array.IndexOf(tabBarItems, item); if (itemIndex < 0) { goto OnError; } var tabBarDatas = LevelFilteringNavigationController.GetPrivateField <object[]>("_tabBarDatas"); if (itemIndex >= tabBarDatas.Length) { goto OnError; } var levelPacks = tabBarDatas[itemIndex].GetField <IAnnotatedBeatmapLevelCollection[]>("annotatedBeatmapLevelCollections"); if (levelPacks == null) { goto OnError; } IAnnotatedBeatmapLevelCollection levelPack = levelPacks.FirstOrDefault(x => x.collectionName == lastLevelPackID || (x is IBeatmapLevelPack && ((IBeatmapLevelPack)x).packID == lastLevelPackID)); if (levelPack == null) { goto OnError; } // this should trigger the LevelPackSelected() delegate and sort the level pack as well LevelFilteringNavigationController.SelectAnnotatedBeatmapLevelCollection(levelPack); // try to select last level as well string[] lastLevelData = PluginConfig.LastLevelID.Split(new string[] { PluginConfig.LastLevelIDSeparator }, StringSplitOptions.None); if (lastLevelData.Length != 3) { return; } // select last level on the next frame, since the sort mode reselection done in LevelPackSelected // will be delayed to the next frame and will cause the level to be deselected UnityCoroutineHelper.StartDelayedAction(delegate() { string levelID = lastLevelData[0]; if (levelPack.beatmapLevelCollection?.beatmapLevels == null) { return; } IPreviewBeatmapLevel level = levelPack.beatmapLevelCollection.beatmapLevels.FirstOrDefault(x => x.levelID == levelID); if (level != null) { SelectLevel(level); } else { // could not find level with levelID // either song was deleted or is a WIP level and was changed // try using song name and level author as fallback string songName = lastLevelData[1]; string levelAuthor = lastLevelData[2]; level = levelPack.beatmapLevelCollection.beatmapLevels.FirstOrDefault(x => x.songName == songName && x.levelAuthorName == levelAuthor); if (level != null) { SelectLevel(level); } } }, 2, false); return; OnError: SongSortModule.ResetSortMode(); if (ButtonPanel.IsSingletonAvailable) { ButtonPanel.instance.UpdateSortButtons(); } }
public BottomScreen() { _floatingScreen = FloatingScreen.CreateFloatingScreen(new Vector2(DefaultXSize, DefaultYSize), false, new Vector3(1.5f, 0.05f, 1.5f), Quaternion.Euler(50f, 0f, 0f)); (_floatingScreen.transform as RectTransform).pivot = new Vector2(1f, 0f); // this is needed to fix HoverHint position issues that occur because of the change in pivot done to the floating screen var wrapperCanvasGO = new GameObject("Wrapper", typeof(RectTransform), typeof(Canvas), typeof(VRGraphicRaycaster), typeof(SetMainCameraToCanvas)); var rt = wrapperCanvasGO.transform as RectTransform; rt.SetParent(_floatingScreen.transform, false); rt.anchorMin = Vector2.zero; rt.anchorMax = Vector2.one; rt.sizeDelta = Vector2.zero; var cameraSetter = wrapperCanvasGO.GetComponent <SetMainCameraToCanvas>(); cameraSetter.SetField("_canvas", wrapperCanvasGO.GetComponent <Canvas>()); cameraSetter.SetField("_mainCamera", Resources.FindObjectsOfTypeAll <MainCamera>().FirstOrDefault(camera => camera.camera?.stereoTargetEye != StereoTargetEyeMask.None) ?? Resources.FindObjectsOfTypeAll <MainCamera>().FirstOrDefault()); _outlineImage = new GameObject("Outline").AddComponent <Image>(); _outlineImage.color = OutlineColour; _outlineImage.material = UIUtilities.NoGlowMaterial; _outlineImage.type = Image.Type.Sliced; _outlineImage.sprite = Resources.FindObjectsOfTypeAll <Sprite>().LastOrDefault(x => x.name == "RoundRectSmallStroke"); _outlineImage.preserveAspect = true; _outlineImage.rectTransform.SetParent(wrapperCanvasGO.transform, false); _outlineImage.rectTransform.anchorMin = Vector2.zero; _outlineImage.rectTransform.anchorMax = Vector2.one; _outlineImage.rectTransform.sizeDelta = Vector2.zero; var hlg = new GameObject("HorizontalLayoutGroup").AddComponent <HorizontalLayoutGroup>(); hlg.spacing = 3.5f; hlg.padding = new RectOffset(2, 2, 1, 1); hlg.childAlignment = TextAnchor.MiddleCenter; hlg.childForceExpandWidth = false; hlg.childForceExpandHeight = false; rt = hlg.transform as RectTransform; rt.SetParent(wrapperCanvasGO.transform, false); rt.anchorMin = new Vector2(1f, 0f); rt.anchorMax = new Vector2(1f, 0f); rt.pivot = new Vector2(1f, 0f); rt.sizeDelta = new Vector2(DefaultXSize, DefaultYSize); // icon _iconImage = new GameObject("Icon").AddComponent <Image>(); _iconImage.material = UIUtilities.NoGlowMaterial; _iconImage.sprite = BSUIUtilities.LoadSpriteFromResources("EnhancedSearchAndFilters.Assets.bars.png"); _iconImage.preserveAspect = true; var le = _iconImage.gameObject.AddComponent <LayoutElement>(); le.preferredWidth = 4.5f; le.preferredHeight = 4.5f; _iconImage.rectTransform.SetParent(rt, false); // text _text = BeatSaberUI.CreateText(rt, "OPTIONS", Vector2.zero, Vector2.zero); _text.fontSize = 4.4f; _text.alignment = TextAlignmentOptions.Center; // this needs to be the last child, otherwise the outline image will capture all the controller raycasts first UIUtilities.ParseBSML("EnhancedSearchAndFilters.UI.Views.BottomScreen.BottomScreenView.bsml", wrapperCanvasGO, this); _hoverEventHandler = _floatingScreen.gameObject.AddComponent <EnterExitEventHandler>(); _hoverEventHandler.PointerEntered += delegate() { if (_revealAnimation != null) { return; } else if (_contractAnimation != null) { UnityCoroutineHelper.Stop(_contractAnimation); _contractAnimation = null; } _expandAnimation = UnityCoroutineHelper.Start(ExpandAnimationCoroutine()); }; _hoverEventHandler.PointerExited += delegate() { if (_revealAnimation != null) { return; } bool immediate = false; if (_expandAnimation != null) { UnityCoroutineHelper.Stop(_expandAnimation); _expandAnimation = null; immediate = true; } else if (_contractAnimation != null) { UnityCoroutineHelper.Stop(_contractAnimation); _contractAnimation = null; } _contractAnimation = UnityCoroutineHelper.Start(ContractAnimationCoroutine(immediate)); }; var sortModeTab = new SortModeTab(_container); sortModeTab.SortButtonPressed += () => SortButtonPressed?.Invoke(); sortModeTab.Visible = true; _currentTab = sortModeTab; _tabs[0] = sortModeTab; Logger.log.Notice($"finished constructor, currentTab?={_currentTab == null}"); HideScreen(true); }