using Cryville.Crtr.Extension; using Cryville.Crtr.Extensions.Umg; using Cryville.Crtr.Extensions; using Cryville.Crtr.UI; using Newtonsoft.Json; using System.Collections.Generic; using System.IO; using System; using System.Linq; using Cryville.Crtr.Browsing.Actions; namespace Cryville.Crtr.Browsing.Legacy { internal class LegacyResourceStore : IResourceDestination { public string RootPath { get; private set; } public IResourceAction ImportAction { get; private set; } public event Action ResourceImported; static bool _init; public LegacyResourceStore(string rootPath) { RootPath = rootPath; ImportAction = new ImportResourceAction(this); if (!_init) { _init = true; ExtensionManager.Init(rootPath); } } public bool CanImport(Uri uri) { if (!uri.IsFile) return false; return CanImportFile(new FileInfo(uri.LocalPath)); } protected bool CanImportFile(FileInfo file) { return !file.FullName.StartsWith(new DirectoryInfo(RootPath).FullName); } public bool ImportFrom(Uri uri) { var file = new FileInfo(uri.LocalPath); if (!ExtensionManager.TryGetConverters(file.Extension, out IEnumerable converters)) return false; foreach (var converter in converters) { var resources = new List(); var ses = new ConversionSession { OnResourceAdd = res => resources.Add(res) }; try { converter.Convert(file, ses); } 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(Path.Combine(RootPath, "charts", res.Name)); if (!dir.Exists) dir.Create(); using (var writer = new StreamWriter(Path.Combine(dir.FullName, ".json"))) { writer.Write(JsonConvert.SerializeObject(ConvertChartData(tres.Main), Game.GlobalJsonSerializerSettings)); } using (var writer = new StreamWriter(Path.Combine(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 tres) { DirectoryInfo dest; bool singleFileFlag = false; if (res is ChartResource) dest = new DirectoryInfo(Path.Combine(RootPath, "charts", res.Name)); else if (res is ExtensionResource) { dest = new DirectoryInfo(Path.Combine(RootPath, "extensions")); singleFileFlag = true; Popup.Create("Please restart the game to reload the extensions"); } else if (res is RulesetResource) dest = new DirectoryInfo(Path.Combine(RootPath, "rulesets", res.Name)); else if (res is SkinResource) dest = new DirectoryInfo(Path.Combine(RootPath, "skins", (res as SkinResource).RulesetName, res.Name)); else if (res is SongResource) dest = new DirectoryInfo(Path.Combine(RootPath, "songs", res.Name)); else { LogAndPopup(3, "Attempt to import unsupported file resource: {0}", res); continue; } if (singleFileFlag || !dest.Exists) { dest.Create(); tres.Master.CopyTo(Path.Combine(dest.FullName, singleFileFlag ? tres.Master.Name : tres.Master.Extension)); foreach (var attachment in tres.Attachments) { if (singleFileFlag) throw new InvalidOperationException("Internal error"); attachment.CopyTo(Path.Combine(dest.FullName, attachment.Name)); } } else Game.MainLogger.Log(1, "Resource", "Resource already exists: {0}", res); } else { LogAndPopup(3, "Attempt to import unsupported resource: {0}", res); } } ResourceImported?.Invoke(); return true; } return false; } void LogAndPopup(int level, string format, params object[] args) { var msg = string.Format(format, args); Game.MainLogger.Log(level, "Resource", msg); Popup.Create(msg); } void LogAndPopupExtra(int level, object extraLog, string format, params object[] args) { var msg = string.Format(format, args); Game.MainLogger.Log(level, "Resource", "{0}\n{1}", msg, extraLog); Popup.Create(msg); } 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(); } } }