예제 #1
0
        private void splitROM_Click(object sender, EventArgs e)
        {
            GC.Collect();

            OpenFileDialog openFileDialog1 = new OpenFileDialog();

            openFileDialog1.Filter = "ROM File|*.z64";
            openFileDialog1.Title  = "Select a ROM";

            if (openFileDialog1.ShowDialog() != System.Windows.Forms.DialogResult.OK)
            {
                return;
            }

            string path = openFileDialog1.FileName;

            path = Path.GetFullPath(path);

            ROM rom    = new ROM(File.ReadAllBytes(path));
            int offset = Convert.ToInt32(addressTextBox.Text, 16);

            if (offset == 0)
            {
                MessageBox.Show("Failed to parse address, input correct address", "Level Split", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            List <Region> regions = new List <Region>();

            // 1st pass : find out where regions are
            LevelScript.PerformRegionParse(rom, regions, offset, checkBoxOldScrolls.Checked);

            foreach (Region region in regions)
            {
                Console.WriteLine(GetTab(region.state) + "Region {0:x} {1:x} {2:x}", region.romStart, region.romStart + region.length, region.state.ToString());
            }

            // 2nd pass : with known regions, relocate data
            // GraphicsData position independent
            // Collision    position independent
            // DisplayList to 0E000000 of GraphicsData
            // GeoLayout   to 0E000000 of DisplayList
            // AreaHeader  to 19000000 of GeoLayout
            // ObjectsLoad to 19000000 of GeoLayout
            // AreaFooter  to 0E000000 of Collision
            StaticRelocationTable table = new StaticRelocationTable();

            foreach (Region region in regions)
            {
                RelocationUnit unit = new RelocationUnit(region, rom, isFromStatic: false);
                table.AddUnit(unit);
            }

            // Fill in data from rom
            foreach (Region region in regions)
            {
                region.data = new byte[region.length];
                rom.ReadData(region.romStart, region.length, region.data);
            }

            SortedSet <int> areasTrimmed = new SortedSet <int>();

            // Trim AreaData if flag is checked
            foreach (Region region in regions)
            {
                if (region.state != RegionState.AreaData && region.state != RegionState.AreaScrolls)
                {
                    continue;
                }

                ObjectsTrimmer.Trim(region, !areasTrimmed.Contains(region.area));
                areasTrimmed.Add(region.area);
            }

            // Relocate!
            foreach (Region region in regions)
            {
                try
                {
                    region.Relocate(table);
                }
                catch (ArgumentException)
                {
                    string answer = String.Format("Region relocation failed for {0}", region.state);
                    if (region.area != -1)
                    {
                        answer += String.Format(", area {0}", region.area);
                    }
                    if (region.model != -1)
                    {
                        answer += String.Format(", model {0}", region.model);
                    }
                    answer += ", region might be broken";

                    MessageBox.Show(answer, "Level Split", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
            }

            Dictionary <RegionState, int> dictionary = new Dictionary <RegionState, int>();

            foreach (RegionState state in (RegionState[])Enum.GetValues(typeof(RegionState)))
            {
                dictionary[state] = 0;
            }

            string dirPostfix            = addressTextBox.Text;
            int    levelScriptEntryPoint = Convert.ToInt32(addressTextBox.Text, 16);

            if (LevelInfo.IsValidLevelScriptEntry(levelScriptEntryPoint))
            {
                dirPostfix = (LevelInfo.GetLevel(levelScriptEntryPoint) + 1).ToString();
            }

            string dirname = Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path), dirPostfix);

            if (deleteFolderCheckbox.Checked)
            {
                if (Directory.Exists(dirname))
                {
                    DialogResult result = MessageBox.Show(String.Format("Path {0} already exists! Delete it anyways?", dirname), "Warning", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);
                    if (result == DialogResult.OK)
                    {
                        Directory.Delete(dirname, true);
                    }
                    else
                    {
                        return;
                    }
                }
            }

            Directory.CreateDirectory(dirname);
            SortedSet <string> truncatedFiles = new SortedSet <string>();

            foreach (Region region in regions)
            {
                switch (region.state)
                {
                case RegionState.LevelHeader:
                    if (!levelHeaderCheckbox.Checked)
                    {
                        continue;
                    }
                    break;

                case RegionState.LevelFooter:
                    if (!levelFooterCheckbox.Checked)
                    {
                        continue;
                    }
                    break;

                case RegionState.ModelsLoader:
                    if (!modelsDescriptorCheckbox.Checked)
                    {
                        continue;
                    }
                    break;

                case RegionState.AreaHeader:
                    if (!areaHeaderCheckbox.Checked)
                    {
                        continue;
                    }
                    break;

                case RegionState.AreaData:
                case RegionState.AreaScrolls:
                    if (!areaObjectsDataCheckbox.Checked)
                    {
                        continue;
                    }
                    break;

                case RegionState.AreaFooter:
                    if (!areaFooterCheckbox.Checked)
                    {
                        continue;
                    }
                    break;

                case RegionState.GeoLayout:
                case RegionState.DisplayList:
                case RegionState.GraphicsData:
                    if (region.area != -1)
                    {
                        if (!areaGraphicsCheckBox.Checked)
                        {
                            continue;
                        }
                    }
                    else if (region.model != -1)
                    {
                        if (!modelsGraphicsCheckbox.Checked)
                        {
                            continue;
                        }
                    }
                    break;

                case RegionState.Collision:
                    if (!levelCollisionCheckbox.Checked)
                    {
                        continue;
                    }
                    break;
                }

                string regionPath = null;
                try
                {
                    regionPath = PathComposer.ComposeName(dirname, region.state, region.area, region.model, region.number);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(String.Format("Failed to compose path for {0}, reason: {1}", region.state, ex.Message), "Level Split", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                if (regionPath == null)
                {
                    continue;
                }

                Directory.CreateDirectory(Path.GetDirectoryName(regionPath));

                //if (deleteFolderCheckbox.Checked && File.Exists(regionPath))
                //    throw new Exception("Such region was written already!");

                if (!truncatedFiles.Contains(regionPath))
                {
                    File.Delete(regionPath);
                    truncatedFiles.Add(regionPath);
                }
                else
                {
                    if (region.state != RegionState.ModelsLoader &&
                        region.state != RegionState.AreaData &&
                        region.state != RegionState.AreaScrolls)
                    {
                        MessageBox.Show(String.Format("Appending data from region {0}, this might be bug", region.state), "Level Split", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    }
                }

                using (var stream = new FileStream(regionPath, FileMode.Append))
                    stream.Write(region.data, 0, region.data.Length);
            }

            MessageBox.Show(String.Format("ROM was splitted successfully at {0}", dirname), "Level Split", MessageBoxButtons.OK, MessageBoxIcon.Information);
            splittedPathTextBox.Text = dirname;
            //regions.Sort((x, y) => x.start.CompareTo(y.start));
        }
예제 #2
0
        private void ParseGraphics(string dirname, DataBuilder segment0E, DataBuilder segmentGeoLayouts, ROM rom, out RelocationUnit unit, out RelocationUnit graphicsDataUnit, int area = -1, int model = -1)
        {
            RelocationUnit retValue     = null;
            RelocationUnit graphicsUnit = null;

            segmentGeoLayouts.Backup();
            segment0E.Backup();
            try
            {
                DynamicRegion graphicsDataRegion = new DynamicRegion(dirname, RegionState.GraphicsData, area, model);
                // no relocation needed for dynamic region
                segment0E.AddRegion(graphicsDataRegion);
                segment0E.RoundOffset();

                // Display lists needs to be relocated with static graphics relocation table
                StaticRelocationTable graphicsRelocationTable = new StaticRelocationTable();
                graphicsUnit = new RelocationUnit(graphicsDataRegion, rom, isFromStatic: true);
                graphicsRelocationTable.AddUnit(graphicsUnit);

                // Geolayouts needs to be relocated with queued display lists, will be filled during relocation with graphicsRelocationTable
                QueueRelocationTable dispRelocationTable = new QueueRelocationTable();

                RelocationUnit dispRelocationUnit = null;
                for (int dispNumber = 0; dispNumber < 0xFF; dispNumber++)
                {
                    if (!PathComposer.IsRegionFileExists(dirname, RegionState.DisplayList, area, model, dispNumber))
                    {
                        break;
                    }

                    DisplayListRegion dispRegion = new DisplayListRegion(dirname, area, model, dispNumber);
                    DisplayList.PerformRegionRelocation(dispRegion, graphicsRelocationTable);
                    segment0E.AddRegion(dispRegion);
                    segment0E.RoundOffset();

                    dispRelocationUnit = new RelocationUnit(dispRegion, rom, isFromStatic: true);
                    dispRelocationTable.AddUnit(dispRelocationUnit);
                }

                // Not even one disp relocation unit, sounds like a bug
                if (dispRelocationUnit == null)
                {
                    throw new IOException("No display lists found!");
                }

                // Geolayout might or might not exist for model, check if it exists and if needed, relocate it
                if (PathComposer.IsRegionFileExists(dirname, RegionState.GeoLayout, area, model))
                {
                    // Load geolayout and relocate it with display lists
                    GeoLayoutRegion modelGeoLayoutRegion = new GeoLayoutRegion(dirname, area, model);
                    GeoLayout.PerformRegionRelocation(modelGeoLayoutRegion, dispRelocationTable);
                    segmentGeoLayouts.AddRegion(modelGeoLayoutRegion);
                    segmentGeoLayouts.RoundOffset();

                    // Finalize with returning geolayout for model
                    retValue = new RelocationUnit(modelGeoLayoutRegion, rom, isFromStatic: true);
                }
                else
                {
                    // Return display list only, there should be only one, if more, it is undefinied behaviour :3
                    retValue = dispRelocationUnit;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(String.Format("Failed to load model {0}, reason : '{1}'", model, ex.Message), "Level Combiner", MessageBoxButtons.OK, MessageBoxIcon.Error);
                segment0E.Restore();
                segmentGeoLayouts.Restore();
            }

            unit             = retValue;
            graphicsDataUnit = graphicsUnit;
        }