using LibW4M.Data; using LibW4M.Data.Awards; using LibW4M.Data.Highscores; using LibW4M.Data.InputMapping; using LibW4M.Data.Schemes; using LibW4M.Data.Stats; using LibW4M.Data.Teams; using LibW4M.Data.WeaponFactory; using LibW4M.Data.WXFE; using LibW4M.Data.WXFE.UnlockableItem; using LibW4M.Data.X; using LibW4M.PS2; using LibXom; using LibXom.Blocks; using LibXom.Data; using LibXom.Exceptions; using LibXom.Streams; using System.Reflection; using System.Runtime.InteropServices; using System.Xml.XPath; namespace LibW4M { public class W4SaveFile { private List unlockableItems; private XomFile xomFile; public DataBank XDataBank; public WeaponsCollective WeaponFactoryCollective; public TeamsCollective TeamDataColective; public SchemesCollective SchemesCollective; public HighscoreCollective HighscoreCollective; public StatsCollective StatsCollective; public TeamStatsCollective TeamStatsCollective; public InputMappingCollective InputMappingCollective; public TeamAwardsData TeamAwardsContainer; public XomString Message; public XomString FEResourceID; public XomFile OriginalXom { get { return this.xomFile; } } public UnlockableItemData[] UnlockableItems { get { return unlockableItems.ToArray(); } } internal WeaponData findWeaponWithContainerId(int containerId) { if(WeaponFactoryCollective is not null) { for (int i = 0; i < WeaponFactoryCollective.Length; i++) { WeaponStore weaponStore = (WeaponStore)WeaponFactoryCollective[i]; if (weaponStore.Weapon.containerId == containerId) return weaponStore.Weapon; if (weaponStore.Cluster.containerId == containerId) return weaponStore.Cluster; } } return new WeaponData(this, LookupContainerById(containerId)); } public void Load() { unlockableItems = new List(); XDataBank = new DataBank(this, this.xomFile.GetTypeByName("XDataBank").Containers.First()); foreach(ContainerResourceDetail containerResourceDetail in XDataBank.ContainerResourceDetails) { switch (containerResourceDetail.Name.Value) { case "DATA.Weapons": WeaponFactoryCollective = new WeaponsCollective(this, containerResourceDetail.Value); break; case "DATA.TeamBarracks": TeamDataColective = new TeamsCollective(this, containerResourceDetail.Value); HighscoreCollective = new HighscoreCollective(this, containerResourceDetail.Value); break; case "DATA.Schemes": SchemesCollective = new SchemesCollective(this, containerResourceDetail.Value); break; case "PersistStats": StatsCollective = new StatsCollective(this, containerResourceDetail.Value); TeamStatsCollective = new TeamStatsCollective(this, containerResourceDetail.Value); break; case "Awards": TeamAwardsContainer = new TeamAwardsData(this, containerResourceDetail.Value); break; case "InputMapping": InputMappingCollective = new InputMappingCollective(this, containerResourceDetail.Value); break; default: // stupid hack; the only other option is manually hardcoding every unlockable item in the game // but this way atleast allows for it to be more generic incase for some reason not all (or more) are present. // Team17, why isnt there a collective for this? if (containerResourceDetail.Value.Type.Name.Equals("WXFE_UnlockableItem", StringComparison.InvariantCultureIgnoreCase)) { UnlockableItemData itemData = new UnlockableItemData(this, containerResourceDetail.Value); itemData.nameOverride = containerResourceDetail.Name.Value; unlockableItems.Add(itemData); } else { Console.Error.WriteLine("Unknown container resource: " + containerResourceDetail.Name); } break; } } } internal void saveData() { #if !DEBUG xomFile.ClearAllStrings(); #endif XDataBank.Save(); WeaponFactoryCollective.Save(); // Save Teams, Highscores TeamDataColective.Save(); HighscoreCollective.Save(); SchemesCollective.Save(); // Save Stats, TeamStats StatsCollective.Save(); TeamStatsCollective.Save(); TeamAwardsContainer.Save(); InputMappingCollective.Save(); foreach (UnlockableItemData unlockableItem in UnlockableItems) unlockableItem.Save(); } public void SavePC(Stream pcSaveStream) { saveData(); using (MemoryStream ms = new MemoryStream()) { XomWriter.WriteXom(xomFile, pcSaveStream); ms.Seek(0, SeekOrigin.Begin); ms.CopyTo(pcSaveStream); } } public void SavePS2PSU(Stream ps2PsuSaveStream) { using (ps2PsuSaveStream) { Ps2Save.CreatePSU(this, ps2PsuSaveStream); } } public void SavePS2(Stream ps2SaveStream) { using (ps2SaveStream) { Ps2Save.CreateSaveFile(this, ps2SaveStream); } } public void SavePS2(string newXom) { SavePS2(File.OpenWrite(newXom)); } public void SavePS2PSU(string newXom) { SavePS2PSU(File.OpenWrite(newXom)); } public void SavePC(string newXom) { SavePC(File.OpenWrite(newXom)); } public void ExtractAllContainers(string path) { foreach(XomType type in xomFile.XomTypes) { string outfolder = Path.Combine(path, type.Name); if (Directory.Exists(outfolder)) Directory.Delete(outfolder, true); Directory.CreateDirectory(outfolder); foreach(XomContainer container in type.Containers) { while (true) { try { File.WriteAllBytes(Path.ChangeExtension(Path.Combine(outfolder, container.Id.ToString("X2")), ".bin"), container.GetData()); break; } catch { continue; } } } } } public XomString[] StringArrayToXomStringArray(string[] strings) { XomString[] xstrings = new XomString[strings.Length]; for (int i = 0; i < xstrings.Length; i++) xstrings[i] = LookupString(strings[i]); return xstrings; } public string[] XomStringArrayToStringArray(XomString[] xstrings) { string[] strings = new string[xstrings.Length]; for (int i = 0; i < strings.Length; i++) strings[i] = xstrings[i].Value; return strings; } public int[] XomStringArrayToIntArray(XomString[] strs) { int[] ids = new int[strs.Length]; for (int i = 0; i < ids.Length; i++) ids[i] = strs[i].Id; return ids; } public XomString[] IntArrayToXomStringArray(int[] stringIds) { XomString[] strings = new XomString[stringIds.Length]; for (int i = 0; i < strings.Length; i++) strings[i] = this.LookupStringFromId(stringIds[i]); return strings; } public XomContainer LookupContainerById(int id) { return xomFile.GetContainerById(id); } public XomString LookupStringFromId(int id) { return xomFile.GetStringById(id); } public XomString LookupString(string value) { return xomFile.AddOrGetString(value); } public W4SaveFile(XomFile w4Save) { this.xomFile = w4Save; Load(); } } }