Пример #1
0
        private void renderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var Node = GetSelectedFile();

            if (Node != null)
            {
                if (IsValidNode(Node))
                {
                    Log.Write("{0}: Rendering {1}.sav", GetType().Name, Node.Text);
                    using (var FS = File.OpenRead(GetName(Node)))
                    {
                        SaveFile F;
                        try
                        {
                            F = SaveFile.Open(FS);
                        }
                        catch (Exception ex)
                        {
                            Log.Write(new Exception("Attempted to render invalid file", ex));
                            InvalidMessage();
                            return;
                        }
                        PreviewFile(F);
                    }
                }
                else
                {
                    InvalidMessage();
                }
            }
        }
Пример #2
0
        public void OpenFile(string SaveFileName)
        {
            Log.Write("{0}: Loading {1}", GetType().Name, SaveFileName);
            try
            {
                using (var FS = File.OpenRead(SaveFileName))
                {
                    F = SaveFile.Open(FS);
                    if (F == null)
                    {
                        throw new InvalidDataException("We are unable to load your save file. It looks invalid.");
                    }
                    FileName    = SaveFileName;
                    HasChange   = false;
                    NameChanged = false;
                    if (S.ShowLimited)
                    {
                        S.ShowLimited = false;
                        MessageBox.Show(@"This is still in development and functionality is limited.
If something breaks, please open an issue on GitHub so we can fix it.", "Limited Functionality", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                    RedrawMap();
                    Log.Write("{0}: File loaded. {1} entries total", GetType().Name, F.Entries.Count);
                }
            }
            catch (Exception ex)
            {
                Log.Write(new Exception("Unable to load the save file", ex));
                Tools.E($"Unable to load the specified file\r\n{ex.Message}", "File read error");
            }
        }
        private void renderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var Node = GetSelectedFile();

            if (Node != null)
            {
                if (IsValidNode(Node))
                {
                    Log.Write("{0}: Rendering {1}.sav", GetType().Name, Node.Text);
                    using (var FS = File.OpenRead(GetName(Node)))
                    {
                        SaveFile F;
                        try
                        {
                            F = SaveFile.Open(FS);
                        }
                        catch (Exception ex)
                        {
                            Log.Write(new Exception("Attempted to render invalid file", ex));
                            InvalidMessage();
                            return;
                        }
                        using (var BMP = MapRender.RenderFile(F))
                        {
                            using (var frm = new Form())
                            {
                                frm.Text                  = "Preview of " + Node.Text;
                                frm.ShowIcon              = frm.ShowInTaskbar = false;
                                frm.WindowState           = FormWindowState.Maximized;
                                frm.BackgroundImageLayout = ImageLayout.Zoom;
                                frm.BackgroundImage       = BMP;
                                Tools.SetupEscHandler(frm);
                                frm.ShowDialog();
                            }
                        }
                    }
                }
                else
                {
                    InvalidMessage();
                }
            }
        }
Пример #4
0
        private void renameToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var Node = GetSelectedFile();

            if (Node != null)
            {
                FileStream FS = null;
                SaveFile   F  = null;
                try
                {
                    FS = File.OpenRead(GetName(Node));
                }
                catch (Exception ex)
                {
                    Log.Write(new Exception("Unable to rename the file", ex));
                    Tools.E($"Unable to rename the file.\r\n{ex.Message}", "File rename");
                    return;
                }
                using (FS)
                {
                    F = SaveFile.Open(FS);
                }
                if (F != null)
                {
                    using (var Ren = new frmRename(F.SessionName, Node.Text))
                    {
                        if (Ren.ShowDialog() == DialogResult.OK)
                        {
                            var NewName = Path.Combine(Path.GetDirectoryName(GetName(Node)), Ren.RenameFileName + ".sav");
                            //Show rename dialog if the file itself is renamed and the destination exists already
                            if (
                                Node.Text == Ren.RenameFileName ||
                                !File.Exists(NewName) ||
                                MessageBox.Show($"There is already a file named {Ren.RenameFileName}.sav. Overwrite this file?", "Confirm overwrite", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                            {
                                F.SessionName = Ren.RenameSessionName;
                                try
                                {
                                    FS = File.Create(NewName);
                                }
                                catch (Exception ex)
                                {
                                    Log.Write(new Exception("Unable to rename the file", ex));
                                    FS = null;
                                    Tools.E($"Unable to rename the file.\r\n{ex.Message}", "File rename");
                                }
                                if (FS != null)
                                {
                                    using (FS)
                                    {
                                        F.Export(FS);
                                        try
                                        {
                                            File.Delete(GetName(Node));
                                        }
                                        catch (Exception ex)
                                        {
                                            Log.Write(new Exception("Unable to delete the old copy", ex));
                                            Tools.E($"File renamed, but we are unable to delete the old copy. Please do so manually.\r\n{ex.Message}", "Unable to rename");
                                        }
                                        InitFiles();
                                    }
                                }
                            }
                        }
                    }
                }
                else
                {
                    InvalidMessage();
                }
            }
        }
Пример #5
0
        private void btnImport_Click(object sender, EventArgs e)
        {
            if (OFD.ShowDialog() == DialogResult.OK)
            {
                FileStream FS;
                try
                {
                    FS = File.OpenRead(OFD.FileName);
                }
                catch (Exception ex)
                {
                    Log.Write(new Exception($"Unable to import {OFD.FileName}", ex));
                    Tools.E($"Unable to open the selected file.\r\n{ex.Message}", "Import error");
                    return;
                }
                using (FS)
                {
                    var NewName = Path.GetFileName(OFD.FileName);
                    if (NewName.ToLower().Contains(".sav"))
                    {
                        //Make .sav the last part of the name
                        NewName = NewName.Substring(0, NewName.ToLower().LastIndexOf(".sav")) + ".sav";
                        if (NewName == ".sav")
                        {
                            NewName = "Import.sav";
                        }
                    }
                    else
                    {
                        //Add .sav extension because it's not there
                        NewName += ".sav";
                    }
                    //Make name unique
                    int i = 1;
                    while (File.Exists(Path.Combine(Program.SaveDirectory, NewName)))
                    {
                        NewName = NewName.Substring(0, NewName.Length - 4) + $"_{i++}.sav";
                    }

                    //Check if selected file is actually a (somewhat) valid save game
                    var F = SaveFile.Open(FS);
                    if (F == null)
                    {
                        NewName = Path.Combine(Program.SaveDirectory, NewName);
                        if (MessageBox.Show("This file doesn't looks like it's a save file. Import anyways?", "Incompatible file", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes)
                        {
                            //User decided to copy anyway. Decompress the file now as needed
                            FS.Seek(0, SeekOrigin.Begin);
                            if (Tools.IsGzFile(FS))
                            {
                                Log.Write("{0}: looks compressed: {1}", GetType().Name, OFD.FileName);
                                try
                                {
                                    using (var GZS = new GZipStream(FS, CompressionMode.Decompress))
                                    {
                                        //Try to manually decompress a few bytes before fully copying.
                                        //This will throw an exception for files that are not decompressable before the output file is created
                                        byte[] Data = new byte[100];
                                        int    R    = GZS.Read(Data, 0, Data.Length);
                                        using (var OUT = File.Create(NewName))
                                        {
                                            OUT.Write(Data, 0, R);
                                            GZS.CopyTo(OUT);
                                        }
                                    }
                                    InitFiles();
                                    FeatureReport.Used(FeatureReport.Feature.RestoreBackup);
                                }
                                catch (Exception ex)
                                {
                                    Log.Write(new Exception($"Unable to decompress {OFD.FileName}", ex));
                                    Tools.E($"File looks compressed, but we are unable to decompress it.\r\n{ex.Message}", "Decompression error");
                                }
                            }
                            else
                            {
                                Log.Write("{0}: Importing uncompressed {1}", GetType().Name, OFD.FileName);
                                //File is not compressed. Just copy as-is
                                using (var OUT = File.Create(NewName))
                                {
                                    FS.CopyTo(OUT);
                                    InitFiles();
                                }
                            }
                        }
                    }
                    else
                    {
                        //Supply the NewName path to have a name that's not a conflict by default
                        using (var Ren = new frmRename(F.SessionName, Path.GetFileNameWithoutExtension(NewName)))
                        {
                            if (Ren.ShowDialog() == DialogResult.OK)
                            {
                                NewName = Path.Combine(Program.SaveDirectory, Ren.RenameFileName + ".sav");
                                if (!File.Exists(NewName) || MessageBox.Show($"There is already a file named {Ren.RenameFileName}.sav. Overwrite this file?", "Confirm overwrite", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                                {
                                    F.SessionName = Ren.RenameSessionName;
                                    using (var OUT = File.Create(NewName))
                                    {
                                        F.Export(OUT);
                                    }
                                    InitFiles();
                                }
                                else
                                {
                                    Log.Write("{0}: import destination exists: User cancelled", GetType().Name);
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #6
0
        private void InitFiles()
        {
            tvFiles.Nodes.Clear();
            var    Sessions = new Dictionary <string, TreeNode>();
            Thread T        = new Thread(delegate()
            {
                foreach (var FileName in Directory.GetFiles(Program.SaveDirectory, "*.sav", SearchOption.AllDirectories))
                {
                    if (Disposing || IsDisposed)
                    {
                        return;
                    }
                    SaveFile F = null;
                    try
                    {
                        using (var FS = File.OpenRead(FileName))
                        {
                            F = SaveFile.Open(FS);
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Write(new Exception($"Invalid or locked save file: {FileName}", ex));
                    }

                    if (F != null)
                    {
                        //File is valid game file
                        TreeNode Node   = null;
                        var SessionName = string.IsNullOrWhiteSpace(F.SessionName) ? "<no name>" : F.SessionName;
                        if (Sessions.ContainsKey(SessionName))
                        {
                            Node = Sessions[SessionName];
                        }
                        else
                        {
                            Invoke((MethodInvoker) delegate()
                            {
                                Node = tvFiles.Nodes.Add(SessionName);
                                Sessions.Add(SessionName, Node);
                            });
                        }
                        Invoke((MethodInvoker) delegate()
                        {
                            var AddedNode = Node.Nodes.Add(Path.GetFileNameWithoutExtension(FileName));
                            AddedNode.Tag = new LocalFileView(FileName, true);
                            Node.ExpandAll();
                        });
                    }
                    else
                    {
                        //File is invalid game file
                        TreeNode InvalidNode = null;
                        if (Sessions.ContainsKey(""))
                        {
                            InvalidNode = Sessions[""];
                        }
                        else
                        {
                            Sessions[""]          = InvalidNode = new TreeNode("INVALID");
                            InvalidNode.ForeColor = Color.Red;
                            InvalidNode.BackColor = Color.Yellow;
                        }
                        var Invalid       = InvalidNode.Nodes.Add(Path.GetFileNameWithoutExtension(FileName));
                        Invalid.ForeColor = Color.Red;
                        Invalid.Tag       = new LocalFileView(FileName, false);
                    }
                }
                //Add invalid nodes on the bottom
                if (Sessions.ContainsKey(""))
                {
                    Log.Write("{0}: At least one invalid save file was found", GetType().Name);
                    Invoke((MethodInvoker) delegate()
                    {
                        if (Sessions[""].TreeView == null)
                        {
                            tvFiles.Nodes.Add(Sessions[""]);
                            Sessions[""].ExpandAll();
                        }
                    });
                }
            });

            T.Start();
        }
Пример #7
0
        private static void Test()
        {
            const string WHITELIST      = "/Buildable/|ResourceNode|ResourceDeposit";
            const string PROTECTED      = "MamIntegrated|HubTerminal|WorkBenchIntegrated|StorageIntegrated|GeneratorIntegratedBiomass";
            var          WLItems        = WHITELIST.Split('|');
            var          ProtectedItems = PROTECTED.Split('|');
            var          ZeroPos        = new Vector3();

            //Note to testers: Do not close the stream early. This protects you from overwriting the save file.
            using (var FS = File.OpenRead(Path.Combine(SaveDirectory, "Reset.sav")))
            {
                var F = SaveFile.Open(FS);

                var R = new Random();
                foreach (var E in F.Entries)
                {
                    if (E.EntryType == ObjectTypes.OBJECT_TYPE.OBJECT)
                    {
                        var o = (ObjectTypes.GameObject)E.ObjectData;
                        if (
                            !o.ObjectPosition.Equals(ZeroPos) &&
                            WLItems.Any(n => o.Name.Contains(n)) &&
                            !ProtectedItems.Any(n => o.Name.Contains(n)))
                        {
                            var newPos = Tools.TranslateToMap(new System.Drawing.PointF((float)R.NextDouble(), (float)R.NextDouble()));
                            newPos.Z         = 18000;
                            o.ObjectPosition = newPos;
                        }
                    }
                }

                //Show all entries
                Console.Error.WriteLine(string.Join("\r\n", F.Entries.OrderBy(m => m.Properties.Length).Select(m => m.ObjectData.Name).Distinct()));

                /* Test code to "align" things
                 * var o = (ObjectTypes.GameObject)e.ObjectData;
                 * o.ObjectPosition.X = (int)o.ObjectPosition.X;
                 * o.ObjectPosition.Y = (int)o.ObjectPosition.Y;
                 * o.ObjectPosition.Z = (int)o.ObjectPosition.Z;
                 *
                 * o.ObjectPosition.X -= o.ObjectPosition.X % 10;
                 * o.ObjectPosition.Y -= o.ObjectPosition.Y % 10;
                 * o.ObjectPosition.Z -= o.ObjectPosition.Z % 10;
                 * //o.ObjectRotation.W = o.ObjectRotation.X = o.ObjectRotation.Y = o.ObjectRotation.Z = 0;
                 * //Console.Error.WriteLine("{0} {1}", o.ObjectPosition, o.ObjectRotation);
                 * //*/

                /*
                 * //Duplicator test
                 * var BaseF = (SaveFileEntry)F.Entries.First(m => m.ObjectData.Name == "/Game/FactoryGame/Buildable/Building/Foundation/Build_Foundation_8x2_01.Build_Foundation_8x2_01_C").Clone();
                 * var BaseObject = (ObjectTypes.GameObject)BaseF.ObjectData;
                 * var BaseName = BaseObject.InternalName;
                 * BaseName = BaseName.Substring(0, BaseName.Length - 1);
                 * BaseObject.ObjectPosition.X = -324000;
                 * BaseObject.ObjectPosition.Y = -374000;
                 * BaseObject.ObjectPosition.Z = 18000;
                 *
                 * int ctr = F.Entries.Count(m => m.ObjectData.Name == "/Game/FactoryGame/Buildable/Building/Foundation/Build_Foundation_8x2_01.Build_Foundation_8x2_01_C");
                 * for (var x = 0; x < 940; x += 5)
                 * {
                 *  for (var y = 0; y < 940; y += 5)
                 *  {
                 *      var Copy = (SaveFileEntry)BaseF.Clone();
                 *      var o = (ObjectTypes.GameObject)Copy.ObjectData;
                 *      o.InternalName = BaseName + (ctr++).ToString();
                 *      o.ObjectPosition.X += x * 800;
                 *      o.ObjectPosition.Y += y * 800;
                 *      F.Entries.Add(Copy);
                 *  }
                 *  Console.Error.WriteLine(x);
                 * }
                 * Console.Error.WriteLine("Placed {0} foundations", ctr);
                 * //*/
                using (var FSOut = File.Create(Path.Combine(Environment.ExpandEnvironmentVariables(SAVEDIR), "Test-Edited.sav")))
                {
                    F.Export(FSOut);
                }
            }
        }
Пример #8
0
        private static int HandleArguments(string[] args)
        {
            var    Ops         = new List <Modes>();
            string Filename    = null;
            string SessionName = null;

            if (args.Contains("/?"))
            {
                Help();
                return(RET.HELP);
            }
            for (var i = 0; i < args.Length; i++)
            {
                var arg = args[i];
                Log.Write("{0}: processing argument: {1}", nameof(HandleArguments), arg);
                switch (arg.ToLower())
                {
                case "/verify":
                    Ops.Add(Modes.Verify);
                    break;

                case "/list":
                    Ops.Add(Modes.List);
                    break;

                case "/pack":
                    Ops.Add(Modes.Pack);
                    break;

                case "/render":
                    Ops.Add(Modes.Render);
                    break;

                case "/info":
                    Ops.Add(Modes.Info);
                    break;

                case "/rename":
                    Ops.Add(Modes.RenameSession);
                    if (i < args.Length - 1)
                    {
                        SessionName = args[++i];
                    }
                    else
                    {
                        Log.Write("{0}: /rename requires a new session name", nameof(HandleArguments));
                        Console.WriteLine("/rename requires a new session name");
                        return(RET.ARG);
                    }
                    break;

                default:
                    if (string.IsNullOrEmpty(Filename))
                    {
                        Filename = arg;
                    }
                    else
                    {
                        Log.Write("{0}: unknown argument: {1}", nameof(HandleArguments), arg);
                        Console.WriteLine("Unknown argument: {0}", arg);
                        return(RET.ARG);
                    }
                    break;
                }
            }

            if (Ops.Count == 0 && args.Length < 2)
            {
                return(RET.UI);
            }

            Tools.AllocConsole();

            if (string.IsNullOrEmpty(Filename))
            {
                Log.Write("{0}: No file name argument supplied", nameof(HandleArguments));
                Console.WriteLine("No file name argument supplied");
                return(RET.ARG);
            }

            Ops = Ops.Distinct().ToList();

            var        Changes = false;
            var        IsGz    = false;
            SaveFile   SF      = null;
            FileStream FS      = null;

            try
            {
                FS = File.Open(Filename, FileMode.Open, FileAccess.ReadWrite, FileShare.Read);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Unable to open input file");
                Log.Write("{0}: Unable to open input file", nameof(HandleArguments));
                Log.Write(ex);
                return(RET.IO);
            }
            using (FS)
            {
                IsGz = Tools.IsGzFile(FS);
                try
                {
                    SF = SaveFile.Open(FS);
                    if (SF == null)
                    {
                        throw new InvalidDataException("The file is not a valid satisfactory save game");
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Invalid game file");
                    Log.Write("{0}: Invalid game file", nameof(HandleArguments));
                    Log.Write(ex);
                    return(RET.IO);
                }


                if (Ops.Contains(Modes.Verify))
                {
                    Log.Write("{0}: Verifying file", nameof(HandleArguments));
                    //Verify does nothing on its own
                    Check(SF.PlayTime.Ticks >= 0, "Positive play time");
                    Check(Tools.IsMatch(SF.SessionName, @"^[\w\.\- ]{1,31}$"), "Non-Problematic Session Name");
                    Check(SF.LevelType == SaveFile.DEFAULT_LEVEL_TYPE, $"Level type is '{SaveFile.DEFAULT_LEVEL_TYPE}'");
                    Check(SF.SaveDate.ToUniversalTime() < DateTime.UtcNow, "Date in past");
                    foreach (var key in "sessionName Visibility startloc".Split(' '))
                    {
                        Check(SF.Properties.ContainsKey(key), $"Header contains field '{key}'");
                    }
                    //Don't double error with the previous one
                    if (SF.Properties.ContainsKey("sessionName"))
                    {
                        Check(SF.Properties["sessionName"] == SF.SessionName, "Both session names match");
                    }
                    else
                    {
                        Console.WriteLine("[SKIP]: Both session names match");
                    }
                }

                if (Ops.Contains(Modes.List))
                {
                    Log.Write("{0}: Printing item list", nameof(HandleArguments));
                    foreach (var e in SF.Entries.GroupBy(m => m.ObjectData.Name).OrderBy(m => m.Key))
                    {
                        Console.WriteLine("{1}\t{0}", e.Key, e.Count());
                    }
                }

                if (Ops.Contains(Modes.Render))
                {
                    var ImgFile = Path.ChangeExtension(Filename, ".png");
                    Log.Write("{0}: Rendering map as original size to {1}", nameof(HandleArguments), ImgFile);
                    Console.WriteLine("Initializing image...");
                    MapRender.Init(-1, -1);
                    Console.WriteLine("Rendering file...");
                    using (var IMG = MapRender.RenderFile(SF, 8.192))
                    {
                        Console.WriteLine("Saving image...");
                        IMG.Save(ImgFile);
                    }
                }

                if (Ops.Contains(Modes.Info))
                {
                    Log.Write("{0}: Showing game info", nameof(HandleArguments));
                    Console.WriteLine("Save File Size:\t{0}", FS.Position);
                    Console.WriteLine("Build Version:\t{0}", SF.BuildVersion);
                    Console.WriteLine("Save Version:\t{0}", SF.SaveVersion);
                    Console.WriteLine("Header Version:\t{0}", SF.SaveHeaderVersion);
                    Console.WriteLine("Session Name:\t{0}", SF.SessionName);
                    Console.WriteLine("Save Date:\t{0}", SF.SaveDate);
                    Console.WriteLine("Play Time:\t{0}", SF.PlayTime);
                    foreach (var KV in SF.Properties)
                    {
                        Console.WriteLine("{0}:\t{1}", KV.Key, KV.Value);
                    }
                    Console.WriteLine("Object Count:\t{0}", SF.Entries.Count);
                    Console.WriteLine("String List:\t{0}", SF.StringList.Count);
                }

                if (Ops.Contains(Modes.RenameSession))
                {
                    Log.Write("{0}: Renaming session to {1}", nameof(HandleArguments), SessionName);
                    SF.SetSessionName(SessionName);
                    Changes = true;
                }

                if (Ops.Contains(Modes.Pack))
                {
                    string     NewFile;
                    FileStream OUT;
                    FS.Seek(0, SeekOrigin.Begin);
                    if (IsGz)
                    {
                        if (Filename.ToLower().EndsWith(".sav.gz"))
                        {
                            NewFile = Path.ChangeExtension(Filename, null);
                        }
                        else
                        {
                            NewFile = Path.ChangeExtension(Filename, ".sav");
                        }
                    }
                    else
                    {
                        NewFile = Filename + ".gz";
                    }
                    try
                    {
                        OUT = File.Create(NewFile);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("Can't create output file");
                        Log.Write("{0}: Can't create {1}", nameof(HandleArguments), NewFile);
                        Log.Write(ex);
                        return(RET.IO);
                    }
                    Log.Write("{0}: {1} file", nameof(HandleArguments), IsGz ? "Compressing" : "Decompressing");
                    using (OUT)
                    {
                        if (IsGz)
                        {
                            Compression.DecompressStream(FS, OUT);
                        }
                        else
                        {
                            Compression.CompressStream(FS, OUT);
                        }
                    }
                    Log.Write("{0}: {1} file OK", nameof(HandleArguments), IsGz ? "Compressing" : "Decompressing");
                }
                if (Changes)
                {
                    Log.Write("{0}: Writing back changes", nameof(HandleArguments));
                    FS.Seek(0, SeekOrigin.Begin);
                    SF.Export(FS);
                    FS.Flush();
                    FS.SetLength(FS.Position);
                }
            }

            return(RET.SUCCESS);
        }