public static List <stamData> ReadLM(this BufferedStreamReader streamReader) { var stamList = new List <stamData>(); var lmStart = streamReader.Position(); streamReader.Read <int>(); var lmEnd = streamReader.Read <int>() + lmStart; streamReader.Seek(0x8, SeekOrigin.Current); while (streamReader.Position() < lmEnd) { var tag = streamReader.Peek <int>(); switch (tag) { case stam: stamList.Add(streamReader.ReadStam()); break; default: streamReader.SkipBasicAXSStruct(); break; } //Make sure to stop the loop if needed if (stamList[stamList.Count - 1].lastStam == true) { break; } } streamReader.Seek(lmEnd, SeekOrigin.Begin); return(stamList); }
public static List <int> ReadVTBFMGX(BufferedStreamReader streamReader) { List <int> mgxIds = new List <int>(); //For now, just get these. The data inside is pretty accessible, but we have nothing to do with it int dataEnd = (int)streamReader.BaseStream().Length; //Seek past vtbf tag streamReader.Seek(0x10, SeekOrigin.Current); //VTBF tags while (streamReader.Position() < dataEnd) { var data = ReadVTBFTag(streamReader, out string tagType, out int ptrCount, out int entryCount); switch (tagType) { case "DOC ": break; case "MAGR": Debug.WriteLine((int)data[0][0xFF]); mgxIds.Add((int)data[0][0xFF]); break; default: //Data being null signfies that the last thing read wasn't a proper tag. This should mean the end of the VTBF stream if nothing else. if (data == null) { return(mgxIds); } throw new System.Exception($"Unexpected tag at {streamReader.Position().ToString("X")}! {tagType} Please report!"); } } return(mgxIds); }
/// <summary> /// Creates a <see cref="HintFile"/> from a byte array. /// </summary> /// <param name="fileData">The hint file to parse.</param> public static unsafe HintFile FromArray(byte[] fileData) { using (MemoryStream fileDataStream = new MemoryStream(fileData)) { var reader = new BufferedStreamReader(fileDataStream, 4096); // Get all entries. var entries = new List <Entry>((fileData.Length / 2) / sizeof(Entry)); Entry entry; do { reader.Read(out entry); entries.Add(entry); }while (entry != Entry.Null); entries.RemoveAt(entries.Count - 1); // Convert all entries to managed. fixed(byte *stringDataPtr = &fileData[reader.Position()]) { var managedEntries = new ManagedEntry[entries.Count]; for (int i = 0; i < managedEntries.Length; i++) { var textPtr = &stringDataPtr[entries[i].Offset]; var text = _encoder.GetString(textPtr, Strlen(textPtr)); managedEntries[i] = new ManagedEntry(entries[i], text); } return(new HintFile(managedEntries)); } } }
public static stamData ReadStam(this BufferedStreamReader streamReader) { var stamDataObj = new stamData(); var stamStart = streamReader.Position(); streamReader.Read <int>(); streamReader.Seek(0x8, SeekOrigin.Current); var stamSize = streamReader.Read <int>(); streamReader.Seek(0x8, SeekOrigin.Current); var stamTexCount = streamReader.Read <ushort>(); streamReader.Seek(0x12, SeekOrigin.Current); int texOffset = streamReader.Read <int>(); if (texOffset == 0) { stamDataObj.lastStam = true; return(stamDataObj); } streamReader.Seek(stamStart + texOffset, SeekOrigin.Begin); for (int i = 0; i < stamTexCount; i++) { var key0 = BitConverter.GetBytes(streamReader.Read <int>()); int key1 = streamReader.Read <int>(); stamDataObj.texIds.Add(key0[0].ToString("X2") + key0[1].ToString("X2") + key0[2].ToString("X2") + key0[3].ToString("X2") + key1.ToString("X")); streamReader.Seek(0x18, SeekOrigin.Current); } //streamReader.Seek(stamEnd, SeekOrigin.Begin); return(stamDataObj); }
public static NGSSHAD ReadNGSSHAD(BufferedStreamReader streamReader, int offset) { NGSSHAD shad = new NGSSHAD(); shad.unk0 = streamReader.Read <int>(); shad.pixelShader = streamReader.Read <PSO2String>(); shad.vertexShader = streamReader.Read <PSO2String>(); shad.shadDetailOffset = streamReader.Read <int>(); shad.shadExtraOffset = streamReader.Read <int>(); long bookmark = streamReader.Position(); //Some shaders, like some player ones apparently, do not use the extra structs... if (shad.shadDetailOffset > 0) { streamReader.Seek(shad.shadDetailOffset + offset, System.IO.SeekOrigin.Begin); shad.shadDetail = streamReader.Read <SHADDetail>(); streamReader.Seek(shad.shadExtraOffset + offset, System.IO.SeekOrigin.Begin); for (int i = 0; i < shad.shadDetail.shadExtraCount; i++) { shad.shadExtra.Add(streamReader.Read <SHADExtraEntry>()); } } else if (shad.shadExtraOffset > 0) { Console.WriteLine("**Apparently shadExtraOffset is allowed to be used without shadDetailOffset???**"); } streamReader.Seek(bookmark, System.IO.SeekOrigin.Begin); return(shad); }
public static LobbyActionCommon ReadNIFLRebootLAC(BufferedStreamReader streamReader, int offset) { var lac = new LobbyActionCommon(); var nifl = streamReader.Read <AquaCommon.NIFL>(); var end = nifl.NOF0Offset + offset; var rel0 = streamReader.Read <AquaCommon.REL0>(); streamReader.Seek(rel0.REL0DataStart + offset, SeekOrigin.Begin); lac.header = streamReader.Read <LobbyActionCommon.lacHeader>(); streamReader.Seek(lac.header.dataInfoPointer + offset, SeekOrigin.Begin); lac.info = streamReader.Read <LobbyActionCommon.dataInfo>(); streamReader.Seek(lac.info.blockOffset + offset, SeekOrigin.Begin); for (int i = 0; i < lac.info.blockCount; i++) { var block = streamReader.Read <LobbyActionCommon.dataBlockReboot>(); long bookmark = streamReader.Position(); lac.rebootDataBlocks.Add(LobbyActionCommon.ReadDataBlockReboot(streamReader, offset, block)); streamReader.Seek(bookmark, SeekOrigin.Begin); } return(lac); }
private List <DatFileEntry>?GetEntriesForPointerPattern(string datFileName, BufferedStreamReader streamReader, int offset) { // Validate if first entry streamReader.Seek(offset, SeekOrigin.Begin); streamReader.Read(out DatFileEntry headerEntry); streamReader.Read(out DatFileEntry firstEntry); var savedPos = streamReader.Position(); if (!headerEntry.IsFirstEntry(streamReader, MemoryToRawAddress, firstEntry, datFileName)) { return(null); } streamReader.Seek(savedPos, SeekOrigin.Begin); // Populate other entries. var entries = new List <DatFileEntry>(new[] { firstEntry }); DatFileEntry entry; while (!(entry = streamReader.Read <DatFileEntry>()).IsLastEntry()) { entries.Add(entry); } return(entries); }
public static void AlignReader(BufferedStreamReader streamReader, int align) { //Align to int align while (streamReader.Position() % align > 0) { streamReader.Read <byte>(); } }
public static eertStruct ReadEert(this BufferedStreamReader streamReader) { eertStruct boneList = new eertStruct(); long bookmark = streamReader.Position(); streamReader.Seek(0x4, SeekOrigin.Current); var len = streamReader.Read <int>(); streamReader.Seek(0x4, SeekOrigin.Current); var trueLen = streamReader.Read <int>(); boneList.boneCount = streamReader.Read <int>(); streamReader.Seek(bookmark + 0x100, SeekOrigin.Begin); for (int i = 0; i < boneList.boneCount; i++) { rttaStruct bone = new rttaStruct(); bookmark = streamReader.Position(); bone.magic = streamReader.Read <int>(); bone.len = streamReader.Read <int>(); bone.int_08 = streamReader.Read <int>(); bone.trueLen = streamReader.Read <int>(); bone.nodeName = streamReader.Read <AquaCommon.PSO2String>(); bone.int_30 = streamReader.Read <int>(); bone.meshNodePtr = streamReader.Read <int>(); bone.int_38 = streamReader.Read <int>(); bone.parentNodeId = streamReader.Read <int>(); bone.childNodeCount = streamReader.Read <short>(); streamReader.Seek(0x3E, SeekOrigin.Current); bone.pos = streamReader.Read <Vector3>(); streamReader.Seek(0x4, SeekOrigin.Current); bone.quatRot = streamReader.Read <Quaternion>(); bone.scale = streamReader.Read <Vector3>(); streamReader.Seek(0x4, SeekOrigin.Current); boneList.rttaList.Add(bone); streamReader.Seek(bookmark + bone.trueLen, SeekOrigin.Begin); } return(boneList); }
public static void SkipBasicAXSStruct(this BufferedStreamReader streamReader) { long bookmark = streamReader.Position(); streamReader.Read <int>(); var trueLen = streamReader.Read <int>(); //Doesn't include padding so shouldn't be used streamReader.Read <int>(); var len = streamReader.Read <int>(); streamReader.Seek(bookmark, SeekOrigin.Begin); if (len == 0) { len = trueLen; } streamReader.Seek(len, SeekOrigin.Current); }
public static ipnbStruct ReadIpnb(this BufferedStreamReader streamReader) { long bookmark = streamReader.Position(); ipnbStruct ipbnStr = new ipnbStruct(); ipbnStr.magic = streamReader.Read <int>(); ipbnStr.len = streamReader.Read <int>(); ipbnStr.int_08 = streamReader.Read <int>(); ipbnStr.paddedLen = streamReader.Read <int>(); int count = (ipbnStr.len - 0x10) / 2; for (int i = 0; i < count; i++) { ipbnStr.shortList.Add(streamReader.Read <short>()); } streamReader.Seek(bookmark + ipbnStr.paddedLen, SeekOrigin.Begin); return(ipbnStr); }
public static PSO2Text ReadNIFLText(BufferedStreamReader streamReader, int offset, string fileName) { var txt = new PSO2Text(); var nifl = streamReader.Read <AquaCommon.NIFL>(); var end = nifl.NOF0Offset + offset; var rel0 = streamReader.Read <AquaCommon.REL0>(); streamReader.Seek(rel0.REL0DataStart + offset, SeekOrigin.Begin); var categoryPointer = streamReader.Read <int>(); var categoryCount = streamReader.Read <int>(); //Read through categories streamReader.Seek(categoryPointer + offset, SeekOrigin.Begin); for (int i = 0; i < categoryCount; i++) { var categoryNameOffset = streamReader.Read <int>(); var categoryDataInfoOffset = streamReader.Read <int>(); var subCategoryCount = streamReader.Read <int>(); //Setup subcategory lists txt.text.Add(new List <List <PSO2Text.textPair> >()); for (int j = 0; j < subCategoryCount; j++) { txt.text[i].Add(new List <PSO2Text.textPair>()); } //Get category name long bookmark = streamReader.Position(); streamReader.Seek(categoryNameOffset + offset, SeekOrigin.Begin); txt.categoryNames.Add(ReadCString(streamReader)); //Get Category Info streamReader.Seek(categoryDataInfoOffset + offset, SeekOrigin.Begin); for (int sub = 0; sub < subCategoryCount; sub++) { var categoryIndexOffset = streamReader.Read <int>(); var subCategoryId = streamReader.Read <int>(); var categoryIndexCount = streamReader.Read <int>(); var bookMarkSub = streamReader.Position(); streamReader.Seek(categoryIndexOffset + offset, SeekOrigin.Begin); for (int j = 0; j < categoryIndexCount; j++) { var pair = new PSO2Text.textPair(); int nameLoc = streamReader.Read <int>(); int textLoc = streamReader.Read <int>(); long bookmarkLocal = streamReader.Position(); streamReader.Seek(nameLoc + offset, SeekOrigin.Begin); pair.name = ReadCString(streamReader); streamReader.Seek(textLoc + offset, SeekOrigin.Begin); pair.str = ReadUTF16String(streamReader, end); txt.text[i][subCategoryId].Add(pair); streamReader.Seek(bookmarkLocal, SeekOrigin.Begin); } streamReader.Seek(bookMarkSub, SeekOrigin.Begin); } streamReader.Seek(bookmark, SeekOrigin.Begin); } #if DEBUG if (fileName != null) { StringBuilder output = new StringBuilder(); for (int i = 0; i < txt.text.Count; i++) { output.AppendLine(txt.categoryNames[i]); for (int j = 0; j < txt.text[i].Count; j++) { output.AppendLine($"Group {j}"); for (int k = 0; k < txt.text[i][j].Count; k++) { var pair = txt.text[i][j][k]; output.AppendLine($"{pair.name} - {pair.str}"); } output.AppendLine(); } output.AppendLine(); } File.WriteAllText(fileName + ".txt", output.ToString()); } #endif return(txt); }
public static AquaMotion ReadAAI(string filePath) { using (Stream stream = (Stream) new FileStream(filePath, FileMode.Open)) using (var streamReader = new BufferedStreamReader(stream, 8192)) { int fType = streamReader.Read <int>(); if (fType != FAA) { return(null); } streamReader.Seek(0xC, SeekOrigin.Current); int innerFtype = streamReader.Read <int>(); int len = streamReader.Read <int>(); streamReader.Seek(len - 0x8, SeekOrigin.Current); int animDataMagic = streamReader.Read <int>(); ushort nodeCount = streamReader.Read <ushort>(); ushort sht_06 = streamReader.Read <ushort>(); ushort sht_08 = streamReader.Read <ushort>(); ushort sht_0C = streamReader.Read <ushort>(); int timeCount = streamReader.Read <int>(); int finalFrame = streamReader.Read <int>(); int unkAddress0 = streamReader.Read <int>(); int unkAddress1 = streamReader.Read <int>(); int unkAddress2 = streamReader.Read <int>(); int unkAddress3 = streamReader.Read <int>(); int unkAddress4 = streamReader.Read <int>(); int unkAddress5 = streamReader.Read <int>(); int unkAddress6 = streamReader.Read <int>(); int unkAddress7 = streamReader.Read <int>(); int unkAddress8 = streamReader.Read <int>(); int nodeDefEndAddress = streamReader.Read <int>(); int unkAddress9 = streamReader.Read <int>(); int unkAddress10 = streamReader.Read <int>(); int int_44 = streamReader.Read <int>(); int clumpCount = 0; List <AnimDefinitionNode> nodes = new List <AnimDefinitionNode>(); int ct14 = 0; int ct24 = 0; int ct30 = 0; int ct34 = 0; int ct44 = 0; for (int i = 0; i < nodeCount; i++) { AnimDefinitionNode node = new AnimDefinitionNode(); node.header0 = streamReader.Read <ushort>(); node.dataCount = streamReader.Read <ushort>(); node.len = streamReader.Read <int>(); node.nameData = streamReader.Read <PSO2String>(); node.name = node.nameData.GetString(); for (int j = 0; j < node.dataCount; j++) { clumpCount++; var test = streamReader.Position().ToString("X"); DataClump dc = new DataClump(); dc.dcStart = streamReader.Read <DataClumpStart>(); switch (dc.dcStart.dcType) { case 0x14: ct14++; dc.d14 = streamReader.Read <DataClump14>(); break; case 0x24: ct24++; dc.d24 = streamReader.Read <DataClump24>(); break; case 0x30: ct30++; dc.d30 = streamReader.Read <DataClump30>(); break; case 0x34: ct34++; dc.d34 = streamReader.Read <DataClump34>(); dc.dcString = dc.d34.clumpName.GetString(); break; case 0x44: ct44++; dc.d44 = streamReader.Read <DataClump44>(); dc.dcString = dc.d44.clumpName.GetString(); break; default: MessageBox.Show($"clumpSize {dc.dcStart.dcType.ToString("X")} at {streamReader.Position().ToString("X")} is unexpected!"); break; } node.data.Add(dc); } nodes.Add(node); } return(null); var offsetTimes = streamReader.ReadOffsetTimeSets(streamReader.Position(), timeCount); List <List <OffsetTimeSet> > setsList = new List <List <OffsetTimeSet> >(); for (int i = 0; i < offsetTimes.Count; i++) { streamReader.Seek(offsetTimes[i].offset, SeekOrigin.Begin); var position = streamReader.Position(); int keyNodeCount = streamReader.Read <int>(); List <OffsetTimeSet> sets = new List <OffsetTimeSet>(); for (int j = 0; j < keyNodeCount; j++) { OffsetTimeSet set = streamReader.Read <OffsetTimeSet>(); sets.Add(set); } setsList.Add(sets); } } return(null); }
public static void ReadFFUBorRDDA(this BufferedStreamReader streamReader, List <ffubStruct> ffubStructs, Dictionary <string, rddaStruct> rddaStructs, Dictionary <string, rddaStruct> imgRddaStructs, Dictionary <string, rddaStruct> vertRddaStructs, Dictionary <string, rddaStruct> faceRddaStructs, ref ffubStruct imgFfub, ref ffubStruct vertFfub, ref ffubStruct faceFfub) { long bookmark = streamReader.Position(); int magic = streamReader.Read <int>(); int len; switch (magic) { case ffub: var ffubData = streamReader.ReadFFUB(magic, out len); switch (ffubData.dataType) { case 0x2: imgFfub = ffubData; break; case 0x3: vertFfub = ffubData; break; case 0x9: faceFfub = ffubData; break; default: ffubStructs.Add(ffubData); Debug.WriteLine($"Unknown ffub type: {ffubData.dataType.ToString("X")}"); break; } break; case rdda: var rddaData = streamReader.ReadRDDA(magic, out len); string md5 = $"{rddaData.md5_1.ToString("X")}{rddaData.md5_2.ToString("X")}"; switch (rddaData.dataType) { case 0x2: imgRddaStructs.Add(md5, rddaData); break; case 0x3: vertRddaStructs.Add(md5, rddaData); break; case 0x9: faceRddaStructs.Add(md5, rddaData); break; default: rddaStructs.Add(md5, rddaData); Debug.WriteLine($"Unknown rdda type: {rddaData.dataType.ToString("X")}"); break; } break; default: throw new Exception(magic.ToString("X")); } streamReader.Seek(bookmark, SeekOrigin.Begin); streamReader.Seek(len, SeekOrigin.Current); }
/// <summary> /// Reads an archive from a stream. /// </summary> /// <param name="stream">Stream pointing to the start of the archive.</param> /// <param name="archiveSize">Size of the archive file.</param> public ArchiveReader(Stream stream, int archiveSize) { _stream = stream; _startPos = stream.Position; // Extract Data. using var streamReader = new BufferedStreamReader(stream, 2048); streamReader.Read(out int binCount); Groups = new Group[binCount]; // Get group item counts. for (int x = 0; x < Groups.Length; x++) { Groups[x].Files = new Structs.Parser.File[streamReader.Read <byte>()]; } // Alignment streamReader.Seek(Utilities.Utilities.RoundUp((int)streamReader.Position(), 4) - streamReader.Position(), SeekOrigin.Current); // Skip section containing first item for each group. streamReader.Seek(sizeof(short) * Groups.Length, SeekOrigin.Current); // Populate IDs for (int x = 0; x < Groups.Length; x++) { Groups[x].Id = streamReader.Read <ushort>(); } // Populate offsets. int[] offsets = new int[Groups.Select(x => x.Files.Length).Sum()]; for (int x = 0; x < offsets.Length; x++) { offsets[x] = streamReader.Read <int>(); } int offsetIndex = 0; for (int x = 0; x < Groups.Length; x++) { var fileCount = Groups[x].Files.Length; for (int y = 0; y < fileCount; y++) { // Do not fill if no more elements left. if (offsetIndex >= offsets.Length) { break; } var offset = (int)offsets[offsetIndex]; int nextOffsetIndex = offsetIndex; offsetIndex += 1; // Find next non-zero value within array; if not found, use archive size.. do { nextOffsetIndex += 1; }while (nextOffsetIndex < offsets.Length && offsets[nextOffsetIndex] == 0); var nextOffset = nextOffsetIndex < offsets.Length ? offsets[nextOffsetIndex] : archiveSize; // Set offsets Groups[x].Files[y].Offset = offset; Groups[x].Files[y].Size = nextOffset - offset; } } }
static void DumpFpk(string filePath) { var fileDict = new Dictionary <int, string>(); var storeDict = new Dictionary <int, byte[]>(); var luaFiles = new List <string>(); var refText = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase).Substring(6), "FpkTool.txt"); //Get name references if they exist if (File.Exists(refText)) { Console.WriteLine("FpkTool.txt exists"); using (StreamReader reader = File.OpenText(refText)) { string line; while ((line = reader.ReadLine()) != null) { string[] fileKey = line.Split(' '); fileDict.Add(int.Parse(fileKey[0], System.Globalization.NumberStyles.HexNumber), fileKey[1]); } } } else { Console.WriteLine("FpkTool.txt does not exist"); } //Extract files and apply names if applicable Console.WriteLine("Proceeding..."); if (File.Exists(filePath)) { var fpk = File.ReadAllBytes(filePath); using (var fileStream = new FileStream(filePath, FileMode.Open)) using (var streamReader = new BufferedStreamReader(fileStream, 8192)) { List <FileEntry> table = new List <FileEntry>(); streamReader.Seek(0xC, SeekOrigin.Begin); streamReader.Read <UInt32>(out UInt32 entryCount); for (int i = 0; i < entryCount; i++) { streamReader.Read(out FileEntry value); table.Add(value); } long tableEnd = streamReader.Position(); foreach (FileEntry entry in table) { storeDict.Add(entry.Hash, streamReader.ReadBytes(entry.Offset + tableEnd, (int)entry.Length)); } } var outputDirectory = Path.Combine(Path.GetDirectoryName(filePath), Path.GetFileNameWithoutExtension(filePath)); Directory.CreateDirectory(outputDirectory + "_"); using (StreamWriter fpkList = new StreamWriter(outputDirectory + ".txt")) { foreach (var file in storeDict) { string name; if (fileDict.ContainsKey(file.Key)) { name = fileDict[file.Key]; } else { name = file.Key.ToString("X") + ".lua"; } var fileOutput = Path.Combine(outputDirectory + "_", $"{name}"); File.WriteAllBytes(fileOutput, file.Value); fpkList.WriteLine(file.Key.ToString("X") + " " + name); } } } }
//We're not realistically going to fully convert everything, but we can get vertex data and bones if nothing else //Returns an aqp ready for the ConvertToNGSPSO2Mesh method public static AquaObject ReadAXS(string filePath, out AquaNode aqn) { AquaObject aqp = new NGSAquaObject(); aqn = new AquaNode(); using (Stream stream = (Stream) new FileStream(filePath, FileMode.Open)) using (var streamReader = new BufferedStreamReader(stream, 8192)) { Debug.WriteLine(Path.GetFileName(filePath)); long last__oaPos = 0; eertStruct eertNodes = null; ipnbStruct tempLpnbList = null; List <ffubStruct> ffubList = new List <ffubStruct>(); List <XgmiStruct> xgmiList = new List <XgmiStruct>(); List <string> texNames = new List <string>(); List <MeshDefinitions> meshDefList = new List <MeshDefinitions>(); List <stamData> stamList = new List <stamData>(); Dictionary <string, rddaStruct> rddaList = new Dictionary <string, rddaStruct>(); Dictionary <string, rddaStruct> imgRddaList = new Dictionary <string, rddaStruct>(); Dictionary <string, rddaStruct> vertRddaList = new Dictionary <string, rddaStruct>(); Dictionary <string, rddaStruct> faceRddaList = new Dictionary <string, rddaStruct>(); Dictionary <string, int> xgmiIdByCombined = new Dictionary <string, int>(); Dictionary <string, int> xgmiIdByUnique = new Dictionary <string, int>(); ffubStruct imgFfub = new ffubStruct(); ffubStruct vertFfub = new ffubStruct(); ffubStruct faceFfub = new ffubStruct(); var fType = streamReader.Read <int>(); var fsaLen = streamReader.Read <int>(); streamReader.Seek(0x8, SeekOrigin.Current); //Go to Vert definition, node, material, and misc data while (streamReader.Position() < fsaLen) { var tag = streamReader.Peek <int>(); var test = Encoding.UTF8.GetString(BitConverter.GetBytes(tag)); Debug.WriteLine(streamReader.Position().ToString("X")); Debug.WriteLine(test); switch (tag) { case __oa: last__oaPos = streamReader.Position(); streamReader.Seek(0xD0, SeekOrigin.Current); break; case FIA: streamReader.Seek(0x10, SeekOrigin.Current); break; case __lm: var stam = streamReader.ReadLM(); if (stam != null && stam.Count > 0) { stamList = stam; } break; case __bm: streamReader.ReadBM(meshDefList, tempLpnbList, stamList, last__oaPos); break; case lpnb: tempLpnbList = streamReader.ReadIpnb(); break; case eert: eertNodes = streamReader.ReadEert(); break; //case ssem: // streamReader.SkipBasicAXSStruct(); //Maybe use for material data later. Remember to store ordered id for _bm mesh entries for this // break; case Xgmi: var xgmiData = streamReader.ReadXgmi(); if (!xgmiIdByCombined.ContainsKey(xgmiData.stamCombinedId)) { xgmiIdByCombined.Add(xgmiData.stamCombinedId, xgmiList.Count); } xgmiIdByUnique.Add(xgmiData.stamUniqueId, xgmiList.Count); xgmiList.Add(xgmiData); break; default: streamReader.SkipBasicAXSStruct(); break; } } //Assemble aqn from eert if (eertNodes != null) { for (int i = 0; i < eertNodes.boneCount; i++) { var rttaNode = eertNodes.rttaList[i]; Matrix4x4 mat = Matrix4x4.Identity; mat *= Matrix4x4.CreateScale(rttaNode.scale); var rotation = Matrix4x4.CreateFromQuaternion(rttaNode.quatRot); mat *= rotation; mat *= Matrix4x4.CreateTranslation(rttaNode.pos); var parentId = rttaNode.parentNodeId; //If there's a parent, multiply by it if (i != 0) { if (rttaNode.parentNodeId == -1) { parentId = 0; } var pn = aqn.nodeList[parentId]; var parentInvTfm = new Matrix4x4(pn.m1.X, pn.m1.Y, pn.m1.Z, pn.m1.W, pn.m2.X, pn.m2.Y, pn.m2.Z, pn.m2.W, pn.m3.X, pn.m3.Y, pn.m3.Z, pn.m3.W, pn.m4.X, pn.m4.Y, pn.m4.Z, pn.m4.W); Matrix4x4.Invert(parentInvTfm, out var invParentInvTfm); mat = mat * invParentInvTfm; } else { parentId = -1; } rttaNode.nodeMatrix = mat; //Create AQN node NODE aqNode = new NODE(); aqNode.animatedFlag = 1; aqNode.parentId = parentId; aqNode.unkNode = -1; aqNode.pos = rttaNode.pos; aqNode.eulRot = QuaternionToEuler(rttaNode.quatRot); if (Math.Abs(aqNode.eulRot.Y) > 120) { aqNode.scale = new Vector3(-1, -1, -1); } else { aqNode.scale = new Vector3(1, 1, 1); } Matrix4x4.Invert(mat, out var invMat); aqNode.m1 = new Vector4(invMat.M11, invMat.M12, invMat.M13, invMat.M14); aqNode.m2 = new Vector4(invMat.M21, invMat.M22, invMat.M23, invMat.M24); aqNode.m3 = new Vector4(invMat.M31, invMat.M32, invMat.M33, invMat.M34); aqNode.m4 = new Vector4(invMat.M41, invMat.M42, invMat.M43, invMat.M44); aqNode.boneName = rttaNode.nodeName; Debug.WriteLine($"{i} " + aqNode.boneName.GetString()); aqn.nodeList.Add(aqNode); } } //Go to mesh buffers streamReader.Seek(fsaLen, SeekOrigin.Begin); if (streamReader.Position() >= stream.Length) { return(null); } var fType2 = streamReader.Read <int>(); //Read mesh data if (fType2 != FMA) { Debug.WriteLine("Unexpected struct in location of FMA!"); return(null); } streamReader.Seek(0xC, SeekOrigin.Current); //Skip daeh int meshSettingLen = streamReader.ReadDAEH(); //Read ffub and rdda //Count mesh count here for now and store starts and ends of data long meshSettingStart = streamReader.Position(); while (streamReader.Position() < meshSettingStart + meshSettingLen) { streamReader.ReadFFUBorRDDA(ffubList, rddaList, imgRddaList, vertRddaList, faceRddaList, ref imgFfub, ref vertFfub, ref faceFfub); } int meshCount = meshDefList.Count; //Read image data var ext = Path.GetExtension(filePath); for (int i = 0; i < xgmiList.Count; i++) { var xgmiData = xgmiList[i]; var imgBufferInfo = imgRddaList[$"{xgmiData.md5_1.ToString("X")}{xgmiData.md5_2.ToString("X")}"]; Debug.WriteLine($"Image set {i}: " + imgBufferInfo.md5_1.ToString("X") + " " + imgBufferInfo.dataStartOffset.ToString("X") + " " + imgBufferInfo.toTagStruct.ToString("X") + " " + (meshSettingStart + imgFfub.dataStartOffset + imgBufferInfo.dataStartOffset).ToString("X")); var position = meshSettingStart + imgFfub.dataStartOffset + imgBufferInfo.dataStartOffset; var buffer = streamReader.ReadBytes(position, imgBufferInfo.dataSize); var outImagePath = filePath.Replace(ext, $"_tex_{i}" + ".dds"); texNames.Add(Path.GetFileName(outImagePath)); try { string name = Path.GetFileName(filePath); Debug.WriteLine($"{name}_xgmi_{ i}"); var image = AIFMethods.GetImage(xgmiData, buffer); File.WriteAllBytes(filePath.Replace(ext, $"_tex_{i}" + ".dds"), image); } catch (Exception exc) { #if DEBUG string name = Path.GetFileName(filePath); Debug.WriteLine($"Extract tex {i} failed."); File.WriteAllBytes($"C:\\{name}_xgmiHeader_{i}.bin", xgmiData.GetBytes()); File.WriteAllBytes($"C:\\{name}_xgmiBuffer_{i}.bin", buffer); Debug.WriteLine(exc.Message); #endif } buffer = null; } //Read model data - Since ffubs are initialized, they default to 0. int vertFfubPadding = imgFfub.structSize; int faceFfubPadding = imgFfub.structSize + vertFfub.structSize; for (int i = 0; i < meshCount; i++) { var mesh = meshDefList[i]; var nodeMatrix = Matrix4x4.Identity; for (int bn = 0; bn < eertNodes.boneCount; bn++) { var node = eertNodes.rttaList[bn]; if (node.meshNodePtr == mesh.oaPos) { nodeMatrix = node.nodeMatrix; break; } } var vertBufferInfo = vertRddaList[$"{mesh.salvStr.md5_1.ToString("X")}{mesh.salvStr.md5_2.ToString("X")}"]; var faceBufferInfo = faceRddaList[$"{mesh.lxdiStr.md5_1.ToString("X")}{mesh.lxdiStr.md5_2.ToString("X")}"]; Debug.WriteLine($"Vert set {i}: " + vertBufferInfo.md5_1.ToString("X") + " " + vertBufferInfo.dataStartOffset.ToString("X") + " " + vertBufferInfo.toTagStruct.ToString("X") + " " + (meshSettingStart + vertFfubPadding + vertFfub.dataStartOffset + vertBufferInfo.dataStartOffset).ToString("X")); Debug.WriteLine($"Face set {i}: " + faceBufferInfo.md5_1.ToString("X") + " " + faceBufferInfo.dataStartOffset.ToString("X") + " " + faceBufferInfo.toTagStruct.ToString("X") + " " + (meshSettingStart + faceFfubPadding + faceFfub.dataStartOffset + faceBufferInfo.dataStartOffset).ToString("X")); //Vert data var vertCount = vertBufferInfo.dataSize / mesh.salvStr.vertLen; AquaObject.VTXL vtxl = new AquaObject.VTXL(); streamReader.Seek((meshSettingStart + vertFfubPadding + vertFfub.dataStartOffset + vertBufferInfo.dataStartOffset), SeekOrigin.Begin); AquaObjectMethods.ReadVTXL(streamReader, mesh.vtxe, vtxl, vertCount, mesh.vtxe.vertDataTypes.Count); vtxl.convertToLegacyTypes(); //Fix vert transforms for (int p = 0; p < vtxl.vertPositions.Count; p++) { vtxl.vertPositions[p] = Vector3.Transform(vtxl.vertPositions[p], nodeMatrix); if (vtxl.vertNormals.Count > 0) { vtxl.vertNormals[p] = Vector3.TransformNormal(vtxl.vertNormals[p], nodeMatrix); } } //Handle bone indices if (mesh.ipnbStr != null && mesh.ipnbStr.shortList.Count > 0) { vtxl.bonePalette = (mesh.ipnbStr.shortList.ConvertAll(delegate(short num) { return((ushort)num); })); //Convert the indices based on the global bone list as pso2 will expect for (int bn = 0; bn < vtxl.bonePalette.Count; bn++) { vtxl.bonePalette[bn] = (ushort)mesh.lpnbStr.shortList[vtxl.bonePalette[bn]]; } } aqp.vtxlList.Add(vtxl); //Face data AquaObject.GenericTriangles genMesh = new AquaObject.GenericTriangles(); int faceIndexCount = faceBufferInfo.dataSize / 2; List <int> faceList = new List <int>(); streamReader.Seek((meshSettingStart + faceFfubPadding + faceFfub.dataStartOffset + faceBufferInfo.dataStartOffset), SeekOrigin.Begin); int maxStep = streamReader.Read <ushort>(); for (int fId = 0; fId < faceIndexCount - 1; fId++) { faceList.Add(streamReader.Read <ushort>()); } //Convert the data to something usable with this algorithm and then destripify it. List <ushort> triList = unpackInds(inverseWatermarkTransform(faceList, maxStep)).ConvertAll(delegate(int num) { return((ushort)num); }); var tempFaceData = new AquaObject.stripData() { triStrips = triList, format0xC33 = true, triIdCount = triList.Count }; genMesh.triList = tempFaceData.GetTriangles(); //Extra genMesh.vertCount = vertCount; genMesh.matIdList = new List <int>(new int[genMesh.triList.Count]); for (int j = 0; j < genMesh.matIdList.Count; j++) { genMesh.matIdList[j] = aqp.tempMats.Count; } aqp.tempTris.Add(genMesh); //Material var mat = new AquaObject.GenericMaterial(); mat.texNames = GetTexNames(mesh, xgmiIdByCombined, xgmiIdByUnique, texNames); aqp.tempMats.Add(mat); } return(aqp); } }
public void readVertexList(Matrix4x4 mat) { var vtxe = ReadNjVtxe(streamReader, be); streamReader.Seek(vtxe.vertexListOffset, SeekOrigin.Begin); var vtxl = new VTXL(); bool readUv = false; bool readNormal = false; bool readColor = false; int size = (int)vtxe.vertexSize; //pos size -= 0xC; //Process bitflags if ((vtxe.vertexType & 0x01) != 0) { readUv = true; size -= 0x8; } if ((vtxe.vertexType & 0x02) != 0) { readNormal = true; size -= 0xC; } if ((vtxe.vertexType & 0x04) != 0) { readColor = true; size -= 0x4; } if (size != 0) { Console.WriteLine($"Vert size is not 0 at vtxe {(streamReader.Position() - 0x10).ToString("X")}"); } //Read vertices for (int i = 0; i < vtxe.vertexCount; i++) { var pos = streamReader.ReadBEV3(be) * rootScale; var newPos = Vector3.Transform(pos, mat); vtxl.vertPositions.Add(newPos); if (readNormal) { var nrm = streamReader.ReadBEV3(be); var newNrm = Vector3.TransformNormal(nrm, mat); vtxl.vertNormals.Add(newNrm); } if (readColor) { byte[] color = new byte[4]; color[0] = streamReader.Read <byte>(); color[1] = streamReader.Read <byte>(); color[2] = streamReader.Read <byte>(); color[3] = streamReader.Read <byte>(); vtxl.vertColors.Add(color); } if (readUv) { vtxl.uv1List.Add(streamReader.ReadBEV2(be)); } //skip unexpected sections if (size > 0) { streamReader.Seek(size, SeekOrigin.Current); } } aqObj.vtxlList.Add(vtxl); }
public static bool TryGuess(Stream stream, int streamLength) { var data = new BufferedStreamReader(stream, 4096); var pos = stream.Position; try { var initialPos = data.Position(); // Total Groups data.Read(out int binCount); // Safeguard against unlikely big files. if (binCount is > short.MaxValue or < 1) { return(false); } // Total Items Span <byte> groups = stackalloc byte[binCount]; for (int x = 0; x < binCount; x++) { groups[x] = data.Read <byte>(); } // Alignment data.Seek(Utilities.RoundUp((int)data.Position(), 4) - data.Position(), SeekOrigin.Current); // Now compare against total running file count. int currentCount = 0; int expectedCount = 0; for (int x = 0; x < binCount; x++) { expectedCount = data.Read <short>(); if (currentCount != expectedCount) { return(false); } currentCount += groups[x]; } // Skip group ids. data.Seek(sizeof(short) * binCount, SeekOrigin.Current); // Check offsets. var firstFileOffset = data.Peek <int>(); if (streamLength != -1 && firstFileOffset > streamLength) { return(false); } // Seek to expected first file position. data.Seek(sizeof(int) * currentCount, SeekOrigin.Current); data.Seek(Utilities.RoundUp((int)data.Position(), 16), SeekOrigin.Begin); // Alignment // Try checking if first file is past expected header size, or empty 0. var currentOffset = data.Position() - initialPos; return(firstFileOffset == 0 || firstFileOffset >= (currentOffset)); } finally { stream.Position = pos; } }
public static void ReadBM(this BufferedStreamReader streamReader, List <MeshDefinitions> defs, ipnbStruct tempLpnbList, List <stamData> stamList, long last__oaPos) { int counter = 0; MeshDefinitions mesh = null; var bmStart = streamReader.Position(); streamReader.Read <int>(); var bmEnd = streamReader.Read <int>() + bmStart; streamReader.Seek(0x8, SeekOrigin.Current); while (streamReader.Position() < bmEnd) { var tag = streamReader.Peek <int>(); switch (tag) { case ydbm: if (mesh != null) { Debug.WriteLine(defs.Count); defs.Add(mesh); } mesh = new MeshDefinitions(); mesh.oaPos = last__oaPos; mesh.lpnbStr = tempLpnbList; mesh.ydbmStr = streamReader.ReadYdbm(); if (stamList.Count > counter) { mesh.stam = stamList[counter]; } else if (stamList.Count > 0) { mesh.stam = stamList[stamList.Count - 1]; } else { mesh.stam = null; } counter++; break; case lxdi: mesh.lxdiStr = streamReader.ReadLxdi(); break; case salv: mesh.salvStr = streamReader.ReadSalv(); mesh.vtxe = GenerateGenericPSO2VTXE(mesh.salvStr.vertDef0, mesh.salvStr.vertDef1, mesh.salvStr.vertDef2, mesh.salvStr.vertDef3, mesh.salvStr.vertDef4, mesh.salvStr.vertLen); break; case ipnb: mesh.ipnbStr = streamReader.ReadIpnb(); break; default: streamReader.SkipBasicAXSStruct(); break; } } if (mesh != null) { Debug.WriteLine(defs.Count); defs.Add(mesh); } }