Artentus / ModMyFactory2

Rewrite of ModMyFactory, the Factorio mod manager
GNU General Public License v3.0
56 stars 18 forks source link

Saving on linux #11

Closed Rihoj closed 4 years ago

Rihoj commented 4 years ago

I am trying to make a modpack, but when I close the window the application freezes during the save. I tried to get my system setup to be able to help debug the issue, but I am running into too many errors dealing with the dotnet framework (and I am not a dotnet or C# dev) trying to get it to build.

System and application information

Description: Ubuntu 20.04.1 LTS Release: 20.04 Codename: focal Application version: 2.2.0.11-alpha_standalone_linux64 Using only Steam Factorio 1.0 Mods preinstalled

Install steps:

  1. unzip standalone into ~/Downloads/2.2.0.11-alpha_standalone_linux64 dir.
  2. change permissions on file sudo chmod +x ~/Downloads/2.2.0.11-alpha_standalone_linux64/ModMyFactoryGUI
  3. Changed theme to dark mode
  4. Clicked add mods and added my current list found in ~/.factorio/mods
    • Construction Drones 0.6.11
    • Creative Mod 1.6
    • Factorio Library 0.3.1
    • Factorio Standard Library 1.4.4
    • Fluid Must Flow 1.2.9
    • FNEI 0.3.4
    • Helmod: assistant for planning your base 0.11
    • Krastorio 2 1.0.4
    • LTN - Logistic Train Network 1.14.1
    • Miniloader 1.11.3
    • Nanobots: Early Bots 3.2.8
    • Ultimate Belts_Owoshima_And_Pankeko-mod 0.18.1

Steps to reproduce

  1. Open application ~/Downloads/2.2.0.11-alpha_standalone_linux64/ModMyFactoryGUI
  2. Click New modpack name Vanilla Ext
  3. Drag over the following mods
    • Construction Drones 0.6.11
    • Factorio Library 0.3.1
    • Factorio Standard Library 1.4.4
    • Helmod: assistant for planning your base 0.11
    • LTN - Logistic Train Network 1.14.1
  4. Close application. At this point the logs say it is saving, but then nothing happens afterwords. The window becomes unresponsive.

Log Output:


[11:54:23 INF] Using ModMyFactory v1.1.0.57-alpha
[11:54:23 INF] Using ModMyFactory.BaseTypes v1.1.1.16-alpha
[11:54:23 INF] Using ModMyFactory.Export v1.0.0.18-alpha
[11:54:23 INF] Using ModMyFactory.Localization v1.0.0.6-alpha
[11:54:23 INF] Using ModMyFactory.ModSettings v1.0.0.17-alpha
[11:54:23 INF] Using ModMyFactory.WebApi v1.0.2.26-alpha
[11:54:23 INF] Using ModMyFactory.Win32 v1.0.0.10-alpha
[11:54:23 VRB] Application directory: /home/james/Downloads/2.2.0.11-alpha_standalone_linux64
[11:54:23 VRB] Data directory: /home/james/.modmyfactorygui
[11:54:23 DBG] Settings loaded:
    factorio_location: #appdata
    mod_location: #appdata
    language: en
    theme: BaseDark
    selected_instance: _home_james_.steam_steam_steamapps_common_factorio
    window_restore_state: 3972;32;1422;737
    manager_grid_length_1: 1*
    manager_grid_length_2: 1*
    online_grid_length_1: 1*
    online_grid_length_2: 1*
    online_sub_grid_length_1: 1*
    online_sub_grid_length_2: 1*
    window_maximized: False
[11:54:23 VRB] Successfully loaded Factorio Steam instance
[11:54:23 VRB] Successfully loaded mod miniloader version 1.11.3
[11:54:23 VRB] Successfully loaded mod FNEI version 0.3.4
[11:54:23 VRB] Successfully loaded mod Nanobots version 3.2.8
[11:54:23 VRB] Successfully loaded mod Krastorio2 version 1.0.4
[11:54:23 VRB] Successfully loaded mod FluidMustFlow version 1.2.9
[11:54:23 VRB] Successfully loaded mod Construction_Drones version 0.6.11
[11:54:23 VRB] Successfully loaded mod creative-mod version 1.6
[11:54:23 VRB] Successfully loaded mod flib version 0.3.1
[11:54:23 VRB] Successfully loaded mod LogisticTrainNetwork version 1.14.1
[11:54:23 VRB] Successfully loaded mod UltimateBelts_Owoshima_And_Pankeko-Mod version 0.18.1
[11:54:23 VRB] Successfully loaded mod stdlib version 1.4.4
[11:54:23 VRB] Successfully loaded mod helmod version 0.11
[11:54:23 VRB] Successfully loaded mod list file '/home/james/.modmyfactorygui/mods/0.18/mod-list.json'
[11:54:23 VRB] No mopacks to import
[11:54:23 INF] Language files successfully loaded. Available languages: English, German
[11:54:23 INF] Language set to English
[11:54:23 INF] Themes successfully loaded; available themes: BaseLight, BaseDark
[11:54:24 INF] Theme set to BaseDark
[11:54:24 DBG] Settings saved to '/home/james/.modmyfactorygui/settings.json'.
[11:54:24 VRB] GUI framework successfully initialized
[11:55:08 DBG] Application exited gracefully
[11:55:08 INF] Saving settings...
[11:55:08 DBG] Settings saved to '/home/james/.modmyfactorygui/settings.json'.```
Artentus commented 4 years ago

The log doesn't show any errors, which leads me to believe this is a Linux specific issue with the GUI (when the log reaches "Application exited gracefully" the GUI is supposed to already be closed entirely).

I recently got a new computer and haven't set up my Linux VM yet to test this, but I will as soon as I find the time to.
If you want to help me debug this (which would be greatly appreciated) try using Visual Studio Code with the C# plugin, that's what I'm using and getting it to compile should be fairly straightforward.

shelaf commented 4 years ago

I had the same problem on my Windows. The sync version of UnloadProgramAsync() worked fine on my Windows. Also, without buffering, modpacks.json got corrupted when the file size exceeded 32KB in debug build. But, release build still corrupted. This is my patch.

diff --git a/ModMyFactory.Export/Exporter.cs b/ModMyFactory.Export/Exporter.cs
index 720bf3f..f8a4db0 100644
--- a/ModMyFactory.Export/Exporter.cs
+++ b/ModMyFactory.Export/Exporter.cs
@@ -43,9 +43,9 @@ namespace ModMyFactory.Export
         private async Task ExportPackageAsync(FileInfo file)
         {
             string json = JsonConvert.SerializeObject(Package, Formatting.Indented);
-            using var stream = file.Open(FileMode.Create, FileAccess.Write);
-            using var writer = new StreamWriter(stream);
-            await writer.WriteAsync(json);
+            using var stream = new FileStream(file.FullName, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true);
+            var bytes = Encoding.UTF8.GetBytes(json);
+            await stream.WriteAsync(bytes, 0, bytes.Length);
         }

         private Task ExportArchiveAsync(FileInfo file)
diff --git a/ModMyFactoryGUI/Program.cs b/ModMyFactoryGUI/Program.cs
index 9cbcd68..47c5dcc 100644
--- a/ModMyFactoryGUI/Program.cs
+++ b/ModMyFactoryGUI/Program.cs
@@ -250,11 +250,11 @@ namespace ModMyFactoryGUI
             _modpacks = await LoadModpacksAsync();
         }

-        private static async Task UnloadProgramAsync()
+        private static void UnloadProgram()
         {
             Log.Information("Saving settings...");
             Settings.Save();
-            await SaveModpacksAsync();
+            SaveModpacks();
             Log.Information("Shutting down");
             Log.CloseAndFlush();
         }
@@ -357,7 +357,7 @@ namespace ModMyFactoryGUI
                         finally
                         {
                             SyncContext.EndListen();
-                            await UnloadProgramAsync();
+                            UnloadProgram();
                         }
                     }
                     else
@@ -508,25 +508,10 @@ namespace ModMyFactoryGUI
                 code = ErrorCode.GameStart_General;
             }

-            await UnloadProgramAsync();
+            UnloadProgram();
             return code;
         }

-        // This has not yet been implemented in the latest stable release of CommandLineParser so we have to paste it into here
-        private static Task<TResult> MapResultAsync<T1, T2, TResult>(ParserResult<object> result,
-            Func<T1, Task<TResult>> parsedFunc1,
-            Func<T2, Task<TResult>> parsedFunc2,
-            Func<IEnumerable<Error>, Task<TResult>> notParsedFunc)
-        {
-            if (result is Parsed<object> parsed)
-            {
-                if (parsed.Value is T1) return parsedFunc1((T1)parsed.Value);
-                if (parsed.Value is T2) return parsedFunc2((T2)parsed.Value);
-                throw new InvalidOperationException();
-            }
-            return notParsedFunc(((NotParsed<object>)result).Errors);
-        }
-
         // Initialization code. Don't use any Avalonia, third-party APIs or any
         // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
         // yet and stuff might break.
@@ -541,7 +526,7 @@ namespace ModMyFactoryGUI
             });
             var parsedOptions = parser.ParseArguments<RunOptions, StartGameOptions>(args);

-            var code = await MapResultAsync(parsedOptions,
+            var code = await parsedOptions.MapResult(
                 (RunOptions opts) => StartAppAsync(args, opts),
                 (StartGameOptions opts) => StartGameAsync(opts),
                 errors => Task.FromResult(ErrorCodeFactory.FromCommandLineErrors(errors)));
Rihoj commented 4 years ago

@shelaf Thank you for providing the code. Unfortunately, that did not work on my Linux machine. After playing with it for a little while I did find that this was all I had to change to get the window to close:

diff --git a/ModMyFactoryGUI/Program.cs b/ModMyFactoryGUI/Program.cs
index 9cbcd68..f09ee67 100644
--- a/ModMyFactoryGUI/Program.cs
+++ b/ModMyFactoryGUI/Program.cs
@@ -254,7 +254,7 @@ namespace ModMyFactoryGUI
         {
             Log.Information("Saving settings...");
             Settings.Save();
-            await SaveModpacksAsync();
+            SaveModpacksAsync();
             Log.Information("Shutting down");
             Log.CloseAndFlush();
         }

I also had issue with the modpacks.json file, and your code changes there fixed that issue.

Artentus commented 4 years ago

Everyone who had this issue, please try version 2.2.2

shelaf commented 4 years ago

Seems to be working fine on my Windows. Thanks!

Rihoj commented 4 years ago

@Artentus This does seem to be working for my machine.