using Gallop; using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; //修改(载入通用服装ColorSet相关)(保存当前选中的颜色配置到TXT文件) using System.Text; 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 HeadCostumeList; 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 PageManager ScenePageCtrl; public ScrollRect MessageScrollRect; public TextMeshProUGUI MessageText; public PoseManager PoseManager; public HandleManager HandleManager; //修改(载入通用服装ColorSet相关) public ScrollRect DressColorSetList; [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("jukebox ui resources")] public Button JukeboxButton; public JukeboxSelectionView JukeboxPanel; private GameObject JukeboxSoundPanel; private ScrollRect JukeboxSoundList; private Image JukeboxSelectedJacket; private GameObject JukeboxSelectedPlaceholder; private Text JukeboxSelectedInfo; private Toggle JukeboxShortVersionToggle; private Toggle JukeboxGameSizeVersionToggle; private UmaUIContainer JukeboxMusicItemPrefab; private JukeboxMusicSelect JukeboxSelectedItem; private MasterJukeboxMusicData.JukeboxMusicData JukeboxSelectedMusic; private bool JukeboxUseGameSize; private bool JukeboxListLoaded; private bool JukeboxListLoading; [Header("pose mode")] public Transform HandlesPanel; [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 UISettingsCamera CameraSettings; public UISettingsModel ModelSettings; public UISettingsSound AudioSettings; public UISettingsAnimation AnimationSettings; public UISettingsScreenshot ScreenshotSettings; public UISettingsAssets AssetSettings; public UISettingsOther OtherSettings; 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 UmaUIContainer UmaContainerTogglePrefab; public Color UIColor1, UIColor2; public string CurrentHeadCostumeId = string.Empty; [Header("Live")] public bool LiveTime = false; public bool isRecordVMD; public bool isRequireStage = true; //修改(Live演出的显隐控制和位置变换相关) public bool isControlMode = true; public Dropdown LiveRecoedToggle; public int LiveMode = 1; public FaceDrivenKeyTarget currentFaceDrivenKeyTarget; private void Awake() { Instance = this; } private void Start() { OtherSettings.ApplySettings(); SetupJukeboxSoundUI(); CameraSettings.AAModeDropdown.SetValueWithoutNotify(Config.Instance.AntiAliasing); AssetSettings.LoadedAssetsClear(); UmaAssetManager.OnLoadedBundleUpdate += AssetSettings.LoadedAssetsAdd; UmaAssetManager.OnLoadedBundleRemove += AssetSettings.LoadedAssetsRemove; UmaAssetManager.OnLoadedBundleClear += AssetSettings.LoadedAssetsClear; PoseManager.LoadLocalPoseFiles(); #if UNITY_ANDROID && !UNITY_EDITOR canvasScaler.referenceResolution = new Vector2(1280, 720); #endif StartCoroutine(ApplyGraphicsSettings()); } private void OnDestroy() { UmaAssetManager.OnLoadedBundleUpdate -= AssetSettings.LoadedAssetsAdd; UmaAssetManager.OnLoadedBundleRemove -= AssetSettings.LoadedAssetsRemove; UmaAssetManager.OnLoadedBundleClear -= AssetSettings.LoadedAssetsClear; } private void Update() { if (Builder.CurrentAudioSources.Count > 0 && Builder.CurrentAudioSources[0]) { AudioSource MianSource = Builder.CurrentAudioSources[0]; if (MianSource.clip) { AudioSettings.UpdateTrack(MianSource); } } var umaContainer = Builder.CurrentUMAContainer; if (umaContainer != null && umaContainer.OverrideController != null) { AnimationSettings.UpdateAnimationInfo(umaContainer); } } /// Some settings may not be saved when set in Start() public IEnumerator ApplyGraphicsSettings() { yield return 0; CameraSettings.AAModeDropdown.SetValueWithoutNotify(Config.Instance.AntiAliasing); GraphicsSettings.renderPipelineAsset = Config.Instance.Region == Region.Global ? null : UmaViewerMain.Instance.DefaultRenderPipeline; RuntimeGraphicsSettings.Apply(); } 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 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(); UIPressScaleFeedback.AddTo(container3.gameObject); container3.UseLocalizedText(); 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.UseLocalizedText(); 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.UseLocalizedText = true; pageentry.EnablePressScaleFeedback = true; 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(); UIPressScaleFeedback.AddTo(container2.gameObject); container2.UseLocalizedText(); 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.UseLocalizedText(); 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); } //修改(Mini角色表情滑条修复) 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; if (type == 0) container.Slider.maxValue = 18; else if (type == 1) container.Slider.maxValue = 14; else if (type == 2) container.Slider.maxValue = 14; else if (type == 3) container.Slider.maxValue = 8; 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.125f * (val / 4)); } else if (type == 1) { var vector = mat.GetVector("_UVOffset"); mat.SetVector("_UVOffset", new Vector4(0.25f * (val % 4), -0.125f * (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.125f * (val / 4))); } else if (type == 3) { mat.mainTextureOffset = new Vector2(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, 3); action(EyeBrowList, "Mayu_R_Select", MayuR, 3); } 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, () => ShowLiveSelectPanel(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); } private void SetupJukeboxSoundUI() { if (JukeboxButton == null || JukeboxPanel == null || JukeboxPanel.SongItemPrefab == null) { Debug.LogWarning( "[UmaViewerUI] Assign JukeboxButton, JukeboxPanel and its SongItemPrefab in the Inspector."); return; } if (JukeboxPanel.CloseButton == null || JukeboxPanel.ShortVersionToggle == null || JukeboxPanel.GameSizeVersionToggle == null || JukeboxPanel.SelectedJacket == null || JukeboxPanel.SelectedInfo == null || JukeboxPanel.SongList == null || JukeboxPanel.SongList.content == null || JukeboxPanel.SongItemPrefab.Button == null || JukeboxPanel.SongItemPrefab.Image == null) { Debug.LogWarning("[UmaViewerUI] JukeboxPanel has missing Inspector references."); return; } JukeboxSoundPanel = JukeboxPanel.gameObject; JukeboxSoundList = JukeboxPanel.SongList; JukeboxSelectedJacket = JukeboxPanel.SelectedJacket; JukeboxSelectedPlaceholder = JukeboxPanel.SelectedJacketPlaceholder; JukeboxSelectedInfo = JukeboxPanel.SelectedInfo; JukeboxShortVersionToggle = JukeboxPanel.ShortVersionToggle; JukeboxGameSizeVersionToggle = JukeboxPanel.GameSizeVersionToggle; JukeboxMusicItemPrefab = JukeboxPanel.SongItemPrefab; JukeboxButton.onClick.AddListener(OpenJukeboxSoundPanel); JukeboxPanel.CloseButton.onClick.AddListener(CloseJukeboxSoundPanel); JukeboxShortVersionToggle.onValueChanged.AddListener(OnJukeboxShortVersionChanged); JukeboxGameSizeVersionToggle.onValueChanged.AddListener(OnJukeboxGameSizeVersionChanged); JukeboxShortVersionToggle.SetIsOnWithoutNotify(true); JukeboxGameSizeVersionToggle.SetIsOnWithoutNotify(false); JukeboxSoundPanel.SetActive(false); RefreshJukeboxVersionUI(); } private void OpenJukeboxSoundPanel() { JukeboxButton.interactable = false; JukeboxSoundPanel.transform.SetAsLastSibling(); JukeboxSoundPanel.SetActive(true); LoadJukeboxSoundPanels(); } private void CloseJukeboxSoundPanel() { if (JukeboxSoundPanel != null) JukeboxSoundPanel.SetActive(false); if (JukeboxButton != null) JukeboxButton.interactable = true; } private IEnumerator PopulateJukeboxGrid(List musicEntries) { for (int i = JukeboxSoundList.content.childCount - 1; i >= 0; i--) Destroy(JukeboxSoundList.content.GetChild(i).gameObject); for (int i = 0; i < musicEntries.Count; i++) { if (JukeboxSoundPanel == null || JukeboxSoundList == null) yield break; MasterJukeboxMusicData.JukeboxMusicData music = musicEntries[i]; Sprite jacket = null; try { jacket = Builder.LoadLiveIcon(music.MusicId); } catch (Exception ex) { Debug.LogWarning($"[UmaViewerUI] Could not load jacket for music {music.MusicId}: {ex.Message}"); } JukeboxMusicSelect item = CreateJukeboxGridItem(music, jacket); if (JukeboxSelectedMusic == null) SelectJukeboxMusic(item, false); // AssetBundle loading is synchronous. Yield in small batches so opening // a large regional jukebox does not freeze the UI for one long frame. if ((i + 1) % 8 == 0) yield return null; } JukeboxSoundList.verticalNormalizedPosition = 1f; JukeboxListLoaded = true; JukeboxListLoading = false; if (musicEntries.Count == 0) { JukeboxSelectedInfo.text = "No playable music found"; } } private JukeboxMusicSelect CreateJukeboxGridItem( MasterJukeboxMusicData.JukeboxMusicData music, Sprite jacket) { UmaUIContainer view = Instantiate(JukeboxMusicItemPrefab, JukeboxSoundList.content); JukeboxMusicSelect item = view.GetComponent(); if (item == null) item = view.gameObject.AddComponent(); string title = JukeboxUtil.ResolveSongTitle(music, UmaDatabaseController.Instance.LiveData); item.Initialize(this, view, music, jacket, title); return item; } public void SelectJukeboxMusic(JukeboxMusicSelect item, bool playImmediately = true) { if (item == null || item.Music == null) return; if (JukeboxSelectedItem != null) JukeboxSelectedItem.SetSelected(false); JukeboxSelectedItem = item; JukeboxSelectedItem.SetSelected(true); JukeboxSelectedMusic = item.Music; JukeboxSelectedJacket.sprite = item.Jacket; JukeboxSelectedJacket.enabled = item.Jacket != null; if (JukeboxSelectedPlaceholder != null) JukeboxSelectedPlaceholder.SetActive(item.Jacket == null); if (JukeboxUseGameSize && !item.Music.HasGameSizeAudio) JukeboxUseGameSize = false; else if (!JukeboxUseGameSize && !item.Music.HasShortAudio && item.Music.HasGameSizeAudio) JukeboxUseGameSize = true; RefreshJukeboxVersionUI(); if (playImmediately) PlaySelectedJukeboxMusic(); } private void SelectJukeboxVersion(bool useGameSize) { if (JukeboxSelectedMusic != null) { if (useGameSize && !JukeboxSelectedMusic.HasGameSizeAudio) return; if (!useGameSize && !JukeboxSelectedMusic.HasShortAudio) return; } JukeboxUseGameSize = useGameSize; RefreshJukeboxVersionUI(); PlaySelectedJukeboxMusic(); } private void OnJukeboxShortVersionChanged(bool isOn) { if (!isOn) { if (!JukeboxGameSizeVersionToggle.isOn) JukeboxShortVersionToggle.SetIsOnWithoutNotify(true); return; } JukeboxGameSizeVersionToggle.SetIsOnWithoutNotify(false); SelectJukeboxVersion(false); } private void OnJukeboxGameSizeVersionChanged(bool isOn) { if (!isOn) { if (!JukeboxShortVersionToggle.isOn) JukeboxGameSizeVersionToggle.SetIsOnWithoutNotify(true); return; } JukeboxShortVersionToggle.SetIsOnWithoutNotify(false); SelectJukeboxVersion(true); } private void RefreshJukeboxVersionUI() { bool hasShort = JukeboxSelectedMusic == null || JukeboxSelectedMusic.HasShortAudio; bool hasGameSize = JukeboxSelectedMusic == null || JukeboxSelectedMusic.HasGameSizeAudio; if (JukeboxShortVersionToggle != null) { JukeboxShortVersionToggle.interactable = hasShort; JukeboxShortVersionToggle.SetIsOnWithoutNotify(!JukeboxUseGameSize); } if (JukeboxGameSizeVersionToggle != null) { JukeboxGameSizeVersionToggle.interactable = hasGameSize; JukeboxGameSizeVersionToggle.SetIsOnWithoutNotify(JukeboxUseGameSize); } if (JukeboxSelectedMusic != null && JukeboxSelectedInfo != null) { string title = JukeboxUtil.ResolveSongTitle( JukeboxSelectedMusic, UmaDatabaseController.Instance.LiveData); string version = JukeboxUseGameSize ? "GAME SIZE Ver." : "SHORT Ver."; JukeboxSelectedInfo.text = $"{title}\nMUSIC ID {JukeboxSelectedMusic.MusicId}\n{version}"; } } private void PlaySelectedJukeboxMusic() { if (JukeboxSelectedMusic != null) HomeJukeboxController.Instance.SetupMusicAndPlay( JukeboxSelectedMusic.MusicId, JukeboxUseGameSize); } public void LoadJukeboxSoundPanels() { if (JukeboxSoundList == null || JukeboxListLoaded || JukeboxListLoading) return; try { MasterJukeboxMusicData master = UmaDatabaseController.Instance.JukeboxMusicData; if (master == null) { ShowMessage("Jukebox master data is not available.", UIMessageType.Warning); return; } var musicEntries = new List(); foreach (MasterJukeboxMusicData.JukeboxMusicData music in master.GetAll()) { if (!music.TryGetPreferredAudio(out _, out _)) continue; musicEntries.Add(music); } JukeboxListLoading = true; StartCoroutine(PopulateJukeboxGrid(musicEntries)); } catch (Exception ex) { JukeboxListLoading = false; Debug.LogError($"[UmaViewerUI] Could not load Jukebox UI: {ex}"); ShowMessage($"Could not load Jukebox: {ex.Message}", UIMessageType.Error); } } public void LoadPropPanel() { var pageentrys = new List(); foreach (var prop in Main.AbList .Where(a => IsPreviewableProp(a.Key)) .OrderBy(a => a.Key, StringComparer.OrdinalIgnoreCase)) { 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); } private static bool IsPreviewableProp(string path) { if (string.IsNullOrEmpty(path) || path.IndexOf("clothes", StringComparison.OrdinalIgnoreCase) >= 0) return false; string fileName = Path.GetFileName(path); if (!fileName.StartsWith("pfb_", StringComparison.OrdinalIgnoreCase)) return false; // Legacy assets use pfb_chr_prop; newer hand-held assets may be filed under // prop/item/accessory directories with different prefab names. return path.IndexOf("/prop/", StringComparison.OrdinalIgnoreCase) >= 0 || path.IndexOf("/props/", StringComparison.OrdinalIgnoreCase) >= 0 || path.IndexOf("/item/", StringComparison.OrdinalIgnoreCase) >= 0 || path.IndexOf("/accessory/", StringComparison.OrdinalIgnoreCase) >= 0 || fileName.IndexOf("prop", StringComparison.OrdinalIgnoreCase) >= 0 || fileName.IndexOf("item", StringComparison.OrdinalIgnoreCase) >= 0 || fileName.IndexOf("accessory", StringComparison.OrdinalIgnoreCase) >= 0; } 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; PoseManager.SetPoseMode(false); var selectlist = LiveSelectList.content.GetComponentsInChildren(); if (selectlist != null) { LiveTime = true; ModelSettings.SetEyeTrackingEnable(false); Builder.LoadLive(currentLive, new List(selectlist)); LiveSelectPannel.SetActive(false); } } void ShowLiveSelectPanel(LiveEntry entry, bool loadPreview = true) { LiveSelectPannel.SetActive(true); if (loadPreview) Builder.loadLivePreviewSound(entry.MusicId); bool keepSelections = currentLive == entry; CurrentSeletChara = null; if (!keepSelections) { for (int i = LiveSelectList.content.childCount - 1; i >= 0; i--) { var child = LiveSelectList.content.GetChild(i); child.SetParent(null); Destroy(child.gameObject); } } currentLive = entry; LiveSelectImage.sprite = entry.Icon; int memberCount = entry.MemberCount; if (LiveMode == 0) { memberCount = Main.AbMotions.Count(a => a.Name.StartsWith($"3d/motion/live/body/son{entry.MusicId}") && Path.GetFileName(a.Name).Split('_').Length == 4); LiveSelectInfoText.text = $"{entry.SongName}\nMain Members Count: {memberCount}"; } else { LiveSelectInfoText.text = $"{entry.SongName}\nMembers Count: {memberCount}"; } var selections = new List(LiveSelectList.content.GetComponentsInChildren()); for (int i = selections.Count - 1; i >= memberCount; i--) { selections[i].transform.SetParent(null); Destroy(selections[i].gameObject); selections.RemoveAt(i); } for (int i = selections.Count; i < memberCount; i++) { var chara = Instantiate(LiveSelectPrefab, LiveSelectList.content).GetComponent(); chara.IndexText.text = (i + 1).ToString(); chara.GetComponent