XML to PSO conversion (experimental)

This commit is contained in:
dexy 2018-12-20 04:28:43 +11:00
parent 34a29a5faa
commit 7c31cfb6ee
11 changed files with 2097 additions and 149 deletions

View File

@ -84,9 +84,11 @@
<Compile Include="GameFiles\MetaTypes\MetaTypes.cs" /> <Compile Include="GameFiles\MetaTypes\MetaTypes.cs" />
<Compile Include="GameFiles\MetaTypes\MetaXml.cs" /> <Compile Include="GameFiles\MetaTypes\MetaXml.cs" />
<Compile Include="GameFiles\MetaTypes\Pso.cs" /> <Compile Include="GameFiles\MetaTypes\Pso.cs" />
<Compile Include="GameFiles\MetaTypes\PsoBuilder.cs" />
<Compile Include="GameFiles\MetaTypes\PsoTypes.cs" /> <Compile Include="GameFiles\MetaTypes\PsoTypes.cs" />
<Compile Include="GameFiles\MetaTypes\Rbf.cs" /> <Compile Include="GameFiles\MetaTypes\Rbf.cs" />
<Compile Include="GameFiles\MetaTypes\XmlMeta.cs" /> <Compile Include="GameFiles\MetaTypes\XmlMeta.cs" />
<Compile Include="GameFiles\MetaTypes\XmlPso.cs" />
<Compile Include="GameFiles\Resources\Bounds.cs" /> <Compile Include="GameFiles\Resources\Bounds.cs" />
<Compile Include="GameFiles\Resources\Clip.cs" /> <Compile Include="GameFiles\Resources\Clip.cs" />
<Compile Include="GameFiles\Resources\Drawable.cs" /> <Compile Include="GameFiles\Resources\Drawable.cs" />

View File

@ -2212,16 +2212,27 @@ namespace CodeWalker.GameFiles
var exceptions = new List<Exception>(); var exceptions = new List<Exception>();
var allpsos = new List<string>(); var allpsos = new List<string>();
var diffpsos = new List<string>();
foreach (RpfFile file in AllRpfs) foreach (RpfFile file in AllRpfs)
{ {
foreach (RpfEntry entry in file.AllEntries) foreach (RpfEntry entry in file.AllEntries)
{ {
#if !DEBUG
try try
#endif
{ {
var n = entry.NameLower; 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 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) if (data != null)
{ {
using (MemoryStream ms = new MemoryStream(data)) using (MemoryStream ms = new MemoryStream(data))
@ -2236,19 +2247,43 @@ namespace CodeWalker.GameFiles
allpsos.Add(fentry.Path); allpsos.Add(fentry.Path);
PsoTypes.EnsurePsoTypes(pso); 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) catch (Exception ex)
{ {
UpdateStatus("Error! " + ex.ToString()); UpdateStatus("Error! " + ex.ToString());
exceptions.Add(ex); exceptions.Add(ex);
} }
#endif
} }
} }
string allpsopaths = string.Join("\r\n", allpsos); string allpsopaths = string.Join("\r\n", allpsos);
string diffpsopaths = string.Join("\r\n", diffpsos);
string str = PsoTypes.GetTypesInitString(); string str = PsoTypes.GetTypesInitString();
if (!string.IsNullOrEmpty(str)) if (!string.IsNullOrEmpty(str))

View File

@ -621,9 +621,9 @@ namespace CodeWalker.GameFiles
public ushort Count2 { get; set; } public ushort Count2 { get; set; }
public uint Unk1 { get; set; } public uint Unk1 { get; set; }
public uint PointerDataId { get { return (Pointer & 0xFFF); } } public uint PointerDataId { get { return (Pointer & 0xFFF); } set { Pointer = (Pointer & 0xFFFFF000) + (value & 0xFFF); } }
public uint PointerDataIndex { get { return (Pointer & 0xFFF) - 1; } } public uint PointerDataIndex { get { return (Pointer & 0xFFF) - 1; } set { PointerDataId = value + 1; } }
public uint PointerDataOffset { get { return ((Pointer >> 12) & 0xFFFFF); } } public uint PointerDataOffset { get { return ((Pointer >> 12) & 0xFFFFF); } set { Pointer = (Pointer & 0xFFF) + ((value << 12) & 0xFFFFF000); } }

View File

@ -2007,6 +2007,10 @@ namespace CodeWalker.GameFiles
{ {
return (ushort)(((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8)); 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) public static uint SwapBytes(uint x)
{ {
// swap adjacent 16-bit blocks // swap adjacent 16-bit blocks

View File

@ -5,6 +5,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml;
namespace CodeWalker.GameFiles namespace CodeWalker.GameFiles
{ {
@ -640,6 +641,10 @@ namespace CodeWalker.GameFiles
var structInfo = cont.GetStructureInfo(structName); var structInfo = cont.GetStructureInfo(structName);
if (structInfo == null) if (structInfo == null)
{
structInfo = PsoTypes.GetStructureInfo(structName);//fallback to builtin...
}
if (structInfo == null)
{ {
ErrorXml(sb, indent, "Couldn't find structure info " + name + "!"); ErrorXml(sb, indent, "Couldn't find structure info " + name + "!");
return; return;
@ -708,7 +713,10 @@ namespace CodeWalker.GameFiles
case 0: //int enum case 0: //int enum
var intEVal = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset)); var intEVal = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset));
var intE = enumInfo.FindEntry(intEVal); 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; break;
case 2: //byte enum case 2: //byte enum
var byteEVal = data[eoffset]; var byteEVal = data[eoffset];
@ -718,9 +726,9 @@ namespace CodeWalker.GameFiles
} }
break; break;
case PsoDataType.Flags: case PsoDataType.Flags:
uint fCount = (entry.ReferenceKey >> 16) & 0x0000FFFF; //uint fCount = (entry.ReferenceKey >> 16) & 0x0000FFFF;
uint fEntry = (entry.ReferenceKey & 0xFFFF); uint fEntry = (entry.ReferenceKey & 0xFFF);
var fEnt = structInfo.GetEntry((int)fEntry); var fEnt = (fEntry != 0xFFF) ? structInfo.GetEntry((int)fEntry) : null;
PsoEnumInfo flagsInfo = null; PsoEnumInfo flagsInfo = null;
if ((fEnt != null) && (fEnt.EntryNameHash == MetaName.ARRAYINFO)) if ((fEnt != null) && (fEnt.EntryNameHash == MetaName.ARRAYINFO))
{ {
@ -728,7 +736,9 @@ namespace CodeWalker.GameFiles
} }
if (flagsInfo == null) if (flagsInfo == null)
{ {
flagsInfo = cont.GetEnumInfo(entry.EntryNameHash); if (fEntry != 0xFFF)
{ }
//flagsInfo = cont.GetEnumInfo(entry.EntryNameHash);
} }
uint? flagsVal = null; uint? flagsVal = null;
switch (entry.Unk_5h) switch (entry.Unk_5h)
@ -805,13 +815,14 @@ namespace CodeWalker.GameFiles
default: default:
ErrorXml(sb, cind, ename + ": Unexpected Integer subtype: " + entry.Unk_5h.ToString()); ErrorXml(sb, cind, ename + ": Unexpected Integer subtype: " + entry.Unk_5h.ToString());
break; break;
case 0: //signed int case 0: //signed int (? flags?)
var int6aVal = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset)); var int6aVal = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset));
ValueTag(sb, cind, ename, int6aVal.ToString()); ValueTag(sb, cind, ename, int6aVal.ToString());
break; break;
case 1: //unsigned int case 1: //unsigned int
var int6bVal = MetaTypes.SwapBytes(BitConverter.ToUInt32(data, eoffset)); 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;
} }
break; break;
@ -833,16 +844,16 @@ namespace CodeWalker.GameFiles
ValueTag(sb, cind, ename, short4Val.ToString()); ValueTag(sb, cind, ename, short4Val.ToString());
break; break;
case PsoDataType.HFloat://half float? 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()); ValueTag(sb, cind, ename, short1EVal.ToString());
break; break;
case PsoDataType.String: case PsoDataType.String:
var str0 = GetStringValue(cont.Pso, entry, data, eoffset); var str0 = XmlEscape(GetStringValue(cont.Pso, entry, data, eoffset));
if (str0 == null) //if (str0 == null)
{ //{
ErrorXml(sb, cind, ename + ": Unexpected String subtype: " + entry.Unk_5h.ToString()); // ErrorXml(sb, cind, ename + ": Unexpected String subtype: " + entry.Unk_5h.ToString());
} //}
else //else
{ {
StringTag(sb, cind, ename, str0); StringTag(sb, cind, ename, str0);
} }
@ -909,8 +920,13 @@ namespace CodeWalker.GameFiles
var boffset = offset + block.Offset; var boffset = offset + block.Offset;
var eoffset = boffset + entry.DataOffset; var eoffset = boffset + entry.DataOffset;
var aOffset = offset + entry.DataOffset; var aOffset = offset + entry.DataOffset;
var abOffset = aOffset + block.Offset;
var aBlockId = blockId; var aBlockId = blockId;
uint aCount = (entry.ReferenceKey >> 16) & 0x0000FFFF; 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; var aind = indent + 1;
string arrTag = ename; string arrTag = ename;
PsoStructureEntryInfo arrEntry = estruct.GetEntry((int)(entry.ReferenceKey & 0xFFFF)); PsoStructureEntryInfo arrEntry = estruct.GetEntry((int)(entry.ReferenceKey & 0xFFFF));
@ -922,17 +938,24 @@ namespace CodeWalker.GameFiles
var data = cont.Pso.DataSection.Data; var data = cont.Pso.DataSection.Data;
bool embedded = true;
switch (entry.Unk_5h) switch (entry.Unk_5h)
{ {
default: default:
ErrorXml(sb, indent, ename + ": WIP! Unsupported Array subtype: " + entry.Unk_5h.ToString()); ErrorXml(sb, indent, ename + ": WIP! Unsupported Array subtype: " + entry.Unk_5h.ToString());
break; break;
case 0: //Array_Structure case 0: //Array_Structure
var arrStruc = MetaTypes.ConvertData<Array_Structure>(data, eoffset); arrStruc = MetaTypes.ConvertData<Array_Structure>(data, eoffset);
arrStruc.SwapEnd(); arrStruc.SwapEnd();
aBlockId = (int)arrStruc.PointerDataId; aBlockId = (int)arrStruc.PointerDataId;
aOffset = (int)arrStruc.PointerDataOffset; aOffset = (int)arrStruc.PointerDataOffset;
aCount = arrStruc.Count1; aCount = arrStruc.Count1;
var aBlock = cont.Pso.GetBlock(aBlockId);
if (aBlock != null)
{
abOffset = aOffset + aBlock.Offset;
}
embedded = false;
break; break;
case 1: //Raw in-line array case 1: //Raw in-line array
break; break;
@ -941,11 +964,20 @@ namespace CodeWalker.GameFiles
case 4: //pointer array? default array? case 4: //pointer array? default array?
if (arrEntry.Unk_5h == 3) //pointers... if (arrEntry.Unk_5h == 3) //pointers...
{ {
var arrStruc4 = MetaTypes.ConvertData<Array_Structure>(data, eoffset); arrStruc = MetaTypes.ConvertData<Array_Structure>(data, eoffset);
arrStruc4.SwapEnd(); arrStruc.SwapEnd();
aBlockId = (int)arrStruc4.PointerDataId; aBlockId = (int)arrStruc.PointerDataId;
aOffset = (int)arrStruc4.PointerDataOffset; aOffset = (int)arrStruc.PointerDataOffset;
aCount = arrStruc4.Count1; aCount = arrStruc.Count1;
var aBlock2 = cont.Pso.GetBlock(aBlockId);
if (aBlock2 != null)
{
abOffset = aOffset + aBlock2.Offset;
}
embedded = false;
}
else
{
} }
break; break;
case 129: //also raw inline array? in junctions.pso case 129: //also raw inline array? in junctions.pso
@ -959,10 +991,11 @@ namespace CodeWalker.GameFiles
break; break;
case PsoDataType.Array: case PsoDataType.Array:
var rk0 = (entry.ReferenceKey >> 16) & 0x0000FFFF; 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) 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; aOffset = offset + entry.DataOffset;
OpenTag(sb, indent, arrTag); OpenTag(sb, indent, arrTag);
@ -997,7 +1030,14 @@ namespace CodeWalker.GameFiles
for (int n = 0; n < aCount; n++) for (int n = 0; n < aCount; n++)
{ {
var ptrVal = ptrArr[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); CloseTag(sb, indent, ename);
} }
@ -1050,6 +1090,8 @@ namespace CodeWalker.GameFiles
ErrorXml(sb, indent, ename + ": Unexpected String array subtype: " + entry.Unk_5h.ToString()); ErrorXml(sb, indent, ename + ": Unexpected String array subtype: " + entry.Unk_5h.ToString());
break; break;
case 0: //hash array... case 0: //hash array...
if (embedded)
{ }
var arrHash = MetaTypes.ConvertData<Array_uint>(data, eoffset); var arrHash = MetaTypes.ConvertData<Array_uint>(data, eoffset);
arrHash.SwapEnd(); arrHash.SwapEnd();
var hashArr = PsoTypes.GetHashArray(cont.Pso, arrHash); var hashArr = PsoTypes.GetHashArray(cont.Pso, arrHash);
@ -1064,54 +1106,70 @@ namespace CodeWalker.GameFiles
WriteRawArray(sb, v2Arr, indent, ename, "Vector2", FormatVector2Swap, 1); WriteRawArray(sb, v2Arr, indent, ename, "Vector2", FormatVector2Swap, 1);
break; break;
case PsoDataType.Float3: 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 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); var v4Arr = MetaTypes.ConvertDataArray<Vector4>(data, eoffset, (int)aCount);
WriteRawArray(sb, v4Arr, indent, ename, "Vector3", FormatVector4SwapXYZOnly, 1); WriteRawArray(sb, v4Arr, indent, ename, "Vector3", FormatVector4SwapXYZOnly, 1);
break; break;
case PsoDataType.UByte: case PsoDataType.UByte:
if (embedded)
{ }
else
{ } //block type 2
var barr = new byte[aCount]; var barr = new byte[aCount];
if (aCount > 0) if (aCount > 0)
{ {
var bblock = cont.Pso.GetBlock(aBlockId); //var bblock = cont.Pso.GetBlock(aBlockId);
var boffs = bblock.Offset + aOffset; //var boffs = bblock.Offset + aOffset;
Buffer.BlockCopy(data, boffs, barr, 0, (int)aCount); Buffer.BlockCopy(data, abOffset /*boffs*/, barr, 0, (int)aCount);
} }
WriteRawArray(sb, barr, indent, ename, "byte"); WriteRawArray(sb, barr, indent, ename, "byte");
break; break;
case PsoDataType.Bool: case PsoDataType.Bool:
if (embedded)
{ }
else
{ }
var barr2 = new byte[aCount]; var barr2 = new byte[aCount];
if (aCount > 0) if (aCount > 0)
{ {
var bblock = cont.Pso.GetBlock(aBlockId); //var bblock = cont.Pso.GetBlock(aBlockId);
var boffs = bblock.Offset + aOffset; //var boffs = bblock.Offset + aOffset;
Buffer.BlockCopy(data, boffs, barr2, 0, (int)aCount); Buffer.BlockCopy(data, abOffset /*boffs*/, barr2, 0, (int)aCount);
} }
WriteRawArray(sb, barr2, indent, ename, "boolean"); //todo: true/false output WriteRawArray(sb, barr2, indent, ename, "boolean"); //todo: true/false output
break; break;
case PsoDataType.Float: case PsoDataType.Float:
var arrFloat = MetaTypes.ConvertData<Array_float>(data, eoffset); if (embedded)
arrFloat.SwapEnd(); { }
var arrFloat = new Array_float(arrStruc.Pointer, arrStruc.Count1); //block type 7
var floatArr = PsoTypes.GetFloatArray(cont.Pso, arrFloat); var floatArr = PsoTypes.GetFloatArray(cont.Pso, arrFloat);
WriteRawArray(sb, floatArr, indent, ename, "float"); WriteRawArray(sb, floatArr, indent, ename, "float");
break; break;
case PsoDataType.UShort: case PsoDataType.UShort:
var arrShort = MetaTypes.ConvertData<Array_Structure>(data, eoffset); if (embedded)
arrShort.SwapEnd(); { }
var shortArr = PsoTypes.GetUShortArray(cont.Pso, arrShort); var shortArr = PsoTypes.GetUShortArray(cont.Pso, arrStruc); //block type 4
WriteRawArray(sb, shortArr, indent, ename, "ushort"); WriteRawArray(sb, shortArr, indent, ename, "ushort");
break; break;
case PsoDataType.UInt: 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"); WriteRawArray(sb, intArr, indent, ename, "int");
break; break;
case PsoDataType.SInt: case PsoDataType.SInt:
var arrUint2 = MetaTypes.ConvertData<Array_uint>(data, eoffset); if (embedded)
arrUint2.SwapEnd(); { }
var arrUint2 = new Array_uint(arrStruc.Pointer, arrStruc.Count1); //block type 5
var intArr2 = PsoTypes.GetUintArray(cont.Pso, arrUint2); var intArr2 = PsoTypes.GetUintArray(cont.Pso, arrUint2);
WriteRawArray(sb, intArr2, indent, ename, "int"); WriteRawArray(sb, intArr2, indent, ename, "int");
break; break;
case PsoDataType.Enum: case PsoDataType.Enum:
if (embedded)
{ }
var arrEnum = MetaTypes.ConvertData<Array_uint>(data, eoffset); var arrEnum = MetaTypes.ConvertData<Array_uint>(data, eoffset);
arrEnum.SwapEnd(); arrEnum.SwapEnd();
var enumArr = PsoTypes.GetUintArray(cont.Pso, arrEnum); var enumArr = PsoTypes.GetUintArray(cont.Pso, arrEnum);
@ -1139,41 +1197,23 @@ namespace CodeWalker.GameFiles
var mapidx2 = (entry.ReferenceKey >> 16) & 0x0000FFFF; var mapidx2 = (entry.ReferenceKey >> 16) & 0x0000FFFF;
var mapreftype1 = structInfo.Entries[mapidx2]; var mapreftype1 = structInfo.Entries[mapidx2];
var mapreftype2 = structInfo.Entries[mapidx1]; var mapreftype2 = structInfo.Entries[mapidx1];
var x1 = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset));//same as ref key? var x1 = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset));
var x2 = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset + 4));//0? var x2 = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset + 4));
var x3 = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset + 8));//pointer? var sptr = MetaTypes.ConvertData<Array_Structure>(data, eoffset + 8);
var x4 = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset + 12));// sptr.SwapEnd();
var x5 = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset + 16));//count/capacity?
var x6 = MetaTypes.SwapBytes(BitConverter.ToInt32(data, eoffset + 20));//
//File.WriteAllText("C:\\CodeWalker.Projects\\testxml.xml", sb.ToString());
if (x1 != 0x1000000) if (x1 != 0x1000000)
{ } { }
if (x2 != 0) if (x2 != 0)
{ } { }
if (x4 != 0) if (mapreftype2.ReferenceKey != 0)
{ }
if (x6 != 0)
{ } { }
var xBlockId = (int)sptr.PointerDataId;// x3 & 0xFFF;
var xBlockId = x3 & 0xFFF; var xOffset = sptr.PointerDataOffset;// (x3 >> 12) & 0xFFFFF;
var xOffset = (x3 >> 12) & 0xFFFFF; var xCount1 = sptr.Count1;// x5 & 0xFFFF;
var xCount1 = x5 & 0xFFFF; var xCount2 = sptr.Count2;// (x5 >> 16) & 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 xBlock = cont.Pso.GetBlock(xBlockId); var xBlock = cont.Pso.GetBlock(xBlockId);
if ((xBlock == null) && (xCount1 > 0)) if ((xBlock == null) && (xCount1 > 0))
@ -1183,8 +1223,7 @@ namespace CodeWalker.GameFiles
else else
{ {
if (xCount1 != xCount2) if (xCount1 != xCount2)
{ { }
}
if (xCount1 > 0) if (xCount1 > 0)
{ {
var xStruct = cont.GetStructureInfo(xBlock.NameHash); var xStruct = cont.GetStructureInfo(xBlock.NameHash);
@ -1218,10 +1257,10 @@ namespace CodeWalker.GameFiles
{ {
ErrorXml(sb, aind, ename + ": Map Item was not a structure!"); ErrorXml(sb, aind, ename + ": Map Item was not a structure!");
} }
else if (iEntry.Unk_5h != 3) //else if (iEntry.Unk_5h != 3)
{ //{
ErrorXml(sb, aind, ename + ": Map Item was not a structure pointer - TODO!"); // ErrorXml(sb, aind, ename + ": Map Item was not a structure pointer - TODO!");
} //}
else else
{ {
OpenTag(sb, xind, ename); OpenTag(sb, xind, ename);
@ -1236,30 +1275,39 @@ namespace CodeWalker.GameFiles
var kOffset = sOffset + kEntry.DataOffset; var kOffset = sOffset + kEntry.DataOffset;
var iOffset = sOffset + iEntry.DataOffset; var iOffset = sOffset + iEntry.DataOffset;
var kStr = GetStringValue(cont.Pso, kEntry, data, kOffset); var kStr = GetStringValue(cont.Pso, kEntry, data, kOffset);
var iPtr = MetaTypes.ConvertData<PsoPOINTER>(data, iOffset); if (iEntry.ReferenceKey != 0)//(xBlock.NameHash != MetaName.ARRAYINFO)//257,258,259
iPtr.SwapEnd();
var iBlock = cont.Pso.GetBlock(iPtr.BlockID);
if (iBlock == null)
{ {
OpenTag(sb, aind, "Item type=\"" + HashString((MetaName)entry.ReferenceKey) + "\" key=\"" + kStr + "\""); //embedded map values
WriteNode(sb, aind, cont, iPtr.BlockID, (int)iPtr.ItemOffset, XmlTagMode.None, (MetaName)entry.ReferenceKey); 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"); CloseTag(sb, aind, "Item");
} }
else else
{ {
var iStr = "Item type=\"" + HashString(iBlock.NameHash) + "\" key=\"" + kStr + "\""; var iPtr = MetaTypes.ConvertData<PsoPOINTER>(data, iOffset);
var iStruc = cont.GetStructureInfo(iBlock.NameHash); iPtr.SwapEnd();
if (iStruc?.EntriesCount == 0) var iBlock = cont.Pso.GetBlock(iPtr.BlockID);
if (iBlock == null)
{ {
//SelfClosingTag(sb, aind, iStr); ErrorXml(sb, aind, ename + ": Could not find iBlock for Map entry!");
OpenTag(sb, aind, iStr);
CloseTag(sb, aind, "Item");
} }
else else
{ {
OpenTag(sb, aind, iStr); var iStr = "Item type=\"" + HashString(iBlock.NameHash) + "\" key=\"" + kStr + "\"";
WriteNode(sb, aind, cont, iPtr.BlockID, (int)iPtr.ItemOffset, XmlTagMode.None);//, (MetaName)entry.ReferenceKey); var iStruc = cont.GetStructureInfo(iBlock.NameHash);
CloseTag(sb, aind, "Item"); 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; 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 public class PsoCont

View File

@ -205,6 +205,13 @@ namespace CodeWalker.GameFiles
public PsoSTRESection STRESection { get; set; } public PsoSTRESection STRESection { get; set; }
public PsoCHKSSection CHKSSection { 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) public void Load(string fileName)
{ {
using (var stream = new FileStream(fileName, FileMode.Open)) 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) public void Save(string fileName)
{ {
using (var stream = new FileStream(fileName, FileMode.Create)) using (var stream = new FileStream(fileName, FileMode.Create))
@ -280,6 +300,11 @@ namespace CodeWalker.GameFiles
if (DataSection != null) DataSection.Write(writer); if (DataSection != null) DataSection.Write(writer);
if (DataMapSection != null) DataMapSection.Write(writer); if (DataMapSection != null) DataMapSection.Write(writer);
if (SchemaSection != null) SchemaSection.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) public void Write(DataWriter writer)
{ {
Length = Data.Length;
writer.Write(Data); writer.Write(Data);
writer.Position -= Data.Length; writer.Position -= Length;
writer.Write((uint)0x5053494E); writer.Write(Ident);
writer.Write((uint)(Data.Length)); writer.Write((uint)(Length));
writer.Position += Data.Length - 8; writer.Position += Length - 8;
} }
public override string ToString() public override string ToString()
@ -413,10 +440,10 @@ namespace CodeWalker.GameFiles
public void Read(DataReader reader) public void Read(DataReader reader)
{ {
this.NameHash = (MetaName)reader.ReadUInt32(); NameHash = (MetaName)reader.ReadUInt32();
this.Offset = reader.ReadInt32(); Offset = reader.ReadInt32();
this.Unknown_8h = reader.ReadInt32(); Unknown_8h = reader.ReadInt32();
this.Length = reader.ReadInt32(); Length = reader.ReadInt32();
} }
public void Write(DataWriter writer) public void Write(DataWriter writer)
@ -449,7 +476,7 @@ namespace CodeWalker.GameFiles
Length = reader.ReadInt32(); Length = reader.ReadInt32();
Count = reader.ReadUInt32(); Count = reader.ReadUInt32();
this.EntriesIdx = new PsoElementIndexInfo[Count]; EntriesIdx = new PsoElementIndexInfo[Count];
for (int i = 0; i < Count; i++) for (int i = 0; i < Count; i++)
{ {
var entry = new PsoElementIndexInfo(); var entry = new PsoElementIndexInfo();
@ -457,7 +484,7 @@ namespace CodeWalker.GameFiles
EntriesIdx[i] = entry; EntriesIdx[i] = entry;
} }
this.Entries = new PsoElementInfo[Count]; Entries = new PsoElementInfo[Count];
for (int i = 0; i < Count; i++) for (int i = 0; i < Count; i++)
{ {
reader.Position = EntriesIdx[i].Offset; reader.Position = EntriesIdx[i].Offset;
@ -506,7 +533,7 @@ namespace CodeWalker.GameFiles
writer.Write(Ident); writer.Write(Ident);
writer.Write((int)(12 + entriesStream.Length + indexStream.Length)); writer.Write((int)(12 + entriesStream.Length + indexStream.Length));
writer.Write((int)(Entries.Length)); writer.Write((uint)(Entries.Length));
// write entries index data // write entries index data
var buf1 = new byte[indexStream.Length]; var buf1 = new byte[indexStream.Length];
@ -536,8 +563,8 @@ namespace CodeWalker.GameFiles
public void Read(DataReader reader) public void Read(DataReader reader)
{ {
this.NameHash = (MetaName)reader.ReadUInt32(); NameHash = (MetaName)reader.ReadUInt32();
this.Offset = reader.ReadInt32(); Offset = reader.ReadInt32();
} }
public void Write(DataWriter writer) public void Write(DataWriter writer)
@ -590,11 +617,11 @@ namespace CodeWalker.GameFiles
public override void Read(DataReader reader) public override void Read(DataReader reader)
{ {
uint x = reader.ReadUInt32(); uint x = reader.ReadUInt32();
this.Type = (byte)((x & 0xFF000000) >> 24); Type = (byte)((x & 0xFF000000) >> 24);
this.EntriesCount = (short)(x & 0xFFFF); EntriesCount = (short)(x & 0xFFFF);
this.Unk = (byte)((x & 0x00FF0000) >> 16); Unk = (byte)((x & 0x00FF0000) >> 16);
this.StructureLength = reader.ReadInt32(); StructureLength = reader.ReadInt32();
this.Unk_Ch = reader.ReadUInt32(); Unk_Ch = reader.ReadUInt32();
if (Unk_Ch != 0) if (Unk_Ch != 0)
{ } { }
@ -655,7 +682,7 @@ namespace CodeWalker.GameFiles
{ {
public MetaName EntryNameHash { get; set; } public MetaName EntryNameHash { get; set; }
public PsoDataType Type { 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 ushort DataOffset { get; set; }
public uint ReferenceKey { get; set; } // when array -> entry index with type public uint ReferenceKey { get; set; } // when array -> entry index with type
@ -673,11 +700,11 @@ namespace CodeWalker.GameFiles
public void Read(DataReader reader) public void Read(DataReader reader)
{ {
this.EntryNameHash = (MetaName)reader.ReadUInt32(); EntryNameHash = (MetaName)reader.ReadUInt32();
this.Type = (PsoDataType)reader.ReadByte(); Type = (PsoDataType)reader.ReadByte();
this.Unk_5h = reader.ReadByte(); Unk_5h = reader.ReadByte();
this.DataOffset = reader.ReadUInt16(); DataOffset = reader.ReadUInt16();
this.ReferenceKey = reader.ReadUInt32(); ReferenceKey = reader.ReadUInt32();
} }
public void Write(DataWriter writer) public void Write(DataWriter writer)
@ -721,8 +748,8 @@ namespace CodeWalker.GameFiles
public override void Read(DataReader reader) public override void Read(DataReader reader)
{ {
uint x = reader.ReadUInt32(); uint x = reader.ReadUInt32();
this.Type = (byte)((x & 0xFF000000) >> 24); Type = (byte)((x & 0xFF000000) >> 24);
this.EntriesCount = (int)(x & 0x00FFFFFF); EntriesCount = (int)(x & 0x00FFFFFF);
Entries = new PsoEnumEntryInfo[EntriesCount]; Entries = new PsoEnumEntryInfo[EntriesCount];
for (int i = 0; i < EntriesCount; i++) for (int i = 0; i < EntriesCount; i++)
@ -762,6 +789,21 @@ namespace CodeWalker.GameFiles
return null; 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() public override string ToString()
{ {
@ -785,8 +827,8 @@ namespace CodeWalker.GameFiles
public void Read(DataReader reader) public void Read(DataReader reader)
{ {
this.EntryNameHash = (MetaName)reader.ReadUInt32(); EntryNameHash = (MetaName)reader.ReadUInt32();
this.EntryKey = reader.ReadInt32(); EntryKey = reader.ReadInt32();
} }
public void Write(DataWriter writer) public void Write(DataWriter writer)
@ -827,10 +869,25 @@ namespace CodeWalker.GameFiles
public void Write(DataWriter writer) 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(Ident);
writer.Write(Length); 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) 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(Ident);
writer.Write(Length); 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 int Length { get; set; }
public byte[] Data { get; set; } public byte[] Data { get; set; }
//public MetaHash[] Hashes { get; set; }
//public byte[] Decr1 { get; set; } //public byte[] Decr1 { get; set; }
//public byte[] Decr2 { get; set; } //public byte[] Decr2 { get; set; }
@ -899,26 +970,25 @@ namespace CodeWalker.GameFiles
{ {
Data = reader.ReadBytes(Length - 8); 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); //Decr1 = GTACrypto.DecryptAES(Data);
//Decr2 = GTACrypto.DecryptNG(Data, ) //Decr2 = GTACrypto.DecryptNG(Data, )
//TODO: someone plz figure out that encryption
} }
} }
public void Write(DataWriter writer) public void Write(DataWriter writer)
{ {
Length = (Data?.Length??0) + 8;
writer.Write(Ident); writer.Write(Ident);
writer.Write(Length); writer.Write(Length);
if (Length > 8)
{
writer.Write(Data);
}
} }
@ -947,10 +1017,15 @@ namespace CodeWalker.GameFiles
public void Write(DataWriter writer) public void Write(DataWriter writer)
{ {
Length = (Data?.Length ?? 0) + 8;
writer.Write(Ident); writer.Write(Ident);
writer.Write(Length); writer.Write(Length);
if (Length > 8)
{
writer.Write(Data);
}
} }
@ -983,11 +1058,13 @@ namespace CodeWalker.GameFiles
public void Write(DataWriter writer) public void Write(DataWriter writer)
{ {
Length = 20;
writer.Write(Ident); writer.Write(Ident);
writer.Write(Length); writer.Write(Length);
writer.Write(FileSize);
writer.Write(Checksum);
writer.Write(Unk0);
} }
public override string ToString() public override string ToString()

View 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;
}
}
}
}

View File

@ -647,11 +647,11 @@ namespace CodeWalker.GameFiles
new PsoStructureEntryInfo(MetaName.Probabilities, PsoDataType.Array, 8, 0, 0) new PsoStructureEntryInfo(MetaName.Probabilities, PsoDataType.Array, 8, 0, 0)
); );
case (MetaName)2575850962: 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.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.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: case (MetaName)938618322:
return new PsoStructureInfo((MetaName)938618322, 0, 0, 16, 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 blocki = (int)ptr.PointerDataId;// (ptr.Pointer & 0xFFF) - 1;
var offset = (int)ptr.PointerDataOffset;// (ptr.Pointer >> 12) & 0xFFFFF; var offset = (int)ptr.PointerDataOffset;// (ptr.Pointer >> 12) & 0xFFFFF;
var block = pso.GetBlock(blocki); var block = pso.GetBlock(blocki); //nameHash = 1
if (block == null) if (block == null)
{ return null; } { return null; }
//if (block.NameHash != (MetaName)1)
//{ }
var length = ptr.Count1; var length = ptr.Count1;
var lastbyte = offset + length; var lastbyte = offset + length;
if (lastbyte >= block.Length) if (lastbyte >= block.Length)
@ -16133,10 +16136,13 @@ namespace CodeWalker.GameFiles
var blocki = (int)ptr.PointerDataId;// (ptr.Pointer & 0xFFF) - 1; var blocki = (int)ptr.PointerDataId;// (ptr.Pointer & 0xFFF) - 1;
var offset = (int)ptr.PointerDataOffset;// (ptr.Pointer >> 12) & 0xFFFFF; var offset = (int)ptr.PointerDataOffset;// (ptr.Pointer >> 12) & 0xFFFFF;
var block = pso.GetBlock(blocki); var block = pso.GetBlock(blocki); //nameHash = 1
if (block == null) if (block == null)
{ return null; } { return null; }
//if (block.NameHash != (MetaName)1)
//{ }
//var length = ptr.Count1; //var length = ptr.Count1;
//var lastbyte = offset + length; //var lastbyte = offset + length;
//if (lastbyte >= block.Length) //if (lastbyte >= block.Length)
@ -16217,6 +16223,13 @@ namespace CodeWalker.GameFiles
public uint ItemOffset { get { return ((Pointer>>12) & 0xFFFFF); } } //byte offset 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() public override string ToString()
{ {
return BlockID.ToString() + ", " + ItemOffset.ToString() + ", " + Unk2.ToString(); return BlockID.ToString() + ", " + ItemOffset.ToString() + ", " + Unk2.ToString();

File diff suppressed because it is too large Load Diff

View File

@ -2251,6 +2251,8 @@ namespace CodeWalker
var fi = new FileInfo(fpath); var fi = new FileInfo(fpath);
var fname = fi.Name; var fname = fi.Name;
var fnamel = fname.ToLowerInvariant(); var fnamel = fname.ToLowerInvariant();
var mformat = MetaFormat.RSC;
var trimlength = 4;
if (!fnamel.EndsWith(".xml")) if (!fnamel.EndsWith(".xml"))
{ {
@ -2259,8 +2261,8 @@ namespace CodeWalker
} }
if (fnamel.EndsWith(".pso.xml")) if (fnamel.EndsWith(".pso.xml"))
{ {
MessageBox.Show(fname + ": PSO XML import not yet supported.", "Cannot import XML"); mformat = MetaFormat.PSO;
continue; trimlength = 8;
} }
if (fnamel.EndsWith(".rbf.xml")) if (fnamel.EndsWith(".rbf.xml"))
{ {
@ -2268,8 +2270,8 @@ namespace CodeWalker
continue; continue;
} }
fname = fname.Substring(0, fname.Length - 4); fname = fname.Substring(0, fname.Length - trimlength);
fnamel = fnamel.Substring(0, fnamel.Length - 4); fnamel = fnamel.Substring(0, fnamel.Length - trimlength);
var doc = new XmlDocument(); var doc = new XmlDocument();
string text = File.ReadAllText(fpath); string text = File.ReadAllText(fpath);
@ -2278,21 +2280,46 @@ namespace CodeWalker
doc.LoadXml(text); doc.LoadXml(text);
} }
var meta = XmlMeta.GetMeta(doc); byte[] data = null;
switch (mformat)
if ((meta.DataBlocks?.Data == null) || (meta.DataBlocks.Count == 0))
{ {
MessageBox.Show(fname + ": Schema not supported.", "Cannot import XML"); case MetaFormat.RSC:
continue; {
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 #if !DEBUG
catch (Exception ex) catch (Exception ex)

View File

@ -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!) data = ResourceBuilder.Build(meta, 2); //meta is RSC "Version":2 (it's actually a type identifier, not a version!)
break; break;
case MetaFormat.PSO: case MetaFormat.PSO:
MessageBox.Show("Sorry, PSO import is not supported yet.", "Cannot import PSO XML"); var pso = XmlPso.GetPso(doc);
return false; 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: case MetaFormat.RBF:
MessageBox.Show("Sorry, RBF import is not supported.", "Cannot import RBF XML"); MessageBox.Show("Sorry, RBF import is not supported.", "Cannot import RBF XML");
return false; return false;