using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; using UnityEngine; public class KF3AssetLibrary : AssetLibrary { public List CharaData = new List(); public List AssetBundles = new List(); public List Characters = new List(); public List Animations = new List(); public List AnimationSets = new List(); public List Ceruleans = new List(); public Dictionary> CeruleansD = new Dictionary>(); public List CeruleanAnimationSets = new List(); public List Effects = new List(); public List Furniture = new List(); public List Icons = new List(); public List Miracles = new List(); public List Skies = new List(); public List Stages = new List(); public List Misc = new List(); public static KF3AssetLibrary Instance => GetInstance(); public IEnumerator Init() { _mainInstance = this; string charaData = LoadGzipFile("CHARA_DATA"); if (charaData != "error") { Error.Log(Color.green, "Loaded Chara_Data from KF3 cache"); CharaData = JsonHelper.getJsonArray(charaData).ToList(); } KF3Names.LoadCeruleanNames(); if (GetComponent().IsOnline) { yield return GetAbList(); } if (AssetBundles.Count <= 0) { Error.Log(Color.red, "Failed to load ab_list.txt"); } yield break; } public string LoadGzipFile(string fileName) { string openFile = Path.Combine(Settings.CacheDirectory, "CHARA_DATA.d"); if (!File.Exists(openFile)) { Error.Log(Color.blue, "CHARA_DATA cache file not found, character names may be outdated"); return "error"; } using (Stream decompress = new GZipStream(File.OpenRead(openFile), CompressionMode.Decompress)) using (StreamReader stringWriter = new StreamReader(decompress)) { return stringWriter.ReadToEnd(); } } private IEnumerator GetAbList() { //LOAD GAME VERSION Error.Log(Color.green, $"Game Version is {Settings.GameVersion}"); //LOAD ASSETS URL Error.Log(Color.green, $"Assets server address is: {Settings.AssetsUrl}"); //LOAD AB_LIST string filePath = Path.Combine(Settings.AssetListDirectory, "ab_list.txt"); if (File.Exists(filePath)) { LoadText(File.ReadAllText(filePath)); Error.Log(Color.green, $"Loaded ab file from {filePath}"); } else if (KF3ModelViewerMain.Instance.IsOnline) { WWW www = new WWW(Settings.AssetsUrl + "/Windows/1.0.0/ja/ab_list.txt"); yield return www; string response = www.text; if (!string.IsNullOrEmpty(response)) { LoadText(response); Error.Log(Color.green, $"ab file downloaded"); File.WriteAllText(filePath, response); } else { Error.Log(Color.red, $"Failed to load ab file"); } } else { Error.Log(Color.red, $"Failed to load ab file"); } //Load loose assets foreach(var fileName in Directory.GetFiles(Settings.LooseAssetsDirectory)) { string name = Path.GetFullPath(fileName); KF3AssetBundle bundle = new KF3AssetBundle(Path.GetFileName(name)); bundle.FullPath = name; AddToCategory(bundle, bundle.DisplayName); } } public KF3AssetBundle Find(string fileName) { return AssetBundles.FirstOrDefault(ab => ab.FileName == fileName); } public IEnumerator LoadAsset(KF3AssetBundle bundle, Action callback) { if(bundle == null) { callback?.Invoke(null); yield break; } if (File.Exists(bundle.FullPath)) { callback?.Invoke(AssetBundle.LoadFromFile(bundle.FullPath)); yield break; } else if (KF3ModelViewerMain.Instance.IsOnline) { AssetBundle assetBundle = null; yield return DownloadAssetBundle(bundle, (ab) => { assetBundle = ab; }); if(assetBundle != null) { callback?.Invoke(assetBundle); yield break; } else { callback?.Invoke(null); yield break; } } else { Error.Log(Color.yellow, $"{bundle.FileName} Does not exist"); callback?.Invoke(null); } } public IEnumerator DownloadAssetBundle(KF3AssetBundle bundle, System.Action callback) { string saveTo = bundle.FullPath; string url = Settings.AssetsUrl + "/Windows/1.0.0/ja/assets/" + bundle.FileName; Error.Log($"Downloading\n{url}\nto\n{saveTo}", Color.blue); WWW www = new WWW(url); yield return www; if (!string.IsNullOrEmpty(www.error)) { Error.Log(Color.red, www.error); www.Dispose(); callback(null); yield break; } byte[] bytes = www.bytes; Directory.CreateDirectory(Path.GetDirectoryName(saveTo)); File.WriteAllBytes(saveTo, bytes); www.Dispose(); Error.Log(Color.green, $"Download Successful"); callback(AssetBundle.LoadFromFile(saveTo)); } /// /// Load AssetBundle list /// private void LoadText(string abListTxt) { int loaded = 0; int total = 0; using (StringReader reader = new StringReader(abListTxt)) { while (reader.Peek() >= 0) { total++; string line = reader.ReadLine(); if (string.IsNullOrEmpty(line)) { continue; } loaded++; string[] temp = line.Split(new string[] { " ", "\t" }, StringSplitOptions.RemoveEmptyEntries); string bundleName = temp[0]; KF3AssetBundle bundle = new KF3AssetBundle(bundleName); AddToCategory(bundle, bundleName); } } Error.Log(Color.green, $"Loaded {loaded}/{total} AB lines"); } private void AddToCategory(KF3AssetBundle bundle, string bundleName) { //add to global list AssetBundles.Add(bundle); //add to characters list if (bundleName.StartsWith("ch_") && bundleName.EndsWith("_a.prefab")) { bundle.IdStr = bundleName.Split('_', '.')[1]; bundle.IdNum = int.Parse(bundle.IdStr); if (bundle.IdNum < 10000) { Characters.Add(bundle); } else { bundle.DisplayName = KF3Names.GetEnemyName(bundle.IdNum); Ceruleans.Add(bundle); if (CeruleansD.ContainsKey(bundle.DisplayName)) { CeruleansD[bundle.DisplayName].Add(bundle); } else { CeruleansD.Add(bundle.DisplayName, new List() { bundle }); } } } else if (bundleName.StartsWith("icon_")) { Icons.Add(bundle); } else if (bundleName.StartsWith("captainroom_")) { bundle.DisplayName = bundle.DisplayName.Replace("captainroom_obj_", "").Replace("_mdl.prefab", ""); Furniture.Add(bundle); } else if (bundleName.StartsWith("ch_") && bundleName.EndsWith("_mot.prefab")) { bundle.IdStr = bundleName.Split('_', '.')[1]; bundle.IdNum = int.Parse(bundle.IdStr); Animations.Add(bundle); if (bundleName.EndsWith("a_mot.prefab")) { if (bundle.IdNum < 10000) { bundle.DisplayName = bundle.IdStr + "_" + KF3Names.GetCharaName(bundle.IdNum); AnimationSets.Add(bundle); } else { bundle.DisplayName = KF3Names.GetEnemyName(bundle.IdNum); CeruleanAnimationSets.Add(bundle); } } } else if (bundleName.StartsWith("st_")) { Stages.Add(bundle); } else if (bundleName.StartsWith("sky_")) { Skies.Add(bundle); } else if (bundleName.StartsWith("ef_auth")) { bundle.DisplayName = bundleName.Replace("ef_auth", ""); Miracles.Add(bundle); } else if (bundleName.StartsWith("ef_")) { Effects.Add(bundle); Misc.Add(bundle); } } /// /// Get a list of costumes from selected character id /// public List GetCostumesFromId(int id) { if (id > 9999) { id = id / 10; return AssetBundles.Where(k => k.FileName.StartsWith($"ch_{id.ToString().PadLeft(4, '0')}") && !k.FileName.Contains("mot") && k.FileName.Split(new char[] { '.', '_' }).Length == 4) .ToList().ConvertAll(o=>(KF3AssetBundle)o); } else { return AssetBundles.Where(k => k.FileName.StartsWith($"ch_{id.ToString().PadLeft(4, '0')}") && !k.FileName.Contains("mot") && k.FileName.Split(new char[] { '.', '_' }).Length == 4) .ToList().ConvertAll(o => (KF3AssetBundle)o); } } public KF3AssetBundle GetAnimationSet(string name) { if(int.TryParse(name.Split('_','.')[1], out int id)){ return GetAnimationSet(id); } return (KF3AssetBundle)AnimationSets.FirstOrDefault(a => a.DisplayName == name || a.FileName == name); } public KF3AssetBundle GetAnimationSet(int id) { return (KF3AssetBundle)AnimationSets.FirstOrDefault(a => int.Parse(a.FileName.Split('_', '.')[1]) == id); } public List GetMisc() { return Misc.ConvertAll(k=>(KF3AssetBundle)k); } public List GetMiracles() { return Miracles.ConvertAll(k => (KF3AssetBundle)k); } public List GetCeruleans(string name) { return CeruleansD[name]; } public KF3AssetBundle GetFurnitureBundle(string bundleName) { return (KF3AssetBundle)Furniture.FirstOrDefault(a => a.DisplayName == bundleName || a.FileName == bundleName); } public KF3AssetBundle GetMiscBundle(string bundleName) { return (KF3AssetBundle)Misc.FirstOrDefault(a => a.DisplayName == bundleName || a.FileName == bundleName); } public KF3AssetBundle GetMiracleBundle(string bundleName) { return (KF3AssetBundle)Miracles.FirstOrDefault(a => a.DisplayName == bundleName || a.FileName == bundleName); } }