private void DrawBgmTooltip(BgmInfo bgm) { ImGui.BeginTooltip(); ImGui.PushTextWrapPos(GuiScale(400f)); ImGui.TextColored(new Vector4(0, 1, 0, 1), "Song Info"); ImGui.TextWrapped($"Title: {bgm.Title}"); ImGui.TextWrapped(string.IsNullOrEmpty(bgm.Location) ? "Location: Unknown" : $"Location: {bgm.Location}"); if (!string.IsNullOrEmpty(bgm.AdditionalInfo)) { ImGui.TextWrapped($"Info: {bgm.AdditionalInfo}"); } ImGui.Text($"File path: {bgm.FilePath}"); ImGui.PopTextWrapPos(); ImGui.EndTooltip(); }
private void UpdateBgmDescription(ushort currentBgmId, BgmInfo currentBgm) { string songDescription = $"({currentBgmId}) {currentBgm.Title}"; string truncateFormat = "{0} ... (?)"; if (ImGui.CalcTextSize(songDescription).X < 280f) { _songDescription = songDescription; } else { string tmpDesc; int substring = songDescription.Length; do { tmpDesc = string.Format(truncateFormat, songDescription.Substring(0, substring--)); } while (ImGui.CalcTextSize(tmpDesc).X > 280f); _songDescription = tmpDesc; } }
private void DrawCreation() { if (!ImGui.BeginTabItem("Create")) { return; } ImGui.Text("This tab allows you to create a custom title screen."); ImGui.Text("It is recommended to use first-person view."); #if DEBUG ImGui.BeginChild("scrolling", new Vector2(0, GuiScale(400)), true, ImGuiWindowFlags.NoScrollbar); #else ImGui.BeginChild("scrolling", new Vector2(0, GuiScale(400)), true, ImGuiWindowFlags.NoScrollWithMouse | ImGuiWindowFlags.NoScrollbar); #endif bool stateInvalid; BgmInfo selectedBgm = new BgmInfo { Title = "Unknown", FilePath = "" }; Vector3 eyesPos = default; Vector3 lookAt = default; #if !DEBUG if (_clientState.LocalPlayer?.Position == null) { ImGui.TextColored(new Vector4(1f, 0f, 0f, 1f), "The current game state is invalid for creating a title screen."); stateInvalid = true; _nameEmpty = false; //hax } else #endif { ImGui.Text("Name of custom title screen:"); ImGui.SameLine(); ImGui.SetNextItemWidth(GuiScale(280f)); if (ImGui.InputText("##title_screen_name", ref _customTsName, 64)) { _nameEmpty = false; _nameContainsInvalidCharacters = false; _nameAlreadyExists = false; if (string.IsNullOrEmpty(_customTsName)) { _nameEmpty = true; } else if (_customTsName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0 || _customTsName.StartsWith("TE_")) { _nameContainsInvalidCharacters = true; } else { _titleScreenSavePath = Path.Combine(_titleScreenFolder, _customTsName + ".json"); if (File.Exists(_titleScreenSavePath) || _customTsName == "Random" || _customTsName == "Random (custom)") { _nameAlreadyExists = true; } } } stateInvalid = _nameAlreadyExists | _nameContainsInvalidCharacters | _nameEmpty; ImGui.Text("Logo setting:"); ImGui.SameLine(); if (_titleLogosCreate[_selectedLogoIndexCreate] != "Unspecified") { ImGui.SetNextItemWidth(GuiScale(263f)); } else { ImGui.SetNextItemWidth(GuiScale(368f)); } ImGui.Combo("##titleeditLogoSetting", ref _selectedLogoIndexCreate, _titleLogosCreate, _titleLogosCreate.Length); if (_titleLogosCreate[_selectedLogoIndexCreate] != "Unspecified") { ImGui.SameLine(); ImGui.Checkbox("Display logo", ref _selectedLogoVisibleCreate); } #if DEBUG ImGui.Text("Terri path:"); ImGui.SameLine(); ImGui.SetNextItemWidth(GuiScale(220f)); ImGui.InputText("##manualTerritype", ref _terriPath, 64); var search = _territoryPaths.Values.Where(row => row.Bg == _terriPath); var results = search as TerritoryType[] ?? search.ToArray(); if (results.Any()) { var val = results[0]; ImGui.SameLine(); ImGui.PushTextWrapPos(GuiScale(450f)); ImGui.TextWrapped($"{val.PlaceName.Value.Name}"); ImGui.PopTextWrapPos(); } #else if (!_territoryPaths.ContainsKey(_clientState.TerritoryType)) { ImGui.TextColored(new Vector4(1f, 0f, 0f, 1f), "The current territory is not valid for a title screen."); stateInvalid = true; } else { ImGui.Text($"Title screen zone: {_territoryPaths[_clientState.TerritoryType].PlaceName.Value.Name}"); } #endif eyesPos = EyesPos(_clientState.LocalPlayer?.Position ?? new Vector3 { X = 0, Y = 0, Z = 0 }); ImGui.Text($"Camera position: {eyesPos.X:F2}, {eyesPos.Y:F2}, {eyesPos.Z:F2}"); lookAt = LookAt(new Vector3(eyesPos.X, eyesPos.Y, eyesPos.Z)); ImGui.Text($"\"Fix-on\" position: {lookAt.X:F2}, {lookAt.Y:F2}, {lookAt.Z:F2}"); ImGui.Text("Title camera FOV (in-game FoV will not change)"); ImGui.SameLine(); ImGui.SetNextItemWidth(GuiScale(128f)); ImGui.SliderFloat("##customTsFovY", ref _fovY, 0.01f, 3f, "%.2f"); ImGui.SameLine(); if (ImGui.Button("Reset##resetFovY")) { _fovY = 1f; } // Weather var newType = _clientState.TerritoryType; if (newType != _lastTerritoryId) { _lastTerritoryId = newType; UpdateWeathers(newType); } byte currentWeather = _titleEdit.GetWeather(); ImGui.Text($"Current weather: {GetWeatherDescriptor(currentWeather)}"); ImGui.SameLine(); ImGui.SetCursorPosX(GuiScale(383f)); if (ImGui.Button("Set Current##weather")) { _inputIntWeatherId = currentWeather; _weatherId = currentWeather; if (_territoryWeathers != null) { for (int i = 0; i < _territoryWeathers.Length; i++) { if (_territoryWeathers[i] != _weatherId) { continue; } _selectedWeatherIndex = i; break; } } } ImGui.Text("Title zone weather:"); ImGui.SameLine(); #if !DEBUG if (_territoryWeathers == null || _territoryWeathers.Length == 0) #endif { ImGui.SetNextItemWidth(GuiScale(90)); if (ImGui.InputInt("##customTSweather", ref _inputIntWeatherId)) { _weatherId = _inputIntWeatherId; } } #if !DEBUG else { ImGui.SetNextItemWidth(GuiScale(332f)); if (ImGui.BeginCombo("##customTSweatherCombo", GetWeatherDescriptor(_territoryWeathers[_selectedWeatherIndex]))) { for (int i = 0; i < _territoryWeathers.Length; i++) { if (ImGui.Selectable(GetWeatherDescriptor(_territoryWeathers[i]))) { _selectedWeatherIndex = i; _weatherId = _territoryWeathers[_selectedWeatherIndex]; } } ImGui.EndCombo(); } } #endif if (_weatherId < 1 || _weatherId > 255 || !_weathers.ContainsKey((uint)_inputIntWeatherId)) { ImGui.SameLine(); ImGui.TextColored(new Vector4(1f, 0f, 0f, 1f), "(invalid)"); stateInvalid = true; } else if (_territoryWeathers == null || _territoryWeathers.Length == 0) { ImGui.SameLine(); ImGui.Text(GetWeatherDescriptor((ushort)_weatherId)); } // Music ushort currentBgmId = _titleEdit.GetSong(); var currentBgm = _bgmSheet.GetBgmInfo(currentBgmId); if (_lastBgmId != currentBgmId) { _lastBgmId = currentBgmId; UpdateBgmDescription(currentBgmId, currentBgm); } ImGui.Text("Current song:"); ImGui.SameLine(); ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(0.5f, 0.5f, 0.5f, 1)); ImGui.Text(_songDescription); ImGui.PopStyleColor(); if (ImGui.IsItemHovered()) { DrawBgmTooltip(currentBgm); } ImGui.SameLine(); ImGui.SetCursorPosX(GuiScale(383f)); if (ImGui.Button("Set Current##music")) { _selectedBgmId = currentBgmId; } ImGui.Text("Title zone music:"); ImGui.SameLine(); ImGui.SetNextItemWidth(GuiScale(150f)); ImGui.InputInt("##customTSmusic", ref _selectedBgmId); selectedBgm = _bgmSheet.GetBgmInfo((ushort)_selectedBgmId); if (ImGui.IsItemHovered()) { DrawBgmTooltip(selectedBgm); } ImGui.SameLine(); if (_selectedBgmId < 1 || currentBgm.Title == "Invalid") { ImGui.TextColored(new Vector4(1f, 0f, 0f, 1f), "(invalid)"); stateInvalid = true; } else { ImGui.TextWrapped($"{selectedBgm.Title}"); } // Time long etS = 0; unsafe { etS = FFXIVClientStructs.FFXIV.Client.System.Framework.Framework.Instance()->EorzeaTime; } var et = DateTimeOffset.FromUnixTimeSeconds(etS); ImGui.Text($"Current time: {et.Hour:D2}:{et.Minute:D2}"); ImGui.SameLine(); ImGui.SetCursorPosX(GuiScale(383f)); if (ImGui.Button("Set Current##time")) { _tsTimeHrs = et.Hour; _tsTimeMin = et.Minute; var scaled = _tsTimeMin / 60f * 100; _tsTimeOffset = (int)(_tsTimeHrs * 100 + scaled % 100); } ImGui.Text("Time:"); ImGui.SameLine(); float timeWidth = GuiScale(50f); ImGui.SetNextItemWidth(timeWidth); if (ImGui.InputInt("hrs", ref _tsTimeHrs, 0, 23)) { var scaled = _tsTimeMin / 60f * 100; _tsTimeOffset = (int)(_tsTimeHrs * 100 + scaled % 100); } ImGui.SameLine(); ImGui.SetNextItemWidth(timeWidth); if (ImGui.InputInt("mins", ref _tsTimeMin, 0, 59)) { var scaled = _tsTimeMin / 60f * 100; _tsTimeOffset = (int)(_tsTimeHrs * 100 + scaled % 100); } } #if DEBUG ImGui.Text($"_stateInvalid: {stateInvalid}"); ImGui.Text($"_nameEmpty: {_nameEmpty}"); ImGui.Text($"_fileWasCreatedRecently: {_fileWasCreatedRecently}"); ImGui.Text($"_nameAlreadyExists: {_nameAlreadyExists}"); ImGui.Text($"_nameContainsInvalidCharacters: {_nameContainsInvalidCharacters}"); #endif ImGui.EndChild(); if (_fileWasCreatedRecently) { ImGui.TextColored(new Vector4(0f, 1f, 0f, 1f), "Title screen created!"); ImGui.EndTabItem(); return; } if (_nameEmpty) { ImGui.TextColored(new Vector4(1f, 0f, 0f, 1f), "The title screen name is empty."); } if (_nameAlreadyExists) { ImGui.TextColored(new Vector4(1f, 0f, 0f, 1f), "A custom title screen already exists by this name."); } else if (_nameContainsInvalidCharacters) { ImGui.TextColored(new Vector4(1f, 0f, 0f, 1f), "Title must be a valid filename without extension."); } if (stateInvalid) { ImGui.EndTabItem(); return; } if (ImGui.Button("Generate")) { TitleEditScreen scr = new TitleEditScreen(); scr.Name = _customTsName; scr.Logo = _titleLogosCreate[_selectedLogoIndexCreate]; scr.DisplayLogo = _selectedLogoVisibleCreate; #if DEBUG scr.TerritoryPath = _terriPath; #else scr.TerritoryPath = _territoryPaths[_clientState.TerritoryType].Bg.ToString(); #endif scr.CameraPos = eyesPos; scr.FixOnPos = lookAt; scr.FovY = _fovY; scr.WeatherId = (byte)_weatherId; scr.TimeOffset = (ushort)_tsTimeOffset; scr.BgmPath = selectedBgm.FilePath; var text = JsonConvert.SerializeObject(scr, Formatting.Indented); bool createSuccess = false; try { File.WriteAllText(_titleScreenSavePath, text); EnumerateTitleScreenFiles(); createSuccess = true; } catch (Exception e) { PluginLog.LogError(e, "Error occurred saving title screen."); } if (createSuccess) { _nameAlreadyExists = true; _fileWasCreatedRecently = true; Task.Delay(2000).ContinueWith(_ => _fileWasCreatedRecently = false); } } ImGui.EndTabItem(); }