using CriWareFormats; using Gallop; using Gallop.Live; using NAudio.Wave; using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.IO; using System.Linq; using UmaMusumeAudio; using UnityEngine; using UnityEngine.SceneManagement; using Debug = UnityEngine.Debug; using Random = UnityEngine.Random; public class UmaViewerBuilder : MonoBehaviour { public static UmaViewerBuilder Instance; static UmaViewerMain Main => UmaViewerMain.Instance; static UmaViewerUI UI => UmaViewerUI.Instance; public List Loaded; public List ShaderList = new List(); public Material TransMaterialCharas; public Material TransMaterialProps; public UmaContainerCharacter CurrentUMAContainer; public UmaContainer CurrentOtherContainer; public UmaHeadData CurrentHead; public List CurrentAudioSources = new List(); public List CurrentLyrics = new List(); public AnimatorOverrideController OverrideController; public AnimatorOverrideController FaceOverrideController; public AnimatorOverrideController CameraOverrideController; public Animator AnimationCameraAnimator; public Camera AnimationCamera; public GameObject LiveControllerPrefab; private void Awake() { Instance = this; } public IEnumerator LoadUma(CharaEntry chara, string costumeId, bool mini) { int id = chara.Id; var umaContainer = new GameObject($"Chara_{id}_{costumeId}").AddComponent(); CurrentUMAContainer = umaContainer; if (mini) { umaContainer.CharaData = UmaDatabaseController.ReadCharaData(chara); LoadMiniUma(umaContainer, chara, costumeId); } else if (chara.IsMob) { umaContainer.CharaData = UmaDatabaseController.ReadCharaData(chara); LoadMobUma(umaContainer, chara, costumeId, loadMotion: true); } else if (UI.isHeadFix && CurrentHead != null && CurrentHead.chara.IsMob) { umaContainer.CharaData = UmaDatabaseController.ReadCharaData(CurrentHead.chara); LoadMobUma(umaContainer, CurrentHead.chara, costumeId, chara.Id, true); } else { umaContainer.CharaData = UmaDatabaseController.ReadCharaData(chara); LoadNormalUma(umaContainer, chara, costumeId, true); } yield break; } public void LoadLiveUma(List characters) { for (int i = 0; i < characters.Count; i++) { if (characters[i].CharaEntry.Name != "") { var umaContainer = new GameObject($"Chara_{characters[i].CharaEntry.Id}_{characters[i].CostumeId}").AddComponent(); umaContainer.IsLive = true; umaContainer.CharaData = UmaDatabaseController.ReadCharaData(characters[i].CharaEntry); var charObjs = Gallop.Live.Director.instance.charaObjs; umaContainer.transform.parent = charObjs[i]; umaContainer.transform.localPosition = new Vector3(); if (characters[i].CharaEntry.IsMob) { LoadMobUma(umaContainer, characters[i].CharaEntry, characters[i].CostumeId); } else { LoadNormalUma(umaContainer, characters[i].CharaEntry, characters[i].CostumeId); } Gallop.Live.Director.instance.CharaContainerScript.Add(umaContainer); } } } private void LoadNormalUma(UmaContainerCharacter umaContainer, CharaEntry chara, string costumeId, bool loadMotion = false) { int id = chara.Id; umaContainer.CharaEntry = chara; DataRow charaData = umaContainer.CharaData; bool genericCostume = umaContainer.IsGeneric = costumeId.Length >= 4; string skin, height, socks, bust, sex, shape, costumeIdShort = ""; skin = charaData["skin"].ToString(); height = charaData["height"].ToString(); socks = charaData["socks"].ToString(); bust = charaData["bust"].ToString(); sex = charaData["sex"].ToString(); shape = charaData["shape"].ToString(); UmaDatabaseEntry asset = null; if (genericCostume) { costumeIdShort = costumeId.Remove(costumeId.LastIndexOf('_')); umaContainer.VarCostumeIdShort = costumeIdShort; umaContainer.VarCostumeIdLong = costumeId; umaContainer.VarBust = bust; umaContainer.VarSkin = skin; umaContainer.VarSocks = socks; umaContainer.VarHeight = height; // Pattern for generic body type is as follows: // // (costume id)_(body_type_sub)_(body_setting)_(height)_(shape)_(bust) // // body_type_sub is used for variants like the summer/winter uniform or the swimsuit/towel // body_setting is used for subvariants of each variant like the big belly version of the uniform, and the genders for the tracksuits // // Some models will naturally be missing due to how this system is designed. string body = UmaDatabaseController.BodyPath + $"bdy{costumeIdShort}/pfb_bdy{costumeId}_{height}_{shape}_{bust}"; UmaViewerMain.Instance.AbList.TryGetValue(body, out asset); } else UmaViewerMain.Instance.AbList.TryGetValue(UmaDatabaseController.BodyPath + $"bdy{id}_{costumeId}/pfb_bdy{id}_{costumeId}", out asset); if (asset == null) { Debug.LogError("No body, can't load!"); return; } else if (genericCostume) { string texPattern1 = "", texPattern2 = "", texPattern3 = "", texPattern4 = "", texPattern5 = ""; switch (costumeId.Split('_')[0]) { case "0001": texPattern1 = $"tex_bdy{costumeIdShort}_00_{skin}_{bust}_0{socks}"; texPattern2 = $"tex_bdy{costumeIdShort}_00_0_{bust}"; texPattern3 = $"tex_bdy{costumeIdShort}_zekken"; texPattern4 = $"tex_bdy{costumeIdShort}_00_waku"; texPattern5 = $"tex_bdy{costumeIdShort}_num"; break; case "0003": texPattern1 = $"tex_bdy{costumeIdShort}_00_{skin}_{bust}"; texPattern2 = $"tex_bdy{costumeIdShort}_00_0_{bust}"; break; case "0006": //last var is color? texPattern1 = $"tex_bdy{costumeId}_{skin}_{bust}_0{0}"; texPattern2 = $"tex_bdy{costumeId}_0_{bust}_00_"; break; default: texPattern1 = $"tex_bdy{costumeId}_{skin}_{bust}"; texPattern2 = $"tex_bdy{costumeId}_0_{bust}"; break; } Debug.Log(texPattern1 + " " + texPattern2); //Load Body Textures foreach (var asset1 in UmaViewerMain.Instance.AbChara.Where(a => a.Name.StartsWith(UmaDatabaseController.BodyPath) && (a.Name.Contains(texPattern1) || a.Name.Contains(texPattern2) || (string.IsNullOrEmpty(texPattern3) ? false : a.Name.Contains(texPattern3)) || (string.IsNullOrEmpty(texPattern4) ? false : a.Name.Contains(texPattern4)) || (string.IsNullOrEmpty(texPattern5) ? false : a.Name.Contains(texPattern5))))) { umaContainer.LoadTextures(asset1); } //Load Body umaContainer.LoadBody(asset); //Load Physics if (Main.AbList.TryGetValue(UmaDatabaseController.BodyPath + $"bdy{costumeIdShort}/clothes/pfb_bdy{costumeIdShort}_cloth00", out _)) { var asset1 = Main.AbList[UmaDatabaseController.BodyPath + $"bdy{costumeIdShort}/clothes/pfb_bdy{costumeIdShort}_cloth00"]; umaContainer.LoadPhysics(asset1); asset1 = Main.AbList[UmaDatabaseController.BodyPath + $"bdy{costumeIdShort}/clothes/pfb_bdy{costumeIdShort}_bust{bust}_cloth00"]; umaContainer.LoadPhysics(asset1); } } else { umaContainer.LoadBody(asset); //Load Physics var asset1 = Main.AbList[UmaDatabaseController.BodyPath + $"bdy{id}_{costumeId}/clothes/pfb_bdy{id}_{costumeId}_cloth00"]; umaContainer.LoadPhysics(asset1); asset1 = Main.AbList[UmaDatabaseController.BodyPath + $"bdy{id}_{costumeId}/clothes/pfb_bdy{id}_{costumeId}_bust_cloth00"]; umaContainer.LoadPhysics(asset1); } // Record Head Data int head_id; string head_costumeId; int tailId = Convert.ToInt32(charaData["tail_model_id"]); if (UI.isHeadFix && CurrentHead != null) { head_id = CurrentHead.id; head_costumeId = CurrentHead.costumeId; tailId = CurrentHead.tailId; } else { head_id = id; head_costumeId = costumeId; CurrentHead = new UmaHeadData { id = id, costumeId = costumeId, tailId = tailId, chara = chara }; } string head = UmaDatabaseController.HeadPath + $"chr{head_id}_{head_costumeId}/pfb_chr{head_id}_{head_costumeId}"; asset = null; Main.AbList.TryGetValue(head, out asset); bool isDefaultHead = false; //Some costumes don't have custom heads if (head_costumeId != "00" && asset == null) { asset = Main.AbList[UmaDatabaseController.HeadPath + $"chr{head_id}_00/pfb_chr{head_id}_00"]; isDefaultHead = true; } if (asset != null) { //Load Hair Textures foreach (var asset1 in UmaViewerMain.Instance.AbChara.Where(a => a.Name.StartsWith($"{UmaDatabaseController.HeadPath}chr{head_id}_{head_costumeId}/textures"))) { umaContainer.LoadTextures(asset1); } //Load Head umaContainer.LoadHead(asset); //Load Physics if (isDefaultHead) { var asset1 = Main.AbList[UmaDatabaseController.HeadPath + $"chr{id}_00/clothes/pfb_chr{id}_00_cloth00"]; umaContainer.LoadPhysics(asset1); } else { var asset1 = Main.AbList[UmaDatabaseController.HeadPath + $"chr{head_id}_{head_costumeId}/clothes/pfb_chr{head_id}_{head_costumeId}_cloth00"]; umaContainer.LoadPhysics(asset1); } } if (tailId != 0) { string tailName = $"tail{tailId.ToString().PadLeft(4, '0')}_00"; string tailPath = $"3d/chara/tail/{tailName}/"; string tailPfb = tailPath + $"pfb_{tailName}"; asset = null; Main.AbList.TryGetValue(tailPfb, out asset); if (asset != null) { foreach (var asset2 in UmaViewerMain.Instance.AbChara.Where(a => a.Name.StartsWith($"{tailPath}textures/tex_{tailName}_{head_id}") || a.Name.StartsWith($"{tailPath}textures/tex_{tailName}_0000"))) { umaContainer.LoadTextures(asset2); } umaContainer.LoadTail(asset); //Load Physics var asset1 = Main.AbList[$"{tailPath}clothes/pfb_{tailName}_cloth00"]; umaContainer.LoadPhysics(asset1); } else { Debug.Log("no tail"); } } umaContainer.LoadPhysics(); umaContainer.SetDynamicBoneEnable(UI.DynamicBoneEnable); umaContainer.LoadFaceMorph(id, costumeId); umaContainer.TearControllers.ForEach(a => a.SetDir(a.CurrentDir)); umaContainer.HeadBone = (GameObject)umaContainer.Body.GetComponent()._assetTable["head"]; umaContainer.EyeHeight = umaContainer.Head.GetComponent()._assetTableValue["head_center_offset_y"]; umaContainer.MergeModel(); umaContainer.SetHeight(-1); umaContainer.Initialize(!UI.isTPose); umaContainer.Position = umaContainer.transform.Find("Position"); umaContainer.SetupBoneHandles(); if (!UI.isTPose && loadMotion) { if (Main.AbList.TryGetValue($"3d/motion/event/body/chara/chr{id}_00/anm_eve_chr{id}_00_idle01_loop", out UmaDatabaseEntry entry)) { umaContainer.LoadAnimation(entry); } } } private void LoadMobUma(UmaContainerCharacter umaContainer, CharaEntry chara, string costumeId, int bodyid = -1, bool loadMotion = false) { int id = chara.Id; umaContainer.CharaEntry = chara; umaContainer.IsMob = chara.IsMob; umaContainer.MobDressColor = UmaDatabaseController.ReadMobDressColor(umaContainer.CharaData["dress_color_id"].ToString()); umaContainer.MobHeadColor = UmaDatabaseController.ReadMobHairColor(umaContainer.CharaData["chara_hair_color"].ToString()); DataRow charaData = umaContainer.CharaData; bool genericCostume = umaContainer.IsGeneric = costumeId.Length >= 4; string skin, height, socks, bust, sex, shape, costumeIdShort = ""; string faceid, hairid, personality; faceid = charaData["chara_face_model"].ToString(); hairid = charaData["chara_hair_model"].ToString(); personality = charaData["default_personality"].ToString(); skin = charaData["chara_skin_color"].ToString(); height = "1"; socks = charaData["socks"].ToString(); bust = charaData["chara_bust_size"].ToString(); sex = charaData["sex"].ToString(); shape = "0"; UmaDatabaseEntry asset = null; if (genericCostume) { costumeIdShort = costumeId.Remove(costumeId.LastIndexOf('_')); umaContainer.VarCostumeIdShort = costumeIdShort; umaContainer.VarCostumeIdLong = costumeId; umaContainer.VarBust = bust; umaContainer.VarSkin = skin; umaContainer.VarSocks = socks; umaContainer.VarHeight = height; // Pattern for generic body type is as follows: // // (costume id)_(body_type_sub)_(body_setting)_(height)_(shape)_(bust) // // body_type_sub is used for variants like the summer/winter uniform or the swimsuit/towel // body_setting is used for subvariants of each variant like the big belly version of the uniform, and the genders for the tracksuits // // Some models will naturally be missing due to how this system is designed. string body = ""; body = UmaDatabaseController.BodyPath + $"bdy{costumeIdShort}/pfb_bdy{costumeId}_{height}_{shape}_{bust}"; Debug.Log("Looking for " + body); Main.AbList.TryGetValue(body, out asset); } else Main.AbList.TryGetValue($"{UmaDatabaseController.BodyPath}bdy{bodyid}_{costumeId}/pfb_bdy{bodyid}_{costumeId}", out asset); if (asset == null) { Debug.LogError("No body, can't load!"); return; } else if (genericCostume) { string texPattern1 = "", texPattern2 = "", texPattern3 = "", texPattern4 = "", texPattern5 = ""; switch (costumeId.Split('_')[0]) { case "0001": texPattern1 = $"tex_bdy{costumeIdShort}_00_{skin}_{bust}_0{socks}"; texPattern2 = $"tex_bdy{costumeIdShort}_00_0_{bust}"; texPattern3 = $"tex_bdy{costumeIdShort}_zekken"; texPattern4 = $"tex_bdy{costumeIdShort}_00_waku"; texPattern5 = $"tex_bdy{costumeIdShort}_num"; break; case "0003": texPattern1 = $"tex_bdy{costumeIdShort}_00_{skin}_{bust}"; texPattern2 = $"tex_bdy{costumeIdShort}_00_0_{bust}"; break; case "0006": //last var is color? texPattern1 = $"tex_bdy{costumeId}_{skin}_{bust}_0{0}"; texPattern2 = $"tex_bdy{costumeId}_0_{bust}_00_"; break; default: texPattern1 = $"tex_bdy{costumeId}_{skin}_{bust}"; texPattern2 = $"tex_bdy{costumeId}_0_{bust}"; break; } Debug.Log(texPattern1 + " " + texPattern2); //Load Body Textures foreach (var asset1 in UmaViewerMain.Instance.AbChara.Where(a => a.Name.StartsWith(UmaDatabaseController.BodyPath) && (a.Name.Contains(texPattern1) || a.Name.Contains(texPattern2) || (string.IsNullOrEmpty(texPattern3) ? false : a.Name.Contains(texPattern3)) || (string.IsNullOrEmpty(texPattern4) ? false : a.Name.Contains(texPattern4)) || (string.IsNullOrEmpty(texPattern5) ? false : a.Name.Contains(texPattern5))))) { umaContainer.LoadTextures(asset1); } //Load Body umaContainer.LoadBody(asset); //Load Physics if (Main.AbList.TryGetValue(UmaDatabaseController.BodyPath + $"bdy{costumeIdShort}/clothes/pfb_bdy{costumeIdShort}_cloth00", out _)) { var asset1 = Main.AbList[UmaDatabaseController.BodyPath + $"bdy{costumeIdShort}/clothes/pfb_bdy{costumeIdShort}_cloth00"]; umaContainer.LoadPhysics(asset1); asset1 = Main.AbList[UmaDatabaseController.BodyPath + $"bdy{costumeIdShort}/clothes/pfb_bdy{costumeIdShort}_bust{bust}_cloth00"]; umaContainer.LoadPhysics(asset1); } } else { umaContainer.LoadBody(asset); //Load Physics var asset1 = Main.AbList[UmaDatabaseController.BodyPath + $"bdy{bodyid}_{costumeId}/clothes/pfb_bdy{bodyid}_{costumeId}_cloth00"]; umaContainer.LoadPhysics(asset1); asset1 = Main.AbList[UmaDatabaseController.BodyPath + $"bdy{bodyid}_{costumeId}/clothes/pfb_bdy{bodyid}_{costumeId}_bust_cloth00"]; umaContainer.LoadPhysics(asset1); } // Record Head Data int head_id = 1; string head_costumeId = "00"; int tailId = 1; CurrentHead = new UmaHeadData { id = id, costumeId = costumeId, tailId = tailId, chara = chara }; var head_s = head_id.ToString().PadLeft(4, '0'); string head = UmaDatabaseController.HeadPath + $"chr{head_s}_{head_costumeId}/pfb_chr{head_s}_{head_costumeId}_face{faceid.PadLeft(3, '0')}"; string hair = UmaDatabaseController.HeadPath + $"chr{head_s}_{head_costumeId}/pfb_chr{head_s}_{head_costumeId}_hair{hairid.PadLeft(3, '0')}"; Main.AbList.TryGetValue(head, out asset); Main.AbList.TryGetValue(hair, out UmaDatabaseEntry hairasset); bool isDefaultHead = true; if (asset != null && hairasset != null) { //Load Face And Hair Textures foreach (var asset1 in UmaViewerMain.Instance.AbChara.Where(a => a.Name.StartsWith($"{UmaDatabaseController.HeadPath}chr{head_s}_{head_costumeId}/textures"))) { if (asset1.Name.Contains($"tex_chr{head_s}_{head_costumeId}_face{faceid.PadLeft(3, '0')}_0") || asset1.Name.Contains($"tex_chr{head_s}_{head_costumeId}_face{faceid.PadLeft(3, '0')}_{skin}")) { umaContainer.LoadTextures(asset1); } if (asset1.Name.Contains($"tex_chr{head_s}_{head_costumeId}_hair{hairid.PadLeft(3, '0')}")) { umaContainer.LoadTextures(asset1); } } //Load face umaContainer.LoadHead(asset); //Load hair umaContainer.LoadHair(hairasset); umaContainer.MergeHairModel(); //Load Physics if (isDefaultHead) { if (Main.AbList.TryGetValue($"{UmaDatabaseController.HeadPath}chr{head_s}_00/clothes/pfb_chr{head_s}_00_hair{hairid.PadLeft(3, '0')}_cloth00", out UmaDatabaseEntry asset1)) { umaContainer.LoadPhysics(asset1); } } } if (tailId != 0) { string tailName = $"tail{tailId.ToString().PadLeft(4, '0')}_00"; string tailPath = $"3d/chara/tail/{tailName}/"; string tailPfb = tailPath + $"pfb_{tailName}"; asset = UmaViewerMain.Instance.AbChara.FirstOrDefault(a => a.Name == tailPfb); if (asset != null) { foreach (var asset1 in UmaViewerMain.Instance.AbChara.Where(a => a.Name.StartsWith($"{tailPath}textures/tex_{tailName}_{head_s}") || a.Name.StartsWith($"{tailPath}textures/tex_{tailName}_0000"))) { umaContainer.LoadTextures(asset1); } umaContainer.LoadTail(asset); //Load Physics if (Main.AbList.TryGetValue($"{tailPath}clothes/pfb_{tailName}_cloth00", out UmaDatabaseEntry asset2)) { umaContainer.LoadPhysics(asset2); } } else { Debug.Log("no tail"); } } umaContainer.LoadPhysics(); //Need to load physics before loading FacialMorph umaContainer.SetDynamicBoneEnable(UI.DynamicBoneEnable); //Load FacialMorph umaContainer.LoadFaceMorph(id, costumeId); umaContainer.TearControllers.ForEach(a => a.SetDir(a.CurrentDir)); umaContainer.HeadBone = (GameObject)umaContainer.Body.GetComponent()._assetTable["head"]; umaContainer.EyeHeight = umaContainer.Head.GetComponent()._assetTableValue["head_center_offset_y"]; umaContainer.MergeModel(); umaContainer.SetHeight(-1); umaContainer.Initialize(!UI.isTPose); umaContainer.Position = umaContainer.transform.Find("Position"); umaContainer.SetupBoneHandles(); if (!UI.isTPose && loadMotion) { if (Main.AbList.TryGetValue($"3d/motion/event/body/type00/anm_eve_type00_homestand{personality.PadLeft(2, '0')}_loop", out UmaDatabaseEntry entry)) { umaContainer.LoadAnimation(entry); } } } private void LoadMiniUma(UmaContainerCharacter umaContainer, CharaEntry chara, string costumeId) { int id = chara.Id; umaContainer.CharaEntry = chara; DataRow charaData = umaContainer.CharaData; umaContainer.IsMini = true; bool isGeneric = umaContainer.IsGeneric = costumeId.Length >= 4; string skin = charaData["skin"].ToString(), height = charaData["height"].ToString(), socks = charaData["socks"].ToString(), bust = charaData["bust"].ToString(), sex = charaData["sex"].ToString(), costumeIdShort = ""; bool customHead = true; UmaDatabaseEntry asset = null; if (isGeneric) { costumeIdShort = costumeId.Remove(costumeId.LastIndexOf('_')); string body = $"3d/chara/mini/body/mbdy{costumeIdShort}/pfb_mbdy{costumeId}_0"; Main.AbList.TryGetValue(body,out asset); } else Main.AbList.TryGetValue($"3d/chara/mini/body/mbdy{id}_{costumeId}/pfb_mbdy{id}_{costumeId}",out asset); if (asset == null) { Debug.LogError("No body, can't load!"); return; } else if (isGeneric) { string texPattern1 = ""; switch (costumeId.Split('_')[0]) { case "0003": texPattern1 = $"tex_mbdy{costumeIdShort}_00_{skin}_{0}"; break; default: texPattern1 = $"tex_mbdy{costumeId}_{skin}_{0}"; break; } //Load Body Textures foreach (var asset1 in UmaViewerMain.Instance.AbChara.Where(a => a.Name.StartsWith("3d/chara/mini/body/") && a.Name.Contains(texPattern1))) { umaContainer.LoadTextures(asset1); } //Load Body umaContainer.LoadBody(asset); } else umaContainer.LoadBody(asset); string hair = $"3d/chara/mini/head/mchr{id}_{costumeId}/pfb_mchr{id}_{costumeId}_hair"; Main.AbList.TryGetValue(hair, out asset); if (costumeId != "00" && asset == null) { customHead = false; Main.AbList.TryGetValue($"3d/chara/mini/head/mchr{id}_00/pfb_mchr{id}_00_hair", out asset); } if (asset != null) { //Load Hair Textures if (customHead) { foreach (var asset1 in UmaViewerMain.Instance.AbChara.Where(a => a.Name.StartsWith($"3d/chara/mini/head/mchr{id}_{costumeId}/textures"))) { umaContainer.LoadTextures(asset1); } } else { foreach (var asset1 in UmaViewerMain.Instance.AbChara.Where(a => a.Name.StartsWith($"3d/chara/mini/head/mchr{id}_00/textures"))) { umaContainer.LoadTextures(asset1); } } //Load Hair umaContainer.LoadHead(asset); } string head = $"3d/chara/mini/head/mchr0001_00/pfb_mchr0001_00_face0"; Main.AbList.TryGetValue(head,out asset); if (asset != null) { //Load Head Textures foreach (var asset1 in UmaViewerMain.Instance.AbChara.Where(a => a.Name.StartsWith($"3d/chara/mini/head/mchr0001_00/textures/tex_mchr0001_00_face0_{skin}"))) { umaContainer.LoadTextures(asset1); } //Load Head umaContainer.LoadHead(asset); } umaContainer.MergeModel(); var matList = new List(umaContainer.GetComponentsInChildren()); var eyemat = matList.FirstOrDefault(a => a.gameObject.name.Equals("M_Eye")); var mouthmat = matList.FirstOrDefault(a => a.gameObject.name.Equals("M_Mouth")); var eyebrowLmat = matList.FirstOrDefault(a => a.gameObject.name.Equals("M_Mayu_L")); var eyebrowRmat = matList.FirstOrDefault(a => a.gameObject.name.Equals("M_Mayu_R")); UI.LoadFacialPanelsMini(eyemat.material, eyebrowLmat.material, eyebrowRmat.material, mouthmat.material); umaContainer.Position = umaContainer.transform.Find("Position"); umaContainer.SetupBoneHandles(); if (Main.AbList.TryGetValue($"3d/motion/mini/event/body/chara/chr{id}_00/anm_min_eve_chr{id}_00_idle01_loop",out asset)) { umaContainer.LoadAnimation(asset); } } public void LoadProp(UmaDatabaseEntry entry) { UnloadProp(); UmaAssetManager.UnloadAllBundle(); var prop = new GameObject(Path.GetFileName(entry.Name)).AddComponent(); prop.LoadProp(entry); CurrentOtherContainer = prop; } public void LoadLive(LiveEntry live, List characters) { characters.ForEach(a => { if (a.CharaEntry == null || a.CostumeId == "") { a.CharaEntry = Main.Characters[Random.Range(0, Main.Characters.Count / 2)]; a.CostumeId = "0002_00_00"; } });//fill empty UmaAssetManager.PreLoadAndRun(Director.GetLiveAllVoiceEntry(live.MusicId, characters), delegate { UmaSceneController.LoadScene("LiveScene", delegate { GameObject MainLive = Instantiate(LiveControllerPrefab); Director mController = MainLive.GetComponentInChildren(); mController.live = live; mController.IsRecordVMD = UI.isRecordVMD; mController.RequireStage = UI.isRequireStage; List transferObjs = new List() { MainLive, GameObject.Find("ViewerMain"), GameObject.Find("Directional Light"), GameObject.Find("GlobalShaderController"), GameObject.Find("AudioManager") }; // Move the GameObject (you attach this in the Inspector) to the newly loaded Scene transferObjs.ForEach(o => SceneManager.MoveGameObjectToScene(o, SceneManager.GetSceneByName("LiveScene"))); mController.Initialize(); var actual_member_count = mController._liveTimelineControl.data.worksheetList[0].charaMotSeqList.Count; if (actual_member_count > characters.Count) { Debug.LogWarning($"actual member count is {actual_member_count} current {characters.Count}"); var actual_characters = new List(); for (int i = 0; i < actual_member_count; i++) { actual_characters.Add(characters[i % characters.Count]); } characters = actual_characters; } LoadLiveUma(characters); var Lyrics = LoadLiveLyrics(live.MusicId); if (Lyrics != null) { LiveViewerUI.Instance.CurrentLyrics = Lyrics; } }, delegate { Director.instance.InitializeUI(); Director.instance.InitializeTimeline(characters, UI.LiveMode); Director.instance.InitializeMusic(live.MusicId, characters); Director.instance.Play(); LiveViewerUI.Instance.RecordingUI.SetActive(Gallop.Live.Director.instance.IsRecordVMD); }); }); } //Use decrypt function public void LoadLiveSound(int songid, UmaDatabaseEntry SongAwb, bool needLyrics = true) { //load character voice if (SongAwb != null) { PlaySound(SongAwb); } //load BG string nameVar = $"snd_bgm_live_{songid}_oke"; UmaDatabaseEntry BGawb = Main.AbSounds.FirstOrDefault(a => a.Name.Contains(nameVar) && a.Name.EndsWith("awb")); if (BGawb != null) { var BGclip = LoadAudio(BGawb); if (BGclip.Count > 0) { AddAudioSource(BGclip[0]); } } if (needLyrics) { LoadLiveLyrics(songid); } } public void loadLivePreviewSound(int songid) { string nameVar = $"snd_bgm_live_{songid}_preview_02"; UmaDatabaseEntry previewAwb = Main.AbSounds.FirstOrDefault(a => a.Name.Contains(nameVar) && a.Name.EndsWith("awb")); if (previewAwb != null) { PlaySound(previewAwb, volume : 0.4f, loop : true); } } public void PlaySound(UmaDatabaseEntry SongAwb, int subindex = -1, float volume = 1, bool loop = false) { CurrentLyrics.Clear(); if (CurrentAudioSources.Count > 0) { var tmp = CurrentAudioSources[0]; CurrentAudioSources.Clear(); Destroy(tmp.gameObject); UI.ResetAudioPlayer(); } if (subindex == -1) { foreach (AudioClip clip in LoadAudio(SongAwb)) { AddAudioSource(clip, volume, loop); } } else { AddAudioSource(LoadAudio(SongAwb)[subindex], volume, loop); } } private void AddAudioSource(AudioClip clip, float volume = 1, bool loop = false) { AudioSource source; if (CurrentAudioSources.Count > 0) { source = CurrentAudioSources[0].gameObject.AddComponent(); } else { source = new GameObject("SoundController").AddComponent(); } CurrentAudioSources.Add(source); source.clip = clip; source.volume = volume; source.loop = loop; source.Play(); } public static List LoadAudio(UmaDatabaseEntry awb) { List clips = new List(); string awbPath = awb.FilePath; if (!File.Exists(awbPath)) return clips; FileStream awbFile = File.OpenRead(awbPath); AwbReader awbReader = new AwbReader(awbFile); foreach (Wave wave in awbReader.Waves) { var stream = new UmaWaveStream(awbReader, wave.WaveId); var sampleProvider = stream.ToSampleProvider(); int channels = stream.WaveFormat.Channels; int bytesPerSample = stream.WaveFormat.BitsPerSample / 8; int sampleRate = stream.WaveFormat.SampleRate; AudioClip clip = AudioClip.Create( Path.GetFileNameWithoutExtension(awb.Name) + "_" + wave.WaveId.ToString(), (int)(stream.Length / channels / bytesPerSample), channels, sampleRate, true, data => sampleProvider.Read(data, 0, data.Length), position => stream.Position = position * channels * bytesPerSample); clips.Add(clip); } return clips; } public List LoadLiveLyrics(int songid) { if (CurrentLyrics.Count > 0) CurrentLyrics.Clear(); string lyricsVar = $"live/musicscores/m{songid}/m{songid}_lyrics"; UmaDatabaseEntry lyricsAsset = Main.AbList[lyricsVar]; AssetBundle bundle = UmaAssetManager.LoadAssetBundle(lyricsAsset); TextAsset asset = bundle.LoadAsset(Path.GetFileNameWithoutExtension(lyricsVar)); string[] lines = asset.text.Split("\n"[0]); for (int i = 1; i < lines.Length; i++) { string[] words = lines[i].Split(','); if (words.Length > 0) { try { UmaLyricsData lyricsData = new UmaLyricsData() { time = float.Parse(words[0]) / 1000, text = (words.Length > 1) ? words[1] : "" }; CurrentLyrics.Add(lyricsData); } catch { } } } return CurrentLyrics; } public void LoadAssetPath(string path, Transform SetParent) { Instantiate(UmaViewerMain.Instance.AbList[path].Get(), SetParent); } public void SetPreviewCamera(AnimationClip clip) { if (clip) { if (!AnimationCameraAnimator.runtimeAnimatorController) { AnimationCameraAnimator.runtimeAnimatorController = Instantiate(CameraOverrideController); } (AnimationCameraAnimator.runtimeAnimatorController as AnimatorOverrideController)["clip_1"] = clip; AnimationCamera.enabled = true; AnimationCameraAnimator.Play("motion_1", 0, 0); CurrentUMAContainer?.SetHeight(0); } else { AnimationCamera.enabled = false; CurrentUMAContainer?.SetHeight(-1); } } public Sprite LoadCharaIcon(string id) { string value = $"chara/chr{id}/chr_icon_{id}"; if (UmaViewerMain.Instance.AbList.TryGetValue(value, out UmaDatabaseEntry entry)) { AssetBundle assetBundle = UmaAssetManager.LoadAssetBundle(entry, true); if (assetBundle.Contains($"chr_icon_{id}")) { Texture2D texture = (Texture2D)assetBundle.LoadAsset($"chr_icon_{id}"); Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero); assetBundle.Unload(false); return sprite; } } return null; } public Sprite LoadMobCharaIcon(string id) { string value = $"mob/mob_chr_icon_{id}_000001_01"; if (UmaViewerMain.Instance.AbList.TryGetValue(value, out UmaDatabaseEntry entry)) { string path = entry.FilePath; AssetBundle assetBundle = UmaAssetManager.LoadAssetBundle(entry, true); if (assetBundle.Contains($"mob_chr_icon_{id}_000001_01")) { Texture2D texture = (Texture2D)assetBundle.LoadAsset($"mob_chr_icon_{id}_000001_01"); Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero); assetBundle.Unload(false); return sprite; } } return null; } public Sprite LoadSprite(UmaDatabaseEntry item) { AssetBundle assetBundle = UmaAssetManager.LoadAssetBundle(item, true); Texture2D texture = (Texture2D)assetBundle.LoadAsset(assetBundle.GetAllAssetNames()[0]); Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero); assetBundle.Unload(false); return sprite; } public Sprite LoadLiveIcon(int musicid) { string value = $"live/jacket/jacket_icon_l_{musicid}"; if (UmaViewerMain.Instance.AbList.TryGetValue(value, out UmaDatabaseEntry entry)) { AssetBundle assetBundle = UmaAssetManager.LoadAssetBundle(entry, true); if (assetBundle.Contains($"jacket_icon_l_{musicid}")) { Texture2D texture = (Texture2D)assetBundle.LoadAsset($"jacket_icon_l_{musicid}"); Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero); assetBundle.Unload(false); return sprite; } } return null; } public void UnloadProp() { if (CurrentOtherContainer != null) { Destroy(CurrentOtherContainer.gameObject); } } public void UnloadUma() { PoseManager.SetPoseModeStatic(false); if (CurrentUMAContainer != null) { //It seems that OnDestroy will executed after new model loaded, which cause new FacialPanels empty... UmaViewerUI.Instance.currentFaceDrivenKeyTarget = null; UmaViewerUI.Instance.LoadEmotionPanels(null); UmaViewerUI.Instance.LoadFacialPanels(null); if (UmaViewerUI.Instance.MaterialsList) foreach (Transform t in UmaViewerUI.Instance.MaterialsList.content) { Destroy(t.gameObject); } if (CurrentUMAContainer.transform.parent && CurrentUMAContainer.transform.parent.name.Contains("Root")) { Destroy(CurrentUMAContainer.transform.parent.gameObject); } else { Destroy(CurrentUMAContainer.gameObject); } } } public void ClearMorphs() { var umaContainer = CurrentUMAContainer; if (umaContainer != null && umaContainer.FaceDrivenKeyTarget != null) { foreach (var container in UI.EmotionList.GetComponentsInChildren()) { if (container.Slider != null) container.Slider.value = 0; } foreach (var container in UI.FacialList.GetComponentsInChildren()) { if (container.Slider != null) container.Slider.SetValueWithoutNotify(0); } if (umaContainer.FaceDrivenKeyTarget) { umaContainer.FaceDrivenKeyTarget.ClearAllWeights(); umaContainer.FaceDrivenKeyTarget.ChangeMorph(); } } } public void UnloadAllBundle() => UmaAssetManager.UnloadAllBundle(true); private void FixedUpdate() { if (AnimationCamera && AnimationCamera.enabled == true) { var fov = AnimationCamera.gameObject.transform.parent.transform.localScale.x; AnimationCamera.fieldOfView = fov; } } }