diff --git a/LibW4M/Data/Stats/TeamStatsCollective.cs b/LibW4M/Data/Stats/TeamStatsCollective.cs index 0117401..98f0343 100644 --- a/LibW4M/Data/Stats/TeamStatsCollective.cs +++ b/LibW4M/Data/Stats/TeamStatsCollective.cs @@ -10,11 +10,10 @@ namespace LibW4M.Data.Stats { public class TeamStatsCollective : SaveDataCollective { - public List TeamNames; + public List TeamNames = new List(); public TeamStatsCollective(W4SaveFile fileBelongs, XomContainer mainContainer) : base(fileBelongs, mainContainer) { - TeamNames = new List(); } public override void Load() @@ -44,8 +43,6 @@ namespace LibW4M.Data.Stats this.collectiveEntries.Add(stats); } - - } public override void Save() @@ -84,7 +81,7 @@ namespace LibW4M.Data.Stats // add team names too - newCollective[teamStatsStart] = teamNamesLen; + newCollective[teamNamesStart] = teamNamesLen; for (int i = 0; i < teamNamesLen; i++) newCollective[teamNamesStart + i + 1] = this.TeamNames[i].Id; diff --git a/LibW4M/Data/Teams/TeamData.cs b/LibW4M/Data/Teams/TeamData.cs index 4e58edb..b9e4dc4 100644 --- a/LibW4M/Data/Teams/TeamData.cs +++ b/LibW4M/Data/Teams/TeamData.cs @@ -21,33 +21,10 @@ namespace LibW4M.Data.Teams } - private int weaponContainerId; - private int clusterContainerId; - public WeaponData SecretWeapon - { - get - { - return fileBelongs.findWeaponWithContainerId(weaponContainerId); - } - set - { - weaponContainerId = value.containerId; - } - } - public WeaponData SecretWeaponCluster - { - get - { - return fileBelongs.findWeaponWithContainerId(clusterContainerId); - } - set - { - clusterContainerId = value.containerId; - } - } - + public WeaponData SecretWeapon; + public WeaponData SecretWeaponCluster; public XomString Name; public XomString[] Worms; public int TutorialsDone; @@ -92,8 +69,8 @@ namespace LibW4M.Data.Teams this.AllMissionsDone = reader.ReadBool(); this.Player = fileBelongs.LookupStringFromId(reader.ReadCompressedInt()); - this.weaponContainerId = reader.ReadCompressedInt(); - this.clusterContainerId = reader.ReadCompressedInt(); + this.SecretWeapon = fileBelongs.findWeaponWithContainerId(reader.ReadCompressedInt()); + this.SecretWeaponCluster = fileBelongs.findWeaponWithContainerId(reader.ReadCompressedInt()); this.CustomWeapon = fileBelongs.LookupStringFromId(reader.ReadCompressedInt()); diff --git a/LibW4M/LibW4M.csproj b/LibW4M/LibW4M.csproj index 0ea52ae..172c4a0 100644 --- a/LibW4M/LibW4M.csproj +++ b/LibW4M/LibW4M.csproj @@ -11,4 +11,28 @@ + + + True + True + PS2SaveResources.resx + + + True + True + SaveResources.resx + + + + + + ResXFileCodeGenerator + PS2SaveResources.Designer.cs + + + ResXFileCodeGenerator + SaveResources.Designer.cs + + + diff --git a/LibW4M/PS2/Ps2Save.cs b/LibW4M/PS2/Ps2Save.cs new file mode 100644 index 0000000..ea15452 --- /dev/null +++ b/LibW4M/PS2/Ps2Save.cs @@ -0,0 +1,72 @@ +using LibXom.Data; +using LibXom.Streams; +using LibXom; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using LibW4M.Data.Stats; + +namespace LibW4M.PS2 +{ + public static class Ps2Save + { + private const int PS2_MAX_SZ = 0x20000; + + public static void CreateSaveFile(W4SaveFile save, Stream output) + { + // Remove all stats ... + foreach (StatsContainerData stat in save.StatsCollective.ToArray()) + save.StatsCollective.Delete(stat); + + // Save changes + save.saveData(); + XomWriter.WriteXom(save.OriginalXom,output); + Ps2Save.CalcAndWriteChecksum(output); + } + public static void CalcAndWriteChecksum(Stream s) + { + XomStreamReader reader = new XomStreamReader(s); + XomStreamWriter writer = new XomStreamWriter(s); + + // Set size to ps2 save size. + + s.SetLength(PS2_MAX_SZ); + s.Seek(0, SeekOrigin.Begin); + + // Calculate checksum + + Int64 chk = 0; + + for (int i = 0; i < (PS2_MAX_SZ - 4); i += 4) + { + int c = reader.ReadInt32(); + chk = (chk + c) & UInt32.MaxValue; + } + + writer.WriteUInt32(Convert.ToUInt32(chk)); + + s.Seek(0, SeekOrigin.Begin); + } + + public static void CreatePSU(W4SaveFile save, Stream output) + { + PsuFile psuFile = new PsuFile(); + psuFile.InitalizePSU("BESLES-53096W4MA"); + psuFile.CreateFile("Icon1.ico", SaveResources.IconFile); + psuFile.CreateFile("icon.sys", SaveResources.IconSys); + + using(MemoryStream ms = new MemoryStream()) + { + CreateSaveFile(save, ms); + ms.Seek(0, SeekOrigin.Begin); + psuFile.CreateFile("BESLES-53096W4MA", ms.ToArray()); + } + + psuFile.WritePSU(output); + } + + + } +} diff --git a/LibW4M/PS2/PsuEntryType.cs b/LibW4M/PS2/PsuEntryType.cs new file mode 100644 index 0000000..a42ea9e --- /dev/null +++ b/LibW4M/PS2/PsuEntryType.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace LibW4M.PS2 +{ + public enum PsuEntryType : ushort + { + DIRECTORY_ENTRY = 0x8427, + FILE_ENTRY = 0x8497, + SYSTEM_ENTRY = 0xA027 + } +} diff --git a/LibW4M/PS2/PsuFile.cs b/LibW4M/PS2/PsuFile.cs new file mode 100644 index 0000000..13427df --- /dev/null +++ b/LibW4M/PS2/PsuFile.cs @@ -0,0 +1,176 @@ +using LibXom.Streams; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Globalization; +using System.Linq; +using System.Reflection.PortableExecutable; +using System.Text; +using System.Threading.Tasks; + +namespace LibW4M.PS2 +{ + public class PsuFile + { + public PsuFile() + { + entries = new List(); + } + + private List entries; + + + public PsuFileEntry[] Entires + { + get + { + return entries.ToArray(); + } + } + + public PsuFileEntry[] Files + { + get + { + List tmpList = new List(); + + foreach (PsuFileEntry entry in entries) + { + if (entry.EntryType == PsuEntryType.FILE_ENTRY || entry.EntryType == PsuEntryType.SYSTEM_ENTRY) + { + tmpList.Add(entry); + } + } + + return tmpList.ToArray(); + } + } + public PsuFileEntry[] Directorys + { + get + { + List tmpList = new List(); + + foreach (PsuFileEntry entry in entries) + { + if (entry.EntryType == PsuEntryType.DIRECTORY_ENTRY) + { + tmpList.Add(entry); + } + } + + return tmpList.ToArray(); + } + } + + public void CreateDirectory(string directoryName) + { + this.entries.Add(new PsuFileEntry(PsuEntryType.DIRECTORY_ENTRY, 0x00, DateTime.Now, 0, DateTime.Now, directoryName, null)); + this.entries[0].directoryEntries = this.entries.Count - 1; + } + + public void CreateFile(string fileName, byte[] data) + { + this.entries.Add(new PsuFileEntry(PsuEntryType.FILE_ENTRY, data.Length, DateTime.Now, 0, DateTime.Now, fileName, data)); + this.entries[0].directoryEntries = this.entries.Count - 1; + } + + public void CreateSystemFile(string fileName, byte[] data) + { + this.entries.Add(new PsuFileEntry(PsuEntryType.SYSTEM_ENTRY, data.Length, DateTime.Now, 0, DateTime.Now, fileName, data)); + this.entries[0].directoryEntries = this.entries.Count - 1; + } + + public void InitalizePSU(string titleId) + { + this.entries.Clear(); + CreateDirectory(titleId); + CreateDirectory("."); + CreateDirectory(".."); + } + + public PsuFileEntry GetFileByName(string filename) + { + foreach(PsuFileEntry entry in this.Files) + { + if(entry.Filename.Equals(filename, StringComparison.InvariantCulture)) + { + return entry; + } + } + + throw new FileNotFoundException("Cannot find the file"); + } + + public static PsuFile ReadPSU(string psuFilePath) + { + PsuFile psuFile = new PsuFile(); + psuFile.ReadPSU(File.OpenRead(psuFilePath)); + return psuFile; + } + + public void WritePSU(Stream psuStream) + { + using (XomStreamWriter writer = new XomStreamWriter(psuStream)) + { + + foreach (PsuFileEntry fileEntry in this.Entires) + { + writer.WriteUInt16((ushort)fileEntry.EntryType); + writer.Skip(0x02); + writer.WriteInt32(fileEntry.Filesize); + writer.Skip(0x01); + writer.WriteDateTime(fileEntry.CreationDate); + writer.WriteUInt16(fileEntry.Sector); + writer.Skip(0x07); + writer.WriteDateTime(fileEntry.ModifiedDate); + writer.Skip(0x20); + writer.WriteStrLen(fileEntry.Filename, 0x1C0); + + if(fileEntry.FileData != Stream.Null) + { + fileEntry.FileData.Seek(0, SeekOrigin.Begin); + fileEntry.FileData.CopyTo(psuStream); + writer.WritePadding(0xFF, 0x400 - (fileEntry.Filesize % 0x400)); + } + } + } + } + public void ReadPSU(Stream psuStream) + { + using (XomStreamReader reader = new XomStreamReader(psuStream)) + { + do + { + // read header + PsuEntryType type = (PsuEntryType)reader.ReadUInt16(); + reader.Skip(0x02); + int size = reader.ReadInt32(); + reader.Skip(0x01); + DateTime creationDate = reader.ReadDateTime(); + ushort sector = reader.ReadUInt16(); + reader.Skip(0x07); + DateTime modifiedDate = reader.ReadDateTime(); + reader.Skip(0x20); + string filename = reader.ReadStrLen(0x1C0); + + if (type == PsuEntryType.FILE_ENTRY || type == PsuEntryType.SYSTEM_ENTRY) + { + byte[] fileData = reader.ReadBytes(size); + + reader.Skip(0x400 - (size % 0x400)); + this.entries.Add(new PsuFileEntry(type, size, creationDate, sector, modifiedDate, filename, fileData)); + } + else + { + this.entries.Add(new PsuFileEntry(type, size, creationDate, sector, modifiedDate, filename, null)); + } + } + while (psuStream.Position < psuStream.Length); + + } + + } + + } +} diff --git a/LibW4M/PS2/PsuFileEntry.cs b/LibW4M/PS2/PsuFileEntry.cs new file mode 100644 index 0000000..445f71f --- /dev/null +++ b/LibW4M/PS2/PsuFileEntry.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LibW4M.PS2 +{ + public class PsuFileEntry + { + + internal int directoryEntries; + + public Stream FileData; + public PsuEntryType EntryType; + public DateTime CreationDate; + public ushort Sector; + public DateTime ModifiedDate; + public string Filename; + public bool IsFile + { + get + { + return (EntryType == PsuEntryType.FILE_ENTRY || EntryType == PsuEntryType.SYSTEM_ENTRY); + } + } + public int Filesize + { + get + { + if (IsFile) + { + return Convert.ToInt32(FileData.Length); + } + else + { + return directoryEntries; + } + } + set + { + if (IsFile) + { + FileData.SetLength(value); + } + else + { + directoryEntries = value; + } + } + } + + public PsuFileEntry(PsuEntryType entryType, int fileSize, DateTime creationDate, ushort sector, DateTime modifiedDate, string fileName, byte[]? fileData) + { + this.EntryType = entryType; + this.directoryEntries = fileSize; + this.CreationDate = creationDate; + this.Sector = sector; + this.ModifiedDate = modifiedDate; + this.Filename = fileName; + + if(fileData is null) + { + this.FileData = Stream.Null; + } + else + { + this.FileData = new MemoryStream(); + this.FileData.Write(fileData, 0, fileSize); + this.FileData.Seek(0, SeekOrigin.Begin); + } + + } + } +} diff --git a/LibW4M/PS2/Resources/Icon1.ico b/LibW4M/PS2/Resources/Icon1.ico new file mode 100644 index 0000000..f8e4e0f Binary files /dev/null and b/LibW4M/PS2/Resources/Icon1.ico differ diff --git a/LibW4M/PS2/Resources/icon.sys b/LibW4M/PS2/Resources/icon.sys new file mode 100644 index 0000000..9505706 Binary files /dev/null and b/LibW4M/PS2/Resources/icon.sys differ diff --git a/LibW4M/PS2/SaveResources.Designer.cs b/LibW4M/PS2/SaveResources.Designer.cs new file mode 100644 index 0000000..5dcad33 --- /dev/null +++ b/LibW4M/PS2/SaveResources.Designer.cs @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace LibW4M.PS2 { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class SaveResources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal SaveResources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("LibW4M.PS2.SaveResources", typeof(SaveResources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + public static byte[] IconFile { + get { + object obj = ResourceManager.GetObject("IconFile", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + public static byte[] IconSys { + get { + object obj = ResourceManager.GetObject("IconSys", resourceCulture); + return ((byte[])(obj)); + } + } + } +} diff --git a/LibW4M/PS2/SaveResources.resx b/LibW4M/PS2/SaveResources.resx new file mode 100644 index 0000000..0d1c006 --- /dev/null +++ b/LibW4M/PS2/SaveResources.resx @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Resources\Icon1.ico;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Resources\icon.sys;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/LibW4M/Properties/PublishProfiles/FolderProfile.pubxml b/LibW4M/Properties/PublishProfiles/FolderProfile.pubxml deleted file mode 100644 index 5f2ccee..0000000 --- a/LibW4M/Properties/PublishProfiles/FolderProfile.pubxml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Release - Any CPU - bin\Release\net7.0\publish\win-x86\ - FileSystem - <_TargetId>Folder - net7.0 - win-x86 - true - true - true - false - - \ No newline at end of file diff --git a/LibW4M/Properties/PublishProfiles/FolderProfile.pubxml.user b/LibW4M/Properties/PublishProfiles/FolderProfile.pubxml.user deleted file mode 100644 index 3896d83..0000000 --- a/LibW4M/Properties/PublishProfiles/FolderProfile.pubxml.user +++ /dev/null @@ -1,10 +0,0 @@ - - - - - False|2023-02-18T17:31:12.6646298Z; - - - \ No newline at end of file diff --git a/LibW4M/W4SaveFile.cs b/LibW4M/W4SaveFile.cs index 670fcd5..57b0118 100644 --- a/LibW4M/W4SaveFile.cs +++ b/LibW4M/W4SaveFile.cs @@ -9,11 +9,13 @@ 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; @@ -21,24 +23,31 @@ namespace LibW4M { public class W4SaveFile { - public const int PS2_MAX_SZ = 0x20000; 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 StatsCollective TeamStatsCollective; + 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 @@ -84,7 +93,7 @@ namespace LibW4M break; case "PersistStats": StatsCollective = new StatsCollective(this, containerResourceDetail.Value); - TeamStatsCollective = new StatsCollective(this, containerResourceDetail.Value); + TeamStatsCollective = new TeamStatsCollective(this, containerResourceDetail.Value); break; case "Awards": TeamAwardsContainer = new TeamAwardsData(this, containerResourceDetail.Value); @@ -114,11 +123,15 @@ namespace LibW4M } } } + - private void saveData() + internal void saveData() { - XDataBank.Save(); +#if !DEBUG + xomFile.ClearAllStrings(); +#endif + XDataBank.Save(); WeaponFactoryCollective.Save(); // Save Teams, Highscores @@ -137,60 +150,44 @@ namespace LibW4M 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) { - // Remove all stats ... - foreach(StatsContainerData stat in StatsCollective.ToArray()) - StatsCollective.Delete(stat); - - // Save changes - saveData(); - - using(FileStream fs = File.OpenWrite(newXom)) - { - using (MemoryStream ms = new MemoryStream()) - { - using (XomStreamReader reader = new XomStreamReader(ms)) - { - using (XomStreamWriter writer = new XomStreamWriter(ms)) - { - XomWriter.WriteXom(xomFile, ms); - - // Set size to ps2 save size. - - ms.SetLength(PS2_MAX_SZ); - ms.Seek(0, SeekOrigin.Begin); - - // Calculate checksum - - Int64 chk = 0; - - for (int i = 0; i < (PS2_MAX_SZ - 4); i += 4) - { - int c = reader.ReadInt32(); - chk = (chk + c) & UInt32.MaxValue; - } - - writer.WriteUInt32(Convert.ToUInt32(chk)); - - - ms.Seek(0, SeekOrigin.Begin); - ms.CopyTo(fs); - } - } - - } - } - + SavePS2(File.OpenWrite(newXom)); } - public void Save(string newXom) + public void SavePS2PSU(string newXom) { - saveData(); - - XomWriter.WriteXom(xomFile, newXom); + SavePS2PSU(File.OpenWrite(newXom)); + } + public void SavePC(string newXom) + { + SavePC(File.OpenWrite(newXom)); } public void ExtractAllContainers(string path) diff --git a/LibXom/Data/XomFile.cs b/LibXom/Data/XomFile.cs index a012901..4a05e1a 100644 --- a/LibXom/Data/XomFile.cs +++ b/LibXom/Data/XomFile.cs @@ -12,6 +12,7 @@ namespace LibXom.Data { private int version; private int unk0; + private List xomStrings = new List(); private List xomTypes = new List(); @@ -47,14 +48,25 @@ namespace LibXom.Data xomStrings[stringId] = newStr; } + internal int addString(XomString xStr) + { + xomStrings.Add(xStr); + return xomStrings.Count - 1; + } + + public void ClearAllStrings() + { + xomStrings.Clear(); + } + public XomString AddOrGetString(string value) { XomString[] strings = XomStrings; for (int i = 0; i < strings.Length; i++) - if (strings[i].Value == value) return strings[i]; + if (strings[i].Equals(value)) return strings[i]; XomString str = new XomString(this, value); - xomStrings.Add(str); + addString(str); return str; } @@ -78,6 +90,15 @@ namespace LibXom.Data throw new XomTypeNotFoundException("Type \"" + typeName + "\" was not found in XOM."); } + + internal int calculateIdForXomStrings(XomString searchString, XomString[] stringsList) + { + for (int i = 0; i < stringsList.Length; i++) + if (stringsList[i].Equals(searchString)) return i; + + return addString(searchString); + } + internal int calculateIdForXomFileComponent(string searchUuid, XomFileComponent[] components) { for (int i = 0; i < components.Length; i++) @@ -90,11 +111,13 @@ namespace LibXom.Data { XomContainer[] containers = this.XomContainers; XomType[] types = this.XomTypes; - XomString[] strings = XomStrings; + XomString[] strings = this.XomStrings; List blocks = new List(); + // add MOIK block blocks.Add(new MoikBlock(this.version, containers.Length, types.Length)); + // add type blocks foreach (XomType type in types) blocks.Add(new TypeBlock(type.Containers.Length, type.Md5, type.Name)); diff --git a/LibXom/Data/XomString.cs b/LibXom/Data/XomString.cs index 134e0d6..9e6c66c 100644 --- a/LibXom/Data/XomString.cs +++ b/LibXom/Data/XomString.cs @@ -15,7 +15,7 @@ namespace LibXom.Data { get { - return this.fileBelongs.calculateIdForXomFileComponent(this.uuid, fileBelongs.XomStrings) - 1; + return this.fileBelongs.calculateIdForXomStrings(this, fileBelongs.XomStrings); } } public string Value @@ -34,13 +34,23 @@ namespace LibXom.Data } } - /* - public void OverwriteXomString(string newValue) + public override bool Equals(object? obj) { - this.value = newValue; - fileBelongs.updateStringById(this.Id, this); + XomString? xStr = obj as XomString; + if (xStr is XomString) + return this.Value.Equals(xStr.Value, StringComparison.InvariantCulture); + else + return false; } - */ + + + /* + public void OverwriteXomString(string newValue) + { + this.value = newValue; + fileBelongs.updateStringById(this.Id, this); + } + */ public override string ToString() { return this.Value; diff --git a/LibXom/Data/XomType.cs b/LibXom/Data/XomType.cs index d2aa0ad..2cf983b 100644 --- a/LibXom/Data/XomType.cs +++ b/LibXom/Data/XomType.cs @@ -50,7 +50,10 @@ namespace LibXom.Data return i; } } - throw new XomContainerNotFoundException("Could not find Xom Container with uuid: " + container.uuid + " in type: " + this.Name); + + // maybe removed this container by mistakes; so lets just add it back + container.Type.xomContainers.Add(container); + return getContainerIndex(container); } public void ReplaceContainerData(XomContainer container, byte[] newData) { diff --git a/LibXom/Streams/XomStreamReader.cs b/LibXom/Streams/XomStreamReader.cs index 2e9591e..3694978 100644 --- a/LibXom/Streams/XomStreamReader.cs +++ b/LibXom/Streams/XomStreamReader.cs @@ -53,6 +53,19 @@ namespace LibXom.Streams xStream.Read(buffer, 0, amt); return buffer; } + + public DateTime ReadDateTime() + { + byte secs = ReadByte(); + byte minutes = ReadByte(); + byte hours = ReadByte(); + byte days = ReadByte(); + byte months = ReadByte(); + UInt16 years = ReadUInt16(); + + return new DateTime(years, months, days, hours, minutes, secs); + } + public bool ReadBool() { return (ReadByte() == 0x01); @@ -92,6 +105,16 @@ namespace LibXom.Streams { return BitConverter.ToSingle(ReadBytes(0x4)); } + + public ushort ReadUInt16() + { + return BitConverter.ToUInt16(ReadBytes(0x2)); + } + public short ReadInt16() + { + return BitConverter.ToInt16(ReadBytes(0x2)); + } + public uint ReadUInt32() { return BitConverter.ToUInt32(ReadBytes(0x4)); diff --git a/LibXom/Streams/XomStreamWriter.cs b/LibXom/Streams/XomStreamWriter.cs index 29f4b0f..abc7a8a 100644 --- a/LibXom/Streams/XomStreamWriter.cs +++ b/LibXom/Streams/XomStreamWriter.cs @@ -95,6 +95,26 @@ namespace LibXom.Streams WriteBytes(buffer); } + public void WriteDateTime(DateTime date) + { + WriteByte(Convert.ToByte(date.Second)); + WriteByte(Convert.ToByte(date.Minute)); + WriteByte(Convert.ToByte(date.Hour)); + WriteByte(Convert.ToByte(date.Day)); + WriteByte(Convert.ToByte(date.Month)); + WriteUInt16(Convert.ToUInt16(date.Year)); + } + public void WriteUInt16(ushort value) + { + byte[] buffer = BitConverter.GetBytes((ushort)value); + WriteBytes(buffer); + } + + public void WriteInt16(short value) + { + byte[] buffer = BitConverter.GetBytes((short)value); + WriteBytes(buffer); + } public void WriteUInt32(uint value) { byte[] buffer = BitConverter.GetBytes((uint)value); diff --git a/W4Gui/Components/StringList.cs b/W4Gui/Components/StringList.cs index f444834..53089a7 100644 --- a/W4Gui/Components/StringList.cs +++ b/W4Gui/Components/StringList.cs @@ -68,7 +68,7 @@ namespace W4Gui.Components { int sel = lst.SelectedIndex; if (sel >= 0) - lst.Items[sel] = newEntry.Text; + lst.Items[sel] = newEntry.Text.ToString(); } private void newEntry_KeyDown(object sender, KeyEventArgs e) @@ -93,7 +93,9 @@ namespace W4Gui.Components private void lst_SelectedIndexChanged(object sender, EventArgs e) { - if (prevSelected >= 0) + if (prevSelected == lst.SelectedIndex) return; + + if (prevSelected >= 0 && prevSelected < lst.Items.Count) lst.Items[prevSelected] = newEntry.Text; if (lst.SelectedIndex >= 0) diff --git a/W4Gui/DataManager.cs b/W4Gui/DataManager.cs index c37d2d8..bacfd2e 100644 --- a/W4Gui/DataManager.cs +++ b/W4Gui/DataManager.cs @@ -10,6 +10,9 @@ namespace W4Gui { public static class DataManager { + public static SaveType LoadedSaveType; + public static string LoadedSavePath; + public static bool SaveLoaded = false; public static W4SaveFile SaveFile; public static void SaveAll() diff --git a/W4Gui/Main.Designer.cs b/W4Gui/Main.Designer.cs index ca7d9c0..294b8ed 100644 --- a/W4Gui/Main.Designer.cs +++ b/W4Gui/Main.Designer.cs @@ -58,6 +58,7 @@ namespace W4Gui this.awardPanel = new W4Gui.Tabs.AwardTab(); this.variablesTab = new System.Windows.Forms.TabPage(); this.variablesPage = new W4Gui.Tabs.VariablesTab.VariablesTabs(); + this.saveAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.mainMenuStrip.SuspendLayout(); this.mainTabControl.SuspendLayout(); this.weaponTab.SuspendLayout(); @@ -87,7 +88,8 @@ namespace W4Gui // this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.openToolStripMenuItem, - this.saveToolStripMenuItem}); + this.saveToolStripMenuItem, + this.saveAsToolStripMenuItem}); this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); this.fileToolStripMenuItem.Text = "File"; @@ -95,7 +97,7 @@ namespace W4Gui // openToolStripMenuItem // this.openToolStripMenuItem.Name = "openToolStripMenuItem"; - this.openToolStripMenuItem.Size = new System.Drawing.Size(103, 22); + this.openToolStripMenuItem.Size = new System.Drawing.Size(180, 22); this.openToolStripMenuItem.Text = "Open"; this.openToolStripMenuItem.Click += new System.EventHandler(this.openToolStripMenuItem_Click); // @@ -103,7 +105,7 @@ namespace W4Gui // this.saveToolStripMenuItem.Enabled = false; this.saveToolStripMenuItem.Name = "saveToolStripMenuItem"; - this.saveToolStripMenuItem.Size = new System.Drawing.Size(103, 22); + this.saveToolStripMenuItem.Size = new System.Drawing.Size(180, 22); this.saveToolStripMenuItem.Text = "Save"; this.saveToolStripMenuItem.Click += new System.EventHandler(this.saveToolStripMenuItem_Click); // @@ -331,6 +333,14 @@ namespace W4Gui this.variablesPage.Size = new System.Drawing.Size(182, 62); this.variablesPage.TabIndex = 0; // + // saveAsToolStripMenuItem + // + this.saveAsToolStripMenuItem.Enabled = false; + this.saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem"; + this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.saveAsToolStripMenuItem.Text = "Save As"; + this.saveAsToolStripMenuItem.Click += new System.EventHandler(this.saveAsToolStripMenuItem_Click); + // // Main // this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); @@ -389,5 +399,6 @@ namespace W4Gui private TabPage awardsTab; private AwardTab awardPanel; private InputEventMappingTab inputEventMappingsPanel; + private ToolStripMenuItem saveAsToolStripMenuItem; } } \ No newline at end of file diff --git a/W4Gui/Main.cs b/W4Gui/Main.cs index b142ae4..b9d0749 100644 --- a/W4Gui/Main.cs +++ b/W4Gui/Main.cs @@ -1,5 +1,6 @@ using LibW4M; using LibW4M.Data.WeaponFactory; +using LibW4M.PS2; using LibXom; using LibXom.Data; using System; @@ -29,20 +30,47 @@ namespace W4Gui } + private SaveType getTypeFromName(string filename) + { + switch (Path.GetExtension(filename)) + { + + case ".psu": + return SaveType.PS2; + case ".xom": + default: + return SaveType.PC; + } + } + private void openToolStripMenuItem_Click(object sender, EventArgs e) { OpenFileDialog fd = new OpenFileDialog(); - fd.Filter = "Worms 4: Mayhem Save File|*.xom"; + fd.Filter = "Worms 4: Mayhem Save Files|*.xom;*.psu|Worms 4: Mayhem PC Save File|*.xom|Worms 4: Mayhem PS2 Save File|*.psu"; fd.Title = "Open Worms 4 Save File"; if(fd.ShowDialog() == DialogResult.OK) { - DataManager.SaveFile = new W4SaveFile(XomReader.ReadXomFile(fd.FileName)); + DataManager.LoadedSavePath = fd.FileName; + DataManager.LoadedSaveType = getTypeFromName(DataManager.LoadedSavePath); + + switch (DataManager.LoadedSaveType) + { + case SaveType.PS2: + DataManager.SaveFile = new W4SaveFile(XomReader.ReadXomFile(PsuFile.ReadPSU(fd.FileName).GetFileByName("BESLES-53096W4MA").FileData)); + break; + case SaveType.PC: + default: + DataManager.SaveFile = new W4SaveFile(XomReader.ReadXomFile(fd.FileName)); + break; + } + this.mainTabControl.Enabled = true; this.saveToolStripMenuItem.Enabled = true; + this.saveAsToolStripMenuItem.Enabled = true; this.convertToolStripMenuItem.Enabled = true; - this.Text = defaultTitle + " [" + fd.FileName + "]"; + this.Text = defaultTitle + " (" + DataManager.LoadedSaveType.ToString() + ") " + "[" + fd.FileName + "]"; DataManager.LoadAll(); } @@ -50,19 +78,22 @@ namespace W4Gui private void saveToolStripMenuItem_Click(object sender, EventArgs e) { - SaveFileDialog fd = new SaveFileDialog(); - fd.Filter = "Worms 4: Mayhem Save File|*.xom"; - fd.Title = "Save Worms 4 Save File"; - fd.FileName = "SaveGame.xom"; - if (fd.ShowDialog() == DialogResult.OK) + mainTabControl.Enabled = false; + DataManager.SaveAll(); + switch (DataManager.LoadedSaveType) { - this.mainTabControl.Enabled = false; - - DataManager.SaveAll(); - DataManager.SaveFile.Save(fd.FileName); - - this.mainTabControl.Enabled = true; + case SaveType.PC: + DataManager.SaveFile.SavePC(DataManager.LoadedSavePath); + break; + case SaveType.PS2: + DataManager.SaveFile.SavePS2PSU(DataManager.LoadedSavePath); + break; + case SaveType.XBOX: + break; } + mainTabControl.Enabled = true; + MessageBox.Show("File saved to: " + DataManager.LoadedSavePath, "Save Complete!", MessageBoxButtons.OK, MessageBoxIcon.Information); + } private void extractAllXomContainersToolStripMenuItem_Click(object sender, EventArgs e) @@ -131,5 +162,33 @@ namespace W4Gui this.mainTabControl.Enabled = true; } } + + private void saveAsToolStripMenuItem_Click(object sender, EventArgs e) + { + SaveFileDialog fd = new SaveFileDialog(); + fd.Filter = "Worms 4: Mayhem Save Files|*.xom;*.psu|Worms 4: Mayhem PC Save File|*.xom|Worms 4: Mayhem PS2 Single Save File|*.psu"; + fd.Title = "Save Worms 4 Save File"; + fd.FileName = Path.GetFileName(DataManager.LoadedSavePath); + if (fd.ShowDialog() == DialogResult.OK) + { + this.mainTabControl.Enabled = false; + + DataManager.SaveAll(); + SaveType saveType = getTypeFromName(fd.FileName); + + switch (saveType) + { + case SaveType.PS2: + DataManager.SaveFile.SavePS2PSU(fd.FileName); + break; + case SaveType.PC: + DataManager.SaveFile.SavePC(fd.FileName); + break; + } + + MessageBox.Show("File saved to: " + fd.FileName, "Save Complete!", MessageBoxButtons.OK, MessageBoxIcon.Information); + this.mainTabControl.Enabled = true; + } + } } } diff --git a/W4Gui/Properties/PublishProfiles/FolderProfile.pubxml.user b/W4Gui/Properties/PublishProfiles/FolderProfile.pubxml.user index 6ee82eb..74e488b 100644 --- a/W4Gui/Properties/PublishProfiles/FolderProfile.pubxml.user +++ b/W4Gui/Properties/PublishProfiles/FolderProfile.pubxml.user @@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - True|2023-02-28T20:19:31.4651141Z;True|2023-02-25T21:53:35.8769435+13:00;True|2023-02-20T23:18:32.2496478+13:00;True|2023-02-19T06:40:54.2502643+13:00;False|2023-02-16T17:57:46.9563146+13:00;True|2023-01-19T20:41:26.7371208+13:00;True|2023-01-15T17:06:35.5919106+13:00;True|2023-01-14T13:57:56.0824690+13:00;True|2023-01-11T22:22:28.8737310+13:00;True|2023-01-11T22:16:55.3469226+13:00; + True|2023-03-03T15:40:06.7859106Z;True|2023-03-01T11:45:37.3479871+13:00;True|2023-03-01T09:19:31.4651141+13:00;True|2023-02-25T21:53:35.8769435+13:00;True|2023-02-20T23:18:32.2496478+13:00;True|2023-02-19T06:40:54.2502643+13:00;False|2023-02-16T17:57:46.9563146+13:00;True|2023-01-19T20:41:26.7371208+13:00;True|2023-01-15T17:06:35.5919106+13:00;True|2023-01-14T13:57:56.0824690+13:00;True|2023-01-11T22:22:28.8737310+13:00;True|2023-01-11T22:16:55.3469226+13:00; \ No newline at end of file diff --git a/W4Gui/SaveType.cs b/W4Gui/SaveType.cs new file mode 100644 index 0000000..7b6e0ef --- /dev/null +++ b/W4Gui/SaveType.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace W4Gui +{ + public enum SaveType + { + PC, + PS2, + XBOX + } +}