Example #1
0
        public static void Split(string filename)
        {
            nodenames.Clear();
            modelfiles.Clear();
            motionfiles.Clear();

            Console.WriteLine("Splitting file {0}...", filename);
            byte[] fc;
            if (Path.GetExtension(filename).Equals(".prs", StringComparison.OrdinalIgnoreCase))
            {
                fc = Prs.Decompress(filename);
            }
            else
            {
                fc = File.ReadAllBytes(filename);
            }
            EventIniData ini = new EventIniData()
            {
                Name = Path.GetFileNameWithoutExtension(filename)
            };
            string            path = Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(Path.GetFullPath(filename)), Path.GetFileNameWithoutExtension(filename))).FullName;
            uint              key;
            List <NJS_MOTION> motions = null;
            bool              battle;
            bool              dcbeta;

            if (fc[0] == 0x81)
            {
                if (fc[0x2B] <= 0x01 && fc[0x2A] == 0)
                {
                    Console.WriteLine("File is in GC/PC format.");
                    ByteConverter.BigEndian = true;
                    key         = 0x8125FE60;
                    ini.Game    = Game.SA2B;
                    battle      = true;
                    dcbeta      = false;
                    motions     = ReadMotionFile(Path.ChangeExtension(filename, null) + "motion.bin");
                    ini.Motions = motions.Select(a => a?.Name).ToList();
                    foreach (var mtn in motions.Where(a => a != null))
                    {
                        motionfiles[mtn.Name] = new MotionInfo(null, mtn);
                    }
                }
                else
                {
                    Console.WriteLine("File is in GC/PC Beta format.");
                    ByteConverter.BigEndian = true;
                    key      = 0x812FFE60;
                    ini.Game = Game.SA2B;
                    battle   = false;
                    dcbeta   = false;
                }
            }
            else
            {
                if ((fc[37] == 0x25) || (fc[38] == 0x22) || ((fc[36] == 0) && ((fc[1] == 0xFE) || (fc[1] == 0xF2) || ((fc[1] == 0x27) && fc[2] == 0x9F))))
                {
                    Console.WriteLine("File is in DC Beta format.");
                    ByteConverter.BigEndian = false;
                    key      = 0xC600000;
                    ini.Game = Game.SA2;
                    battle   = false;
                    dcbeta   = true;
                }
                else
                {
                    Console.WriteLine("File is in DC format.");
                    ByteConverter.BigEndian = false;
                    key      = 0xC600000;
                    ini.Game = Game.SA2;
                    battle   = false;
                    dcbeta   = false;
                }
            }
            int ptr = fc.GetPointer(0x20, key);

            if (ptr != 0)
            {
                if (!dcbeta)
                {
                    for (int i = 0; i < (battle ? 18 : 16); i++)
                    {
                        string upnam = upgradenames[i];
                        string chnam = upnam;
                        switch (i)
                        {
                        case 0:
                            chnam = "Sonic";
                            break;

                        case 4:
                            chnam = "Shadow";
                            break;

                        case 6:
                            chnam = "Knuckles";
                            break;

                        case 12:
                            chnam = "Rouge";
                            break;

                        case 16:
                            chnam = "Mech Tails";
                            break;

                        case 17:
                            chnam = "Mech Eggman";
                            break;
                        }
                        UpgradeInfo info = new UpgradeInfo();
                        info.RootNode = GetModel(fc, ptr, key, $"{chnam} Root.sa2mdl");
                        if (info.RootNode != null)
                        {
                            int ptr2 = fc.GetPointer(ptr + 4, key);
                            if (ptr2 != 0)
                            {
                                info.AttachNode1 = $"object_{ptr2:X8}";
                            }
                            int ptr3 = fc.GetPointer(ptr + 8, key);
                            if (ptr3 != 0)
                            {
                                info.Model1 = GetModel(fc, ptr + 8, key, $"{upnam} Model 1.sa2mdl");
                            }
                            ptr2 = fc.GetPointer(ptr + 0xC, key);
                            if (ptr2 != 0)
                            {
                                info.AttachNode2 = $"object_{ptr2:X8}";
                            }
                            ptr3 = fc.GetPointer(ptr + 0x10, key);
                            if (ptr3 != 0)
                            {
                                info.Model2 = GetModel(fc, ptr + 0x10, key, $"{upnam} Model 2.sa2mdl");
                            }
                        }
                        ini.Upgrades.Add(info);
                        ptr += 0x14;
                    }
                }
                else
                {
                    for (int i = 0; i < 14; i++)
                    {
                        string upnam = upgradebetanames[i];
                        string chnam = upnam;
                        switch (i)
                        {
                        case 0:
                            chnam = "Sonic";
                            break;

                        case 4:
                            chnam = "Shadow";
                            break;

                        case 6:
                            chnam = "Knuckles";
                            break;

                        case 10:
                            chnam = "Rouge";
                            break;
                        }
                        UpgradeInfo info = new UpgradeInfo();
                        info.RootNode = GetModel(fc, ptr, key, $"{chnam} Root.sa2mdl");
                        if (info.RootNode != null)
                        {
                            int ptr2 = fc.GetPointer(ptr + 4, key);
                            if (ptr2 != 0)
                            {
                                info.AttachNode1 = $"object_{ptr2:X8}";
                            }
                            int ptr3 = fc.GetPointer(ptr + 8, key);
                            if (ptr3 != 0)
                            {
                                info.Model1 = GetModel(fc, ptr + 8, key, $"{upnam} Model 1.sa2mdl");
                            }
                            ptr2 = fc.GetPointer(ptr + 0xC, key);
                            if (ptr2 != 0)
                            {
                                info.AttachNode2 = $"object_{ptr2:X8}";
                            }
                            ptr3 = fc.GetPointer(ptr + 0x10, key);
                            if (ptr3 != 0)
                            {
                                info.Model2 = GetModel(fc, ptr + 0x10, key, $"{upnam} Model 2.sa2mdl");
                            }
                        }
                        ini.Upgrades.Add(info);
                        ptr += 0x14;
                    }
                }
            }
            else
            {
                Console.WriteLine("Event contains no character upgrades.");
            }
            ptr = fc.GetPointer(0x18, key);
            if (ptr != 0)
            {
                for (int i = 0; i < 93; i++)
                {
                    string name = $"object_{ptr:X8}";
                    if (name != null)
                    {
                        ini.MechParts.Add(i, name);
                    }
                    ptr += 4;
                }
            }
            else
            {
                Console.WriteLine("Event contains no mech parts.");
            }
            int gcnt = ByteConverter.ToInt32(fc, 8);

            ptr = fc.GetPointer(0, key);
            if (ptr != 0)
            {
                Console.WriteLine("Event contains {0} scene(s).", gcnt + 1);
                for (int gn = 0; gn <= gcnt; gn++)
                {
                    Directory.CreateDirectory(Path.Combine(path, $"Scene {gn + 1}"));
                    SceneInfo scn  = new SceneInfo();
                    int       ptr2 = fc.GetPointer(ptr, key);
                    int       ecnt = ByteConverter.ToInt32(fc, ptr + 4);
                    if (ptr2 != 0)
                    {
                        Console.WriteLine("Scene {0} contains {1} entit{2}.", gn + 1, ecnt, ecnt == 1 ? "y" : "ies");
                        for (int en = 0; en < ecnt; en++)
                        {
                            EntityInfo ent = new EntityInfo();
                            ent.Model = GetModel(fc, ptr2, key, $"Scene {gn + 1}\\Entity {en + 1} Model.sa2mdl");
                            if (ent.Model != null)
                            {
                                ent.Motion = GetMotion(fc, ptr2 + 4, key, $"Scene {gn + 1}\\Entity {en + 1} Motion.saanim", motions, modelfiles[ent.Model].Model.CountAnimated());
                                if (ent.Motion != null)
                                {
                                    modelfiles[ent.Model].Motions.Add(motionfiles[ent.Motion].Filename);
                                }
                                ent.ShapeMotion = GetMotion(fc, ptr2 + 8, key, $"Scene {gn + 1}\\Entity {en + 1} Shape Motion.saanim", motions, modelfiles[ent.Model].Model.CountMorph());
                                if (ent.ShapeMotion != null)
                                {
                                    modelfiles[ent.Model].Motions.Add(motionfiles[ent.ShapeMotion].Filename);
                                }
                            }
                            if (battle)
                            {
                                ent.GCModel     = GetGCModel(fc, ptr2 + 12, key, $"Scene {gn + 1}\\Entity {en + 1} GC Model.sa2bmdl");
                                ent.ShadowModel = GetModel(fc, ptr2 + 16, key, $"Scene {gn + 1}\\Entity {en + 1} Shadow Model.sa2mdl");
                                ent.Position    = new Vertex(fc, ptr2 + 24);
                                ent.Flags       = ByteConverter.ToUInt32(fc, ptr2 + 36);
                                ent.Layer       = ByteConverter.ToUInt32(fc, ptr2 + 40);
                            }
                            else
                            {
                                ent.Position = new Vertex(fc, ptr2 + 16);
                                ent.Flags    = ByteConverter.ToUInt32(fc, ptr2 + 28);
                            }
                            scn.Entities.Add(ent);
                            ptr2 += battle ? 0x2C : 0x20;
                        }
                    }
                    else
                    {
                        Console.WriteLine("Scene {0} contains no entities.", gn + 1);
                    }
                    ptr2 = fc.GetPointer(ptr + 8, key);
                    if (ptr2 != 0)
                    {
                        int cnt = ByteConverter.ToInt32(fc, ptr + 12);
                        for (int i = 0; i < cnt; i++)
                        {
                            scn.CameraMotions.Add(GetMotion(fc, ptr2, key, $"Scene {gn + 1}\\Camera Motion {i + 1}.saanim", motions, 1));
                            ptr2 += sizeof(int);
                        }
                    }
                    ptr2 = fc.GetPointer(ptr + 0x18, key);
                    if (ptr2 != 0)
                    {
                        BigInfo big = new BigInfo();
                        big.Model = GetModel(fc, ptr2, key, $"Scene {gn + 1}\\Big Model.sa2mdl");
                        if (big.Model != null)
                        {
                            int anicnt = modelfiles[big.Model].Model.CountAnimated();
                            int ptr3   = fc.GetPointer(ptr2 + 4, key);
                            if (ptr3 != 0)
                            {
                                int cnt = ByteConverter.ToInt32(fc, ptr2 + 8);
                                for (int i = 0; i < cnt; i++)
                                {
                                    big.Motions.Add(new string[] { GetMotion(fc, ptr3, key, $"Scene {gn + 1}\\Big Motion {i + 1}a.saanim", motions, anicnt), GetMotion(fc, ptr3 + 4, key, $"Scene {gn + 1}\\Big Motion {i + 1}b.saanim", motions, anicnt) });
                                    ptr3 += 8;
                                }
                            }
                        }
                        big.Unknown = ByteConverter.ToInt32(fc, ptr2 + 12);
                        scn.Big     = big;
                    }
                    scn.FrameCount = ByteConverter.ToInt32(fc, ptr + 28);
                    ini.Scenes.Add(scn);
                    ptr += 0x20;
                }
            }
            else
            {
                Console.WriteLine("Event contains no scenes.");
            }
            ptr = fc.GetPointer(0x1C, key);
            if (ptr != 0)
            {
                ini.TailsTails = GetModel(fc, ptr, key, $"Tails' tails.sa2mdl");
            }
            else
            {
                Console.WriteLine("Event does not contain Tails' tails.");
            }
            ptr = fc.GetPointer(4, key);
            if (ptr == 0)
            {
                Console.WriteLine("Event does not contain an internal texture list.");
            }
            ptr = fc.GetPointer(0xC, key);
            if (ptr == 0)
            {
                Console.WriteLine("Event does not contain texture sizes.");
            }
            ptr = fc.GetPointer(0x24, key);
            if (ptr == 0)
            {
                Console.WriteLine("Event does not contain texture animation data.");
            }
            if (battle && fc[0x2B] == 0)
            {
                Console.WriteLine("Event does not use GC shadow maps.");
            }
            if (battle && fc[0x2B] == 1)
            {
                Console.WriteLine("Event uses GC shadow maps.");
            }
            foreach (var item in motionfiles.Values)
            {
                string fn = item.Filename ?? $"Unknown Motion {motions.IndexOf(item.Motion)}.saanim";
                string fp = Path.Combine(path, fn);
                item.Motion.Save(fp);
                ini.Files.Add(fn, HelperFunctions.FileHash(fp));
            }
            foreach (var item in modelfiles.Values)
            {
                string fp = Path.Combine(path, item.Filename);
                ModelFile.CreateFile(fp, item.Model, item.Motions.ToArray(), null, null, null, item.Format);
                ini.Files.Add(item.Filename, HelperFunctions.FileHash(fp));
            }
            JsonSerializer js = new JsonSerializer
            {
                Formatting        = Formatting.Indented,
                NullValueHandling = NullValueHandling.Ignore
            };

            using (var tw = File.CreateText(Path.Combine(path, Path.ChangeExtension(Path.GetFileName(filename), ".json"))))
                js.Serialize(tw, ini);
        }
Example #2
0
 private static extern void BigCompute(BigInfo info, out double outMag, out ushort dwell);