using System; using System.Collections.Generic; using System.IO; namespace NHSE.Core; /// /// Logic for dumping decrypted game files. /// /// public static class GameFileDumper { /// /// Dumps a copy of the 's files in their decrypted state to the requested . /// /// Save Data to dump /// Path to dump to public static void Dump(this HorizonSave sav, string path) { sav.Main.Dump(path); foreach (var p in sav.Players) { var dir = Path.Combine(path, p.DirectoryName); p.Dump(dir); } } /// /// Dumps a copy of the 's files in their decrypted state to the requested . /// /// Save Data to dump /// Path to dump to public static void Dump(this Player player, string path) { foreach (var pair in player) pair.Dump(path); } /// /// Dumps a copy of the 's files in their decrypted state to the requested . /// /// Save Data to dump /// Path to dump to public static void Dump(this EncryptedFilePair pair, string path) { Dump(path, pair.Data, pair.NameData); } private static void Dump(string path, ReadOnlySpan data, string name) { Directory.CreateDirectory(path); var file = Path.Combine(path, name); File.WriteAllBytes(file, data); } /// /// Dumps all villager houses to the requested . /// /// /// /// Path to dump to public static void DumpPlayerHouses(this IReadOnlyList houses, IReadOnlyList players, string path) { for (int i = 0; i < houses.Count; i++) { var filename = i < players.Count ? players[i].Personal.PlayerName : $"House {i}"; houses[i].Dump(filename, path); } } /// /// Dumps all villager houses to the requested . /// /// Save Data to dump from /// Path to dump to public static void DumpPlayerHouses(this HorizonSave sav, string path) { var count = Math.Min(sav.Players.Count, MainSaveOffsets.PlayerCount); for (int i = 0; i < count; i++) { var p = sav.Players[i]; var h = sav.Main.GetPlayerHouse(i); h.Dump(path, p.Personal); } } private static void Dump(this IPlayerHouse h, string path, Personal p) => h.Dump(p.PlayerName, path); private static void Dump(this IPlayerHouse h, string player, string path) { var dest = Path.Combine(path, $"{player}.{h.Extension}"); var data = h.Write(); File.WriteAllBytes(dest, data); } /// /// Dumps all villager houses to the requested . /// /// Save Data to dump from /// Path to dump to public static void DumpVillagerHouses(this MainSave sav, string path) { for (int i = 0; i < MainSaveOffsets.VillagerCount; i++) { var v = sav.GetVillager(i); var h = sav.GetVillagerHouse(i); h.Dump(path, v); } } private static void Dump(this IVillagerHouse h, string path, IVillager v) { var name = GameInfo.Strings.GetVillager(v.InternalName); var dest = Path.Combine(path, $"{name}.{h.Extension}"); var data = h.Write(); File.WriteAllBytes(dest, data); } /// /// Dumps all villagers to the requested . /// /// Data to dump from /// Path to dump to public static void Dump(this IEnumerable villagers, string path) { foreach (var v in villagers) v.Dump(path); } private static void Dump(this IVillager v, string path) { var name = GameInfo.Strings.GetVillager(v.InternalName); var dest = Path.Combine(path, $"{name}.{v.Extension}"); File.WriteAllBytes(dest, v.Write()); } /// /// Dumps all designs to the requested . /// /// Save Data to dump from /// Path to dump to /// Export file names prepended with design index public static void DumpDesigns(this MainSave sav, string path, bool indexed) { for (int i = 0; i < sav.Offsets.PatternCount; i++) { var dp = sav.GetDesign(i); dp.Dump(path, i, indexed); } } /// /// Dumps all designs to the requested . /// /// Patterns to dump /// Path to dump to /// Export file names prepended with design index public static void Dump(this IReadOnlyList patterns, string path, bool indexed) { for (var index = 0; index < patterns.Count; index++) { var dp = patterns[index]; dp.Dump(path, index, indexed); } } private static void Dump(this DesignPattern dp, string path, int index, bool indexed) { var name = dp.DesignName; string fn = indexed ? $"{index:00} - {name}.nhd" : $"{name}.nhd"; fn = StringUtil.CleanFileName(fn); var dest = Path.Combine(path, fn); File.WriteAllBytes(dest, dp.Data); } /// /// Loads all designs from the requested . /// /// Patterns to load /// Path to load from /// Change origins of Patterns public static void Load(this DesignPattern[] patterns, string path, Personal player, bool changeOrigins) { if (patterns.Length == 0) return; var files = Directory.GetFiles(path, "*.nhd", SearchOption.TopDirectoryOnly); int ctr = 0; foreach (var f in files) { var fi = new FileInfo(f); if (fi.Length != DesignPattern.SIZE) continue; var data = File.ReadAllBytes(f); var p = new DesignPattern(data); if (changeOrigins) p.ChangeOrigins(player, data); patterns[ctr] = p; if (++ctr >= patterns.Length) break; } } /// /// Dumps all designs to the requested . /// /// Save Data to dump from /// Path to dump to /// Export file names prepended with design index public static void DumpDesignsPRO(this MainSave sav, string path, bool indexed) { for (int i = 0; i < sav.Offsets.PatternCount; i++) { var dp = sav.GetDesignPRO(i); dp.Dump(path, i, indexed); } } /// /// Dumps all designs to the requested . /// /// Patterns to dump /// Path to dump to /// Export file names prepended with design index public static void Dump(this IReadOnlyList patterns, string path, bool indexed) { for (var index = 0; index < patterns.Count; index++) { var dp = patterns[index]; dp.Dump(path, index, indexed); } } /// /// Loads all designs from the requested . /// /// Patterns to load /// Path to load from /// Change origins of Patterns /// Sort the files by file name instead of depending on the Operating System's return order public static void Load(this DesignPatternPRO[] patterns, string path, Personal player, bool changeOrigins, bool sortAlpha = true) { if (patterns.Length == 0) return; var files = Directory.GetFiles(path, "*.nhpd", SearchOption.TopDirectoryOnly); if (sortAlpha) Array.Sort(files); int ctr = 0; foreach (var f in files) { var fi = new FileInfo(f); if (fi.Length != DesignPatternPRO.SIZE) continue; var data = File.ReadAllBytes(f); var p = new DesignPatternPRO(data); if (changeOrigins) p.ChangeOrigins(player, data); patterns[ctr] = p; if (++ctr >= patterns.Length) break; } } private static void Dump(this DesignPatternPRO dp, string path, int index, bool indexed) { var name = dp.DesignName; string fn = indexed ? $"{index:00} - {name}.nhpd" : $"{name}.nhpd"; fn = StringUtil.CleanFileName(fn); var dest = Path.Combine(path, fn); File.WriteAllBytes(dest, dp.Data); } }