Worms4Editor/LibXom/Data/XomFile.cs

142 lines
5.4 KiB
C#

using LibXom.Blocks;
using LibXom.Exceptions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LibXom.Data
{
public class XomFile
{
private int version;
private int unk0;
private List<XomString> xomStrings = new List<XomString>();
private List<XomType> xomTypes = new List<XomType>();
public XomString[] XomStrings
{
get
{
return xomStrings.ToArray();
}
}
public XomType[] XomTypes
{
get
{
return xomTypes.ToArray();
}
}
public XomContainer[] XomContainers
{
get
{
List<XomContainer> xomContainers = new List<XomContainer>();
foreach(XomType type in xomTypes)
foreach(XomContainer container in type.Containers)
xomContainers.Add(container);
return xomContainers.ToArray();
}
}
public XomString GetStringById(int stringId)
{
return XomStrings[stringId];
}
public XomContainer GetContainerById(int containerId)
{
return XomContainers[containerId];
}
public XomType GetTypeByName(string typeName)
{
foreach(XomType type in XomTypes)
if (type.Name.Equals(typeName, StringComparison.InvariantCulture)) return type;
throw new XomTypeNotFoundException("Type \"" + typeName + "\" was not found in XOM.");
}
internal int calculateIdForXomFileComponent(string searchUuid, XomFileComponent[] components)
{
for (int i = 0; i < components.Length; i++)
if (components[i].uuid.Equals(searchUuid, StringComparison.CurrentCultureIgnoreCase)) return i;
throw new XomFileComponentNotFoundException("A XOM Components ID could not be found in the Component List.");
}
internal XomFile(XomBlock[] xomBlocks)
{
MoikBlock? moikBlock = XomBlockHandler.GetBlockByName(xomBlocks, "MOIK") as MoikBlock;
SchmBlock? schemeBlock = XomBlockHandler.GetBlockByName(xomBlocks, "SCHM") as SchmBlock;
StrsBlock? stringBlock = XomBlockHandler.GetBlockByName(xomBlocks, "STRS") as StrsBlock;
// Get Types
XomBlock[] typeBlocks = XomBlockHandler.GetBlocksByName(xomBlocks, "TYPE");
// Get Containers
XomBlock[] containerBlocks = XomBlockHandler.GetBlocksByName(xomBlocks, "CTNR");
if (moikBlock is not MoikBlock) throw new XomBlockNotFoundException("XOM contained no MOIK block!, Is it corrupted?");
if (schemeBlock is not SchmBlock) throw new XomBlockNotFoundException("XOM contained no SCHM block!, Is it corrupted?");
if (stringBlock is not StrsBlock) throw new XomBlockNotFoundException("XOM contained no STRS block!, Is it corrupted?");
version = moikBlock.Version;
unk0 = schemeBlock.Unk0;
/// Read Strings
// Create a list of all strings and the offset they would appear in the strs block.
Dictionary<int, string> stringOffsets = new Dictionary<int, string>();
int loc = 0;
foreach (string str in stringBlock.StringList)
{
stringOffsets.Add(loc, str);
loc += str.Length + 1; // str length, + \0 for terminator.
}
// Now create the list of XomStrings ...
for (int i = 0; i < stringBlock.NumStrs; i++)
{
int offset = stringBlock.OffsetList[i];
string value = stringOffsets[offset];
// Were storing the offset here so that i can figure out how to best order the values again
// when reconstructing the value (eg make it as close to the actual game)
// ideally this wouldnt be needed.
// TODO: Figure out how strings are ordered, so i can ditch the offset variable.
xomStrings.Add(new XomString(this, offset, value));
}
/// Read Types
// keep a global count of how many container blocks have been processed
int cnt = 0;
foreach (TypeBlock type in typeBlocks)
{
string typeName = type.TypeName;
byte[] md5 = type.Md5;
int numContainers = type.NumCtnr;
// Create a list of containers, inside this type.
List<XomContainer> xomContainers = new List<XomContainer>();
// Read numContainers many containers from the container blocks list,
// and then create XomContainer from it.
for (int i = 0; i < numContainers; i++)
{
// Get the container block from the global count ..
CtnrBlock? containerBlock = containerBlocks[cnt] as CtnrBlock;
if (containerBlock is not CtnrBlock) continue;
// Add the new container to the list
xomContainers.Add(new XomContainer(this, typeName, containerBlock.Data));
cnt++; // Increment the global container block count.
}
this.xomTypes.Add(new XomType(this, md5, typeName, xomContainers.ToArray()));
}
}
}
}