381 lines
15 KiB
C#
381 lines
15 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 LibW4M.PS2;
|
|
using LibW4M.XBOX;
|
|
using LibXom;
|
|
using LibXom.Blocks;
|
|
using LibXom.Data;
|
|
using LibXom.Exceptions;
|
|
using LibXom.Streams;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
using System.Runtime.InteropServices;
|
|
using System.Xml.XPath;
|
|
using static System.Runtime.InteropServices.JavaScript.JSType;
|
|
|
|
namespace LibW4M
|
|
{
|
|
public class W4SaveFile
|
|
{
|
|
|
|
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 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();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
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 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
|
|
{
|
|
#if !DEBUG
|
|
throw new XomException("Unknown container resource: " + containerResourceDetail.Name);
|
|
#else
|
|
Console.Error.WriteLine("Unknown container resource: " + containerResourceDetail.Name);
|
|
#endif
|
|
|
|
}
|
|
|
|
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 Save(Stream pcSaveStream)
|
|
{
|
|
saveData();
|
|
using (pcSaveStream)
|
|
{
|
|
using (MemoryStream ms = new MemoryStream())
|
|
{
|
|
XomWriter.WriteXom(xomFile, pcSaveStream);
|
|
|
|
ms.Seek(0, SeekOrigin.Begin);
|
|
ms.CopyTo(pcSaveStream);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
private static byte[] getXomTypeXBytes(string name)
|
|
{
|
|
switch (name)
|
|
{
|
|
case "WeaponFactoryContainer":
|
|
return new byte[0x10] { 0xA5, 0x36, 0x42, 0x20, 0xF4, 0x4D, 0x60, 0x4F, 0x90, 0x97, 0x4F, 0xA8, 0x87, 0xD5, 0xC7, 0x4D };
|
|
case "StoreWeaponFactory":
|
|
return new byte[0x10] { 0xB5, 0x2C, 0x2F, 0xE3, 0x3A, 0x13, 0x1C, 0x4F, 0xB6, 0x4A, 0x81, 0xB8, 0x97, 0x30, 0x2E, 0x82 };
|
|
case "WeaponFactoryCollective":
|
|
return new byte[0x10] { 0xB2, 0x4A, 0x97, 0x29, 0xF8, 0x2E, 0x3D, 0x4E, 0xB7, 0x98, 0xF5, 0x8D, 0x3F, 0x36, 0x07, 0xFF };
|
|
case "StoredTeamData":
|
|
return new byte[0x10] { 0x55, 0xB4, 0x6A, 0x78, 0x13, 0x63, 0xC6, 0x4D, 0xA1, 0xA3, 0xA5, 0x4B, 0x67, 0xD5, 0x2C, 0xDE };
|
|
case "HighScoreData":
|
|
return new byte[0x10] { 0xED, 0xB1, 0x58, 0x90, 0x67, 0x06, 0x31, 0x44, 0xBC, 0x6B, 0x7E, 0x56, 0x6C, 0x8C, 0xBC, 0xE4 };
|
|
case "TeamDataColective":
|
|
return new byte[0x10] { 0x39, 0x11, 0x7C, 0x55, 0xF9, 0xEA, 0xBF, 0x49, 0x99, 0x8D, 0x05, 0xD8, 0x52, 0x59, 0x86, 0x55 };
|
|
case "WeaponSettingsData":
|
|
return new byte[0x10] { 0x16, 0x2E, 0xAC, 0x14, 0x90, 0x16, 0x97, 0x43, 0xBA, 0x75, 0x20, 0x4D, 0xAC, 0x1C, 0x56, 0x3F };
|
|
case "SchemeData":
|
|
return new byte[0x10] { 0x6B, 0xDD, 0x69, 0x39, 0x1A, 0xAF, 0xBF, 0x40, 0xBF, 0x2C, 0x21, 0xE3, 0x7C, 0x4B, 0xFC, 0xFE };
|
|
case "SchemeColective":
|
|
return new byte[0x10] { 0x1E, 0x40, 0x13, 0xDF, 0xC6, 0x8F, 0x50, 0x44, 0x8C, 0x7F, 0x55, 0xC6, 0x72, 0xA7, 0x27, 0x25 };
|
|
case "WXFE_UnlockableItem":
|
|
return new byte[0x10] { 0x72, 0x12, 0xCB, 0x5B, 0x48, 0xBF, 0x9F, 0x4A, 0xA2, 0xD3, 0xD1, 0x21, 0xA9, 0x82, 0xD7, 0x3A };
|
|
case "InputDetailsContainer":
|
|
return new byte[0x10] { 0x66, 0xE0, 0x60, 0xA5, 0xAB, 0x92, 0xC2, 0x43, 0x8E, 0x71, 0x46, 0xE8, 0x34, 0xF5, 0xDF, 0x80 };
|
|
case "InputEventMappingContainer":
|
|
return new byte[0x10] { 0x30, 0x7B, 0x4E, 0x74, 0x00, 0xED, 0x46, 0x4C, 0xA4, 0x5D, 0x87, 0x0C, 0xD3, 0x52, 0x81, 0xD8 };
|
|
case "InputMappingDetails":
|
|
return new byte[0x10] { 0x7B, 0x26, 0x21, 0x39, 0xC6, 0x3E, 0x69, 0x4C, 0xB7, 0xDD, 0x19, 0x9A, 0xED, 0xEB, 0x71, 0x5C };
|
|
case "StatsContainer":
|
|
return new byte[0x10] { 0x13, 0x54, 0xBC, 0xDF, 0x36, 0x80, 0x71, 0x4F, 0x83, 0x71, 0x6F, 0x3B, 0x5D, 0x87, 0x63, 0xED };
|
|
case "StoredStatsCollective":
|
|
return new byte[0x10] { 0x25, 0x1D, 0x56, 0xF7, 0x90, 0xD3, 0xF9, 0x4B, 0xA7, 0xE3, 0xE6, 0x73, 0xD6, 0x75, 0xCE, 0x03 };
|
|
case "TeamAwardsContainer":
|
|
return new byte[0x10] { 0xBB, 0x77, 0x14, 0x26, 0x44, 0xC0, 0xAC, 0x4C, 0xA4, 0x18, 0x90, 0x8F, 0xE9, 0x07, 0x5C, 0xF8 };
|
|
case "XResourceDetails":
|
|
return new byte[0x10] { 0xF2, 0x56, 0x75, 0xE7, 0x95, 0xA4, 0x1A, 0x49, 0x85, 0x63, 0x00, 0x6C, 0xE2, 0x57, 0x72, 0x44 };
|
|
case "XIntResourceDetails":
|
|
return new byte[0x10] { 0x8D, 0x9B, 0x88, 0x7D, 0x14, 0x2C, 0x5E, 0x44, 0x96, 0x1F, 0x5E, 0x0E, 0x55, 0x20, 0x41, 0x6A };
|
|
case "XUintResourceDetails":
|
|
return new byte[0x10] { 0x7C, 0x11, 0xE5, 0x93, 0xDA, 0x8A, 0xFB, 0x4A, 0xB1, 0x7A, 0x66, 0x8D, 0x0B, 0xDD, 0x15, 0xE6 };
|
|
case "XStringResourceDetails":
|
|
return new byte[0x10] { 0x72, 0x58, 0xDC, 0x7C, 0xA3, 0x2C, 0xCC, 0x4F, 0xAE, 0x66, 0x43, 0x10, 0x71, 0xE5, 0xCE, 0x67 };
|
|
case "XFloatResourceDetails":
|
|
return new byte[0x10] { 0x5F, 0x9D, 0x88, 0x08, 0x39, 0x80, 0xEA, 0x4C, 0xBA, 0x5B, 0x9C, 0x05, 0x9A, 0xC0, 0x57, 0x0E };
|
|
case "XVectorResourceDetails":
|
|
return new byte[0x10] { 0x63, 0x45, 0x1F, 0x07, 0xB3, 0x8C, 0x96, 0x49, 0xB7, 0x9F, 0xB0, 0xF5, 0xCA, 0xEC, 0x9D, 0x99 };
|
|
case "XContainerResourceDetails":
|
|
return new byte[0x10] { 0x20, 0xBF, 0xB6, 0xE0, 0x0B, 0xF8, 0x29, 0x43, 0xB6, 0xEB, 0x19, 0x98, 0xED, 0x8A, 0xEC, 0x1F };
|
|
case "XDataBank":
|
|
return new byte[0x10] { 0xAC, 0x61, 0xE6, 0x93, 0x41, 0xD9, 0x2A, 0x44, 0xA1, 0x8E, 0xE9, 0x9B, 0x79, 0x58, 0x79, 0xDC };
|
|
case "XContainer":
|
|
return new byte[0x10] { 0x46, 0xD4, 0x1C, 0x5E, 0xA3, 0x48, 0xFE, 0x44, 0xA5, 0x5A, 0xE2, 0x47, 0xB8, 0xF5, 0xE7, 0x13 };
|
|
default:
|
|
return new byte[0x10];
|
|
}
|
|
}
|
|
|
|
private static int findInStringArray(string str, string[] arr)
|
|
{
|
|
for(int i = 0; i < arr.Length; i++)
|
|
{
|
|
if (str.Equals(arr[i], StringComparison.InvariantCulture)) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
private int getXomTypeInsertPos(string typeName)
|
|
{
|
|
XomType[] types = xomFile.XomTypes;
|
|
string[] typesOrder = new string[] {
|
|
"WeaponFactoryContainer",
|
|
"StoreWeaponFactory",
|
|
"WeaponFactoryCollective",
|
|
"StoredTeamData",
|
|
"HighScoreData",
|
|
"TeamDataColective",
|
|
"WeaponSettingsData",
|
|
"SchemeData",
|
|
"SchemeColective",
|
|
"WXFE_UnlockableItem",
|
|
"InputDetailsContainer",
|
|
"InputEventMappingContainer",
|
|
"InputMappingDetails",
|
|
"StatsContainer",
|
|
"StoredStatsCollective",
|
|
"TeamAwardsContainer",
|
|
"XResourceDetails",
|
|
"XIntResourceDetails",
|
|
"XUintResourceDetails",
|
|
"XStringResourceDetails",
|
|
"XFloatResourceDetails",
|
|
"XVectorResourceDetails",
|
|
"XContainerResourceDetails",
|
|
"XDataBank",
|
|
"XContainer"
|
|
};
|
|
|
|
int loc = findInStringArray(typeName, typesOrder);
|
|
|
|
string[] strs = new string[typesOrder.Length];
|
|
|
|
for (int i = 0; i < types.Length; i++)
|
|
{
|
|
int f = findInStringArray(types[i].Name, typesOrder);
|
|
strs[f] = types[i].Name;
|
|
}
|
|
|
|
strs[loc] = typeName;
|
|
|
|
int ins = 0;
|
|
foreach(string str in strs)
|
|
{
|
|
if (str == null)
|
|
continue;
|
|
if (str == typeName)
|
|
break;
|
|
ins++;
|
|
}
|
|
return ins - 1;
|
|
}
|
|
|
|
public void CreateXomType(string typeName)
|
|
{
|
|
byte[] xbytes = getXomTypeXBytes(typeName);
|
|
int insertInto = getXomTypeInsertPos(typeName);
|
|
xomFile.CreateXomType(xbytes, typeName, insertInto);
|
|
}
|
|
|
|
public XomContainer CreateContainer(string type)
|
|
{
|
|
try
|
|
{
|
|
return xomFile.CreateContainer(type);
|
|
}
|
|
catch(XomTypeNotFoundException) { this.CreateXomType(type); return this.CreateContainer(type); }
|
|
}
|
|
public XomContainer LookupContainerById(int id)
|
|
{
|
|
return xomFile.GetContainerById(id);
|
|
}
|
|
public XomContainer LookupContainerByUuid(string uuid)
|
|
{
|
|
return xomFile.GetContainerByUuid(uuid);
|
|
}
|
|
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();
|
|
|
|
}
|
|
}
|
|
} |