public GeoAnimData(byte[] file, int address, uint imageBase, LandTableFormat format, Dictionary <int, string> labels, Dictionary <int, Attach> attaches) { ModelFormat mfmt = 0; switch (format) { case LandTableFormat.SA1: mfmt = ModelFormat.Basic; break; case LandTableFormat.SADX: mfmt = ModelFormat.BasicDX; break; case LandTableFormat.SA2: mfmt = ModelFormat.Chunk; break; } Unknown1 = ByteConverter.ToInt32(file, address); Unknown2 = ByteConverter.ToSingle(file, address + 4); Unknown3 = ByteConverter.ToSingle(file, address + 8); Model = new NJS_OBJECT(file, (int)(ByteConverter.ToUInt32(file, address + 0xC) - imageBase), imageBase, mfmt, labels, attaches); int actionaddr = (int)(ByteConverter.ToUInt32(file, address + 0x10) - imageBase); int motionaddr = (int)(ByteConverter.ToUInt32(file, actionaddr + 4) - imageBase); Animation = NJS_MOTION.ReadDirect(file, Model.CountAnimated(), motionaddr, imageBase, labels, attaches); Unknown4 = ByteConverter.ToInt32(file, address + 0x14); if (labels.ContainsKey(actionaddr)) { ActionName = labels[actionaddr]; } else { NJS_ACTION action = new NJS_ACTION(file, actionaddr, imageBase, mfmt, labels, attaches); ActionName = action.Name; labels.Add(actionaddr + (int)imageBase, ActionName); } }
// Scan for Motions static void ScanMotions() { CurrentStep++; CurrentScanData = "Motions" + (ModelParts > 0 ? " with " + ModelParts.ToString() + " or more nodes" : ""); Console.WriteLine("Step {0}: Scanning for motions with at least {1} model parts... ", CurrentStep, ModelParts); if (ShortRot) { Console.WriteLine("Using short rotations"); } ByteConverter.BigEndian = BigEndian; if (!SingleOutputFolder) { Directory.CreateDirectory(Path.Combine(OutputFolder, "actions")); } for (uint address = StartAddress; address < EndAddress; address += 1) { if (CancelScan) { break; } if (ConsoleMode && address % 1000 == 0) { Console.Write("\r{0} ", address.ToString("X8")); } CurrentAddress = address; // Check for a valid MDATA pointer uint mdatap = ByteConverter.ToUInt32(datafile, (int)address); if (mdatap < ImageBase || mdatap >= datafile.Length - 12 + ImageBase || mdatap == 0) { //Console.WriteLine("Mdatap {0} fail", mdatap.ToString("X8")); continue; } uint frames = ByteConverter.ToUInt32(datafile, (int)address + 4); if (frames > 2000 || frames < 1) { //Console.WriteLine("Frames {0} fail", frames.ToString()); continue; } AnimFlags animtype = (AnimFlags)ByteConverter.ToUInt16(datafile, (int)address + 8); if (animtype == 0) { continue; } int mdata = 0; //Console.WriteLine("Flags: {0}", animtype.ToString()); if (animtype.HasFlag(AnimFlags.Position)) { mdata++; } if (animtype.HasFlag(AnimFlags.Rotation)) { mdata++; } if (animtype.HasFlag(AnimFlags.Scale)) { mdata++; } if (animtype.HasFlag(AnimFlags.Vector)) { mdata++; } if (animtype.HasFlag(AnimFlags.Vertex)) { mdata++; } if (animtype.HasFlag(AnimFlags.Normal)) { mdata++; } if (animtype.HasFlag(AnimFlags.Color)) { continue; } if (animtype.HasFlag(AnimFlags.Intensity)) { continue; } if (animtype.HasFlag(AnimFlags.Target)) { continue; } if (animtype.HasFlag(AnimFlags.Spot)) { continue; } if (animtype.HasFlag(AnimFlags.Point)) { continue; } if (animtype.HasFlag(AnimFlags.Roll)) { continue; } int mdatasize = 0; bool lost = false; switch (mdata) { case 1: case 2: mdatasize = 16; break; case 3: mdatasize = 24; break; case 4: mdatasize = 32; break; case 5: mdatasize = 40; break; default: lost = true; break; } if (lost) { continue; } // Check MKEY pointers int mdatas = 0; for (int u = 0; u < 255; u++) { for (int m = 0; m < mdata; m++) { if (lost) { continue; } uint pointer = ByteConverter.ToUInt32(datafile, (int)(mdatap - ImageBase) + mdatasize * u + 4 * m); if (pointer < ImageBase || pointer >= datafile.Length - 8 + ImageBase) { if (pointer != 0) { lost = true; //Console.WriteLine("Mkey pointer {0} lost", pointer.ToString("X8")); } } if (!lost) { // Read frame count int framecount = ByteConverter.ToInt32(datafile, (int)(mdatap - ImageBase) + mdatasize * u + 4 * mdata + 4 * m); if (framecount < 0 || framecount > 2000) { //Console.WriteLine("Framecount lost: {0}", framecount.ToString("X8")); lost = true; } if (pointer == 0 && framecount != 0) { //Console.WriteLine("Framecount non zero"); lost = true; } //if (!lost) Console.WriteLine("Mdata size: {0}, MkeyP: {1}, Frames: {2}", mdatasize, pointer.ToString("X8"), framecount.ToString()); } } if (!lost) { mdatas++; //Console.WriteLine("Mdata {0}, total {1}", u, mdatas); } } if (mdatas > 0 && mdatas >= ModelParts) { try { Console.WriteLine("\rAdding motion at {0}: {1} nodes", address.ToString("X8"), mdatas); //Console.WriteLine("trying Address: {0}, MdataP: {1}, mdatas: {2}", address.ToString("X8"), mdatap.ToString("X8"), mdata); NJS_MOTION mot = NJS_MOTION.ReadDirect(datafile, mdatas, (int)address, ImageBase, new Dictionary <int, Attach>(), ShortRot); if (mot.ModelParts <= 0) { continue; } if (mot.Frames <= 0) { continue; } if (mot.Models.Count == 0) { continue; } string fileOutputPath = Path.Combine(OutputFolder, "actions", address.ToString("X8") + ".saanim"); if (SingleOutputFolder) { fileOutputPath = Path.Combine(OutputFolder, address.ToString("X8") + ".saanim"); } mot.Save(fileOutputPath, NoMeta); FoundMotions++; addresslist.Add(address, "NJS_MOTION"); uint[] arr = new uint[2]; arr[0] = address; arr[1] = (uint)mot.ModelParts; actionlist.Add(address, arr); } catch (Exception ex) { Console.WriteLine("\rError adding motion at {0}: {1}", address.ToString("X8"), ex.Message); } } } Console.WriteLine("\rFound {0} motions", FoundMotions); }