using Cryville.Common; using Cryville.Common.Unity; using Cryville.Crtr.Extension; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEngine; using Logger = Cryville.Common.Logger; namespace Cryville.Crtr.Browsing { internal class LegacyResourceManager : IResourceManager { private readonly string _rootPath; private DirectoryInfo cd; private DirectoryInfo[] items = new DirectoryInfo[0]; public string[] CurrentDirectory { get; private set; } static readonly Dictionary> converters = new Dictionary>(); static readonly Dictionary localRes = new Dictionary(); public LegacyResourceManager(string rootPath) { _rootPath = rootPath; } static LegacyResourceManager() { foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) { foreach (var type in asm.GetTypes()) { if (!type.IsSubclassOf(typeof(ExtensionInterface))) continue; var ext = (ExtensionInterface)Activator.CreateInstance(type); try { var cs = ext.GetResourceConverters(); if (cs != null) { foreach (var c in cs) { var fs = c.GetSupportedFormats(); if (fs == null) continue; foreach (var f in fs) { if (f == null) continue; if (!converters.ContainsKey(f)) converters.Add(f, new List { c }); else converters[f].Add(c); } } } var fs2 = ext.GetResourceFinders(); if (fs2 != null) { foreach (var f in fs2) { var name = f.Name; var path = f.GetRootPath(); if (name != null && path != null) localRes.Add(name, path); } } Logger.Log("main", 1, "Resource", "Loaded extension {0}", ReflectionHelper.GetNamespaceQualifiedName(type)); } catch (Exception ex) { Logger.Log("main", 4, "Resource", "Failed to initialize extension {0}: {1}", ReflectionHelper.GetNamespaceQualifiedName(type), ex); } } } } public int ChangeDirectory(string[] dir) { CurrentDirectory = dir; cd = new DirectoryInfo(_rootPath + "/charts/" + string.Join("/", dir)); items = cd.GetDirectories(); return items.Length; } public int OpenDirectory(int id) { string[] nd = new string[CurrentDirectory.Length + 1]; Array.Copy(CurrentDirectory, nd, CurrentDirectory.Length); nd[CurrentDirectory.Length] = items[id].Name; return ChangeDirectory(nd); } public int ReturnToDirectory(int id) { string[] nd = new string[id + 1]; Array.Copy(CurrentDirectory, nd, id + 1); return ChangeDirectory(nd); } public ResourceItemMeta GetItemMeta(int id) { var item = items[id]; var meta = new ChartMeta(); string name = item.Name; string desc = "(Unknown)"; var metaFile = new FileInfo(item.FullName + "/.umgc"); if (metaFile.Exists) { using (var reader = new StreamReader(metaFile.FullName)) { meta = JsonConvert.DeserializeObject(reader.ReadToEnd()); name = meta.song.name; desc = meta.name; } } AsyncDelivery cover = null; if (meta.cover != null && meta.cover != "") { var coverFile = item.GetFiles(meta.cover); if (coverFile.Length > 0) { cover = new AsyncDelivery(); var task = new LoadTextureTask(Game.FileProtocolPrefix + coverFile[0].FullName, cover.Deliver); cover.CancelSource = task.Cancel; Game.NetworkTaskWorker.SubmitNetworkTask(task); } } return new ResourceItemMeta { IsDirectory = false, Icon = cover, Name = name, DescriptionMain = desc, }; } public ChartDetail GetItemDetail(int id) { var item = items[id]; var meta = new ChartMeta(); var metaFile = new FileInfo(item.FullName + "/.umgc"); if (metaFile.Exists) { using (var reader = new StreamReader(metaFile.FullName)) { meta = JsonConvert.DeserializeObject(reader.ReadToEnd()); } } AsyncDelivery cover = null; if (meta.cover != null && meta.cover != "") { var coverFile = item.GetFiles(meta.cover); if (coverFile.Length > 0) { cover = new AsyncDelivery(); var task = new LoadTextureTask(Game.FileProtocolPrefix + coverFile[0].FullName, cover.Deliver); cover.CancelSource = task.Cancel; Game.NetworkTaskWorker.SubmitNetworkTask(task); } } return new ChartDetail { Cover = cover, Meta = meta, }; } public string GetItemPath(int id) { var item = items[id]; var meta = new ChartMeta(); var metaFile = new FileInfo(item.FullName + "/.umgc"); using (var reader = new StreamReader(metaFile.FullName)) { meta = JsonConvert.DeserializeObject(reader.ReadToEnd()); } return string.Format("{0}/{1}.json", items[id].Name, meta.data); } public bool ImportItemFrom(string path) { var file = new FileInfo(path); if (!converters.ContainsKey(file.Extension)) return false; foreach (var converter in converters[file.Extension]) { IEnumerable resources = null; try { resources = converter.ConvertFrom(file); } catch (Exception ex) { LogAndPopupExtra(4, ex, "Failed to import resource: {0}", ex.Message); return false; } foreach (var res in resources) { if (!res.Valid) { LogAndPopup(3, "Attempt to import invalid resource: {0}", res); } else if (res is RawChartResource) { var tres = (RawChartResource)res; var dir = new DirectoryInfo(_rootPath + "/charts/" + res.Name); if (!dir.Exists) dir.Create(); using (var writer = new StreamWriter(dir.FullName + "/.json")) { writer.Write(JsonConvert.SerializeObject(ConvertChartData(tres.Main), Game.GlobalJsonSerializerSettings)); } using (var writer = new StreamWriter(dir.FullName + "/.umgc")) { tres.Meta.data = ""; writer.Write(JsonConvert.SerializeObject(tres.Meta, Game.GlobalJsonSerializerSettings)); } if (tres.Meta.cover != null) { var coverFile = new FileInfo(Path.Combine(file.Directory.FullName, tres.Meta.cover)); if (coverFile.Exists) coverFile.CopyTo(Path.Combine(dir.FullName, tres.Meta.cover), true); } } else if (res is FileResource) { var tres = (FileResource)res; DirectoryInfo dest; if (res is ChartResource) dest = new DirectoryInfo(_rootPath + "/charts/" + res.Name); else if (res is RulesetResource) dest = new DirectoryInfo(_rootPath + "/rulesets/" + res.Name); else if (res is SkinResource) dest = new DirectoryInfo(_rootPath + "/skins/" + (res as SkinResource).RulesetName + "/" + res.Name); else if (res is SongResource) dest = new DirectoryInfo(_rootPath + "/songs/" + res.Name); else { LogAndPopup(3, "Attempt to import unsupported file resource: {0}", res); continue; } if (!dest.Exists) { dest.Create(); tres.Master.CopyTo(Path.Combine(dest.FullName, tres.Master.Extension)); foreach (var attachment in tres.Attachments) { attachment.CopyTo(Path.Combine(dest.FullName, attachment.Name)); } } else LogAndPopup(1, "Resource already exists: {0}", res); } else { LogAndPopup(3, "Attempt to import unsupported resource: {0}", res); } } return true; } return false; } void LogAndPopup(int level, string format, params object[] args) { var msg = string.Format(format, args); Logger.Log("main", level, "Resource", msg); Popup.Create(msg); } void LogAndPopupExtra(int level, object extraLog, string format, params object[] args) { var msg = string.Format(format, args); Logger.Log("main", level, "Resource", "{0}\n{1}", msg, extraLog); Popup.Create(msg); } public string[] GetSupportedFormats() { return converters.Keys.ToArray(); } public Dictionary GetPresetPaths() { return localRes; } static Chart ConvertChartData(ChartData i) { return new Chart { endtime = ConvertBeatTime(i.endtime), format = i.format, groups = ConvertGroups(i.groups), motions = ConvertMotions(i.motions), ruleset = i.ruleset, sigs = ConvertSignatures(i.sigs), sounds = ConvertSounds(i.sounds), time = ConvertBeatTime(i.time), }; } static BeatTime? ConvertBeatTime(Extension.BeatTime? value) { if (value == null) return null; return new BeatTime(value.Value.b, value.Value.n, value.Value.d); } static List ConvertGroups(List l) { return l.Select(i => new Chart.Group { endtime = ConvertBeatTime(i.endtime), motions = ConvertMotions(i.motions), notes = ConvertNotes(i.notes), time = ConvertBeatTime(i.time), tracks = ConvertTracks(i.tracks), }).ToList(); } static List ConvertJudges(List l) { return l.Select(i => new Chart.Judge { endtime = ConvertBeatTime(i.endtime), name = i.name, time = ConvertBeatTime(i.time), }).ToList(); } static List ConvertMotions(List l) { return l.Select(i => new Chart.Motion { endtime = ConvertBeatTime(i.endtime), motion = i.motion, sumfix = i.sumfix, time = ConvertBeatTime(i.time), }).ToList(); } static List ConvertNotes(List l) { return l.Select(i => new Chart.Note { endtime = ConvertBeatTime(i.endtime), judges = ConvertJudges(i.judges), motions = ConvertMotions(i.motions), time = ConvertBeatTime(i.time), }).ToList(); } static List ConvertSignatures(List l) { return l.Select(i => new Chart.Signature { endtime = ConvertBeatTime(i.endtime), tempo = i.tempo, time = ConvertBeatTime(i.time), }).ToList(); } static List ConvertSounds(List l) { return l.Select(i => new Chart.Sound { endtime = ConvertBeatTime(i.endtime), id = i.id, offset = i.offset, time = ConvertBeatTime(i.time), }).ToList(); } static List ConvertTracks(List l) { return l.Select(i => new Chart.Track { endtime = ConvertBeatTime(i.endtime), motions = ConvertMotions(i.motions), time = ConvertBeatTime(i.time), }).ToList(); } } }