Worms4Editor/LibW4M/W4SaveFile.cs

274 lines
9.3 KiB
C#

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 LibXom;
using LibXom.Blocks;
using LibXom.Data;
using LibXom.Exceptions;
using LibXom.Streams;
using System.Runtime.InteropServices;
using System.Xml.XPath;
namespace LibW4M
{
public class W4SaveFile
{
public const int PS2_MAX_SZ = 0x20000;
private List<UnlockableItemData> 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 InputMappingCollective InputMappingCollective;
public TeamAwardsData TeamAwardsContainer;
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<UnlockableItemData>();
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 StatsCollective(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;
}
}
}
private void saveData()
{
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 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);
}
}
}
}
}
public void Save(string newXom)
{
saveData();
XomWriter.WriteXom(xomFile, 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();
}
}
}