示例#1
0
        private void A_PatchGame(object sender, EventArgs e)
        {
            if (Process.GetProcessesByName("ScrapMechanic.exe").Length != 0)
            {
                MessageBox.Show("You cannot install mods while the game is running. Please close it first.", "Please close Scrap Mechanic", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            DialogResult box = MessageBox.Show("Have you verified the game cache?\n\nThis is necessary for the patching to work. Your game might stop working if you skipped the previous step.", "Are you sure?", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);

            if (box == DialogResult.Yes)
            {
                // Check for dependency issues
                foreach (ModInfo i in this.Mods)
                {
                    foreach (string dependency in i.Dependencies.Where((d) => !ModIDs.Contains(d)))
                    {
                        try
                        {
                            // Show error
                            string[] dependencyInfo = ModInfo.ParseModID(dependency);
                            MessageBox.Show("Error: Mod " + i.ModName + " requires you have the mod " + dependencyInfo[1] + " by " + dependencyInfo[0], "Mod dependency error");
                            return;
                        }
                        catch
                        { }
                    }
                }

                Dictionary <ModInfo, ZipFile> modZipFiles = new Dictionary <ModInfo, ZipFile>();
                try
                {
                    pbPatch.Value = 5;

                    // Load reader
                    GameReader reader = new GameReader(ScrapMechanicFolder);

                    // 1. Load physics materials
                    // 2. Load blocks
                    // 3. Load rotation sets
                    // 4. Load shapesets
                    // 5. Load inventory item descriptions
                    // 6. Load IconMap images
                    Dictionary <string, Material> materials = reader.ReadPhysicsMaterials();
                    pbPatch.Value = 6;
                    Dictionary <Guid, Block> blocks = reader.ReadBlocks(materials);
                    pbPatch.Value = 7;
                    Dictionary <string, RotationSet> rotationSets = reader.ReadRotationSets();
                    pbPatch.Value = 8;
                    Dictionary <string, ShapeSet> shapeSets = reader.ReadShapesets(rotationSets, materials);
                    pbPatch.Value = 9;
                    Dictionary <Guid, InventoryItemDescription> invItemDescs = reader.ReadInventoryItemDescriptions();
                    pbPatch.Value = 10;
                    Dictionary <Guid, Image> icons = reader.ReadIconMap();
                    pbPatch.Value = 11;

                    Dictionary <string, byte[]> resources = new Dictionary <string, byte[]>();

                    List <string> addedMaterials    = new List <string>();
                    List <Guid>   addedBlocks       = new List <Guid>();
                    List <string> addedRotationSets = new List <string>();
                    List <Guid>   addedInvItemDescs = new List <Guid>();
                    List <Guid>   addedIcons        = new List <Guid>();

                    // 7. Load for all mods mods those things in same order
                    string physicsMaterialsPath          = "Data/Objects/Database/physicsmaterials.json";
                    string blocksPath                    = "Data/Objects/Database/basicmaterials.json";
                    string shapeSetsListPath             = "Data/Objects/Database/shapesets.json";
                    string rotationSetsPath              = "Data/Objects/Database/rotationsets.json";
                    string inventoryItemDescriptionsPath = "Data/Gui/InventoryItemDescriptions.json";

                    foreach (ModInfo i in this.Mods)
                    {
                        modZipFiles[i] = ZipFile.Read(i.FileName);
                    }
                    pbPatch.Value = 15;

                    // Read physics materials
                    foreach (ZipFile zip in modZipFiles.Values)
                    {
                        // If the mod offers new Physics Materials
                        if (zip.ContainsEntry(physicsMaterialsPath))
                        {
                            // Read and parse the physics materials
                            Dictionary <string, Material> thisModMaterials = Material.ReadFromJson(Zip.ReadText(zip[physicsMaterialsPath]));
                            // Loop over each material
                            foreach (KeyValuePair <string, Material> kvp in thisModMaterials)
                            {
                                // If there is already a material with this name
                                if (!addedMaterials.Contains(kvp.Key))
                                {
                                    // Add the material to the material dictionary, and make sure it won't be overwritten
                                    materials[kvp.Key] = kvp.Value;
                                    addedMaterials.Add(kvp.Key);
                                }
                            }
                        }
                    }
                    pbPatch.Value = 20;

                    // Read rotation sets
                    foreach (ZipFile zip in modZipFiles.Values)
                    {
                        // If the mod offers new rotation sets
                        if (zip.ContainsEntry(rotationSetsPath))
                        {
                            // Read and parse the rotation sets
                            Dictionary <string, RotationSet> thisModRotationSets = RotationSet.ReadFromJson(Zip.ReadText(zip[rotationSetsPath]));

                            // Loop over each rotation set
                            foreach (KeyValuePair <string, RotationSet> kvp in thisModRotationSets)
                            {
                                // If there is already a rotation set with this name
                                if (!addedRotationSets.Contains(kvp.Key))
                                {
                                    // Add the rotation set to the rotation set dictionary, and make sure it won't be overwritten
                                    rotationSets[kvp.Key] = kvp.Value;
                                    addedRotationSets.Add(kvp.Key);
                                }
                            }
                        }
                    }
                    pbPatch.Value = 25;

                    // Read blocks
                    foreach (ZipFile zip in modZipFiles.Values)
                    {
                        // If the mod offers new rotation sets
                        if (zip.ContainsEntry(blocksPath))
                        {
                            // Read and parse the blocks
                            Dictionary <Guid, Block> thisModBlocks = Block.ReadFromJson(Zip.ReadText(zip[blocksPath]), materials);

                            // Loop over each block
                            foreach (KeyValuePair <Guid, Block> kvp in thisModBlocks)
                            {
                                // If there is already a block with this name
                                if (!addedBlocks.Contains(kvp.Key))
                                {
                                    // Add the block to the rotation set dictionary, and make sure it won't be overwritten
                                    blocks[kvp.Key] = kvp.Value;
                                    addedBlocks.Add(kvp.Key);
                                }
                            }
                        }
                    }
                    pbPatch.Value = 30;

                    // Load ShapeSets
                    foreach (ZipFile zipFile in modZipFiles.Values)
                    {
                        if (zipFile.ContainsEntry(shapeSetsListPath))
                        {
                            // Load the shape set list json to a dictionary
                            string sslJson = Zip.ReadText(zipFile[shapeSetsListPath]);
                            IDictionary <string, object> sslDict = JsonConvert.DeserializeObject <ExpandoObject>(sslJson);

                            // See if it has a shape set list
                            if (sslDict.ContainsKey("shapeSetList"))
                            {
                                // Loop over the shape set list
                                foreach (object lObj in (List <object>)sslDict["shapeSetList"])
                                {
                                    string shapeSetName = lObj.ToString();
                                    if (!shapeSets.ContainsKey(shapeSetName))
                                    {
                                        if (zipFile.ContainsEntry("Data/Objects/Database/ShapeSets/" + shapeSetName))
                                        {
                                            string shapeSetJson = Zip.ReadText(zipFile["Data/Objects/Database/ShapeSets/" + shapeSetName]);
                                            shapeSets[shapeSetName] = new ShapeSet(shapeSetName, shapeSetJson, rotationSets, materials);
                                        }
                                    }
                                    else
                                    {
                                        throw new Exception("There is already a ShapeSet named " + shapeSetName + ".\n\nIf you are the mod maker: To prevent name collisions, prefix your shapesets with your username, and give every ShapeSet in your mods a different name.");
                                    }
                                }
                            }
                        }
                    }
                    pbPatch.Value = 35;

                    // Load inventory items
                    foreach (ZipFile zip in modZipFiles.Values)
                    {
                        // If the mod has an Inventory Item Descriptions file
                        if (zip.ContainsEntry(inventoryItemDescriptionsPath))
                        {
                            // Load the description items
                            Dictionary <Guid, InventoryItemDescription> descs = InventoryItemDescription.ReadFromJson(Zip.ReadText(zip[inventoryItemDescriptionsPath]));
                            foreach (KeyValuePair <Guid, InventoryItemDescription> kvp in descs)
                            {
                                // If no (custom) description for this item exists yet; add one and make sure it won't be overwritten
                                if (!addedInvItemDescs.Contains(kvp.Key))
                                {
                                    addedInvItemDescs.Add(kvp.Key);
                                    invItemDescs[kvp.Key] = kvp.Value;
                                }
                            }
                        }
                    }
                    pbPatch.Value = 40;

                    // Load inventory icons
                    foreach (ZipFile zip in modZipFiles.Values)
                    {
                        // If this mod both has a icon information file ...
                        if (zip.ContainsEntry("Data/Gui/IconMap.json"))
                        {
                            // ... and an actual icon map
                            if (zip.ContainsEntry("Data/Gui/IconMap.png"))
                            {
                                // Load all the points into the iconPoints dictionary
                                IDictionary <string, object> imDict     = JsonConvert.DeserializeObject <ExpandoObject>(Zip.ReadText(zip["Data/Gui/IconMap.json"]));
                                Dictionary <Guid, Point>     iconPoints = new Dictionary <Guid, Point>();

                                foreach (KeyValuePair <string, object> kvp in imDict)
                                {
                                    Guid itemUuid;
                                    if (Guid.TryParse(kvp.Key.ToString(), out itemUuid))
                                    {
                                        IDictionary <string, object> objDict = kvp.Value as IDictionary <string, object>;
                                        if (objDict.ContainsKey("x") && objDict.ContainsKey("y"))
                                        {
                                            int x, y;
                                            if (int.TryParse(objDict["x"].ToString(), out x))
                                            {
                                                if (int.TryParse(objDict["y"].ToString(), out y))
                                                {
                                                    iconPoints.Add(itemUuid, new Point(x, y));
                                                }
                                            }
                                        }
                                    }
                                }

                                // Open the icon map picture
                                using (CrcCalculatorStream stream = zip["Data/Gui/IconMap.png"].OpenReader())
                                {
                                    try
                                    {
                                        using (Image iconMapImage = Image.FromStream(stream))
                                        {
                                            using (Bitmap iconMapImg = new Bitmap(iconMapImage))
                                            {
                                                // And for every item without a (custom) icon the icon image; and make sure it won't be overwritten by a lower mod
                                                foreach (KeyValuePair <Guid, Point> kvp in iconPoints.Where((p) => !addedIcons.Contains(p.Key)))
                                                {
                                                    int       x = kvp.Value.X, y = kvp.Value.Y;
                                                    Rectangle destination = new Rectangle(x, y, Math.Min(80, iconMapImg.Width - x), Math.Min(80, iconMapImg.Height - y));
                                                    Bitmap    newIcon     = iconMapImg.Clone(destination, iconMapImg.PixelFormat);
                                                    icons.Add(kvp.Key, newIcon);
                                                    addedIcons.Add(kvp.Key);
                                                }
                                            }
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        throw new Exception(ex.Message + " Image data invalid.");
                                    }
                                }
                            }
                            else
                            {
                                throw new Exception("Mod provides IconMap.json but no IconMap.png");
                            }
                        }
                    }
                    pbPatch.Value = 45;

                    // Load resources
                    foreach (KeyValuePair <ModInfo, ZipFile> pair in modZipFiles)
                    {
                        foreach (ZipEntry entry in pair.Value.Entries)
                        {
                            // For every entry that is not a shapeset
                            if (entry.FileName.StartsWith("Data/") && !entry.FileName.Contains("/ShapeSets/") && !entry.FileName.EndsWith("/"))
                            {
                                switch (entry.FileName)
                                {
                                // and also is not one of the files already read by
                                case "Data/Objects/Database/physicsmaterials.json":
                                case "Data/Objects/Database/basicmaterials.json":
                                case "Data/Objects/Database/shapesets.json":
                                case "Data/Objects/Database/rotationsets.json":
                                case "Data/Gui/InventoryItemDescriptions.json":
                                case "Data/Gui/IconMap.json":
                                    break;

                                default:
                                    // Find file name for in Scrap Mechanic/Data
                                    string dataFileName = entry.FileName.Substring(5);

                                    // Read bytes from resource file if no higher mod adds this resource as well
                                    if (!resources.ContainsKey(dataFileName))
                                    {
                                        using (BinaryReader r = new BinaryReader(entry.OpenReader()))
                                            resources[dataFileName] = r.ReadBytes((int)entry.UncompressedSize);
                                    }
                                    break;
                                }
                            }
                        }
                    }
                    pbPatch.Value = 50;

                    // Write everything to the game directory
                    GameWriter writer = new GameWriter(Properties.Settings.Default.ScrapMechanicFolder);

                    writer.WritePhysicsMaterials(materials);
                    pbPatch.Value = 60;
                    writer.WriteRotationSets(rotationSets);
                    pbPatch.Value = 70;
                    writer.WriteInventoryItemDescriptions(invItemDescs);
                    pbPatch.Value = 80;
                    writer.WriteBlocks(blocks);
                    pbPatch.Value = 85;
                    writer.WriteResources(resources);
                    pbPatch.Value = 90;
                    writer.WriteIcons(icons);
                    pbPatch.Value = 95;
                    writer.WriteShapesets(shapeSets);
                    pbPatch.Value = 100;

                    DialogResult r2 = MessageBox.Show("All " + this.Mods.Count + " mods are now installed. Do you want to start Scrap Mechanic to test it?", "Mods installed", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
                    if (r2 == System.Windows.Forms.DialogResult.Yes)
                    {
                        Process.Start("steam://rungameid/387990");
                    }
                }
                catch (Exception ex) {
                    MessageBox.Show("An exception occurred while loading the mods.\n\n" + ex.Message + "\n\n" + ex.Source + "\n\n" + ex.StackTrace, "An error occurred", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    Console.WriteLine(ex.Message + " on " + ex.Source);
                }
                finally
                {
                    foreach (ZipFile f in modZipFiles.Values)
                    {
                        f.Dispose();
                    }

                    btnPatchGame.Enabled = false;
                }
            }
        }
示例#2
0
        void AddMod(string fileName)
        {
            if (File.Exists(fileName))
            {
                FileInfo i           = new FileInfo(fileName);
                string   newFileName = Path.GetFileNameWithoutExtension(fileName);
                string   nP          = Path.Combine(this.ScrapMechanicFolder, "Scrapcenter", "Mods", newFileName + ".scrapmod");
                if (File.Exists(nP))
                {
                    FileInfo npI = new FileInfo(nP);
                    if (npI.FullName != i.FullName)
                    {
                        ModInfo q = null;
                        foreach (ModInfo mI in this.Mods)
                        {
                            if (mI.FileName.Equals(fileName))
                            {
                                q = mI;
                            }
                        }

                        if (q != null)
                        {
                            DialogResult r = MessageBox.Show("A mod already exists with this file name. Do you want to overwrite it?", "Confirm overwrite", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
                            if (r == DialogResult.Yes)
                            {
                                RemoveMod(q);
                            }
                            else
                            {
                                return;
                            }
                        }
                        else
                        {
                            File.Delete(nP);
                        }
                    }

                    if (File.Exists(nP))
                    {
                        File.Delete(nP);
                    }
                }

                File.Copy(fileName, nP);

                if (LoadMod(nP))
                {
                    MessageBox.Show("The mod was sucessfully added!", "Mod added", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                else
                {
                    MessageBox.Show("Could not load the mod. The following exception occurred:\n\n" + this.latestException.Message, "Mod error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            else
            {
                MessageBox.Show("This mod does not exist or is not readable.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
示例#3
0
 void RemoveMod(ModInfo mod)
 {
     File.Delete(mod.FileName);
     this.Mods.Remove(mod);
     this.ModIDs.Remove(mod.ToString());
 }