Support XBOX Save
This commit is contained in:
parent
0fbf9e96c9
commit
9fcf29c841
|
@ -50,6 +50,11 @@ namespace LibW4M.PS2
|
||||||
s.Seek(0, SeekOrigin.Begin);
|
s.Seek(0, SeekOrigin.Begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static W4SaveFile ReadPS2Save(string filename)
|
||||||
|
{
|
||||||
|
return new W4SaveFile(XomReader.ReadXomFile(PsuFile.ReadPSU(filename).GetFileByName("BESLES-53096W4MA").FileData));
|
||||||
|
}
|
||||||
|
|
||||||
public static void CreatePSU(W4SaveFile save, Stream output)
|
public static void CreatePSU(W4SaveFile save, Stream output)
|
||||||
{
|
{
|
||||||
PsuFile psuFile = new PsuFile();
|
PsuFile psuFile = new PsuFile();
|
||||||
|
|
|
@ -10,6 +10,7 @@ using LibW4M.Data.WXFE;
|
||||||
using LibW4M.Data.WXFE.UnlockableItem;
|
using LibW4M.Data.WXFE.UnlockableItem;
|
||||||
using LibW4M.Data.X;
|
using LibW4M.Data.X;
|
||||||
using LibW4M.PS2;
|
using LibW4M.PS2;
|
||||||
|
using LibW4M.XBOX;
|
||||||
using LibXom;
|
using LibXom;
|
||||||
using LibXom.Blocks;
|
using LibXom.Blocks;
|
||||||
using LibXom.Data;
|
using LibXom.Data;
|
||||||
|
@ -170,6 +171,14 @@ namespace LibW4M
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SaveXBOX(Stream xboxSaveStream)
|
||||||
|
{
|
||||||
|
using (xboxSaveStream)
|
||||||
|
{
|
||||||
|
XboxSave.CreateSaveFile(this, xboxSaveStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void SavePS2(Stream ps2SaveStream)
|
public void SavePS2(Stream ps2SaveStream)
|
||||||
{
|
{
|
||||||
using (ps2SaveStream)
|
using (ps2SaveStream)
|
||||||
|
@ -177,6 +186,11 @@ namespace LibW4M
|
||||||
Ps2Save.CreateSaveFile(this, ps2SaveStream);
|
Ps2Save.CreateSaveFile(this, ps2SaveStream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SaveXBOX(string newXom)
|
||||||
|
{
|
||||||
|
SaveXBOX(File.OpenWrite(newXom));
|
||||||
|
}
|
||||||
public void SavePS2(string newXom)
|
public void SavePS2(string newXom)
|
||||||
{
|
{
|
||||||
SavePS2(File.OpenWrite(newXom));
|
SavePS2(File.OpenWrite(newXom));
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
using LibW4M.Data.Stats;
|
||||||
|
using LibW4M.PS2;
|
||||||
|
using LibXom;
|
||||||
|
using LibXom.Streams;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace LibW4M.XBOX
|
||||||
|
{
|
||||||
|
public static class XboxSave
|
||||||
|
{
|
||||||
|
private const int SHA1_SIZE = 0x14;
|
||||||
|
private const int XBOX_MAX_SZ = 0x64000;
|
||||||
|
|
||||||
|
public static byte[] XboxSigningKey = new byte[0x40] { 0x20, 0x23, 0x8B, 0x22, 0xED, 0x13, 0xB7, 0xC1, 0x71, 0x5F, 0xC5, 0xB3, 0x72, 0x07, 0xC0, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
|
public static void CreateSaveFile(W4SaveFile save, Stream output)
|
||||||
|
{
|
||||||
|
using(MemoryStream ms = new MemoryStream())
|
||||||
|
{
|
||||||
|
// Remove all stats ...
|
||||||
|
foreach (StatsContainerData stat in save.StatsCollective.ToArray())
|
||||||
|
save.StatsCollective.Delete(stat);
|
||||||
|
|
||||||
|
// Save changes
|
||||||
|
save.saveData();
|
||||||
|
|
||||||
|
XomWriter.WriteXom(save.OriginalXom, ms);
|
||||||
|
ms.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
XboxSave.CalcAndWriteSignature(ms);
|
||||||
|
|
||||||
|
ms.Seek(0, SeekOrigin.Begin);
|
||||||
|
ms.CopyTo(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] xor(byte[] data, byte key)
|
||||||
|
{
|
||||||
|
byte[] outdata = new byte[data.Length];
|
||||||
|
for (int i = 0; i < data.Length; i++)
|
||||||
|
outdata[i] = Convert.ToByte(data[i] ^ key);
|
||||||
|
return outdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] calcSignature(byte[] data)
|
||||||
|
{
|
||||||
|
using (SHA1 sha = SHA1.Create())
|
||||||
|
{
|
||||||
|
using (MemoryStream ms = new MemoryStream())
|
||||||
|
{
|
||||||
|
// hash save data
|
||||||
|
ms.Write(xor(XboxSigningKey, 0x36), 0, XboxSigningKey.Length);
|
||||||
|
ms.Write(data);
|
||||||
|
|
||||||
|
ms.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
byte[] hash = sha.ComputeHash(ms.ToArray());
|
||||||
|
|
||||||
|
// hash that hash
|
||||||
|
ms.Seek(0, SeekOrigin.Begin);
|
||||||
|
ms.SetLength(0);
|
||||||
|
|
||||||
|
ms.Write(xor(XboxSigningKey, 0x5C), 0, XboxSigningKey.Length);
|
||||||
|
ms.Write(hash, 0, hash.Length);
|
||||||
|
|
||||||
|
sha.Initialize();
|
||||||
|
|
||||||
|
return sha.ComputeHash(ms.ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static W4SaveFile ReadXboxSave(string filepath)
|
||||||
|
{
|
||||||
|
using (FileStream fs = File.OpenRead(filepath))
|
||||||
|
{
|
||||||
|
fs.Seek(SHA1_SIZE, SeekOrigin.Begin);
|
||||||
|
return new W4SaveFile(XomReader.ReadXomFile(fs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CalcAndWriteSignature(Stream s)
|
||||||
|
{
|
||||||
|
byte[] data = new byte[XBOX_MAX_SZ];
|
||||||
|
s.Read(data, 0, XBOX_MAX_SZ);
|
||||||
|
byte[] signature = calcSignature(data);
|
||||||
|
using(MemoryStream ms = new MemoryStream())
|
||||||
|
{
|
||||||
|
ms.Write(signature, 0, SHA1_SIZE);
|
||||||
|
ms.Write(data, 0, XBOX_MAX_SZ);
|
||||||
|
|
||||||
|
ms.Seek(0, SeekOrigin.Begin);
|
||||||
|
s.Seek(0, SeekOrigin.Begin);
|
||||||
|
s.SetLength(ms.Length);
|
||||||
|
ms.CopyTo(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
using LibW4M;
|
using LibW4M;
|
||||||
using LibW4M.Data.WeaponFactory;
|
using LibW4M.Data.WeaponFactory;
|
||||||
using LibW4M.PS2;
|
using LibW4M.PS2;
|
||||||
|
using LibW4M.XBOX;
|
||||||
using LibXom;
|
using LibXom;
|
||||||
using LibXom.Data;
|
using LibXom.Data;
|
||||||
using System;
|
using System;
|
||||||
|
@ -30,41 +31,33 @@ 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)
|
private void openToolStripMenuItem_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
OpenFileDialog fd = new OpenFileDialog();
|
OpenFileDialog fd = new OpenFileDialog();
|
||||||
fd.Filter = "Worms 4: Mayhem Save Files|*.xom;*.psu|Worms 4: Mayhem PC Save File|*.xom|Worms 4: Mayhem PS2 Save File|*.psu";
|
fd.Filter = "Worms 4: Mayhem PC Save File|*.xom|Worms 4: Mayhem PS2 Save File|*.psu|Worms 4: Mayhem XBOX Save File|data";
|
||||||
fd.Title = "Open Worms 4 Save File";
|
fd.Title = "Open Worms 4 Save File";
|
||||||
if(fd.ShowDialog() == DialogResult.OK)
|
if(fd.ShowDialog() == DialogResult.OK)
|
||||||
{
|
{
|
||||||
DataManager.LoadedSavePath = fd.FileName;
|
DataManager.LoadedSavePath = fd.FileName;
|
||||||
DataManager.LoadedSaveType = getTypeFromName(DataManager.LoadedSavePath);
|
DataManager.LoadedSaveType = (SaveType)(fd.FilterIndex - 1);
|
||||||
|
|
||||||
switch (DataManager.LoadedSaveType)
|
switch (DataManager.LoadedSaveType)
|
||||||
{
|
{
|
||||||
case SaveType.PS2:
|
|
||||||
DataManager.SaveFile = new W4SaveFile(XomReader.ReadXomFile(PsuFile.ReadPSU(fd.FileName).GetFileByName("BESLES-53096W4MA").FileData));
|
|
||||||
break;
|
|
||||||
case SaveType.PC:
|
case SaveType.PC:
|
||||||
default:
|
default:
|
||||||
DataManager.SaveFile = new W4SaveFile(XomReader.ReadXomFile(fd.FileName));
|
DataManager.SaveFile = new W4SaveFile(XomReader.ReadXomFile(fd.FileName));
|
||||||
break;
|
break;
|
||||||
|
case SaveType.PS2:
|
||||||
|
DataManager.SaveFile = Ps2Save.ReadPS2Save(fd.FileName);
|
||||||
|
break;
|
||||||
|
case SaveType.XBOX:
|
||||||
|
DataManager.SaveFile = XboxSave.ReadXboxSave(fd.FileName);
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.mainTabControl.Enabled = true;
|
this.mainTabControl.Enabled = true;
|
||||||
this.saveToolStripMenuItem.Enabled = true;
|
this.saveToolStripMenuItem.Enabled = true;
|
||||||
this.saveAsToolStripMenuItem.Enabled = true;
|
this.saveAsToolStripMenuItem.Enabled = true;
|
||||||
|
@ -89,6 +82,7 @@ namespace W4Gui
|
||||||
DataManager.SaveFile.SavePS2PSU(DataManager.LoadedSavePath);
|
DataManager.SaveFile.SavePS2PSU(DataManager.LoadedSavePath);
|
||||||
break;
|
break;
|
||||||
case SaveType.XBOX:
|
case SaveType.XBOX:
|
||||||
|
DataManager.SaveFile.SaveXBOX(DataManager.LoadedSavePath);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mainTabControl.Enabled = true;
|
mainTabControl.Enabled = true;
|
||||||
|
@ -166,7 +160,7 @@ namespace W4Gui
|
||||||
private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
|
private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SaveFileDialog fd = new SaveFileDialog();
|
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.Filter = "Worms 4: Mayhem PC Save File|*.xom|Worms 4: Mayhem PS2 Single Save File|*.psu|Worms 4: Mayhem XBOX Save File|data";
|
||||||
fd.Title = "Save Worms 4 Save File";
|
fd.Title = "Save Worms 4 Save File";
|
||||||
fd.FileName = Path.GetFileName(DataManager.LoadedSavePath);
|
fd.FileName = Path.GetFileName(DataManager.LoadedSavePath);
|
||||||
if (fd.ShowDialog() == DialogResult.OK)
|
if (fd.ShowDialog() == DialogResult.OK)
|
||||||
|
@ -174,18 +168,24 @@ namespace W4Gui
|
||||||
this.mainTabControl.Enabled = false;
|
this.mainTabControl.Enabled = false;
|
||||||
|
|
||||||
DataManager.SaveAll();
|
DataManager.SaveAll();
|
||||||
SaveType saveType = getTypeFromName(fd.FileName);
|
SaveType saveType = (SaveType)(fd.FilterIndex-1);
|
||||||
|
|
||||||
switch (saveType)
|
switch (saveType)
|
||||||
{
|
{
|
||||||
case SaveType.PS2:
|
|
||||||
DataManager.SaveFile.SavePS2PSU(fd.FileName);
|
|
||||||
break;
|
|
||||||
case SaveType.PC:
|
case SaveType.PC:
|
||||||
DataManager.SaveFile.SavePC(fd.FileName);
|
DataManager.SaveFile.SavePC(fd.FileName);
|
||||||
break;
|
break;
|
||||||
|
case SaveType.PS2:
|
||||||
|
DataManager.SaveFile.SavePS2PSU(fd.FileName);
|
||||||
|
break;
|
||||||
|
case SaveType.XBOX:
|
||||||
|
DataManager.SaveFile.SaveXBOX(fd.FileName);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DataManager.LoadedSavePath = fd.FileName;
|
||||||
|
DataManager.LoadedSaveType = saveType;
|
||||||
|
|
||||||
MessageBox.Show("File saved to: " + fd.FileName, "Save Complete!", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
MessageBox.Show("File saved to: " + fd.FileName, "Save Complete!", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
this.mainTabControl.Enabled = true;
|
this.mainTabControl.Enabled = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||||
-->
|
-->
|
||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<History>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;</History>
|
<History>True|2023-03-03T16:17:31.1862857Z;True|2023-03-04T04:40:06.7859106+13:00;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;</History>
|
||||||
<LastFailureDetails />
|
<LastFailureDetails />
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
Loading…
Reference in New Issue