public UIManager( ServerManager serverManager, ClientManager clientManager, Game.Settings.GameSettings clientGameSettings, Game.Settings.GameSettings serverGameSettings, ModSettings modSettings, NetClient netClient ) { _modSettings = modSettings; // First we create a gameObject that will hold all other objects of the UI UiGameObject = new GameObject(); // Create event system object var eventSystemObj = new GameObject("EventSystem"); var eventSystem = eventSystemObj.AddComponent <EventSystem>(); eventSystem.sendNavigationEvents = true; eventSystem.pixelDragThreshold = 10; eventSystemObj.AddComponent <StandaloneInputModule>(); Object.DontDestroyOnLoad(eventSystemObj); // Make sure that our UI is an overlay on the screen UiGameObject.AddComponent <Canvas>().renderMode = RenderMode.ScreenSpaceOverlay; // Also scale the UI with the screen size var canvasScaler = UiGameObject.AddComponent <CanvasScaler>(); canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; canvasScaler.referenceResolution = new Vector2(1920f, 1080f); UiGameObject.AddComponent <GraphicRaycaster>(); Object.DontDestroyOnLoad(UiGameObject); PrecacheText(); var pauseMenuGroup = new UIGroup(false); var connectGroup = new UIGroup(parent: pauseMenuGroup); var clientSettingsGroup = new UIGroup(parent: pauseMenuGroup); var serverSettingsGroup = new UIGroup(parent: pauseMenuGroup); new ConnectUI( modSettings, clientManager, serverManager, connectGroup, clientSettingsGroup, serverSettingsGroup ); var inGameGroup = new UIGroup(); var infoBoxGroup = new UIGroup(parent: inGameGroup); InfoBox = new InfoBoxUI(infoBoxGroup); var pingGroup = new UIGroup(parent: inGameGroup); var pingUi = new PingUI( pingGroup, modSettings, clientManager, netClient ); new ClientSettingsUI( modSettings, clientGameSettings, clientManager, clientSettingsGroup, connectGroup, pingUi ); new ServerSettingsUI( serverGameSettings, modSettings, serverManager, serverSettingsGroup, connectGroup ); // Register callbacks to make sure the UI is hidden and shown at correct times On.HeroController.Pause += (orig, self) => { // Execute original method orig(self); // Only show UI in gameplay scenes if (!SceneUtil.IsNonGameplayScene(SceneUtil.GetCurrentSceneName())) { _canShowPauseUi = true; pauseMenuGroup.SetActive(!_isPauseUiHiddenByKeybind); } inGameGroup.SetActive(false); }; On.HeroController.UnPause += (orig, self) => { // Execute original method orig(self); pauseMenuGroup.SetActive(false); _canShowPauseUi = false; // Only show info box UI in gameplay scenes if (!SceneUtil.IsNonGameplayScene(SceneUtil.GetCurrentSceneName())) { inGameGroup.SetActive(true); } }; UnityEngine.SceneManagement.SceneManager.activeSceneChanged += (oldScene, newScene) => { if (SceneUtil.IsNonGameplayScene(newScene.name)) { eventSystem.enabled = false; _canShowPauseUi = false; pauseMenuGroup.SetActive(false); inGameGroup.SetActive(false); } else { eventSystem.enabled = true; inGameGroup.SetActive(true); } }; // The game is automatically unpaused when the knight dies, so we need // to disable the UI menu manually // TODO: this still gives issues, since it displays the cursor while we are supposed to be unpaused ModHooks.Instance.AfterPlayerDeadHook += () => { pauseMenuGroup.SetActive(false); }; MonoBehaviourUtil.Instance.OnUpdateEvent += () => { CheckKeybinds(pauseMenuGroup); }; }
public SettingsUIEntry( UIGroup uiGroup, Vector2 position, string name, Type type, object defaultValue, object currentValue, Action <object> applySetting, bool doubleLine = false, bool autoApply = false ) { _type = type; _defaultValue = defaultValue; _applySetting = applySetting; _doubleLine = doubleLine; new TextComponent( uiGroup, position + new Vector2(50, doubleLine ? -20 : 0), new Vector2(TextWidth, doubleLine ? 40 : 30), name, FontManager.UIFontRegular, 18, alignment: TextAnchor.LowerLeft ); if (type == typeof(byte)) { _input = new InputComponent( uiGroup, position - new Vector2(0, 35 + (doubleLine ? 25 : 0)), new Vector2(InputWidth, InputHeight), currentValue.ToString(), "", TextureManager.InputFieldBackground, FontManager.UIFontRegular, 18, InputField.CharacterValidation.Integer ); // TODO: make the constructor parameter "autoApply" work with integer input new TextComponent( uiGroup, position - new Vector2(0, 60 + (doubleLine ? 25 : 0)), new Vector2(InputWidth, 20), "default value: " + defaultValue, FontManager.UIFontRegular, alignment: TextAnchor.MiddleLeft ); } else if (type == typeof(bool)) { if (currentValue is bool currentChecked) { _checkbox = new CheckboxComponent( uiGroup, position - new Vector2(90, 30 + (doubleLine ? 25 : 0)), new Vector2(20, 20), currentChecked, TextureManager.ToggleBackground, TextureManager.Checkmark ); if (autoApply) { _checkbox.SetOnToggle(_ => { ApplySetting(); }); } } new TextComponent( uiGroup, position - new Vector2(-40, 30 + (doubleLine ? 25 : 0)), new Vector2(InputWidth, 20), "default value: " + defaultValue, FontManager.UIFontRegular, alignment: TextAnchor.MiddleLeft ); } else { throw new ArgumentException("Type of object is not supported"); } }
public InfoBoxUI(UIGroup infoBoxGroup) { _infoBoxGroup = infoBoxGroup; _messages = new TextComponent[MaxMessages]; }
private void CreateSettingsUI() { _settingsGroup.SetActive(false); const float pageYLimit = 250; var x = 1920f - 210.0f; var y = pageYLimit; const int boolMargin = 75; const int doubleBoolMargin = 100; const int intMargin = 100; const int doubleIntMargin = 125; var settingsUIEntries = new List <SettingsUIEntry>(); var pages = new Dictionary <int, UIGroup>(); var currentPage = 0; UIGroup currentPageGroup = null; foreach (var settingsEntry in _settingsEntries) { if (y <= pageYLimit) { currentPage++; currentPageGroup = new UIGroup(currentPage == 1, _settingsGroup); pages.Add(currentPage, currentPageGroup); y = 1080f - 75.0f; } var nameChars = settingsEntry.Name.ToCharArray(); var font = FontManager.UIFontRegular; var nameWidth = 0; foreach (var nameChar in nameChars) { font.GetCharacterInfo(nameChar, out var characterInfo, 18); nameWidth += characterInfo.advance; } var doubleLine = nameWidth >= SettingsUIEntry.TextWidth; settingsUIEntries.Add(new SettingsUIEntry( currentPageGroup, new Vector2(x, y), settingsEntry.Name, settingsEntry.Type, settingsEntry.DefaultValue, settingsEntry.InitialValue, settingsEntry.ApplySetting, doubleLine )); if (doubleLine) { y -= settingsEntry.Type == typeof(bool) ? doubleBoolMargin : doubleIntMargin; } else { y -= settingsEntry.Type == typeof(bool) ? boolMargin : intMargin; } } y = pageYLimit - 80; var nextPageButton = new ButtonComponent( _settingsGroup, new Vector2(x, y), "Next page" ); nextPageButton.SetOnPress(() => { // Disable old current page pages[_currentPage].SetActive(false); // Increment page if we can if (_currentPage < pages.Count) { _currentPage++; } // Enable new current page pages[_currentPage].SetActive(true); }); y -= 40; var previousPageButton = new ButtonComponent( _settingsGroup, new Vector2(x, y), "Previous page" ); previousPageButton.SetOnPress(() => { // Disable old current page pages[_currentPage].SetActive(false); // Decrement page if we can if (_currentPage > 1) { _currentPage--; } // Enable new current page pages[_currentPage].SetActive(true); }); y -= 40; var saveSettingsButton = new ButtonComponent( _settingsGroup, new Vector2(x, y), "Save settings" ); saveSettingsButton.SetOnPress(() => { // TODO: check if there are actually changes, otherwise this button will // bombard clients with packets foreach (var settingsUIEntry in settingsUIEntries) { settingsUIEntry.ApplySetting(); } _modSettings.GameSettings = _gameSettings; _serverManager.OnUpdateGameSettings(); }); y -= 40; new ButtonComponent( _settingsGroup, new Vector2(x, y), "Back" ).SetOnPress(() => { _settingsGroup.SetActive(false); _connectGroup.SetActive(true); }); }