O-n-y / oxy.mods

Oxy.BugTracker
19 stars 2 forks source link

[Mod Manager] "Open folder" doesn't work on Linux #106

Closed Mart-Bogdan closed 1 year ago

Mart-Bogdan commented 1 year ago
  1. Game version: U44-535842-V
  2. Mod version: 2.13.7.125
  3. OS: Manjaro Linux. Kernel: 5.15.81-1-MANJARO

If I click [Open folder] or [Open Log Folder] nothing happens.

image

When I go to logs I can observe following message:

xdg-open: unexpected argument '/home/winnie/.config/unity3d/Klei/Oxygen'
Try 'xdg-open --help' for more information.

From my understanding mod is correctly using xdg-open command, which I originally wanted to suggest as a fix. But it fails to process spaces in path. Full path to game profile dir on Linux is: /home/winnie/.config/unity3d/Klei/Oxygen Not Included/

For example when I run in terminal:

[winnie@bm-linux-nitro517 ~]$ xdg-open /home/winnie/.config/unity3d/Klei/Oxygen Not Included/mods/Steam/1843965353/
xdg-open: unexpected argument 'Not'
Try 'xdg-open --help' for more information.
[winnie@bm-linux-nitro517 ~]$ xdg-open "/home/winnie/.config/unity3d/Klei/Oxygen Not Included/mods/Steam/1843965353/"
[winnie@bm-linux-nitro517 ~]$ 

And second one works.

Perhaps you just should wrap path into quotes, or screen spaces as \.

But what bugs me, that in case of Ony it complains about first path segmend, not on word Not as in my case. Perhaps command line generated by Mod is bigger.

I would be happy to assist in testing on Linux if you provide me with built DLL.

P.S. I can't add labels, seems only repository owner can do this :-(

Thanks.

Mart-Bogdan commented 1 year ago

I was able to create patch by myself. But it requires for me to create second mod, that is loaded after yours.

Would be nice if you could just take my code and include it into your code.

using System;
using System.Diagnostics;
using HarmonyLib;
using UnityEngine;

namespace ModManagerLinuxFix.Patches
{
    internal class ModManagerPatch
    {
        public static void InstallPatch(Harmony harmony)
        {
            var ourType = typeof(ModManagerPatch);
            var updaterType =
                typeof(Ony.OxygenNotIncluded.ModManager.Settings).Assembly.GetType(
                    "Ony.OxygenNotIncluded.ModManager.Updater");

            var method_OpenModFolder = updaterType.GetMethod("OpenModFolder");
            var method_OpenLogFolder = updaterType.GetMethod("OpenLogFolder");

            harmony.Patch(
                method_OpenModFolder,
                prefix: new HarmonyMethod(ourType.GetMethod(nameof(ModManagerPatch.OpenModFolder)))
            );
            harmony.Patch(
                method_OpenLogFolder,
                prefix: new HarmonyMethod(ourType.GetMethod(nameof(ModManagerPatch.OpenLogFolder)))
            );
        }

        public static bool OpenModFolder(KMod.Mod mod)
        {
            string root = mod.file_source.GetRoot();
            if (Application.platform == RuntimePlatform.WindowsPlayer)
                Process.Start("explorer.exe", root.Replace("/", "\\"));
            else
                Process.Start("xdg-open", '"' + root.Replace("\"", "\\\"") + '"');

            // Skip original method
            return false;
        }

        public static bool OpenLogFolder(ModsScreen modsScreen)
        {
            if (Application.platform == RuntimePlatform.WindowsPlayer)
                Process.Start("explorer.exe",
                    Environment.ExpandEnvironmentVariables(
                        "%USERPROFILE%\\AppData\\LocalLow\\Klei\\Oxygen Not Included"));
            else if (Application.platform == RuntimePlatform.OSXPlayer)
                // perhaps use for mac `open` instead of file. But I can't test it.
                // And I don't know if MacOS would expand ~, coz Linux doesn't
                Process.Start("file://", "~/Library/Logs/Unity");
            else
                // ~ isn't expanded by OS. $HOME can be expanded if used with `sh -c` but it become tricky with escaping
                // quotes, so better to expand env variable at C# side, using dotnet(windows) syntax with % instead of $
                Process.Start("xdg-open",
                    '"' + Environment.ExpandEnvironmentVariables("%HOME%/.config/unity3d/Klei/Oxygen Not Included") +
                    '"');

            // Skip original method
            return false;
        }
    }
}

Thanks

O-n-y commented 1 year ago

I will check this out, thank you!

O-n-y commented 1 year ago

xdg-open - i assume this could be os dependent, i.e. not all linux machines could have packet https://wiki.archlinux.org/title/Xdg-utils

Mart-Bogdan commented 1 year ago

Good question. I think it would be present in any modern Desktop distro. I'll read about it.

Mart-Bogdan commented 1 year ago

I've just checked.

This one works properly:

Process.Start("file:///home/winnie/.config/unity3d/Klei/Oxygen%20Not%20Included/");

Single argument. If having two arguments id don't open (and don't throw exception).

But it has Process object with error in it.

And I had to escape space with %20 as it is URL now.

Mart-Bogdan commented 1 year ago

image As I can see orgiginal way of calling don't work, but it returns 0 exit code for some wierd reason. I think it wasn't ablt to create file.

But I beleive that what happens under the scene is that "file://" url is interpreted by xdg-open, just behind the scene. Uless Mono runtime does this by itself.

O-n-y commented 1 year ago

Can you please confirm this works the same way: Process.Start("file://~/.config/unity3d/Klei/Oxygen Not Included");

Mart-Bogdan commented 1 year ago

would do now)

Mart-Bogdan commented 1 year ago

For some reason both:

Opened browser: image

But good news, this one Process.Start("file:///home/winnie/.config/unity3d/Klei/Oxygen Not Included/"); works, so no need to replace space by %20. Just need to expand %HOME% manually from C# side.

and for mods just prepend file:// it sems

O-n-y commented 1 year ago

Can you please confirm, this one works: Process.Start($"file://{Environment.GetEnvironmentVariable("HOME")}/.config/unity3d/Klei/Oxygen Not Included");

Mart-Bogdan commented 1 year ago

So this seems to be final version

        public static void OpenModFolder(KMod.Mod mod)
        {
            string root = mod.file_source.GetRoot();
            if (Application.platform == RuntimePlatform.WindowsPlayer)
                Process.Start("explorer.exe", root.Replace("/", "\\"));
            else
                Process.Start("file://" + root);
        }

        public void bool OpenLogFolder(ModsScreen modsScreen)
        {
            if (Application.platform == RuntimePlatform.WindowsPlayer)
                Process.Start("explorer.exe",
                    Environment.ExpandEnvironmentVariables(
                        "%USERPROFILE%\\AppData\\LocalLow\\Klei\\Oxygen Not Included"));
            else if (Application.platform == RuntimePlatform.OSXPlayer)
                // perhaps use for mac `open` instead of file. But I can't test it.
                // And I don't know if MacOS would expand ~, coz Linux doesn't
                Process.Start("file://", "~/Library/Logs/Unity");
            else
                // ~ isn't expanded by OS. $HOME can be expanded if used with `sh -c` but it become tricky with escaping
                // quotes, so better to expand env variable at C# side, using dotnet(windows) syntax with % instead of $
                Process.Start("file://" + Environment.ExpandEnvironmentVariables("%HOME%/.config/unity3d/Klei/Oxygen Not Included"));

        }
Mart-Bogdan commented 1 year ago

Can you please confirm, this one works: Process.Start($"file://{Environment.GetEnvironmentVariable("HOME")}/.config/unity3d/Klei/Oxygen Not Included");

didn't saw this message. I guess it should work as well.

O-n-y commented 1 year ago

As it is confirmed as working solution, this will be in next Steam release version, thank you!

Mart-Bogdan commented 1 year ago

Yeah it works. with { }

Mart-Bogdan commented 1 year ago

Thanks :-)

Mart-Bogdan commented 1 year ago

P.S. I don't know if it works on Mac, but I guess nobody complains :D

O-n-y commented 1 year ago

i will change it to Process.Start($"file://{Environment.GetEnvironmentVariable("HOME")}/Library/Logs/Unity"); just in case, as i seems to be similar, as Mac - >darwin is Unix-based

Mart-Bogdan commented 1 year ago

Pls don't forget about mods Process.Start("file://" + root);

O-n-y commented 1 year ago

Process.Start("xdg-open", '"' + root.Replace("\"", "\\\"") + '"'); yes, this will be there as well

Mart-Bogdan commented 1 year ago

to be clear. xdg isn't needed here, as rurns out. and "

just Process.Start("file://" + root); with + instead of ,

O-n-y commented 1 year ago

please confirm this is working (OpenModFolder) Process.Start($"file://{folder}");

Mart-Bogdan commented 1 year ago

yeah, it works