KSP-ModularManagement / KSPe

Extensions and utilities for Kerbal Space Program
http://ksp.lisias.net/add-ons/KSPAPIExtensions
Other
11 stars 5 forks source link

TweakScale stopped working in Proton #31

Closed lion328 closed 2 years ago

lion328 commented 2 years ago

Hi! I played KSP in Proton and just updated TweakScale to v2.4.6.13, and it doesn't work anymore. Here's the full log: KSP_tweakscale.log. An excerpt:

[LOG 04:48:09.935] [TweakScale] ERROR: System.TypeInitializationException: The type initializer for 'KSPe.IO.Hierarchy`1' threw an exception. ---> System.TypeInitializationException: The type initializer for 'KSPe.IO.Hierarchy' threw an exception. ---> System.IO.IOException: Invalid handle to path ""
  at Microsoft.Win32.NativeMethods.DuplicateHandle (System.Runtime.InteropServices.HandleRef hSourceProcessHandle, System.Runtime.InteropServices.SafeHandle hSourceHandle, System.Runtime.InteropServices.HandleRef hTargetProcess, Microsoft.Win32.SafeHandles.SafeWaitHandle& targetHandle, System.Int32 dwDesiredAccess, System.Boolean bInheritHandle, System.Int32 dwOptions) [0x0003c] in <ef151b6abb5d474cb2c1cb8906a8b5a4>:0 
  at System.Diagnostics.ProcessWaitHandle..ctor (Microsoft.Win32.SafeHandles.SafeProcessHandle processHandle) [0x0001f] in <ef151b6abb5d474cb2c1cb8906a8b5a4>:0 
  at (wrapper remoting-invoke-with-check) System.Diagnostics.ProcessWaitHandle..ctor(Microsoft.Win32.SafeHandles.SafeProcessHandle)
  at System.Diagnostics.Process.WaitForExit (System.Int32 milliseconds) [0x0001d] in <ef151b6abb5d474cb2c1cb8906a8b5a4>:0 
  at System.Diagnostics.Process.WaitForExit () [0x00000] in <ef151b6abb5d474cb2c1cb8906a8b5a4>:0 
  at (wrapper remoting-invoke-with-check) System.Diagnostics.Process.WaitForExit()
  at KSPe.Multiplatform.Shell.command (System.String command, System.String commandline) [0x00063] in <e2e8454864a846eaafbb2a8f98ed19c4>:0 
  at KSPe.Multiplatform.FileSystem.Reparse_readlink (System.String path) [0x00017] in <e2e8454864a846eaafbb2a8f98ed19c4>:0 
  at KSPe.Multiplatform.FileSystem.ReparsePath (System.String path) [0x00007] in <e2e8454864a846eaafbb2a8f98ed19c4>:0 
  at KSPe.IO.Directory.RealPath (System.String path) [0x0001f] in <e2e8454864a846eaafbb2a8f98ed19c4>:0 
  at KSPe.IO.Directory.Exists (System.String path) [0x00000] in <e2e8454864a846eaafbb2a8f98ed19c4>:0 
  at KSPe.IO.Path.EnsureTrailingSeparatorOnDir (System.String path, System.Boolean blindlyAppend) [0x00033] in <e2e8454864a846eaafbb2a8f98ed19c4>:0 
  at KSPe.IO.Path.Combine (System.String path1, System.String path2) [0x00007] in <e2e8454864a846eaafbb2a8f98ed19c4>:0 
  at KSPe.IO.Hierarchy..cctor () [0x00041] in <e2e8454864a846eaafbb2a8f98ed19c4>:0 
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---
  at (wrapper managed-to-native) System.Object.__icall_wrapper_mono_generic_class_init(intptr)
  at KSPe.Util.SystemTools+Assembly+Loader`1[T].TryPath (System.String path, System.String[] subdirs) [0x00000] in <e2e8454864a846eaafbb2a8f98ed19c4>:0 
  at KSPe.Util.SystemTools+Assembly+Loader.buildSearchPath (System.String[] subdirs) [0x00018] in <e2e8454864a846eaafbb2a8f98ed19c4>:0 
  at KSPe.Util.SystemTools+Assembly+Loader..ctor (System.String namespace, System.String effectivePath, System.String[] subdirs) [0x00014] in <e2e8454864a846eaafbb2a8f98ed19c4>:0 
  at KSPe.Util.SystemTools+Assembly+Loader`1[T]..ctor (System.String[] subdirs) [0x00006] in <e2e8454864a846eaafbb2a8f98ed19c4>:0 
  at TweakScale.Startup.Start () [0x00018] in <a8150fb7e3fc46cbb24418cf77184a20>:0  at error:0

As far as I understand, there are no error other than this one in the log. TweakScale v2.4.6.12 also have the same issue. Latest version that works for me is v2.4.6.11. For the test, I only installed TweakScale, Module Manager, and KSP-Recall, so I don't think this is a conflict from other mods.

The same issue also appeared in Distant Object Enhancement: KSP_distantobject.log. From the log:

[EXC 05:16:53.740] IOException: Invalid handle to path ""
    Microsoft.Win32.NativeMethods.DuplicateHandle (System.Runtime.InteropServices.HandleRef hSourceProcessHandle, System.Runtime.InteropServices.SafeHandle hSourceHandle, System.Runtime.InteropServices.HandleRef hTargetProcess, Microsoft.Win32.SafeHandles.SafeWaitHandle& targetHandle, System.Int32 dwDesiredAccess, System.Boolean bInheritHandle, System.Int32 dwOptions) (at <ef151b6abb5d474cb2c1cb8906a8b5a4>:0)
    System.Diagnostics.ProcessWaitHandle..ctor (Microsoft.Win32.SafeHandles.SafeProcessHandle processHandle) (at <ef151b6abb5d474cb2c1cb8906a8b5a4>:0)
    (wrapper remoting-invoke-with-check) System.Diagnostics.ProcessWaitHandle..ctor(Microsoft.Win32.SafeHandles.SafeProcessHandle)
    System.Diagnostics.Process.WaitForExit (System.Int32 milliseconds) (at <ef151b6abb5d474cb2c1cb8906a8b5a4>:0)
    System.Diagnostics.Process.WaitForExit () (at <ef151b6abb5d474cb2c1cb8906a8b5a4>:0)
    (wrapper remoting-invoke-with-check) System.Diagnostics.Process.WaitForExit()
    KSPe.Multiplatform.Shell.command (System.String command, System.String commandline) (at <c7e3f03c2c4a4d39aa5781c5f1ea7470>:0)
    KSPe.Multiplatform.FileSystem.Reparse_readlink (System.String path) (at <c7e3f03c2c4a4d39aa5781c5f1ea7470>:0)
    KSPe.Multiplatform.FileSystem.ReparsePath (System.String path) (at <c7e3f03c2c4a4d39aa5781c5f1ea7470>:0)
    KSPe.IO.Directory.RealPath (System.String path) (at <c7e3f03c2c4a4d39aa5781c5f1ea7470>:0)
    KSPe.IO.Directory.Exists (System.String path) (at <c7e3f03c2c4a4d39aa5781c5f1ea7470>:0)
    KSPe.IO.Path.EnsureTrailingSeparatorOnDir (System.String path, System.Boolean blindlyAppend) (at <c7e3f03c2c4a4d39aa5781c5f1ea7470>:0)
    KSPe.IO.Path.Combine (System.String path1, System.String path2) (at <c7e3f03c2c4a4d39aa5781c5f1ea7470>:0)
    KSPe.IO.Hierarchy..cctor () (at <c7e3f03c2c4a4d39aa5781c5f1ea7470>:0)
    Rethrow as TypeInitializationException: The type initializer for 'KSPe.IO.Hierarchy' threw an exception.
    KSPe.IO.Directory.Exists (System.String path) (at <c7e3f03c2c4a4d39aa5781c5f1ea7470>:0)
    KSPe.IO.Path.EnsureTrailingSeparatorOnDir (System.String path, System.Boolean blindlyAppend) (at <c7e3f03c2c4a4d39aa5781c5f1ea7470>:0)
    KSPe.IO.Path.GetAbsolutePath (System.String path, System.Boolean iKnowItsDir) (at <c7e3f03c2c4a4d39aa5781c5f1ea7470>:0)
    KSPe.IO.Path.GetAbsolutePath (System.String path) (at <c7e3f03c2c4a4d39aa5781c5f1ea7470>:0)
    KSPe.IO.Path.Origin () (at <c7e3f03c2c4a4d39aa5781c5f1ea7470>:0)
    KSPe.Util.Installation.CheckForWrongDirectoy (System.Type type, System.String name, System.String folder, System.String vendor) (at <c7e3f03c2c4a4d39aa5781c5f1ea7470>:0)
    KSPe.Util.Installation.Check[T] (System.String name, System.String folder, System.String vendor, System.Boolean unique) (at <c7e3f03c2c4a4d39aa5781c5f1ea7470>:0)
    KSPe.Util.Installation.Check[T] (System.Type versionClass, System.Boolean unique) (at <c7e3f03c2c4a4d39aa5781c5f1ea7470>:0)
    KSPe.Util.Installation.Check[T] (System.Boolean unique) (at <c7e3f03c2c4a4d39aa5781c5f1ea7470>:0)
    KSPe.Util.Installation.Check[T] () (at <c7e3f03c2c4a4d39aa5781c5f1ea7470>:0)
    DistantObject.Startup.Awake () (at <ea4997941b57493a9cea25f0991e3b97>:0)
    UnityEngine.DebugLogHandler:LogException(Exception, Object)
    ModuleManager.UnityLogHandle.InterceptLogHandler:LogException(Exception, Object)
    UnityEngine.GameObject:AddComponent(Type)
    AddonLoader:StartAddon(LoadedAssembly, Type, KSPAddon, Startup)
    AddonLoader:StartAddons(Startup)
    <LoadObjects>d__90:MoveNext()
    UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
    <CreateDatabase>d__71:MoveNext()
    UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
    GameDatabase:StartLoad()
    <LoadSystems>d__11:MoveNext()
    UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
    LoadingScreen:Start()

I did a little digging and I suspect that this KSPe commit caused the issue, but I didn't have a setup in order to bisect it. Anyway, I don't think Reparse_readlink should be called inside Proton. I guess the sandbox Proton uses mapped /usr/bin to Z:\usr\bin and the mod found readlink in there (I wonder if this can happen in Windows if I put readlink in C:\usr\bin).

OS: Arch Linux x86_64 Proton 7.0-2 (experimental also didn't work)

Lisias commented 2 years ago

Hi @lion328 !

Yeah, it makes sense. This is related to https://github.com/net-lisias-ksp/KSPe/issues/25 by the way.

The KSPe.Light thingy behaves, it uses the host system's path separator as defined on the C# runtime. Since you are running Proton, the C# runtime believes it's a Windows machine and so KSPe.Light uses "\" as path separator.

IMHO this is a bug on Proton itself - it should be aware of that and somehow tell the Mono's runtime in use to use the "/" as path separator instead - or perhaps applying to the paths it receives from Mono the same handling done when receiving a path from a Windows native code.

There's a reason you are using Proton instead of the native Linux release of KSP?

Lisias commented 2 years ago

Moving this to KSPe, as this is related to KSPe.Light.

Lisias commented 2 years ago

@lion328

Anyway, I don't think Reparse_readlink should be called inside Proton. I guess the sandbox Proton uses mapped /usr/bin to Z:\usr\bin and the mod found readlink in there (I wonder if this can happen in Windows if I put readlink in C:\usr\bin).

In time, it's not. Under Windows, native Windows32 calls are made to do the job (see this link for details).

Your problem is (almost surely) related to #25 (the "\" versus "/" thingy).

lion328 commented 2 years ago

I done more tests today and found out that Proton can run Linux executables inside Windows apps, so part of it is probably a bug when Windows version of Mono run inside Proton. However, I don't see it is the same bug in #25. The last stack trace is similar but it came from a Linux version of Mono, while I use a Windows version of it (inside Proton).

The real problem, in my opinion, is the way the mod detects readlink/realpath here. When run inside *nix systems (and not inside Proton),Directory.GetFiles is working properly. On the other hand, if this run inside WIndows, paths with / in the front are interpreted as the root of the drive, so /usr/bin will become C:\usr\bin if I run KSP from C: drive. This means that I can rename an executable (or anything really) to readlink, put it in C:\usr\bin, and the mod will run it, even in Windows. This is definitely not a Proton bug, but Proton mapped the Linux filesystem to Z: drive, which is why Z:\usr\bin\readlink was detected in the first place. It would be better if the mod check if it's running in Windows first before choosing which method to use.

There's a reason you are using Proton instead of the native Linux release of KSP?

For KSP it just a matter of preference really. I mean it ran pretty well so why not? Some games have an inferior Linux version or worse mod support, so I stopped deciding on this and just run the Windows version whenever I can.

Lisias commented 2 years ago

The real problem, in my opinion, is the way the mod detects readlink/realpath here. When run inside *nix systems (and not inside Proton),Directory.GetFiles is working properly. On the other hand, if this run inside WIndows, paths with / in the front are interpreted as the root of the drive, so /usr/bin will become C:\usr\bin if I run KSP from C: drive. This means that I can rename an executable (or anything really) to readlink, put it in C:\usr\bin, and the mod will run it, even in Windows. This is definitely not a Proton bug, but Proton mapped the Linux filesystem to Z: drive, which is why Z:\usr\bin\readlink was detected in the first place. It would be better if the mod check if it's running in Windows first before choosing which method to use.Linux version or worse mod support, so I stopped deciding on this and just run the Windows version whenever I can.

Nope. Absolutely most of the users are running on Windows, if you were right about that code running under Windows, then I would have a lot of complains.

There's a check at runtime to see if the code is being running under a *nix or Windows, and the code you pinpointed is not used when running on Windows.

If it is being used when running on a Windows environment under Proton, it's because somehow Proton failed to fool the Mono runtime to believe it's under Windows.

https://github.com/net-lisias-ksp/KSPe/blob/2253c080a41f2d5c5161bf769b09f6126684506a/Source/KSPe/Multiplatform/FileSystem.cs#L126

So, unless you can reproduce the problem under Windows (and then it would be a failure on the code that detects the environment), we have a missing use case on Proton itself.

Lisias commented 2 years ago

Suggested reading:

https://github.com/mono/mono/blob/main/mcs/class/System.Core/System/Util.cs

lion328 commented 2 years ago

Nope. Absolutely most of the users are running on Windows, if you were right about that code running under Windows, then I would have a lot of complains.

Let me be the first one to complain, then. I understand that this is a niche problem, which is why you don't have any complaint about this, and it's just a warning in Windows.

I did what I described before in Windows (basically saved an empty file to G:\usr\bin\readlink) and here's the result:

[KSPe] WARNING: Reparse_readlink got a ApplicationName='/usr/bin\readlink', CommandLine='-n "G:\ksptest\GameData\__LOCAL"', CurrentDirectory='', Native error= %1 is not a valid Win32 application.

Full log if you're interested: KSP.log

So yes, KSPe tried to use readlink in Windows. It's because readlink detection is run regardless of OS. It didn't failed catastrophically but it's an unintended behavior (IMO) regardless. Fortunately, the fix is the same for both Proton and Windows. If you didn't want to support Proton, that's fine, but this clearly happens in Windows too.

Now, you might think that this is not a normal thing normal users will do, but I can think of a valid situation for this too. If I have a dual boot setup between Windows and Linux, and for some reason I run games from a Linux partition (from a single partition setup), then I would have this exact problem.

There's a check at runtime to see if the code is being running under a *nix or Windows, and the code you pinpointed is not used when running on Windows.

I don't see why it will not run in Windows (and the fact that it was running from my testing). Since the code is inside the static constructor, it's always run when the class is loaded. That's why I said that it tried to find readlink in Windows too.

If it is being used when running on a Windows environment under Proton, it's because somehow Proton failed to fool the Mono runtime to believe it's under Windows.

https://github.com/net-lisias-ksp/KSPe/blob/2253c080a41f2d5c5161bf769b09f6126684506a/Source/KSPe/Multiplatform/FileSystem.cs#L126

I'm pretty sure Proton will pass this check, but it never had a chance to run it in the first place since KSPe detected a file named "readlink" and run this line first:

https://github.com/net-lisias-ksp/KSPe/blob/2253c080a41f2d5c5161bf769b09f6126684506a/Source/KSPe/Multiplatform/FileSystem.cs#L124

All I ask at this point really is just for you to swap these two lines, and the problem (both in WIndows and Proton) will be gone. It would be better if you just put a check inside the static constructor instead, but it's your call.

lion328 commented 2 years ago

Also, I tested your claim about Proton failed to fool to be Windows by using this code (which copied from here):

using System;

public class WindowsCheck
{
    public static bool IsThisWindows => ((int)System.Environment.OSVersion.Platform < 4);

    public static void Main(string[] args)
    {
        Console.WriteLine(IsThisWindows);
    }
}

Linux:

$ mono windowschk.exe 
False

Proton:

$ STEAM_COMPAT_CLIENT_INSTALL_PATH=/run/media/lion328/Games/Steam STEAM_COMPAT_DATA_PATH="/run/media/lion328/Games/Steam/steamapps/compatdata/220200" WINEPREFIX=$PWD /run/media/lion328/Games/Steam/steamapps/common/Proton\ 7.0/proton run windowschk.exe
fsync: up and running.
wine: RLIMIT_NICE is <= 20, unable to use setpriority safely
True

So it works correctly and LowLevelTools.Windows.IsThisWindows will be true inside Proton.

Lisias commented 2 years ago

So it works correctly and LowLevelTools.Windows.IsThisWindows will be true inside Proton.

Now I'm worried. Because if LowLevelTools.Windows.IsThisWindows is True, and yet readlink is being called, I have a serious flaw somewhere on the code.

I'm checking it.

Lisias commented 2 years ago

JESUS CHRIST - I was completely biased on the problem and failed to read the code with the proper critical mindset.

30 seconds of proper reading the code was all what I had needed to detect and solve the issue.

Fixed on https://github.com/net-lisias-ksp/KSPe/commit/c7fe090eaf89b2873f493e75ad7a123a59df5f08

Lisias commented 2 years ago

KSPe 2.4.1.16 was released with the fix.

Hotfixes for the following Add'Ons are available for download on the respective releases:

@lion328 , thank you very much for your patience!

Cheers!

Lisias commented 2 years ago

(I will keep this open waiting for the confirmation of the fix)

lion328 commented 2 years ago

Tried on Proton and it works now. Thanks!

Lisias commented 2 years ago

Tried on Proton and it works now. Thanks!

Things usually works better when you don't use them by accident on the wrong environment as I did!

Cheers!

Lisias commented 2 years ago

Note to my future self:

When I initially coded that stunt, I assumed that the code would run on Windows or on *NIX, and took no measure to prevent heterogeneous environments as CYGWIN or something, where the TWO filesystems could be valid at the same time.

On Windows, there's absolutely no "/usr" subdirectory on the root file system. Point. So the code that would search for realpath would always fail, and so the pointer to it would always be null. And so I didn't cared about checking if I was running on Windows or similar because that would never happen (users of CYGWIN would have problems, but who would compile KSP on CYGWIN???)

But then Proton came. On Proton, the code thinks it's running on Windows but the UNIX filesystem is also there, and so the realpath code would find it!!! And then I got a situation in which a NIX only tool was being fed with a Windows pathname and things just blew up.

(and I was thinking it was Proton, because it was the only other possible situation where this crapness could happen….)

So I:

  1. Shunted the code that looks for realpath to be run only on *NIX
  2. Inverted the order of the selection to check for Windows first and if positive, call the Windows code first and return.

Any one of the actions above would solve this issue by itself, but I choose to implement both because Murphy is a prophet and sooner or later I will refactor this thing and doing this way I will prevent shooting my own feet on the process.

Lisias commented 2 years ago

Note to my future self:

Keep an eye on this post from forum: https://forum.kerbalspaceprogram.com/index.php?/topic/179030-ksp-130-tweakscale-under-lisias-management-24615-2022-0523/&do=findComment&comment=4114908

You see that '/home/sean/.local/share/Steam/steamapps/common/Proton 5.13/dist/share/default_pfx/dosdevices/z:/boot/efi' stunt? By some reason someone at Steam though it could be a good idea to map a SYSTEM PROTECTED folder, inaccessible by the user, inside his home folder.

cparadis777 commented 2 years ago

Hi, i'm having the same issue, even after trying the fix from #25. Here's the log: `[LOG 08:09:51.368] [AddonLoader]: Instantiating addon 'Startup' from assembly 'DistantObject' [EXC 08:09:52.101] IOException: Invalid handle to path "" Microsoft.Win32.NativeMethods.DuplicateHandle (System.Runtime.InteropServices.HandleRef hSourceProcessHandle, System.Runtime.InteropServices.SafeHandle hSourceHandle, System.Runtime.InteropServices.HandleRef hTargetProcess, Microsoft.Win32.SafeHandles.SafeWaitHandle& targetHandle, System.Int32 dwDesiredAccess, System.Boolean bInheritHandle, System.Int32 dwOptions) (at :0) System.Diagnostics.ProcessWaitHandle..ctor (Microsoft.Win32.SafeHandles.SafeProcessHandle processHandle) (at :0) (wrapper remoting-invoke-with-check) System.Diagnostics.ProcessWaitHandle..ctor(Microsoft.Win32.SafeHandles.SafeProcessHandle) System.Diagnostics.Process.WaitForExit (System.Int32 milliseconds) (at :0) System.Diagnostics.Process.WaitForExit () (at :0) (wrapper remoting-invoke-with-check) System.Diagnostics.Process.WaitForExit() KSPe.Multiplatform.Shell.command (System.String command, System.String commandline) (at :0) KSPe.Multiplatform.FileSystem.Reparse_readlink (System.String path) (at :0) KSPe.Multiplatform.FileSystem.ReparsePath (System.String path) (at :0) KSPe.IO.Directory.RealPath (System.String path) (at :0) KSPe.IO.Directory.Exists (System.String path) (at :0) KSPe.IO.Path.EnsureTrailingSeparatorOnDir (System.String path, System.Boolean blindlyAppend) (at :0) KSPe.IO.Path.Combine (System.String path1, System.String path2) (at :0) KSPe.IO.Hierarchy..cctor () (at :0) Rethrow as TypeInitializationException: The type initializer for 'KSPe.IO.Hierarchy' threw an exception. KSPe.IO.Directory.Exists (System.String path) (at :0) KSPe.IO.Path.EnsureTrailingSeparatorOnDir (System.String path, System.Boolean blindlyAppend) (at :0) KSPe.IO.Path.GetAbsolutePath (System.String path, System.Boolean iKnowItsDir) (at :0) KSPe.IO.Path.GetAbsolutePath (System.String path) (at :0) KSPe.IO.Path.Origin () (at :0) KSPe.Util.Installation.CheckForWrongDirectoy (System.Type type, System.String name, System.String folder, System.String vendor) (at :0) KSPe.Util.Installation.Check[T] (System.String name, System.String folder, System.String vendor, System.Boolean unique) (at :0) KSPe.Util.Installation.Check[T] (System.Type versionClass, System.Boolean unique) (at :0) KSPe.Util.Installation.Check[T] (System.Boolean unique) (at :0) KSPe.Util.Installation.Check[T] () (at :0) DistantObject.Startup.Awake () (at :0) UnityEngine.DebugLogHandler:LogException(Exception, Object) ModuleManager.UnityLogHandle.InterceptLogHandler:LogException(Exception, Object) UnityEngine.GameObject:AddComponent(Type) AddonLoader:StartAddon(LoadedAssembly, Type, KSPAddon, Startup) AddonLoader:StartAddons(Startup)

d__90:MoveNext() UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator) d__71:MoveNext() UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator) GameDatabase:StartLoad() d__11:MoveNext() UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator) LoadingScreen:Start() [LOG 08:09:52.102] [AddonLoader]: Instantiating addon 'Startup' from assembly 'KSPe.Light.DOE' ` I'm running Proton Experimental, with TweakScale 2.4.6.15B and KSP version 1.12.3. The issue arises only when using TweakScale.
Lisias commented 2 years ago

Hi, @cparadis777

Hi, i'm having the same issue, even after trying the fix from #25. Here's the log: I'm running Proton Experimental, with TweakScale 2.4.6.15B and KSP version 1.12.3. The issue arises only when using TweakScale.

Yeah, I had borked something on the KSPe.Light thingy.

Download this file from https://github.com/net-lisias-ksp/TweakScale/releases and replace the KSPe.Light.TweakScale.dll on your GameData with this new one.

In time… why using Proton when there's a Linux release available? Proton does a good job on the translation, but using the real deal on the metal is always faster - a lot faster, sometimes...

cparadis777 commented 2 years ago

I've read a lot of accounts saying that proton was preferable for kidding, as the native Linux version slows down significantly when modded. Thanks for the rapid answer, I'll try the fix!