mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-11-29 02:12:54 +08:00
XML to PSO conversion (experimental)
This commit is contained in:
parent
34a29a5faa
commit
7c31cfb6ee
@ -84,9 +84,11 @@
|
||||
<Compile Include="GameFiles\MetaTypes\MetaTypes.cs" />
|
||||
<Compile Include="GameFiles\MetaTypes\MetaXml.cs" />
|
||||
<Compile Include="GameFiles\MetaTypes\Pso.cs" />
|
||||
<Compile Include="GameFiles\MetaTypes\PsoBuilder.cs" />
|
||||
<Compile Include="GameFiles\MetaTypes\PsoTypes.cs" />
|
||||
<Compile Include="GameFiles\MetaTypes\Rbf.cs" />
|
||||
<Compile Include="GameFiles\MetaTypes\XmlMeta.cs" />
|
||||
<Compile Include="GameFiles\MetaTypes\XmlPso.cs" />
|
||||
<Compile Include="GameFiles\Resources\Bounds.cs" />
|
||||
<Compile Include="GameFiles\Resources\Clip.cs" />
|
||||
<Compile Include="GameFiles\Resources\Drawable.cs" />
|
||||
|
@ -2212,16 +2212,27 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
var exceptions = new List<Exception>();
|
||||
var allpsos = new List<string>();
|
||||
var diffpsos = new List<string>();
|
||||
|
||||
foreach (RpfFile file in AllRpfs)
|
||||
{
|
||||
foreach (RpfEntry entry in file.AllEntries)
|
||||
{
|
||||
#if !DEBUG
|
||||
try
|
||||
#endif
|
||||
{
|
||||
var n = entry.NameLower;
|
||||
if (!(n.EndsWith(".pso") ||
|
||||
n.EndsWith(".ymt") ||
|
||||
n.EndsWith(".ymf") ||
|
||||
n.EndsWith(".ymap") ||
|
||||
n.EndsWith(".ytyp") ||
|
||||
n.EndsWith(".cut")))
|
||||
continue; //PSO files seem to only have these extensions
|
||||
|
||||
var fentry = entry as RpfFileEntry;
|
||||
var data = entry.File.ExtractFile(fentry); //kind of slow, but sure to catch all PSO files
|
||||
var data = entry.File.ExtractFile(fentry);
|
||||
if (data != null)
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream(data))
|
||||
@ -2236,19 +2247,43 @@ namespace CodeWalker.GameFiles
|
||||
allpsos.Add(fentry.Path);
|
||||
|
||||
PsoTypes.EnsurePsoTypes(pso);
|
||||
|
||||
var xml = PsoXml.GetXml(pso);
|
||||
if (!string.IsNullOrEmpty(xml))
|
||||
{ }
|
||||
|
||||
var xdoc = new XmlDocument();
|
||||
xdoc.LoadXml(xml);
|
||||
var pso2 = XmlPso.GetPso(xdoc);
|
||||
var pso2b = pso2.Save();
|
||||
|
||||
var pso3 = new PsoFile();
|
||||
pso3.Load(pso2b);
|
||||
var xml3 = PsoXml.GetXml(pso3);
|
||||
|
||||
if (xml.Length != xml3.Length)
|
||||
{ }
|
||||
if (xml != xml3)
|
||||
{
|
||||
diffpsos.Add(fentry.Path);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#if !DEBUG
|
||||
catch (Exception ex)
|
||||
{
|
||||
UpdateStatus("Error! " + ex.ToString());
|
||||
exceptions.Add(ex);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
string allpsopaths = string.Join("\r\n", allpsos);
|
||||
string diffpsopaths = string.Join("\r\n", diffpsos);
|
||||
|
||||
string str = PsoTypes.GetTypesInitString();
|
||||
if (!string.IsNullOrEmpty(str))
|
||||
|
@ -621,9 +621,9 @@ namespace CodeWalker.GameFiles
|
||||
public ushort Count2 { get; set; }
|
||||
public uint Unk1 { get; set; }
|
||||
|
||||
public uint PointerDataId { get { return (Pointer & 0xFFF); } }
|
||||
public uint PointerDataIndex { get { return (Pointer & 0xFFF) - 1; } }
|
||||
public uint PointerDataOffset { get { return ((Pointer >> 12) & 0xFFFFF); } }
|
||||
public uint PointerDataId { get { return (Pointer & 0xFFF); } set { Pointer = (Pointer & 0xFFFFF000) + (value & 0xFFF); } }
|
||||
public uint PointerDataIndex { get { return (Pointer & 0xFFF) - 1; } set { PointerDataId = value + 1; } }
|
||||
public uint PointerDataOffset { get { return ((Pointer >> 12) & 0xFFFFF); } set { Pointer = (Pointer & 0xFFF) + ((value << 12) & 0xFFFFF000); } }
|
||||
|
||||
|
||||
|
||||
|
@ -2007,6 +2007,10 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
return (ushort)(((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8));
|
||||
}
|
||||
public static short SwapBytes(short x)
|
||||
{
|
||||
return (short)SwapBytes((ushort)x);
|
||||
}
|
||||
public static uint SwapBytes(uint x)
|
||||
{
|
||||
// swap adjacent 16-bit blocks
|
||||
|
@ -5,6 +5,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
|
||||
namespace CodeWalker.GameFiles
|
||||
{
|
||||
@ -640,6 +641,10 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
var structInfo = cont.GetStructureInfo(structName);
|
||||
if (structInfo == null)
|
||||
{
|
||||
structInfo = PsoTypes.GetStructureInfo(structName);//fallback to builtin...
|
||||
}
|
||||
if (structInfo == null)
|
||||
{
|
||||
ErrorXml(sb, indent, "Couldn't find structure info " + name + "!");
|
||||
return;
|
||||
@ -708,7 +713,10 @@ namespace CodeWalker.GameFiles
|
||||
case 0: //int enum
|
||||
var intEVal = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset));
|
||||
var intE = enumInfo.FindEntry(intEVal);
|
||||
StringTag(sb, cind, ename, HashString(intE?.EntryNameHash ?? 0));
|
||||
var intH = HashString(intE?.EntryNameHash ?? 0);
|
||||
if (string.IsNullOrEmpty(intH))
|
||||
{ }
|
||||
StringTag(sb, cind, ename, intH);
|
||||
break;
|
||||
case 2: //byte enum
|
||||
var byteEVal = data[eoffset];
|
||||
@ -718,9 +726,9 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
break;
|
||||
case PsoDataType.Flags:
|
||||
uint fCount = (entry.ReferenceKey >> 16) & 0x0000FFFF;
|
||||
uint fEntry = (entry.ReferenceKey & 0xFFFF);
|
||||
var fEnt = structInfo.GetEntry((int)fEntry);
|
||||
//uint fCount = (entry.ReferenceKey >> 16) & 0x0000FFFF;
|
||||
uint fEntry = (entry.ReferenceKey & 0xFFF);
|
||||
var fEnt = (fEntry != 0xFFF) ? structInfo.GetEntry((int)fEntry) : null;
|
||||
PsoEnumInfo flagsInfo = null;
|
||||
if ((fEnt != null) && (fEnt.EntryNameHash == MetaName.ARRAYINFO))
|
||||
{
|
||||
@ -728,7 +736,9 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
if (flagsInfo == null)
|
||||
{
|
||||
flagsInfo = cont.GetEnumInfo(entry.EntryNameHash);
|
||||
if (fEntry != 0xFFF)
|
||||
{ }
|
||||
//flagsInfo = cont.GetEnumInfo(entry.EntryNameHash);
|
||||
}
|
||||
uint? flagsVal = null;
|
||||
switch (entry.Unk_5h)
|
||||
@ -805,13 +815,14 @@ namespace CodeWalker.GameFiles
|
||||
default:
|
||||
ErrorXml(sb, cind, ename + ": Unexpected Integer subtype: " + entry.Unk_5h.ToString());
|
||||
break;
|
||||
case 0: //signed int
|
||||
case 0: //signed int (? flags?)
|
||||
var int6aVal = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset));
|
||||
ValueTag(sb, cind, ename, int6aVal.ToString());
|
||||
break;
|
||||
case 1: //unsigned int
|
||||
var int6bVal = MetaTypes.SwapBytes(BitConverter.ToUInt32(data, eoffset));
|
||||
ValueTag(sb, cind, ename, "0x" + int6bVal.ToString("X").PadLeft(8, '0'));
|
||||
ValueTag(sb, cind, ename, int6bVal.ToString());
|
||||
//ValueTag(sb, cind, ename, "0x" + int6bVal.ToString("X").PadLeft(8, '0'));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -833,16 +844,16 @@ namespace CodeWalker.GameFiles
|
||||
ValueTag(sb, cind, ename, short4Val.ToString());
|
||||
break;
|
||||
case PsoDataType.HFloat://half float?
|
||||
var short1EVal = MetaTypes.SwapBytes(BitConverter.ToUInt16(data, eoffset));
|
||||
var short1EVal = MetaTypes.SwapBytes(BitConverter.ToInt16(data, eoffset));
|
||||
ValueTag(sb, cind, ename, short1EVal.ToString());
|
||||
break;
|
||||
case PsoDataType.String:
|
||||
var str0 = GetStringValue(cont.Pso, entry, data, eoffset);
|
||||
if (str0 == null)
|
||||
{
|
||||
ErrorXml(sb, cind, ename + ": Unexpected String subtype: " + entry.Unk_5h.ToString());
|
||||
}
|
||||
else
|
||||
var str0 = XmlEscape(GetStringValue(cont.Pso, entry, data, eoffset));
|
||||
//if (str0 == null)
|
||||
//{
|
||||
// ErrorXml(sb, cind, ename + ": Unexpected String subtype: " + entry.Unk_5h.ToString());
|
||||
//}
|
||||
//else
|
||||
{
|
||||
StringTag(sb, cind, ename, str0);
|
||||
}
|
||||
@ -909,8 +920,13 @@ namespace CodeWalker.GameFiles
|
||||
var boffset = offset + block.Offset;
|
||||
var eoffset = boffset + entry.DataOffset;
|
||||
var aOffset = offset + entry.DataOffset;
|
||||
var abOffset = aOffset + block.Offset;
|
||||
var aBlockId = blockId;
|
||||
uint aCount = (entry.ReferenceKey >> 16) & 0x0000FFFF;
|
||||
Array_Structure arrStruc = new Array_Structure();
|
||||
arrStruc.PointerDataId = (uint)aBlockId;
|
||||
arrStruc.PointerDataOffset = (uint)aOffset;
|
||||
arrStruc.Count1 = arrStruc.Count2 = (ushort)aCount;
|
||||
var aind = indent + 1;
|
||||
string arrTag = ename;
|
||||
PsoStructureEntryInfo arrEntry = estruct.GetEntry((int)(entry.ReferenceKey & 0xFFFF));
|
||||
@ -922,17 +938,24 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
var data = cont.Pso.DataSection.Data;
|
||||
|
||||
bool embedded = true;
|
||||
switch (entry.Unk_5h)
|
||||
{
|
||||
default:
|
||||
ErrorXml(sb, indent, ename + ": WIP! Unsupported Array subtype: " + entry.Unk_5h.ToString());
|
||||
break;
|
||||
case 0: //Array_Structure
|
||||
var arrStruc = MetaTypes.ConvertData<Array_Structure>(data, eoffset);
|
||||
arrStruc = MetaTypes.ConvertData<Array_Structure>(data, eoffset);
|
||||
arrStruc.SwapEnd();
|
||||
aBlockId = (int)arrStruc.PointerDataId;
|
||||
aOffset = (int)arrStruc.PointerDataOffset;
|
||||
aCount = arrStruc.Count1;
|
||||
var aBlock = cont.Pso.GetBlock(aBlockId);
|
||||
if (aBlock != null)
|
||||
{
|
||||
abOffset = aOffset + aBlock.Offset;
|
||||
}
|
||||
embedded = false;
|
||||
break;
|
||||
case 1: //Raw in-line array
|
||||
break;
|
||||
@ -941,11 +964,20 @@ namespace CodeWalker.GameFiles
|
||||
case 4: //pointer array? default array?
|
||||
if (arrEntry.Unk_5h == 3) //pointers...
|
||||
{
|
||||
var arrStruc4 = MetaTypes.ConvertData<Array_Structure>(data, eoffset);
|
||||
arrStruc4.SwapEnd();
|
||||
aBlockId = (int)arrStruc4.PointerDataId;
|
||||
aOffset = (int)arrStruc4.PointerDataOffset;
|
||||
aCount = arrStruc4.Count1;
|
||||
arrStruc = MetaTypes.ConvertData<Array_Structure>(data, eoffset);
|
||||
arrStruc.SwapEnd();
|
||||
aBlockId = (int)arrStruc.PointerDataId;
|
||||
aOffset = (int)arrStruc.PointerDataOffset;
|
||||
aCount = arrStruc.Count1;
|
||||
var aBlock2 = cont.Pso.GetBlock(aBlockId);
|
||||
if (aBlock2 != null)
|
||||
{
|
||||
abOffset = aOffset + aBlock2.Offset;
|
||||
}
|
||||
embedded = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
break;
|
||||
case 129: //also raw inline array? in junctions.pso
|
||||
@ -959,10 +991,11 @@ namespace CodeWalker.GameFiles
|
||||
break;
|
||||
case PsoDataType.Array:
|
||||
var rk0 = (entry.ReferenceKey >> 16) & 0x0000FFFF;
|
||||
//var rk1 = entry.ReferenceKey & 0x0000FFFF;
|
||||
//var rk3 = (arrEntry.ReferenceKey >> 16) & 0x0000FFFF;
|
||||
//var rk4 = arrEntry.ReferenceKey & 0x0000FFFF;
|
||||
if (rk0 > 0)
|
||||
{
|
||||
//var arrStruc5 = MetaTypes.ConvertDataArray<Array_StructurePointer>(data, eoffset, (int)rk0);
|
||||
//for (int n = 0; n < rk0; n++) arrStruc5[n].SwapEnd();
|
||||
aOffset = offset + entry.DataOffset;
|
||||
|
||||
OpenTag(sb, indent, arrTag);
|
||||
@ -997,7 +1030,14 @@ namespace CodeWalker.GameFiles
|
||||
for (int n = 0; n < aCount; n++)
|
||||
{
|
||||
var ptrVal = ptrArr[n];
|
||||
WriteNode(sb, aind, cont, ptrVal.BlockID, (int)ptrVal.ItemOffset, XmlTagMode.ItemAndType);
|
||||
if (ptrVal.Pointer == 0)
|
||||
{
|
||||
SelfClosingTag(sb, aind, "Item"); //"null" entry...
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteNode(sb, aind, cont, ptrVal.BlockID, (int)ptrVal.ItemOffset, XmlTagMode.ItemAndType);
|
||||
}
|
||||
}
|
||||
CloseTag(sb, indent, ename);
|
||||
}
|
||||
@ -1050,6 +1090,8 @@ namespace CodeWalker.GameFiles
|
||||
ErrorXml(sb, indent, ename + ": Unexpected String array subtype: " + entry.Unk_5h.ToString());
|
||||
break;
|
||||
case 0: //hash array...
|
||||
if (embedded)
|
||||
{ }
|
||||
var arrHash = MetaTypes.ConvertData<Array_uint>(data, eoffset);
|
||||
arrHash.SwapEnd();
|
||||
var hashArr = PsoTypes.GetHashArray(cont.Pso, arrHash);
|
||||
@ -1064,54 +1106,70 @@ namespace CodeWalker.GameFiles
|
||||
WriteRawArray(sb, v2Arr, indent, ename, "Vector2", FormatVector2Swap, 1);
|
||||
break;
|
||||
case PsoDataType.Float3:
|
||||
aCount = (entry.ReferenceKey >> 16) & 0x0000FFFF;
|
||||
if (!embedded)
|
||||
{ }
|
||||
arrTag += " itemType=\"Vector3\""; //this is actually aligned as vector4, the W values are crazy in places
|
||||
var v4Arr = MetaTypes.ConvertDataArray<Vector4>(data, eoffset, (int)aCount);
|
||||
WriteRawArray(sb, v4Arr, indent, ename, "Vector3", FormatVector4SwapXYZOnly, 1);
|
||||
break;
|
||||
case PsoDataType.UByte:
|
||||
if (embedded)
|
||||
{ }
|
||||
else
|
||||
{ } //block type 2
|
||||
var barr = new byte[aCount];
|
||||
if (aCount > 0)
|
||||
{
|
||||
var bblock = cont.Pso.GetBlock(aBlockId);
|
||||
var boffs = bblock.Offset + aOffset;
|
||||
Buffer.BlockCopy(data, boffs, barr, 0, (int)aCount);
|
||||
//var bblock = cont.Pso.GetBlock(aBlockId);
|
||||
//var boffs = bblock.Offset + aOffset;
|
||||
Buffer.BlockCopy(data, abOffset /*boffs*/, barr, 0, (int)aCount);
|
||||
}
|
||||
WriteRawArray(sb, barr, indent, ename, "byte");
|
||||
break;
|
||||
case PsoDataType.Bool:
|
||||
if (embedded)
|
||||
{ }
|
||||
else
|
||||
{ }
|
||||
var barr2 = new byte[aCount];
|
||||
if (aCount > 0)
|
||||
{
|
||||
var bblock = cont.Pso.GetBlock(aBlockId);
|
||||
var boffs = bblock.Offset + aOffset;
|
||||
Buffer.BlockCopy(data, boffs, barr2, 0, (int)aCount);
|
||||
//var bblock = cont.Pso.GetBlock(aBlockId);
|
||||
//var boffs = bblock.Offset + aOffset;
|
||||
Buffer.BlockCopy(data, abOffset /*boffs*/, barr2, 0, (int)aCount);
|
||||
}
|
||||
WriteRawArray(sb, barr2, indent, ename, "boolean"); //todo: true/false output
|
||||
break;
|
||||
case PsoDataType.Float:
|
||||
var arrFloat = MetaTypes.ConvertData<Array_float>(data, eoffset);
|
||||
arrFloat.SwapEnd();
|
||||
if (embedded)
|
||||
{ }
|
||||
var arrFloat = new Array_float(arrStruc.Pointer, arrStruc.Count1); //block type 7
|
||||
var floatArr = PsoTypes.GetFloatArray(cont.Pso, arrFloat);
|
||||
WriteRawArray(sb, floatArr, indent, ename, "float");
|
||||
break;
|
||||
case PsoDataType.UShort:
|
||||
var arrShort = MetaTypes.ConvertData<Array_Structure>(data, eoffset);
|
||||
arrShort.SwapEnd();
|
||||
var shortArr = PsoTypes.GetUShortArray(cont.Pso, arrShort);
|
||||
if (embedded)
|
||||
{ }
|
||||
var shortArr = PsoTypes.GetUShortArray(cont.Pso, arrStruc); //block type 4
|
||||
WriteRawArray(sb, shortArr, indent, ename, "ushort");
|
||||
break;
|
||||
case PsoDataType.UInt:
|
||||
var intArr = MetaTypes.ConvertDataArray<int>(data, eoffset, (int)aCount);
|
||||
if (embedded)
|
||||
{ }
|
||||
var arrUint = new Array_uint(arrStruc.Pointer, arrStruc.Count1); //block type 6
|
||||
var intArr = PsoTypes.GetUintArray(cont.Pso, arrUint);
|
||||
WriteRawArray(sb, intArr, indent, ename, "int");
|
||||
break;
|
||||
case PsoDataType.SInt:
|
||||
var arrUint2 = MetaTypes.ConvertData<Array_uint>(data, eoffset);
|
||||
arrUint2.SwapEnd();
|
||||
if (embedded)
|
||||
{ }
|
||||
var arrUint2 = new Array_uint(arrStruc.Pointer, arrStruc.Count1); //block type 5
|
||||
var intArr2 = PsoTypes.GetUintArray(cont.Pso, arrUint2);
|
||||
WriteRawArray(sb, intArr2, indent, ename, "int");
|
||||
break;
|
||||
case PsoDataType.Enum:
|
||||
if (embedded)
|
||||
{ }
|
||||
var arrEnum = MetaTypes.ConvertData<Array_uint>(data, eoffset);
|
||||
arrEnum.SwapEnd();
|
||||
var enumArr = PsoTypes.GetUintArray(cont.Pso, arrEnum);
|
||||
@ -1139,41 +1197,23 @@ namespace CodeWalker.GameFiles
|
||||
var mapidx2 = (entry.ReferenceKey >> 16) & 0x0000FFFF;
|
||||
var mapreftype1 = structInfo.Entries[mapidx2];
|
||||
var mapreftype2 = structInfo.Entries[mapidx1];
|
||||
var x1 = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset));//same as ref key?
|
||||
var x2 = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset + 4));//0?
|
||||
var x3 = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset + 8));//pointer?
|
||||
var x4 = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset + 12));//
|
||||
var x5 = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset + 16));//count/capacity?
|
||||
var x6 = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset + 20));//
|
||||
var x1 = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset));
|
||||
var x2 = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset + 4));
|
||||
var sptr = MetaTypes.ConvertData<Array_Structure>(data, eoffset + 8);
|
||||
sptr.SwapEnd();
|
||||
|
||||
//File.WriteAllText("C:\\CodeWalker.Projects\\testxml.xml", sb.ToString());
|
||||
|
||||
if (x1 != 0x1000000)
|
||||
{ }
|
||||
if (x2 != 0)
|
||||
{ }
|
||||
if (x4 != 0)
|
||||
{ }
|
||||
if (x6 != 0)
|
||||
if (mapreftype2.ReferenceKey != 0)
|
||||
{ }
|
||||
|
||||
|
||||
var xBlockId = x3 & 0xFFF;
|
||||
var xOffset = (x3 >> 12) & 0xFFFFF;
|
||||
var xCount1 = x5 & 0xFFFF;
|
||||
var xCount2 = (x5 >> 16) & 0xFFFF;
|
||||
|
||||
//var x1a = x1 & 0xFFF; //block id? for another pointer?
|
||||
//var x1b = (x1 >> 12) & 0xFFFFF; //offset?
|
||||
//var x4u = (uint)x4;
|
||||
//var x4a = x4 & 0xFFF; //block id?
|
||||
//var x4b = (x4 >> 12) & 0xFFFFF; //offset?
|
||||
//var x2h = (MetaHash)(uint)x2;
|
||||
//var x6h = (MetaHash)(uint)x6;
|
||||
//if (x1a > 0)
|
||||
//{ }
|
||||
|
||||
|
||||
var xBlockId = (int)sptr.PointerDataId;// x3 & 0xFFF;
|
||||
var xOffset = sptr.PointerDataOffset;// (x3 >> 12) & 0xFFFFF;
|
||||
var xCount1 = sptr.Count1;// x5 & 0xFFFF;
|
||||
var xCount2 = sptr.Count2;// (x5 >> 16) & 0xFFFF;
|
||||
|
||||
var xBlock = cont.Pso.GetBlock(xBlockId);
|
||||
if ((xBlock == null) && (xCount1 > 0))
|
||||
@ -1183,8 +1223,7 @@ namespace CodeWalker.GameFiles
|
||||
else
|
||||
{
|
||||
if (xCount1 != xCount2)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
if (xCount1 > 0)
|
||||
{
|
||||
var xStruct = cont.GetStructureInfo(xBlock.NameHash);
|
||||
@ -1218,10 +1257,10 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
ErrorXml(sb, aind, ename + ": Map Item was not a structure!");
|
||||
}
|
||||
else if (iEntry.Unk_5h != 3)
|
||||
{
|
||||
ErrorXml(sb, aind, ename + ": Map Item was not a structure pointer - TODO!");
|
||||
}
|
||||
//else if (iEntry.Unk_5h != 3)
|
||||
//{
|
||||
// ErrorXml(sb, aind, ename + ": Map Item was not a structure pointer - TODO!");
|
||||
//}
|
||||
else
|
||||
{
|
||||
OpenTag(sb, xind, ename);
|
||||
@ -1236,30 +1275,39 @@ namespace CodeWalker.GameFiles
|
||||
var kOffset = sOffset + kEntry.DataOffset;
|
||||
var iOffset = sOffset + iEntry.DataOffset;
|
||||
var kStr = GetStringValue(cont.Pso, kEntry, data, kOffset);
|
||||
var iPtr = MetaTypes.ConvertData<PsoPOINTER>(data, iOffset);
|
||||
iPtr.SwapEnd();
|
||||
var iBlock = cont.Pso.GetBlock(iPtr.BlockID);
|
||||
if (iBlock == null)
|
||||
if (iEntry.ReferenceKey != 0)//(xBlock.NameHash != MetaName.ARRAYINFO)//257,258,259
|
||||
{
|
||||
OpenTag(sb, aind, "Item type=\"" + HashString((MetaName)entry.ReferenceKey) + "\" key=\"" + kStr + "\"");
|
||||
WriteNode(sb, aind, cont, iPtr.BlockID, (int)iPtr.ItemOffset, XmlTagMode.None, (MetaName)entry.ReferenceKey);
|
||||
//embedded map values
|
||||
var vOffset = xOffset2 + iEntry.DataOffset;
|
||||
OpenTag(sb, aind, "Item type=\"" + HashString((MetaName)iEntry.ReferenceKey) + "\" key=\"" + kStr + "\"");
|
||||
WriteNode(sb, aind, cont, xBlockId, vOffset, XmlTagMode.None, (MetaName)iEntry.ReferenceKey);
|
||||
CloseTag(sb, aind, "Item");
|
||||
}
|
||||
else
|
||||
{
|
||||
var iStr = "Item type=\"" + HashString(iBlock.NameHash) + "\" key=\"" + kStr + "\"";
|
||||
var iStruc = cont.GetStructureInfo(iBlock.NameHash);
|
||||
if (iStruc?.EntriesCount == 0)
|
||||
var iPtr = MetaTypes.ConvertData<PsoPOINTER>(data, iOffset);
|
||||
iPtr.SwapEnd();
|
||||
var iBlock = cont.Pso.GetBlock(iPtr.BlockID);
|
||||
if (iBlock == null)
|
||||
{
|
||||
//SelfClosingTag(sb, aind, iStr);
|
||||
OpenTag(sb, aind, iStr);
|
||||
CloseTag(sb, aind, "Item");
|
||||
ErrorXml(sb, aind, ename + ": Could not find iBlock for Map entry!");
|
||||
}
|
||||
else
|
||||
{
|
||||
OpenTag(sb, aind, iStr);
|
||||
WriteNode(sb, aind, cont, iPtr.BlockID, (int)iPtr.ItemOffset, XmlTagMode.None);//, (MetaName)entry.ReferenceKey);
|
||||
CloseTag(sb, aind, "Item");
|
||||
var iStr = "Item type=\"" + HashString(iBlock.NameHash) + "\" key=\"" + kStr + "\"";
|
||||
var iStruc = cont.GetStructureInfo(iBlock.NameHash);
|
||||
if (iStruc?.EntriesCount == 0)
|
||||
{
|
||||
//SelfClosingTag(sb, aind, iStr);
|
||||
OpenTag(sb, aind, iStr);
|
||||
CloseTag(sb, aind, "Item");
|
||||
}
|
||||
else
|
||||
{
|
||||
OpenTag(sb, aind, iStr);
|
||||
WriteNode(sb, aind, cont, iPtr.BlockID, (int)iPtr.ItemOffset, XmlTagMode.None);//, (MetaName)entry.ReferenceKey);
|
||||
CloseTag(sb, aind, "Item");
|
||||
}
|
||||
}
|
||||
}
|
||||
xOffset2 += xStruct.StructureLength;
|
||||
@ -1311,7 +1359,17 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static string XmlEscape(string unescaped)
|
||||
{
|
||||
if (unescaped == null) return null;
|
||||
XmlDocument doc = new XmlDocument();
|
||||
XmlNode node = doc.CreateElement("root");
|
||||
node.InnerText = unescaped;
|
||||
var escaped = node.InnerXml;
|
||||
if (escaped != unescaped)
|
||||
{ }
|
||||
return node.InnerXml;
|
||||
}
|
||||
|
||||
|
||||
public class PsoCont
|
||||
|
@ -205,6 +205,13 @@ namespace CodeWalker.GameFiles
|
||||
public PsoSTRESection STRESection { get; set; }
|
||||
public PsoCHKSSection CHKSSection { get; set; }
|
||||
|
||||
|
||||
public void Load(byte[] data)
|
||||
{
|
||||
using (var ms = new MemoryStream(data))
|
||||
Load(ms);
|
||||
}
|
||||
|
||||
public void Load(string fileName)
|
||||
{
|
||||
using (var stream = new FileStream(fileName, FileMode.Open))
|
||||
@ -268,6 +275,19 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public byte[] Save()
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
Save(ms);
|
||||
|
||||
var buf = new byte[ms.Length];
|
||||
ms.Position = 0;
|
||||
ms.Read(buf, 0, buf.Length);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
public void Save(string fileName)
|
||||
{
|
||||
using (var stream = new FileStream(fileName, FileMode.Create))
|
||||
@ -280,6 +300,11 @@ namespace CodeWalker.GameFiles
|
||||
if (DataSection != null) DataSection.Write(writer);
|
||||
if (DataMapSection != null) DataMapSection.Write(writer);
|
||||
if (SchemaSection != null) SchemaSection.Write(writer);
|
||||
if (STRFSection != null) STRFSection.Write(writer);
|
||||
if (STRSSection != null) STRSSection.Write(writer);
|
||||
if (STRESection != null) STRESection.Write(writer);
|
||||
if (PSIGSection != null) PSIGSection.Write(writer);
|
||||
if (CHKSSection != null) CHKSSection.Write(writer);
|
||||
}
|
||||
|
||||
|
||||
@ -342,11 +367,13 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
{
|
||||
Length = Data.Length;
|
||||
|
||||
writer.Write(Data);
|
||||
writer.Position -= Data.Length;
|
||||
writer.Write((uint)0x5053494E);
|
||||
writer.Write((uint)(Data.Length));
|
||||
writer.Position += Data.Length - 8;
|
||||
writer.Position -= Length;
|
||||
writer.Write(Ident);
|
||||
writer.Write((uint)(Length));
|
||||
writer.Position += Length - 8;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
@ -413,10 +440,10 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
public void Read(DataReader reader)
|
||||
{
|
||||
this.NameHash = (MetaName)reader.ReadUInt32();
|
||||
this.Offset = reader.ReadInt32();
|
||||
this.Unknown_8h = reader.ReadInt32();
|
||||
this.Length = reader.ReadInt32();
|
||||
NameHash = (MetaName)reader.ReadUInt32();
|
||||
Offset = reader.ReadInt32();
|
||||
Unknown_8h = reader.ReadInt32();
|
||||
Length = reader.ReadInt32();
|
||||
}
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
@ -449,7 +476,7 @@ namespace CodeWalker.GameFiles
|
||||
Length = reader.ReadInt32();
|
||||
Count = reader.ReadUInt32();
|
||||
|
||||
this.EntriesIdx = new PsoElementIndexInfo[Count];
|
||||
EntriesIdx = new PsoElementIndexInfo[Count];
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
var entry = new PsoElementIndexInfo();
|
||||
@ -457,7 +484,7 @@ namespace CodeWalker.GameFiles
|
||||
EntriesIdx[i] = entry;
|
||||
}
|
||||
|
||||
this.Entries = new PsoElementInfo[Count];
|
||||
Entries = new PsoElementInfo[Count];
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
reader.Position = EntriesIdx[i].Offset;
|
||||
@ -506,7 +533,7 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
writer.Write(Ident);
|
||||
writer.Write((int)(12 + entriesStream.Length + indexStream.Length));
|
||||
writer.Write((int)(Entries.Length));
|
||||
writer.Write((uint)(Entries.Length));
|
||||
|
||||
// write entries index data
|
||||
var buf1 = new byte[indexStream.Length];
|
||||
@ -536,8 +563,8 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
public void Read(DataReader reader)
|
||||
{
|
||||
this.NameHash = (MetaName)reader.ReadUInt32();
|
||||
this.Offset = reader.ReadInt32();
|
||||
NameHash = (MetaName)reader.ReadUInt32();
|
||||
Offset = reader.ReadInt32();
|
||||
}
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
@ -590,11 +617,11 @@ namespace CodeWalker.GameFiles
|
||||
public override void Read(DataReader reader)
|
||||
{
|
||||
uint x = reader.ReadUInt32();
|
||||
this.Type = (byte)((x & 0xFF000000) >> 24);
|
||||
this.EntriesCount = (short)(x & 0xFFFF);
|
||||
this.Unk = (byte)((x & 0x00FF0000) >> 16);
|
||||
this.StructureLength = reader.ReadInt32();
|
||||
this.Unk_Ch = reader.ReadUInt32();
|
||||
Type = (byte)((x & 0xFF000000) >> 24);
|
||||
EntriesCount = (short)(x & 0xFFFF);
|
||||
Unk = (byte)((x & 0x00FF0000) >> 16);
|
||||
StructureLength = reader.ReadInt32();
|
||||
Unk_Ch = reader.ReadUInt32();
|
||||
|
||||
if (Unk_Ch != 0)
|
||||
{ }
|
||||
@ -655,7 +682,7 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
public MetaName EntryNameHash { get; set; }
|
||||
public PsoDataType Type { get; set; }
|
||||
public byte Unk_5h { get; set; }
|
||||
public byte Unk_5h { get; set; } //0 = default, 3 = pointer array?
|
||||
public ushort DataOffset { get; set; }
|
||||
public uint ReferenceKey { get; set; } // when array -> entry index with type
|
||||
|
||||
@ -673,11 +700,11 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
public void Read(DataReader reader)
|
||||
{
|
||||
this.EntryNameHash = (MetaName)reader.ReadUInt32();
|
||||
this.Type = (PsoDataType)reader.ReadByte();
|
||||
this.Unk_5h = reader.ReadByte();
|
||||
this.DataOffset = reader.ReadUInt16();
|
||||
this.ReferenceKey = reader.ReadUInt32();
|
||||
EntryNameHash = (MetaName)reader.ReadUInt32();
|
||||
Type = (PsoDataType)reader.ReadByte();
|
||||
Unk_5h = reader.ReadByte();
|
||||
DataOffset = reader.ReadUInt16();
|
||||
ReferenceKey = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
@ -721,8 +748,8 @@ namespace CodeWalker.GameFiles
|
||||
public override void Read(DataReader reader)
|
||||
{
|
||||
uint x = reader.ReadUInt32();
|
||||
this.Type = (byte)((x & 0xFF000000) >> 24);
|
||||
this.EntriesCount = (int)(x & 0x00FFFFFF);
|
||||
Type = (byte)((x & 0xFF000000) >> 24);
|
||||
EntriesCount = (int)(x & 0x00FFFFFF);
|
||||
|
||||
Entries = new PsoEnumEntryInfo[EntriesCount];
|
||||
for (int i = 0; i < EntriesCount; i++)
|
||||
@ -762,6 +789,21 @@ namespace CodeWalker.GameFiles
|
||||
return null;
|
||||
}
|
||||
|
||||
public PsoEnumEntryInfo FindEntryByName(MetaName name)
|
||||
{
|
||||
if (Entries == null) return null;
|
||||
for (int i = 0; i < Entries.Length; i++)
|
||||
{
|
||||
var entry = Entries[i];
|
||||
if (entry.EntryNameHash == name)
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
@ -785,8 +827,8 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
public void Read(DataReader reader)
|
||||
{
|
||||
this.EntryNameHash = (MetaName)reader.ReadUInt32();
|
||||
this.EntryKey = reader.ReadInt32();
|
||||
EntryNameHash = (MetaName)reader.ReadUInt32();
|
||||
EntryKey = reader.ReadInt32();
|
||||
}
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
@ -827,10 +869,25 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
{
|
||||
var strStream = new MemoryStream();
|
||||
var strWriter = new DataWriter(strStream, Endianess.BigEndian);
|
||||
foreach (var str in Strings)
|
||||
{
|
||||
strWriter.Write(str);
|
||||
}
|
||||
|
||||
Length = (int)strStream.Length + 8;
|
||||
|
||||
writer.Write(Ident);
|
||||
writer.Write(Length);
|
||||
|
||||
if (strStream.Length > 0)
|
||||
{
|
||||
var buf1 = new byte[strStream.Length];
|
||||
strStream.Position = 0;
|
||||
strStream.Read(buf1, 0, buf1.Length);
|
||||
writer.Write(buf1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -867,10 +924,25 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
{
|
||||
var strStream = new MemoryStream();
|
||||
var strWriter = new DataWriter(strStream, Endianess.BigEndian);
|
||||
foreach (var str in Strings)
|
||||
{
|
||||
strWriter.Write(str);
|
||||
}
|
||||
|
||||
Length = (int)strStream.Length + 8;
|
||||
|
||||
writer.Write(Ident);
|
||||
writer.Write(Length);
|
||||
|
||||
if (strStream.Length > 0)
|
||||
{
|
||||
var buf1 = new byte[strStream.Length];
|
||||
strStream.Position = 0;
|
||||
strStream.Read(buf1, 0, buf1.Length);
|
||||
writer.Write(buf1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -886,7 +958,6 @@ namespace CodeWalker.GameFiles
|
||||
public int Length { get; set; }
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
//public MetaHash[] Hashes { get; set; }
|
||||
//public byte[] Decr1 { get; set; }
|
||||
//public byte[] Decr2 { get; set; }
|
||||
|
||||
@ -899,26 +970,25 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
Data = reader.ReadBytes(Length - 8);
|
||||
|
||||
//reader.Position = 8;
|
||||
//List<MetaHash> hashes = new List<MetaHash>();
|
||||
//while (reader.Position < reader.Length)
|
||||
//{
|
||||
// hashes.Add(reader.ReadUInt32());
|
||||
//}
|
||||
//Hashes = hashes.ToArray();
|
||||
|
||||
//Decr1 = GTACrypto.DecryptAES(Data);
|
||||
//Decr2 = GTACrypto.DecryptNG(Data, )
|
||||
|
||||
//TODO: someone plz figure out that encryption
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
{
|
||||
|
||||
Length = (Data?.Length??0) + 8;
|
||||
|
||||
writer.Write(Ident);
|
||||
writer.Write(Length);
|
||||
|
||||
if (Length > 8)
|
||||
{
|
||||
writer.Write(Data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -947,10 +1017,15 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
{
|
||||
Length = (Data?.Length ?? 0) + 8;
|
||||
|
||||
writer.Write(Ident);
|
||||
writer.Write(Length);
|
||||
|
||||
if (Length > 8)
|
||||
{
|
||||
writer.Write(Data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -983,11 +1058,13 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
{
|
||||
Length = 20;
|
||||
|
||||
writer.Write(Ident);
|
||||
writer.Write(Length);
|
||||
|
||||
|
||||
writer.Write(FileSize);
|
||||
writer.Write(Checksum);
|
||||
writer.Write(Unk0);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
504
CodeWalker.Core/GameFiles/MetaTypes/PsoBuilder.cs
Normal file
504
CodeWalker.Core/GameFiles/MetaTypes/PsoBuilder.cs
Normal file
@ -0,0 +1,504 @@
|
||||
using SharpDX;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CodeWalker.GameFiles
|
||||
{
|
||||
public class PsoBuilder
|
||||
{
|
||||
|
||||
|
||||
public PsoBuilderPointer RootPointer { get; set; }
|
||||
|
||||
List<string> STRFStrings = new List<string>();
|
||||
List<string> STRSStrings = new List<string>();
|
||||
|
||||
|
||||
Dictionary<MetaName, PsoStructureInfo> StructureInfos = new Dictionary<MetaName, PsoStructureInfo>();
|
||||
Dictionary<MetaName, PsoEnumInfo> EnumInfos = new Dictionary<MetaName, PsoEnumInfo>();
|
||||
|
||||
|
||||
List<PsoBuilderBlock> Blocks = new List<PsoBuilderBlock>();
|
||||
int MaxBlockLength = 0x100000; //TODO: figure what this should be!
|
||||
|
||||
public PsoBuilderBlock EnsureBlock(MetaName type)
|
||||
{
|
||||
foreach (var block in Blocks)
|
||||
{
|
||||
if (block.StructureNameHash == type)
|
||||
{
|
||||
if (block.TotalSize < MaxBlockLength)
|
||||
{
|
||||
return block;
|
||||
}
|
||||
}
|
||||
}
|
||||
PsoBuilderBlock b = new PsoBuilderBlock();
|
||||
b.StructureNameHash = type;
|
||||
b.Index = Blocks.Count;
|
||||
Blocks.Add(b);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
public PsoBuilderPointer AddItem<T>(MetaName type, T item) where T : struct
|
||||
{
|
||||
byte[] data = MetaTypes.ConvertToBytes(item);
|
||||
return AddItem(type, data);
|
||||
}
|
||||
|
||||
public PsoBuilderPointer AddItem(MetaName type, byte[] data)
|
||||
{
|
||||
PsoBuilderBlock block = EnsureBlock(type);
|
||||
int brem = data.Length % 16;
|
||||
if (brem > 0)
|
||||
{
|
||||
int newlen = data.Length - brem + 16;
|
||||
byte[] newdata = new byte[newlen];
|
||||
Buffer.BlockCopy(data, 0, newdata, 0, data.Length);
|
||||
data = newdata; //make sure item size is multiple of 16... so pointers don't need sub offsets!
|
||||
}
|
||||
int idx = block.AddItem(data);
|
||||
PsoBuilderPointer r = new PsoBuilderPointer();
|
||||
r.BlockID = block.Index + 1;
|
||||
r.Offset = (idx * data.Length);
|
||||
r.Length = data.Length;
|
||||
return r;
|
||||
}
|
||||
|
||||
public PsoBuilderPointer AddItemArray<T>(MetaName type, T[] items) where T : struct
|
||||
{
|
||||
byte[] data = MetaTypes.ConvertArrayToBytes(items);
|
||||
return AddItemArray(type, data, items.Length);
|
||||
}
|
||||
|
||||
public PsoBuilderPointer AddItemArray(MetaName type, byte[] data, int length)
|
||||
{
|
||||
PsoBuilderBlock block = EnsureBlock(type);
|
||||
int datalen = data.Length;
|
||||
int newlen = datalen;
|
||||
//int lenrem = newlen % 16;
|
||||
//if (lenrem != 0)
|
||||
//{
|
||||
// newlen += (16 - lenrem);
|
||||
//}
|
||||
byte[] newdata = new byte[newlen];
|
||||
Buffer.BlockCopy(data, 0, newdata, 0, datalen);
|
||||
int offs = block.TotalSize;
|
||||
int idx = block.AddItem(newdata);
|
||||
PsoBuilderPointer r = new PsoBuilderPointer();
|
||||
r.BlockID = block.Index + 1;
|
||||
r.Offset = offs; //(idx * data.Length);;
|
||||
r.Length = length;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public PsoPOINTER AddItemPtr<T>(MetaName type, T item) where T : struct //helper method for AddItem<T>
|
||||
{
|
||||
var ptr = AddItem(type, item);
|
||||
return new PsoPOINTER(ptr.BlockID, ptr.Offset, 0);
|
||||
}
|
||||
|
||||
public PsoPOINTER AddItemPtr(MetaName type, byte[] data)//helper method for AddItem<T>
|
||||
{
|
||||
var ptr = AddItem(type, data);
|
||||
return new PsoPOINTER(ptr.BlockID, ptr.Offset, 0);
|
||||
}
|
||||
|
||||
public Array_Structure AddItemArrayPtr<T>(MetaName type, T[] items) where T : struct //helper method for AddItemArray<T>
|
||||
{
|
||||
if ((items == null) || (items.Length == 0)) return new Array_Structure();
|
||||
var ptr = AddItemArray(type, items);
|
||||
return new Array_Structure(ptr.Pointer, ptr.Length);
|
||||
}
|
||||
|
||||
public Array_Structure AddItemArrayPtr(MetaName type, byte[][] data) //helper method for AddItemArray<T>
|
||||
{
|
||||
if ((data == null) || (data.Length == 0)) return new Array_Structure();
|
||||
|
||||
int len = 0;
|
||||
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
len += data[i].Length;
|
||||
}
|
||||
|
||||
var newdata = new byte[len];
|
||||
|
||||
int offset = 0;
|
||||
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
Buffer.BlockCopy(data[i], 0, newdata, offset, data[i].Length);
|
||||
offset += data[i].Length;
|
||||
}
|
||||
|
||||
var ptr = AddItemArray(type, newdata, data.Length);
|
||||
return new Array_Structure(ptr.Pointer, ptr.Length);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Array_StructurePointer AddPointerArray(PsoPOINTER[] arr)
|
||||
{
|
||||
if ((arr == null) || (arr.Length == 0)) return new Array_StructurePointer();
|
||||
var ptr = AddItemArray(MetaName.PsoPOINTER, arr);
|
||||
Array_StructurePointer sp = new Array_StructurePointer();
|
||||
sp.Count1 = (ushort)arr.Length;
|
||||
sp.Count2 = sp.Count1;
|
||||
sp.Pointer = ptr.Pointer;
|
||||
return sp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public PsoBuilderPointer AddString(string str)
|
||||
{
|
||||
PsoBuilderBlock block = EnsureBlock((MetaName)1); //PsoSTRING seems to be 1
|
||||
byte[] data = Encoding.ASCII.GetBytes(str + (char)0);
|
||||
int datalen = data.Length;
|
||||
int newlen = datalen;
|
||||
//int lenrem = newlen % 16;
|
||||
//if (lenrem != 0) //pad the data length up to multiple of 16.
|
||||
//{
|
||||
// newlen += (16 - lenrem);
|
||||
//}
|
||||
byte[] newdata = new byte[newlen];
|
||||
Buffer.BlockCopy(data, 0, newdata, 0, datalen);
|
||||
int offs = block.TotalSize;
|
||||
int idx = block.AddItem(newdata);
|
||||
PsoBuilderPointer r = new PsoBuilderPointer();
|
||||
r.BlockID = block.Index + 1;
|
||||
r.Offset = offs;// (idx * data.Length);
|
||||
r.Length = datalen; //actual length of string.
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
public Array_Vector3 AddPaddedVector3ArrayPtr(Vector4[] items)
|
||||
{
|
||||
if ((items == null) || (items.Length == 0)) return new Array_Vector3();
|
||||
var ptr = AddItemArray((MetaName)1, items); //MetaName.VECTOR4 padded to vec4...
|
||||
return new Array_Vector3(ptr.Pointer, items.Length);
|
||||
}
|
||||
public Array_Vector3 AddVector2ArrayPtr(Vector2[] items)
|
||||
{
|
||||
if ((items == null) || (items.Length == 0)) return new Array_Vector3();
|
||||
var ptr = AddItemArray((MetaName)1, items); //MetaName.VECTOR4 padded to vec4...?
|
||||
return new Array_Vector3(ptr.Pointer, items.Length);
|
||||
}
|
||||
public Array_uint AddHashArrayPtr(MetaHash[] items)
|
||||
{
|
||||
if ((items == null) || (items.Length == 0)) return new Array_uint();
|
||||
var ptr = AddItemArray((MetaName)6, items); //MetaName.HASH
|
||||
return new Array_uint(ptr.Pointer, items.Length);
|
||||
}
|
||||
public Array_uint AddUIntArrayPtr(uint[] items)
|
||||
{
|
||||
if ((items == null) || (items.Length == 0)) return new Array_uint();
|
||||
var ptr = AddItemArray((MetaName)6, items);
|
||||
return new Array_uint(ptr.Pointer, items.Length);
|
||||
}
|
||||
public Array_uint AddSIntArrayPtr(int[] items)
|
||||
{
|
||||
if ((items == null) || (items.Length == 0)) return new Array_uint();
|
||||
var ptr = AddItemArray((MetaName)5, items);
|
||||
return new Array_uint(ptr.Pointer, items.Length);
|
||||
}
|
||||
public Array_ushort AddUShortArrayPtr(ushort[] items)
|
||||
{
|
||||
if ((items == null) || (items.Length == 0)) return new Array_ushort();
|
||||
var ptr = AddItemArray((MetaName)4, items);
|
||||
return new Array_ushort(ptr.Pointer, items.Length);
|
||||
}
|
||||
public Array_byte AddByteArrayPtr(byte[] items)
|
||||
{
|
||||
if ((items == null) || (items.Length == 0)) return new Array_byte();
|
||||
var ptr = AddItemArray((MetaName)2, items);
|
||||
return new Array_byte(ptr.Pointer, items.Length);
|
||||
}
|
||||
public Array_float AddFloatArrayPtr(float[] items)
|
||||
{
|
||||
if ((items == null) || (items.Length == 0)) return new Array_float();
|
||||
var ptr = AddItemArray((MetaName)7, items); //MetaName.PsoFLOAT ? comes up as MetaName.POINTER due to RSC meta values
|
||||
return new Array_float(ptr.Pointer, items.Length);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void AddStringToSTRF(string str)
|
||||
{
|
||||
STRFStrings.Add(str);
|
||||
}
|
||||
public void AddStringToSTRS(string str)
|
||||
{
|
||||
STRSStrings.Add(str);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void AddStructureInfo(MetaName name)
|
||||
{
|
||||
if (!StructureInfos.ContainsKey(name))
|
||||
{
|
||||
PsoStructureInfo si = PsoTypes.GetStructureInfo(name);
|
||||
if (si != null)
|
||||
{
|
||||
StructureInfos[name] = si;
|
||||
}
|
||||
}
|
||||
}
|
||||
public void AddEnumInfo(MetaName name)
|
||||
{
|
||||
if (!EnumInfos.ContainsKey(name))
|
||||
{
|
||||
PsoEnumInfo ei = PsoTypes.GetEnumInfo(name);
|
||||
if (ei != null)
|
||||
{
|
||||
EnumInfos[name] = ei;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public PsoStructureInfo AddMapNodeStructureInfo(MetaName valType)
|
||||
{
|
||||
PsoStructureInfo inf = null;
|
||||
|
||||
if (valType == 0)
|
||||
{
|
||||
inf = PsoTypes.GetStructureInfo(MetaName.ARRAYINFO); //default ARRAYINFO with pointer
|
||||
if (!StructureInfos.ContainsKey(inf.IndexInfo.NameHash))
|
||||
{
|
||||
StructureInfos[inf.IndexInfo.NameHash] = inf;
|
||||
}
|
||||
return inf;
|
||||
}
|
||||
|
||||
var structInfo = PsoTypes.GetStructureInfo(valType);
|
||||
if (structInfo == null)
|
||||
{ }//error?
|
||||
|
||||
MetaName xName = MetaName.ARRAYINFO + 1; //257
|
||||
bool nameOk = !StructureInfos.ContainsKey(xName);
|
||||
while (!nameOk)
|
||||
{
|
||||
var exInfo = StructureInfos[xName];
|
||||
var exInfoItem = exInfo.FindEntry(MetaName.Item);
|
||||
if (((MetaName)(exInfoItem?.ReferenceKey ?? 0) == valType))
|
||||
{
|
||||
return exInfo; //this one already exists.. use it!
|
||||
}
|
||||
xName++;
|
||||
nameOk = !StructureInfos.ContainsKey(xName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
inf = new PsoStructureInfo(xName, 0, 2, 8 + structInfo.StructureLength,
|
||||
new PsoStructureEntryInfo(MetaName.Key, PsoDataType.String, 0, 7, 0),
|
||||
new PsoStructureEntryInfo(MetaName.Item, PsoDataType.Structure, 8, 0, valType)
|
||||
);
|
||||
|
||||
if (!StructureInfos.ContainsKey(xName))
|
||||
{
|
||||
StructureInfos[xName] = inf;
|
||||
}
|
||||
|
||||
return inf;
|
||||
|
||||
|
||||
//switch (valType)
|
||||
//{
|
||||
// case (MetaName)331140115: return PsoTypes.GetStructureInfo((MetaName)257);
|
||||
// case (MetaName)2046450505: return PsoTypes.GetStructureInfo((MetaName)258);
|
||||
// case (MetaName)3219912345: return PsoTypes.GetStructureInfo((MetaName)259);
|
||||
// case (MetaName)0: return PsoTypes.GetStructureInfo(MetaName.ARRAYINFO);
|
||||
// default:
|
||||
// return PsoTypes.GetStructureInfo(MetaName.ARRAYINFO);//error?
|
||||
//}
|
||||
//case (MetaName)257:
|
||||
// return new PsoStructureInfo((MetaName)257, 0, 2, 32,
|
||||
// new PsoStructureEntryInfo(MetaName.Key, PsoDataType.String, 0, 7, 0),
|
||||
// new PsoStructureEntryInfo(MetaName.Item, PsoDataType.Structure, 8, 0, (MetaName)331140115)
|
||||
// );
|
||||
//case (MetaName)258:
|
||||
// return new PsoStructureInfo((MetaName)258, 0, 2, 24,
|
||||
// new PsoStructureEntryInfo(MetaName.Key, PsoDataType.String, 0, 7, 0),
|
||||
// new PsoStructureEntryInfo(MetaName.Item, PsoDataType.Structure, 8, 0, (MetaName)2046450505)
|
||||
// );
|
||||
//case (MetaName)259:
|
||||
// return new PsoStructureInfo((MetaName)259, 0, 2, 32,
|
||||
// new PsoStructureEntryInfo(MetaName.Key, PsoDataType.String, 0, 7, 0),
|
||||
// new PsoStructureEntryInfo(MetaName.Item, PsoDataType.Structure, 8, 0, (MetaName)3219912345)
|
||||
// );
|
||||
//case (MetaName)3219912345:
|
||||
// return new PsoStructureInfo((MetaName)3219912345, 0, 0, 24,
|
||||
// new PsoStructureEntryInfo(MetaName.ARRAYINFO, PsoDataType.Structure, 0, 0, (MetaName)2356519750),
|
||||
// new PsoStructureEntryInfo((MetaName)4147768898, PsoDataType.Array, 8, 0, 0)
|
||||
// );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public byte[] GetData()
|
||||
{
|
||||
int totlen = 16;
|
||||
for (int i = 0; i < Blocks.Count; i++)
|
||||
{
|
||||
totlen += Blocks[i].TotalSize;
|
||||
}
|
||||
byte[] data = new byte[totlen];
|
||||
int offset = 16; //reserved space for headers
|
||||
for (int i = 0; i < Blocks.Count; i++)
|
||||
{
|
||||
var block = Blocks[i];
|
||||
for (int j = 0; j < block.Items.Count; j++)
|
||||
{
|
||||
var bdata = block.Items[j];
|
||||
Buffer.BlockCopy(bdata, 0, data, offset, bdata.Length);
|
||||
offset += bdata.Length;
|
||||
}
|
||||
}
|
||||
if (offset != data.Length)
|
||||
{ }
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public PsoFile GetPso()
|
||||
{
|
||||
PsoFile pso = new PsoFile();
|
||||
pso.SchemaSection = new PsoSchemaSection();
|
||||
|
||||
var schEntries = new List<PsoElementInfo>();
|
||||
foreach (var structInfo in StructureInfos.Values)
|
||||
{
|
||||
schEntries.Add(structInfo);
|
||||
}
|
||||
foreach (var enumInfo in EnumInfos.Values)
|
||||
{
|
||||
schEntries.Add(enumInfo);
|
||||
}
|
||||
pso.SchemaSection.Entries = schEntries.ToArray();
|
||||
pso.SchemaSection.EntriesIdx = new PsoElementIndexInfo[schEntries.Count];
|
||||
for (int i = 0; i < schEntries.Count; i++)
|
||||
{
|
||||
pso.SchemaSection.EntriesIdx[i] = new PsoElementIndexInfo();
|
||||
pso.SchemaSection.EntriesIdx[i].NameHash = schEntries[i].IndexInfo.NameHash;
|
||||
}
|
||||
|
||||
if (STRFStrings.Count > 0)
|
||||
{
|
||||
pso.STRFSection = new PsoSTRFSection();
|
||||
pso.STRFSection.Strings = STRFStrings.ToArray();
|
||||
}
|
||||
if (STRSStrings.Count > 0)
|
||||
{
|
||||
pso.STRSSection = new PsoSTRSSection();
|
||||
pso.STRSSection.Strings = STRSStrings.ToArray();
|
||||
}
|
||||
|
||||
|
||||
pso.DataSection = new PsoDataSection();
|
||||
pso.DataSection.Data = GetData();
|
||||
|
||||
pso.DataMapSection = new PsoDataMapSection();
|
||||
pso.DataMapSection.Entries = new PsoDataMappingEntry[Blocks.Count];
|
||||
pso.DataMapSection.RootId = RootPointer.BlockID;
|
||||
var offset = 16;
|
||||
for (int i = 0; i < Blocks.Count; i++)
|
||||
{
|
||||
var b = Blocks[i];
|
||||
var e = new PsoDataMappingEntry();
|
||||
e.NameHash = b.StructureNameHash;
|
||||
e.Length = b.TotalSize;
|
||||
e.Offset = offset;
|
||||
offset += b.TotalSize;
|
||||
pso.DataMapSection.Entries[i] = e;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return pso;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class PsoBuilderBlock
|
||||
{
|
||||
public MetaName StructureNameHash { get; set; }
|
||||
public List<byte[]> Items { get; set; } = new List<byte[]>();
|
||||
public int TotalSize { get; set; } = 0;
|
||||
public int Index { get; set; } = 0;
|
||||
|
||||
public int AddItem(byte[] item)
|
||||
{
|
||||
int idx = Items.Count;
|
||||
Items.Add(item);
|
||||
TotalSize += item.Length;
|
||||
return idx;
|
||||
}
|
||||
|
||||
public uint BasePointer
|
||||
{
|
||||
get
|
||||
{
|
||||
return (((uint)Index + 1) & 0xFFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//public MetaDataBlock GetMetaDataBlock()
|
||||
//{
|
||||
// if (TotalSize <= 0) return null;
|
||||
// byte[] data = new byte[TotalSize];
|
||||
// int offset = 0;
|
||||
// for (int j = 0; j < Items.Count; j++)
|
||||
// {
|
||||
// var bdata = Items[j];
|
||||
// Buffer.BlockCopy(bdata, 0, data, offset, bdata.Length);
|
||||
// offset += bdata.Length;
|
||||
// }
|
||||
// MetaDataBlock db = new MetaDataBlock();
|
||||
// db.StructureNameHash = StructureNameHash;
|
||||
// db.DataLength = TotalSize;
|
||||
// db.Data = data;
|
||||
// return db;
|
||||
//}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public struct PsoBuilderPointer
|
||||
{
|
||||
public int BlockID { get; set; } //1-based id
|
||||
public int Offset { get; set; } //byte offset
|
||||
public int Length { get; set; } //for temp use...
|
||||
public uint Pointer
|
||||
{
|
||||
get
|
||||
{
|
||||
uint bidx = (((uint)BlockID) & 0xFFF);
|
||||
uint offs = (((uint)Offset) & 0xFFFFF) << 12;
|
||||
return bidx + offs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -647,11 +647,11 @@ namespace CodeWalker.GameFiles
|
||||
new PsoStructureEntryInfo(MetaName.Probabilities, PsoDataType.Array, 8, 0, 0)
|
||||
);
|
||||
case (MetaName)2575850962:
|
||||
return new PsoStructureInfo((MetaName)2575850962, 0, 0, 40,
|
||||
return new PsoStructureInfo((MetaName)2575850962, 0, 0, 44 /*40*/,
|
||||
new PsoStructureEntryInfo(MetaName.ARRAYINFO, PsoDataType.UByte, 0, 0, 0),
|
||||
new PsoStructureEntryInfo(MetaName.indices, PsoDataType.Array, 8, 4, (MetaName)262144),
|
||||
new PsoStructureEntryInfo(MetaName.indices, PsoDataType.Array, 8, 4, (MetaName)393216 /*262144*/),
|
||||
new PsoStructureEntryInfo(MetaName.ARRAYINFO, PsoDataType.Bool, 0, 0, 0),
|
||||
new PsoStructureEntryInfo(MetaName.liveries, PsoDataType.Array, 12, 4, (MetaName)1638402)
|
||||
new PsoStructureEntryInfo(MetaName.liveries, PsoDataType.Array, 14 /*12*/, 4, (MetaName)1966082 /*1638402*/)
|
||||
);
|
||||
case (MetaName)938618322:
|
||||
return new PsoStructureInfo((MetaName)938618322, 0, 0, 16,
|
||||
@ -16104,10 +16104,13 @@ namespace CodeWalker.GameFiles
|
||||
var blocki = (int)ptr.PointerDataId;// (ptr.Pointer & 0xFFF) - 1;
|
||||
var offset = (int)ptr.PointerDataOffset;// (ptr.Pointer >> 12) & 0xFFFFF;
|
||||
|
||||
var block = pso.GetBlock(blocki);
|
||||
var block = pso.GetBlock(blocki); //nameHash = 1
|
||||
if (block == null)
|
||||
{ return null; }
|
||||
|
||||
//if (block.NameHash != (MetaName)1)
|
||||
//{ }
|
||||
|
||||
var length = ptr.Count1;
|
||||
var lastbyte = offset + length;
|
||||
if (lastbyte >= block.Length)
|
||||
@ -16133,10 +16136,13 @@ namespace CodeWalker.GameFiles
|
||||
var blocki = (int)ptr.PointerDataId;// (ptr.Pointer & 0xFFF) - 1;
|
||||
var offset = (int)ptr.PointerDataOffset;// (ptr.Pointer >> 12) & 0xFFFFF;
|
||||
|
||||
var block = pso.GetBlock(blocki);
|
||||
var block = pso.GetBlock(blocki); //nameHash = 1
|
||||
if (block == null)
|
||||
{ return null; }
|
||||
|
||||
//if (block.NameHash != (MetaName)1)
|
||||
//{ }
|
||||
|
||||
//var length = ptr.Count1;
|
||||
//var lastbyte = offset + length;
|
||||
//if (lastbyte >= block.Length)
|
||||
@ -16217,6 +16223,13 @@ namespace CodeWalker.GameFiles
|
||||
public uint ItemOffset { get { return ((Pointer>>12) & 0xFFFFF); } } //byte offset
|
||||
|
||||
|
||||
public PsoPOINTER(int blockID, int itemOffset, uint extra)
|
||||
{
|
||||
Pointer = (((uint)itemOffset << 12) & 0xFFFFF000) + ((uint)blockID & 0xFFF);
|
||||
Unk2 = extra;
|
||||
}
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return BlockID.ToString() + ", " + ItemOffset.ToString() + ", " + Unk2.ToString();
|
||||
|
1222
CodeWalker.Core/GameFiles/MetaTypes/XmlPso.cs
Normal file
1222
CodeWalker.Core/GameFiles/MetaTypes/XmlPso.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -2251,6 +2251,8 @@ namespace CodeWalker
|
||||
var fi = new FileInfo(fpath);
|
||||
var fname = fi.Name;
|
||||
var fnamel = fname.ToLowerInvariant();
|
||||
var mformat = MetaFormat.RSC;
|
||||
var trimlength = 4;
|
||||
|
||||
if (!fnamel.EndsWith(".xml"))
|
||||
{
|
||||
@ -2259,8 +2261,8 @@ namespace CodeWalker
|
||||
}
|
||||
if (fnamel.EndsWith(".pso.xml"))
|
||||
{
|
||||
MessageBox.Show(fname + ": PSO XML import not yet supported.", "Cannot import XML");
|
||||
continue;
|
||||
mformat = MetaFormat.PSO;
|
||||
trimlength = 8;
|
||||
}
|
||||
if (fnamel.EndsWith(".rbf.xml"))
|
||||
{
|
||||
@ -2268,8 +2270,8 @@ namespace CodeWalker
|
||||
continue;
|
||||
}
|
||||
|
||||
fname = fname.Substring(0, fname.Length - 4);
|
||||
fnamel = fnamel.Substring(0, fnamel.Length - 4);
|
||||
fname = fname.Substring(0, fname.Length - trimlength);
|
||||
fnamel = fnamel.Substring(0, fnamel.Length - trimlength);
|
||||
|
||||
var doc = new XmlDocument();
|
||||
string text = File.ReadAllText(fpath);
|
||||
@ -2278,21 +2280,46 @@ namespace CodeWalker
|
||||
doc.LoadXml(text);
|
||||
}
|
||||
|
||||
var meta = XmlMeta.GetMeta(doc);
|
||||
byte[] data = null;
|
||||
|
||||
|
||||
if ((meta.DataBlocks?.Data == null) || (meta.DataBlocks.Count == 0))
|
||||
switch (mformat)
|
||||
{
|
||||
MessageBox.Show(fname + ": Schema not supported.", "Cannot import XML");
|
||||
continue;
|
||||
case MetaFormat.RSC:
|
||||
{
|
||||
var meta = XmlMeta.GetMeta(doc);
|
||||
if ((meta.DataBlocks?.Data == null) || (meta.DataBlocks.Count == 0))
|
||||
{
|
||||
MessageBox.Show(fname + ": Schema not supported.", "Cannot import Meta XML");
|
||||
continue;
|
||||
}
|
||||
data = ResourceBuilder.Build(meta, 2); //meta is RSC V:2
|
||||
break;
|
||||
}
|
||||
case MetaFormat.PSO:
|
||||
{
|
||||
var pso = XmlPso.GetPso(doc);
|
||||
if ((pso.DataSection == null) || (pso.DataMapSection == null) || (pso.SchemaSection == null))
|
||||
{
|
||||
MessageBox.Show(fname + ": Schema not supported.", "Cannot import PSO XML");
|
||||
continue;
|
||||
}
|
||||
data = pso.Save();
|
||||
break;
|
||||
}
|
||||
case MetaFormat.RBF:
|
||||
{
|
||||
//todo!
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
byte[] data = ResourceBuilder.Build(meta, 2); //meta is RSC V:2
|
||||
if (data != null)
|
||||
{
|
||||
RpfFile.CreateFile(parentrpffldr, fname, data);
|
||||
}
|
||||
|
||||
|
||||
RpfFile.CreateFile(parentrpffldr, fname, data);
|
||||
|
||||
}
|
||||
#if !DEBUG
|
||||
catch (Exception ex)
|
||||
|
@ -350,8 +350,14 @@ namespace CodeWalker.Forms
|
||||
data = ResourceBuilder.Build(meta, 2); //meta is RSC "Version":2 (it's actually a type identifier, not a version!)
|
||||
break;
|
||||
case MetaFormat.PSO:
|
||||
MessageBox.Show("Sorry, PSO import is not supported yet.", "Cannot import PSO XML");
|
||||
return false;
|
||||
var pso = XmlPso.GetPso(doc);
|
||||
if ((pso.DataSection == null) || (pso.DataMapSection == null) || (pso.SchemaSection == null))
|
||||
{
|
||||
MessageBox.Show("Schema not supported.", "Cannot import PSO XML");
|
||||
return false;
|
||||
}
|
||||
data = pso.Save();
|
||||
break;
|
||||
case MetaFormat.RBF:
|
||||
MessageBox.Show("Sorry, RBF import is not supported.", "Cannot import RBF XML");
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user