Ejemplo n.º 1
0
 private static void WriteResult(StringBuilder result, EntranceTableRecord record, int setup,
                                 ResultType type, string description,
                                 FaroresTest fwTest = FaroresTest.NA)
 {
     result.AppendFormat("{0}\t{1}\t{2}\t{3}\t{4}\t{5}",
                         record.Scene, record.Spawn, setup,
                         (int)fwTest, //fwTest.ToString(),
                         (int)type,   //type.ToString().Replace('_', ' '),
                         description);
     result.AppendLine();
 }
Ejemplo n.º 2
0
        public static StringBuilder Calculate(IExperimentFace face, List <string> files)
        {
            StringBuilder result          = new StringBuilder();
            int           N0_SceneEndAddr = 0x384980;
            int           N0_CodeAddr     = 0x110A0;

            SegmentAddress[] SegmentTable = new SegmentAddress[16];

            Dictionary <short, EntranceTableRecord> EntranceTableSimplified = new Dictionary <short, EntranceTableRecord>();
            Rom N0 = new ORom(files[0], ORom.Build.N0);

            Addresser.TryGetRom(ORom.FileList.code, N0.Version, AddressToken.EntranceIndexTable_Start, out int entranceTableAddress);
            Addresser.TryGetRom(ORom.FileList.code, N0.Version, AddressToken.ActorTable_Start, out int actorTableRomAddress);

            var code_File = N0.Files.GetFile(ORom.FileList.code);
            var codeStr   = new BinaryReader(code_File);

            codeStr.BaseStream.Position = code_File.Record.GetRelativeAddress(entranceTableAddress);

            //remove redundant entrance table records
            for (int i = 0; i < 0x614; i++)
            {
                var   record = new EntranceTableRecord(codeStr);
                short key    = (short)((record.Scene << 8) + record.Spawn);

                if (!EntranceTableSimplified.ContainsKey(key))
                {
                    EntranceTableSimplified.Add(key, record);
                }
            }

            int          lastScene  = -1;
            RomFile      scene_File = null;
            BinaryReader sceneStr   = null;


            foreach (EntranceTableRecord record in EntranceTableSimplified.Values.OrderBy(x => x.Scene))
            {
                if (sceneStr != null)
                {
                    sceneStr.BaseStream.Position = 0;
                }
                if (record.Scene != lastScene)
                {
                    if (record.Scene >= 101)
                    {
                        WriteResult(result, record, -1, ResultType.Crash, "No Scene");
                        continue;
                    }
                    scene_File      = N0.Files.GetSceneFile(record.Scene);
                    sceneStr        = new BinaryReader(scene_File.Stream);
                    SegmentTable[2] = N0_SceneEndAddr - scene_File.Record.VRom.Size;
                }

                //First, 0x18 command
                byte cmdId = sceneStr.ReadByte();
                sceneStr.BaseStream.Position--;

                List <AlternateSetup> setups = new List <AlternateSetup>();

                if (cmdId == 0x18)
                {
                    sceneStr.BaseStream.Position += 4;
                    int headerListOffset = sceneStr.ReadBigInt32() & 0xFFFFFF;
                    sceneStr.BaseStream.Position = headerListOffset + 0xC;
                    for (int i = 0; i < 0xD; i++)
                    {
                        int data = sceneStr.ReadBigInt32();
                        setups.Add(new AlternateSetup(i, data));
                    }
                }
                else
                {
                    setups.Add(new AlternateSetup(-1, 0x02000000));
                }

                //parse headers
                foreach (var setup in setups)
                {
                    SceneHeader sceneHeader = new SceneHeader();
                    FaroresTest ft          = FaroresTest.NA;

                    //resolve header start
                    if (setup.SegmentAddress.Segment != 2 ||
                        !(setup.SegmentAddress.Offset < scene_File.Record.VRom.Size))
                    {
                        WriteResult(result, record, setup.SceneSetup, ResultType.Crash_Likely,
                                    UnresolvedAddress("Scene Setup", setup.SegmentAddress));
                        continue;
                    }
                    //set header start
                    sceneStr.BaseStream.Position = setup.SegmentAddress.Offset;

                    int loop = 32;

                    while (loop > 0)
                    {
                        loop--;
                        cmdId = sceneStr.ReadByte();
                        sceneStr.BaseStream.Position--;

                        switch (cmdId)
                        {
                        case 0x14:
                            if (sceneHeader.Cutscene == 0)
                            {
                                WriteResult(result, record, setup.SceneSetup, ResultType.Cutscene_Pointer, "No Known Issues", ft);
                            }
                            else
                            {
                                WriteResult(result, record, setup.SceneSetup, ResultType.Cutscene, "No Known Issues", ft);
                            }
                            loop = -1; break;

                        case 0x04:     //room definitions
                        {
                            sceneStr.BaseStream.Position += 1;
                            sceneHeader.Rooms             = sceneStr.ReadByte();
                            sceneStr.BaseStream.Position += 2;
                            sceneHeader.RoomsAddress      = sceneStr.ReadBigInt32();
                            break;
                        }

                        case 0x06:     //entrance index definitions
                        {
                            sceneStr.BaseStream.Position += 4;
                            sceneHeader.EntranceIndexDefinitionsAddress = sceneStr.ReadBigInt32();
                            break;
                        }

                        case 0x00:     //Link spawns definitions
                        {
                            long seekBack;
                            sceneStr.BaseStream.Position += 1;
                            sceneHeader.LinkSpawns        = sceneStr.ReadByte();
                            sceneStr.BaseStream.Position += 2;
                            sceneHeader.LinkSpawnsAddress = sceneStr.ReadBigInt32();

                            //start resolving things here I guess
                            SegmentAddress selectEntDefAddr = sceneHeader.EntranceIndexDefinitionsAddress
                                                              + (record.Spawn << 1);


                            if (selectEntDefAddr.Segment != 2 &&
                                selectEntDefAddr.Offset > scene_File.Record.VRom.Size)
                            {
                                WriteResult(result, record, setup.SceneSetup, ResultType.Crash_Likely,
                                            UnresolvedAddress("Entrance Definitions", selectEntDefAddr));
                                loop = -1; break;
                            }

                            seekBack = sceneStr.BaseStream.Position;

                            sceneStr.BaseStream.Position = selectEntDefAddr.Offset;
                            int spawnId = sceneStr.ReadByte();
                            int mapId   = sceneStr.ReadByte();

                            //test if Link Spawn is invalid (phase 1)
                            SegmentAddress selectSpawnAddr = sceneHeader.LinkSpawnsAddress + (spawnId << 4);

                            if (selectSpawnAddr.Segment != 2 &&
                                selectSpawnAddr.Offset > scene_File.Record.VRom.Size)
                            {
                                WriteResult(result, record, setup.SceneSetup, ResultType.Crash_Likely,
                                            UnresolvedAddress("Link Spawn", selectSpawnAddr), ft);
                                loop = -1; break;
                            }

                            //test if Map Id is invalid, making FW mandatory
                            if (!(mapId < sceneHeader.Rooms))
                            {
                                WriteResult(result, record, setup.SceneSetup, ResultType.Crash,
                                            string.Format("Invalid Room Id ({0})", mapId), FaroresTest.Without);
                                ft = FaroresTest.With;
                                //Don't break because we can continue parsing for FW purposes
                            }

                            //Check if Link spawn is valid (phase 2)
                            sceneStr.BaseStream.Position = selectSpawnAddr.Offset;
                            var actorId = sceneStr.ReadBigInt16();
                            int linkActorVarsRomAddr = actorId * 0x20 + 0x14;
                            linkActorVarsRomAddr += actorTableRomAddress;
                            var linkActorVarsRelOff = code_File.Record.GetRelativeAddress(linkActorVarsRomAddr);

                            //pointer to Link's Actor vars can't be resolved
                            if (linkActorVarsRelOff < 0 ||
                                !(linkActorVarsRelOff < code_File.Record.VRom.Size))
                            {
                                WriteResult(result, record, setup.SceneSetup, ResultType.Crash_Likely,
                                            UnresolvedAddress("Link Actor Var Pointer", (int)(linkActorVarsRelOff + N0_CodeAddr)), ft);
                                loop = -1; break;
                            }

                            codeStr.BaseStream.Position = linkActorVarsRelOff;
                            int linkActorVarsWriteAddr = codeStr.ReadBigInt32();
                            int linkActorVarsWriteOff  = (linkActorVarsWriteAddr - N0_CodeAddr + 8) & 0xFFFFFF;

                            //pointer to where to update Link's object number can't be resolved
                            if (linkActorVarsWriteOff < 0 ||
                                !(linkActorVarsWriteOff < code_File.Record.VRom.Size))
                            {
                                WriteResult(result, record, setup.SceneSetup, ResultType.Crash_Likely,
                                            UnresolvedAddress("Link Object Dependency Write", linkActorVarsWriteAddr + 8), ft);
                                loop = -1; break;
                            }

                            //check if pointer is going to do an unaligned write
                            if (linkActorVarsWriteAddr % 2 == 1)
                            {
                                WriteResult(result, record, setup.SceneSetup, ResultType.Crash,
                                            string.Format("N64: Unaligned SH write to address {0:X8}", linkActorVarsWriteAddr + 8), ft);
                            }
                            sceneStr.BaseStream.Position = seekBack;
                            break;
                        }

                        case 0x17:
                        {
                            sceneStr.BaseStream.Position += 4;
                            sceneHeader.Cutscene          = sceneStr.ReadBigInt32();
                            break;
                        }

                        default: sceneStr.BaseStream.Position += 8; break;
                        }
                        if (loop == 0)
                        {
                            WriteResult(result, record, setup.SceneSetup, ResultType.Error, "Header Parse Error");
                        }
                    }
                }
            }
            face.OutputText(result.ToString());
            return(result);
        }