using Gallop; using SFB; using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; public class UmaViewerUI : MonoBehaviour { public static UmaViewerUI Instance; private UmaViewerMain Main => UmaViewerMain.Instance; private UmaViewerBuilder Builder => UmaViewerBuilder.Instance; public CanvasScaler canvasScaler; [Header("normal models")] public ScrollRect CharactersList; public ScrollRect MobCharactersList; public PageManager MobCharactersPageCtrl; public ScrollRect CostumeList; public ScrollRect MobCostumeList; public ScrollRect AnimationSetList; public ScrollRect AnimationList; public PageManager AnimationPageCtrl; [Header("mini models")] public ScrollRect MiniCharactersList; public ScrollRect MiniCostumeList; public ScrollRect MiniAnimationSetList; public ScrollRect MiniAnimationList; public PageManager MiniAnimationPageCtrl; [Header("other")] public ScrollRect PropList; public PageManager PropPageCtrl; public ScrollRect SceneList; public ScrollRect MaterialsList; public PageManager ScenePageCtrl; public ScrollRect MessageScrollRect; public Text MessageText; [Header("lists")] public ScrollRect EmotionList; public Transform FacialList; public ScrollRect EarList; public ScrollRect EyeBrowList; public ScrollRect EyeList; public ScrollRect MouthList; public ScrollRect OtherList; public ScrollRect LiveList; public ScrollRect LiveSoundList; public ScrollRect LiveCharaSoundList; public ScrollRect NormalSoundList; public ScrollRect NormalSubSoundList; public PageManager NormalSoundCtrl; [Header("audio")] public Slider AudioSlider; public Button AudioPlayButton; public TextMeshProUGUI TitleText; public TextMeshProUGUI ProgressText; public Text LyricsText; [Header("animations")] public Slider AnimationSlider; public Slider AnimationSpeedSlider; public Button AnimationPlayButton; public TextMeshProUGUI AnimationTitleText; public TextMeshProUGUI AnimationSpeedText; public TextMeshProUGUI AnimationProgressText; [Header("backgrounds")] public ScrollRect BackGroundList; public PageManager BackGroundPageCtrl; public GameObject BG_Canvas; public GameObject BG_HSVPickerObj; public Image BG_Image; [Header("live settings")] public Sprite CharaIconDefault; public Sprite CostumeIconDefault; public LiveCharacterSelect CurrentSeletChara; public GameObject LiveSelectPrefab; public GameObject LiveSelectPannel; public GameObject SelectCharacterPannel; public ScrollRect LiveSelectList; public Image LiveSelectImage; public Text LiveSelectInfoText; private LiveEntry currentLive; [Header("settings")] public TMP_InputField SSWidth; public TMP_InputField SSHeight; public Toggle SSTransparent; public TMP_InputField GifWidth; public TMP_InputField GifHeight; public Toggle GifTransparent; public Slider GifQuality; public TextMeshProUGUI GifQualityLabel; public Slider GifSlider; public Button GifButton; public Button VMDButton; public Button UpdateDBButton; public TMP_Dropdown WorkModeDropdown; public TMP_Dropdown LanguageDropdown; public List TogglablePanels = new List(); public List TogglableFacials = new List(); [Header("prefabs")] public GameObject UmaContainerPrefab; public GameObject UmaContainerCostumePrefab; public GameObject UmaContainerLivePrefab; public GameObject UmaContainerSliderPrefab; public GameObject UmaContainerAssetsPrefab; public UmaUIContainer UmaContainerTogglePrefab; private int LoadedAssetCount = 0; [SerializeField] private RectTransform LoadedAssetsPanel; public Color UIColor1, UIColor2; public bool isHeadFix = false; public bool isTPose = false; public bool DynamicBoneEnable = true; public bool EnableEyeTracking = true; public bool EnableFaceOverride = true; [Header("Live")] public bool LiveTime = false; public bool isRecordVMD; public Dropdown LiveRecoedToggle; public int LiveMode = 1; public FaceDrivenKeyTarget currentFaceDrivenKeyTarget; private IEnumerator UpdateResVerCoroutine; private void Awake() { Instance = this; AudioPlayButton.onClick.AddListener(AudioPause); AudioSlider.onValueChanged.AddListener(AudioProgressChange); AnimationPlayButton.onClick.AddListener(AnimationPause); AnimationSlider.onValueChanged.AddListener(AnimationProgressChange); AnimationSpeedSlider.onValueChanged.AddListener(AnimationSpeedChange); } private void Start() { WorkModeDropdown.SetValueWithoutNotify((int)Config.Instance.WorkMode); LanguageDropdown.SetValueWithoutNotify((int)Config.Instance.Language); UpdateDBButton.interactable = (Config.Instance.WorkMode == WorkMode.Standalone); UmaAssetManager.OnLoadedBundleUpdate += LoadedAssetsAdd; UmaAssetManager.OnLoadedBundleClear += LoadedAssetsClear; } private void OnDestroy() { UmaAssetManager.OnLoadedBundleUpdate -= LoadedAssetsAdd; UmaAssetManager.OnLoadedBundleClear -= LoadedAssetsClear; } private void Update() { if (Builder.CurrentAudioSources.Count > 0 && Builder.CurrentAudioSources[0]) { AudioSource MianSource = Builder.CurrentAudioSources[0]; if (MianSource.clip) { TitleText.text = MianSource.clip.name; ProgressText.text = string.Format("{0} / {1}", ToTimeFormat(MianSource.time), ToTimeFormat(MianSource.clip.length)); AudioSlider.SetValueWithoutNotify(MianSource.time / MianSource.clip.length); LyricsText.text = UmaUtility.GetCurrentLyrics(MianSource.time, Builder.CurrentLyrics); LyricsText.text = LyricsText.text; } } var umaContainer = Builder.CurrentUMAContainer; if (umaContainer != null && umaContainer.OverrideController != null) { if (umaContainer.OverrideController["clip_2"].name != "clip_2") { bool isLoop = umaContainer.OverrideController["clip_2"].name.Contains("_loop"); var AnimeState = umaContainer.UmaAnimator.GetCurrentAnimatorStateInfo(0); var AnimeClip = umaContainer.OverrideController["clip_2"]; if (AnimeClip && umaContainer.UmaAnimator.speed != 0) { var normalizedTime = (isLoop) ? Mathf.Repeat(AnimeState.normalizedTime, 1) : Mathf.Min(AnimeState.normalizedTime, 1); AnimationTitleText.text = AnimeClip.name; AnimationProgressText.text = string.Format("{0} / {1}", ToFrameFormat(normalizedTime * AnimeClip.length, AnimeClip.frameRate), ToFrameFormat(AnimeClip.length, AnimeClip.frameRate)); AnimationSlider.SetValueWithoutNotify(normalizedTime); } } } } public void HighlightChildImage(Transform mainObject, UmaUIContainer child) { foreach (var t in mainObject.GetComponentsInChildren()) { if (t.transform.parent != mainObject) continue; t.ToggleImage.enabled = (t == child); } } public void LoadedAssetsAdd(UmaDatabaseEntry entry) { if (!LoadedAssetsPanel) return; foreach (UmaUIContainer ui in LoadedAssetsPanel.GetComponentsInChildren()) { if (ui.Name == Path.GetFileName(entry.Name)) return; } LoadedAssetCount++; string filePath = entry.FilePath; var container = Instantiate(UmaContainerAssetsPrefab, LoadedAssetsPanel).GetComponent(); container.Name = Path.GetFileName(entry.Name); container.Button.onClick.AddListener(() => { Process.Start("explorer.exe", "/select," + filePath); }); LoadedAssetsPanel.sizeDelta = new Vector2(0, LoadedAssetCount * 35); } public void LoadedAssetsClear() { if (!LoadedAssetsPanel) return; LoadedAssetCount = 0; foreach (UmaUIContainer ui in LoadedAssetsPanel.GetComponentsInChildren()) { Destroy(ui.gameObject); } LoadedAssetsPanel.sizeDelta = Vector2.zero; } public void LoadModelPanels() { var containerG = Instantiate(UmaContainerPrefab, AnimationSetList.content).GetComponent(); containerG.Name = containerG.name = "Generic"; containerG.Button.onClick.AddListener(() => { HighlightChildImage(AnimationSetList.content, containerG); ListAnimations(-1, false); }); var containerT = Instantiate(UmaContainerPrefab, AnimationSetList.content).GetComponent(); containerT.Name = containerT.name = "Tail"; containerT.Button.onClick.AddListener(() => { HighlightChildImage(AnimationSetList.content, containerT); ListAnimations(-2, false); }); var containerE = Instantiate(UmaContainerPrefab, AnimationSetList.content).GetComponent(); containerE.Name = containerE.name = "Ear"; containerE.Button.onClick.AddListener(() => { HighlightChildImage(AnimationSetList.content, containerE); ListAnimations(-3, false); }); foreach (var chara in Main.Characters.OrderBy(c => c.Id)) { var charaInstance = chara; var container3 = Instantiate(UmaContainerPrefab, CharactersList.content).GetComponent(); container3.Name = container3.name = chara.Id + " " + chara.GetName(); container3.Button.onClick.AddListener(() => { HighlightChildImage(CharactersList.content, container3); ListCostumes(charaInstance, false); }); if (chara.Icon) { container3.Image.sprite = (chara.Icon == null ? CharaIconDefault : chara.Icon); container3.Image.enabled = true; } var container4 = Instantiate(UmaContainerPrefab, AnimationSetList.content).GetComponent(); container4.Name = container4.name = chara.Id + " " + chara.GetName(); container4.Button.onClick.AddListener(() => { HighlightChildImage(AnimationSetList.content, container4); ListAnimations(charaInstance.Id, false); }); if (chara.Icon) { container4.Image.sprite = (chara.Icon == null ? CharaIconDefault : chara.Icon); container4.Image.enabled = true; } } var pageentrys = new List(); foreach (var chara in Main.MobCharacters.OrderBy(c => c.Id)) { var charaInstance = chara; var pageentry = new PageManager.Entry(); pageentry.Name = chara.GetName(); pageentry.OnClick = (container) => { HighlightChildImage(MobCharactersList.content, container); ListCostumes(charaInstance, false); }; if (chara.Icon) { pageentry.Sprite = chara.Icon; } pageentrys.Add(pageentry); } MobCharactersPageCtrl.Initialize(pageentrys, MobCharactersList); } public void LoadMiniModelPanels() { var container1 = Instantiate(UmaContainerPrefab, MiniAnimationSetList.content).GetComponent(); container1.Name = container1.name = "General"; container1.Button.onClick.AddListener(() => { HighlightChildImage(MiniAnimationSetList.content, container1); ListAnimations(-1, true); }); foreach (var chara in Main.Characters.OrderBy(c => c.Id)) { var charaInstance = chara; var container2 = Instantiate(UmaContainerPrefab, MiniCharactersList.content).GetComponent(); container2.Name = container2.name = chara.Id + " " + chara.GetName(); container2.Button.onClick.AddListener(() => { HighlightChildImage(MiniCharactersList.content, container2); ListCostumes(charaInstance, true); }); if (chara.Icon) { container2.Image.sprite = chara.Icon; container2.Image.enabled = true; } var container3 = Instantiate(UmaContainerPrefab, MiniAnimationSetList.content).GetComponent(); container3.Name = container3.name = chara.Id + " " + chara.GetName(); container3.Button.onClick.AddListener(() => { HighlightChildImage(MiniAnimationSetList.content, container3); ListAnimations(charaInstance.Id, true); }); if (chara.Icon) { container3.Image.sprite = chara.Icon; container3.Image.enabled = true; } } } public void LoadFacialPanels(FaceDrivenKeyTarget target) { currentFaceDrivenKeyTarget = target; if(FacialList) foreach (UmaUIContainer ui in FacialList.GetComponentsInChildren(true)) { Destroy(ui.gameObject); } if (target == null) return; List targetMorph = new List(target.OtherMorphs); Action, ScrollRect> action = (UmaContainerSliderPrefab, target, targetMorph, TargetList) => { foreach (FacialMorph morph in targetMorph) { if (morph is FacialOtherMorph extraMorph) { foreach (var prop in extraMorph.BindProperties) { var container = Instantiate(UmaContainerSliderPrefab, TargetList.content).GetComponent(); container.Name = $"{morph.name}({prop.Type})"; container.Slider.value = prop.Value; switch (prop.Type) { case BindProperty.BindType.Shader: case BindProperty.BindType.Texture: container.Slider.maxValue = 1; container.Slider.minValue = 0; break; case BindProperty.BindType.Select: container.Slider.wholeNumbers = true; container.Slider.maxValue = prop.BindPrefabs.Count - 1; container.Slider.minValue = 0; break; case BindProperty.BindType.EyeSelect: container.Slider.wholeNumbers = true; container.Slider.maxValue = prop.BindPrefabs.Count / 2 - 1; container.Slider.minValue = 0; break; case BindProperty.BindType.Enable: case BindProperty.BindType.TearSelect: case BindProperty.BindType.TearSide: container.Slider.wholeNumbers = true; container.Slider.maxValue = 1; container.Slider.minValue = 0; break; case BindProperty.BindType.TearWeight: container.Slider.maxValue = 1; container.Slider.minValue = 0; break; case BindProperty.BindType.TearSpeed: container.Slider.maxValue = 2; container.Slider.minValue = 0; break; } container.Slider.onValueChanged.AddListener((a) => { target.ChangeMorphWeight(prop, a, morph); }); } } else { var container = Instantiate(UmaContainerSliderPrefab, TargetList.content).GetComponent(); container.Name = $"{morph.name}({morph.tag})"; container.Slider.value = morph.weight; container.Slider.maxValue = 1; container.Slider.minValue = morph.tag.Contains("Range") ? -1 : 0; container.Slider.onValueChanged.AddListener((a) => { target.ChangeMorphWeight(morph, a); }); } } }; action(UmaContainerSliderPrefab, target, target.EarMorphs, EarList); action(UmaContainerSliderPrefab, target, target.EyeBrowMorphs, EyeBrowList); action(UmaContainerSliderPrefab, target, target.EyeMorphs, EyeList); action(UmaContainerSliderPrefab, target, target.MouthMorphs, MouthList); action(UmaContainerSliderPrefab, target, targetMorph, OtherList); } public void LoadFacialPanelsMini(Material Eye, Material MayuL, Material MayuR, Material Mouth) { currentFaceDrivenKeyTarget = null; foreach (UmaUIContainer ui in FacialList.GetComponentsInChildren(true)) { Destroy(ui.gameObject); } var action = new Action((list, name, mat, type) => { if (mat == null) return; var container = Instantiate(UmaContainerSliderPrefab, list.content).GetComponent(); container.Name = name; container.Slider.wholeNumbers = true; container.Slider.value = 0; container.Slider.maxValue = 15; container.Slider.minValue = 0; container.Slider.onValueChanged.AddListener((a) => { var val = Convert.ToInt32(a); if (type == 0) { mat.mainTextureOffset = new Vector2(0.25f * (val % 4), -0.25f * (val / 4)); } else if (type == 1) { var vector = mat.GetVector("_UVOffset"); mat.SetVector("_UVOffset", new Vector4(0.25f * (val % 4), -0.25f * (val / 4), vector.z, vector.w)); } else if (type == 2) { var vector = mat.GetVector("_UVOffset"); mat.SetVector("_UVOffset", new Vector4(vector.x, vector.y, 0.25f * (val % 4), -0.25f * (val / 4))); } }); }); action(EyeList, "Eye_L_Select", Eye, 2); action(EyeList, "Eye_R_Select", Eye, 1); action(MouthList, "Mouth_Select", Mouth, 0); action(EyeBrowList, "Mayu_L_Select", MayuL, 0); action(EyeBrowList, "Mayu_R_Select", MayuR, 0); } public void UpdateFacialPanels() { if (currentFaceDrivenKeyTarget) LoadFacialPanels(currentFaceDrivenKeyTarget); } public void LoadEmotionPanels(FaceEmotionKeyTarget target) { if (EmotionList) foreach (UmaUIContainer ui in EmotionList.content.GetComponentsInChildren()) { Destroy(ui.gameObject); } if (target == null) return; foreach (var emotion in target.FaceEmotionKey) { if (emotion.label == "Base") { continue; } var container = Instantiate(UmaContainerSliderPrefab, EmotionList.content).GetComponent(); container.Name = emotion.label; container.Slider.value = emotion.weight; container.Slider.maxValue = 1; container.Slider.minValue = 0; container.Slider.onValueChanged.AddListener((a) => { target.ChangeEmotionWeight(emotion, a); }); } } public void LoadLivePanels() { Action createContainer = (live, containerPrefab, parent, onClickAction) => { var container = Instantiate(containerPrefab, parent.content).GetComponent(); container.Name = " " + live.MusicId + " " + live.SongName; container.Image.sprite = live.Icon; container.Image.enabled = container.Image.sprite; container.Button.onClick.AddListener(() => { HighlightChildImage(parent.content, container); onClickAction.Invoke(); }); }; foreach (var live in Main.Lives.OrderBy(c => c.MusicId)) { createContainer(live, UmaContainerLivePrefab, LiveList, () => ShowLiveSelectPannel(live)); createContainer(live, UmaContainerLivePrefab, LiveSoundList, () => ListLiveSounds(live.MusicId)); } } public void LoadNormalSoundPanels() { NormalSoundCtrl.Clear(); var pageentrys = new List(); foreach (var entry in Main.AbSounds.Where(a => (!a.Name.Contains("live")) && a.Name.EndsWith("awb"))) { var pageentry = new PageManager.Entry(); pageentry.Name = Path.GetFileNameWithoutExtension(entry.Name); pageentry.OnClick = (container) => { HighlightChildImage(NormalSoundList.content, container); ListNormalSubSounds(entry); }; pageentrys.Add(pageentry); } NormalSoundCtrl.Initialize(pageentrys, NormalSoundList); } public void LoadPropPanel() { var pageentrys = new List(); foreach (var prop in Main.AbList.Where(a => a.Key.Contains("pfb_chr_prop") && !a.Key.Contains("clothes"))) { var pageentry = new PageManager.Entry(); pageentry.Name = Path.GetFileName(prop.Key); pageentry.OnClick = (container) => { HighlightChildImage(PropList.content, container); Builder.LoadProp(prop.Value); }; pageentrys.Add(pageentry); } PropPageCtrl.Initialize(pageentrys, PropList); } public void LoadMapPanel() { var pageentrys = new List(); foreach (var scene in Main.AbList.Where(a => ((a.Key.StartsWith("3d/env") && Path.GetFileName(a.Key).StartsWith("pfb_")) || a.Key.StartsWith("cutt/cutt_son") && Path.GetFileName(a.Key).StartsWith("cutt_son")))) { var pageentry = new PageManager.Entry(); pageentry.Name = Path.GetFileName(scene.Key); pageentry.FontSize = 19; pageentry.OnClick = (container) => { HighlightChildImage(SceneList.content, container); Builder.LoadProp(scene.Value); }; pageentrys.Add(pageentry); } ScenePageCtrl.Initialize(pageentrys, SceneList); } public void PlayLive() { if (currentLive == null) return; var selectlist = LiveSelectList.content.GetComponentsInChildren(); if (selectlist != null) { LiveTime = true; SetEyeTrackingEnable(false); Builder.LoadLive(currentLive, new List(selectlist)); LiveSelectPannel.SetActive(false); } } void ShowLiveSelectPannel(LiveEntry entry) { LiveSelectPannel.SetActive(true); for (int i = LiveSelectList.content.childCount - 1; i >= 0; i--) { Destroy(LiveSelectList.content.GetChild(i).gameObject); } if(LiveMode == 1) { currentLive = entry; LiveSelectImage.sprite = entry.Icon; LiveSelectInfoText.text = $"{entry.SongName}\nMembers Count: {entry.MemberCount}"; for (int i = 0; i < entry.MemberCount; i++) { var chara = Instantiate(LiveSelectPrefab, LiveSelectList.content).GetComponent(); chara.IndexText.text = (i + 1).ToString(); chara.GetComponent