From 0fbf9e96c9da17422875febd6aee37034f87f32b Mon Sep 17 00:00:00 2001 From: Li Date: Sat, 4 Mar 2023 04:59:36 +1300 Subject: [PATCH] Make build .psu file! --- LibW4M/Data/Stats/TeamStatsCollective.cs | 7 +- LibW4M/Data/Teams/TeamData.cs | 31 +-- LibW4M/LibW4M.csproj | 24 +++ LibW4M/PS2/Ps2Save.cs | 72 +++++++ LibW4M/PS2/PsuEntryType.cs | 16 ++ LibW4M/PS2/PsuFile.cs | 176 ++++++++++++++++++ LibW4M/PS2/PsuFileEntry.cs | 75 ++++++++ LibW4M/PS2/Resources/Icon1.ico | Bin 0 -> 49622 bytes LibW4M/PS2/Resources/icon.sys | Bin 0 -> 964 bytes LibW4M/PS2/SaveResources.Designer.cs | 83 +++++++++ LibW4M/PS2/SaveResources.resx | 127 +++++++++++++ .../PublishProfiles/FolderProfile.pubxml | 19 -- .../PublishProfiles/FolderProfile.pubxml.user | 10 - LibW4M/W4SaveFile.cs | 105 +++++------ LibXom/Data/XomFile.cs | 29 ++- LibXom/Data/XomString.cs | 22 ++- LibXom/Data/XomType.cs | 5 +- LibXom/Streams/XomStreamReader.cs | 23 +++ LibXom/Streams/XomStreamWriter.cs | 20 ++ W4Gui/Components/StringList.cs | 6 +- W4Gui/DataManager.cs | 3 + W4Gui/Main.Designer.cs | 17 +- W4Gui/Main.cs | 87 +++++++-- .../PublishProfiles/FolderProfile.pubxml.user | 2 +- W4Gui/SaveType.cs | 15 ++ 25 files changed, 829 insertions(+), 145 deletions(-) create mode 100644 LibW4M/PS2/Ps2Save.cs create mode 100644 LibW4M/PS2/PsuEntryType.cs create mode 100644 LibW4M/PS2/PsuFile.cs create mode 100644 LibW4M/PS2/PsuFileEntry.cs create mode 100644 LibW4M/PS2/Resources/Icon1.ico create mode 100644 LibW4M/PS2/Resources/icon.sys create mode 100644 LibW4M/PS2/SaveResources.Designer.cs create mode 100644 LibW4M/PS2/SaveResources.resx delete mode 100644 LibW4M/Properties/PublishProfiles/FolderProfile.pubxml delete mode 100644 LibW4M/Properties/PublishProfiles/FolderProfile.pubxml.user create mode 100644 W4Gui/SaveType.cs 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 0000000000000000000000000000000000000000..f8e4e0fda53db401698356c21dc9d0863ed8b24f GIT binary patch literal 49622 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 literal 0 HcmV?d00001 diff --git a/LibW4M/PS2/Resources/icon.sys b/LibW4M/PS2/Resources/icon.sys new file mode 100644 index 0000000000000000000000000000000000000000..95057064ec9e91d33caa275ada6e18e03e1ce879 GIT binary patch literal 964 zcmWFtHgaKL5MZDlaIj}!H~_>AKnwy6`+)?M4da8vz~Ufzpj?A}T3Q-Z4LTpB2Rkrg za4c^sYwB;B)YRKFxhc5OtU`NW>ZH~Yf~?FU6`Vt$@zJPdYQ@jm{LTE477ft L9673J*oFWAML8y& literal 0 HcmV?d00001 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 + } +}