Monitor221hz / Pandora-Behaviour-Engine-Plus

Patcher for behavior, character, and skeleton project files for Skyrim Special Edition.
Other
355 stars 19 forks source link

[Bug]: Assets are not discoverable on Linux #328

Open poperigby opened 1 month ago

poperigby commented 1 month ago

Check for duplicate issues

Version

2.3.0-beta

Provide Instructions on Reproducing the Problem

  1. Build Pandora on Linux
  2. Launch it
  3. Click on the play button

Description of problem

Pandora crashes with the following error message:

Unhandled exception. System.IO.FileNotFoundException: Could not find file '/nix/store/j9n1q0qhx6waczll7b6x56gj98nhp7hf-pandora-behaviour-engine-2.3.0-beta/lib/pandora-behaviour-engine/Pandora_Engine\Skyrim\Template\vanilla_projectpaths.txt'.
File name: '/nix/store/j9n1q0qhx6waczll7b6x56gj98nhp7hf-pandora-behaviour-engine-2.3.0-beta/lib/pandora-behaviour-engine/Pandora_Engine\Skyrim\Template\vanilla_projectpaths.txt'
   at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirError)
   at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode, Boolean failForSymlink, Boolean& wasSymlink, Func`4 createOpenException)
   at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, UnixFileMode openPermissions, Int64& fileLength, UnixFileMode& filePermissions, Boolean failForSymlink, Boolean& wasSymlink, Func`4 createOpenException)
   at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
   at System.IO.FileInfo.OpenRead()
   at Pandora.Core.Patchers.Skyrim.ProjectManager.LoadTrackedProjects() in /build/source/Pandora Behaviour Engine/Models/Patch/Patchers/Skyrim/ProjectManager.cs:line 101
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
   at Pandora.Patch.Patchers.Skyrim.Nemesis.NemesisAssembler.LoadResourcesAsync() in /build/source/Pandora Behaviour Engine/Models/Patch/Patchers/Skyrim/Nemesis/NemesisAssembler.cs:line 102
   at Pandora.Patch.Patchers.Skyrim.SkyrimPatcher.PreloadAsync() in /build/source/Pandora Behaviour Engine/Models/Patch/Patchers/Skyrim/SkyrimPatcher.cs:line 151
   at Pandora.Core.BehaviourEngine.PreloadAsync() in /build/source/Pandora Behaviour Engine/Models/Patch/Engine/BehaviourEngine.cs:line 43
   at Pandora.ViewModels.EngineViewModel.LaunchEngine(Object parameter) in /build/source/Pandora Behaviour Engine/ViewModels/EngineViewModel.cs:line 420
   at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_0(Object state)
   at Avalonia.Threading.SendOrPostCallbackDispatcherOperation.InvokeCore()
   at Avalonia.Threading.DispatcherOperation.Execute()
   at Avalonia.Threading.Dispatcher.ExecuteJob(DispatcherOperation job)
   at Avalonia.Threading.Dispatcher.ExecuteJobsCore(Boolean fromExplicitBackgroundProcessingCallback)
   at Avalonia.Threading.Dispatcher.OnOSTimer()
   at Avalonia.X11.X11PlatformThreading.RunLoop(CancellationToken cancellationToken)
   at Avalonia.Threading.DispatcherFrame.Run(IControlledDispatcherImpl impl)
   at Avalonia.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
   at Avalonia.Threading.Dispatcher.MainLoop(CancellationToken cancellationToken)
   at Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetime.Start(String[] args)
   at Avalonia.ClassicDesktopStyleApplicationLifetimeExtensions.StartWithClassicDesktopLifetime(AppBuilder builder, String[] args, Action`1 lifetimeBuilder)
   at Pandora.Program.Main(String[] args) in /build/source/Pandora Behaviour Engine/Program.cs:line 12
fish: Job 1, '/nix/store/b7v6ll11l79rski5fnrl…' terminated by signal SIGABRT (Abort)

Presumably because Pandora Behaviour Engine.csproj refers to assets with backslashes instead of forward slashes, which isn't supported on Linux. I believe you could switch to forward slashes with no downsides because Windows supports forward slashes now.

I've verified that the files do indeed exist at that location, so it's just the backslashes screwing things up.

Provide Visual Proof (optional)

No response

Contributing To Development

Monitor221hz commented 1 month ago

Can you confirm the fix on your end, and submit a PR? I could convert all the paths to forward slashes in the csproj file but if that's not the sole cause we'll be back to square one. I don't have a Linux machine readily available to me at the moment.

poperigby commented 4 weeks ago

Sure. It's look like there were a lot of other compatibility issues with path separators in the code itself, so I went ahead and fixed those with Path.Combine. It seems the *paths.txt files also need updating.

poperigby commented 4 weeks ago

OK, I've gotten to a point where I'm not quite sure what to do. I'm getting this error when clicking the play button:

File name: '/nix/store/brx5n52fdq7gxmzsqj4s5i7jkl16aa87-pandora-behaviour-engine-2.3.5-beta/lib/pandora-behaviour-engine/Pandora_Engine/Skyrim/Template/actors/atronachflame/Characters\AtronachFlame.hkx'
   at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirError)
   at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode, Boolean failForSymlink, Boolean& wasSymlink, Func`4 createOpenException)
   at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, UnixFileMode openPermissions, Int64& fileLength, UnixFileMode& filePermissions, Boolean failForSymlink, Boolean& wasSymlink, Func`4 createOpenException)
   at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
   at System.IO.FileInfo.OpenRead()
   at Pandora.Patch.Patchers.Skyrim.Hkx.PackFile..ctor(FileInfo file, Project project) in /build/source/Pandora Behaviour Engine/Models/Patch/Patchers/Skyrim/Hkx/PackFile.cs:line 102
   at Pandora.Patch.Patchers.Skyrim.Hkx.PackFileCharacter..ctor(FileInfo file, Project project) in /build/source/Pandora Behaviour Engine/Models/Patch/Patchers/Skyrim/Hkx/PackFileCharacter.cs:line 14
   at Pandora.Patch.Patchers.Skyrim.Hkx.PackFileCharacter..ctor(FileInfo file) in /build/source/Pandora Behaviour Engine/Models/Patch/Patchers/Skyrim/Hkx/PackFileCharacter.cs:line 19
   at Pandora.Patch.Patchers.Skyrim.Hkx.PackFileCache.LoadPackFileCharacter(FileInfo file) in /build/source/Pandora Behaviour Engine/Models/Patch/Patchers/Skyrim/Hkx/PackFileCache.cs:line 74
   at Pandora.Core.Patchers.Skyrim.Project.GetCharacterFile(PackFile projectFile, PackFileCache cache) in /build/source/Pandora Behaviour Engine/Models/Patch/Patchers/Skyrim/Project.cs:line 167
   at Pandora.Core.Patchers.Skyrim.Project.Create(PackFile projectFile, PackFileCache cache) in /build/source/Pandora Behaviour Engine/Models/Patch/Patchers/Skyrim/Project.cs:line 110
   at Pandora.Core.Patchers.Skyrim.Project.Load(FileInfo file, PackFileCache cache) in /build/source/Pandora Behaviour Engine/Models/Patch/Patchers/Skyrim/Project.cs:line 153
   at Pandora.Core.Patchers.Skyrim.ProjectManager.LoadProject(String projectFilePath) in /build/source/Pandora Behaviour Engine/Models/Patch/Patchers/Skyrim/ProjectManager.cs:line 203
   at Pandora.Core.Patchers.Skyrim.ProjectManager.LoadProjects(List`1 projectPaths) in /build/source/Pandora Behaviour Engine/Models/Patch/Patchers/Skyrim/ProjectManager.cs:line 121
   at Pandora.Core.Patchers.Skyrim.ProjectManager.LoadTrackedProjects() in /build/source/Pandora Behaviour Engine/Models/Patch/Patchers/Skyrim/ProjectManager.cs:line 114
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
   at Pandora.Patch.Patchers.Skyrim.Nemesis.NemesisAssembler.LoadResourcesAsync() in /build/source/Pandora Behaviour Engine/Models/Patch/Patchers/Skyrim/Nemesis/NemesisAssembler.cs:line 102
   at Pandora.Patch.Patchers.Skyrim.SkyrimPatcher.PreloadAsync() in /build/source/Pandora Behaviour Engine/Models/Patch/Patchers/Skyrim/SkyrimPatcher.cs:line 151
   at Pandora.Core.BehaviourEngine.PreloadAsync() in /build/source/Pandora Behaviour Engine/Models/Patch/Engine/BehaviourEngine.cs:line 77
   at Pandora.ViewModels.EngineViewModel.LaunchEngine(Object parameter) in /build/source/Pandora Behaviour Engine/ViewModels/EngineViewModel.cs:line 430
   at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_0(Object state)
   at Avalonia.Threading.SendOrPostCallbackDispatcherOperation.InvokeCore()
   at Avalonia.Threading.DispatcherOperation.Execute()
   at Avalonia.Threading.Dispatcher.ExecuteJob(DispatcherOperation job)
   at Avalonia.Threading.Dispatcher.ExecuteJobsCore(Boolean fromExplicitBackgroundProcessingCallback)
   at Avalonia.Threading.Dispatcher.Signaled()
   at Avalonia.X11.X11PlatformThreading.CheckSignaled()
   at Avalonia.X11.X11PlatformThreading.RunLoop(CancellationToken cancellationToken)
   at Avalonia.Threading.DispatcherFrame.Run(IControlledDispatcherImpl impl)
   at Avalonia.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
   at Avalonia.Threading.Dispatcher.MainLoop(CancellationToken cancellationToken)
   at Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetime.Start(String[] args)
   at Avalonia.ClassicDesktopStyleApplicationLifetimeExtensions.StartWithClassicDesktopLifetime(AppBuilder builder, String[] args, Action`1 lifetimeBuilder)
   at Pandora.Program.Main(String[] args) in /build/source/Pandora Behaviour Engine/Program.cs:line 12
fish: Job 1, '/nix/store/b7v6ll11l79rski5fnrl…' terminated by signal SIGABRT (Abort)

I'm guessing it has something to do with the paths stored in .hkx files? Perhaps Pandora is reading them in a Windows specific way?

This is the commit I'm working from: https://github.com/poperigby/Pandora-Behaviour-Engine-Plus/commit/828cca46ab05727defafe24239750de52c3249e8

SARDONYX-sard commented 4 weeks ago

Can you confirm the fix on your end, and submit a PR? I could convert all the paths to forward slashes in the csproj file but if that's not the sole cause we'll be back to square one. I don't have a Linux machine readily available to me at the moment.

I think this is an interesting discussion.

By using desktop-lite in devcontainer, it is possible to perform GUI development even within a container, so I gave it a try to see if I could build and run it.

Requirements

Commands

  1. Execute Docker
  2. Ctrl + Shift + P -> Dev Containers: Reopen in Container
  3. dotnet build
  4. /workspaces/Pandora-Behaviour-Engine-Plus/Pandora\ Behaviour\ Engine/bin/Debug/net8.0/Pandora\ Behaviour\ Engine+

Result

Looking at the image, the GUI inside the guest container is launched through the host OS's browser. {5B94AFC7-0091-4364-9A7A-D16F9107CB81}

Docker and WSL are required, but it seems that development is possible on a Windows environment using Linux containers. (As a side note, this pattern is also useful when developing a custom OS and using Qemu to display the GUI.)

However, even though the build works, there are currently the following issues:

I was supposed to create this test branch in the forked repository, but I mistakenly did it on the origin. My apologies.