Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions Service/EngineService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,22 @@

var binaryName = $"{_launcherCLIAppName}{EngineExtension}";

foreach (var versionDir in Directory.EnumerateDirectories(installLocation))
IEnumerable<string> versionDirs;
try { versionDirs = Directory.EnumerateDirectories(installLocation).ToList(); }
catch (UnauthorizedAccessException) { yield break; }
catch (IOException) { yield break; }

foreach (var versionDir in versionDirs)
{
var binaryPath = Directory
.EnumerateFiles(versionDir, binaryName, SearchOption.AllDirectories)
.FirstOrDefault();
string? binaryPath = null;
try
{
binaryPath = Directory
.EnumerateFiles(versionDir, binaryName, SearchOption.AllDirectories)
.FirstOrDefault();
}
catch (UnauthorizedAccessException) { }
catch (IOException) { }

if (binaryPath != null)
yield return new InstalledEngine
Expand Down Expand Up @@ -143,7 +154,7 @@
{
var ext = System.IO.Path.GetExtension(f).ToLowerInvariant();
return ext is ".dylib" or ".so" or ""
|| (ext == string.Empty && File.GetUnixFileMode(f).HasFlag(UnixFileMode.UserExecute));

Check warning on line 157 in Service/EngineService.cs

View workflow job for this annotation

GitHub Actions / windows / build-debug / build-windows-x64-Debug

This call site is reachable on all platforms. 'File.GetUnixFileMode(string)' is unsupported on: 'windows'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1416)

Check warning on line 157 in Service/EngineService.cs

View workflow job for this annotation

GitHub Actions / linux / build-debug / build-linux-x64-Debug

This call site is reachable on all platforms. 'File.GetUnixFileMode(string)' is unsupported on: 'windows'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1416)

Check warning on line 157 in Service/EngineService.cs

View workflow job for this annotation

GitHub Actions / macOS / build-debug (arm64) / build-macOS-arm64-Debug

This call site is reachable on all platforms. 'File.GetUnixFileMode(string)' is unsupported on: 'windows'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1416)
});

foreach (var target in signable)
Expand Down
3 changes: 2 additions & 1 deletion ViewModels/AssetDetailViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ internal class AssetFormatOption : ReactiveObject
public string Resolution { get; }
public string Url { get; }
public string Label => $"{Format.ToUpperInvariant()} · {Resolution}";
public List<string> CompanionUrls { get; } = new();
// RelativePath is the inc.Key from the Poly Haven API (e.g. "textures/foo_diff_4k.jpg", "foo.bin")
public List<(string RelativePath, string Url)> CompanionFiles { get; } = new();

private bool _isSelected;
public bool IsSelected
Expand Down
57 changes: 52 additions & 5 deletions ViewModels/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,7 @@ public MainWindowViewModel(IProjectService projectService, IEngineService engine
_ = RunBackgroundTask("Scan local assets", () => Task.Run(() =>
Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(ScanLocalAssets)));
_ = RunBackgroundTask("Load projects", LoadProjectsAsync);
_ = Task.Run(MigrateAssetFoldersAsync);
});

var canConfirm = this.WhenAnyValue(
Expand Down Expand Up @@ -877,7 +878,7 @@ await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
{
var incUrl = incFile["url"]?.GetValue<string>() ?? string.Empty;
if (!string.IsNullOrEmpty(incUrl))
option.CompanionUrls.Add(incUrl);
option.CompanionFiles.Add((inc.Key, incUrl));
}
}
}
Expand Down Expand Up @@ -943,14 +944,17 @@ async Task UI(System.Action a) =>
await DownloadFileWithProgressAsync(fmt.Url, destPath,
pct => UI(() => { op.Progress = pct; }));

// Download companion files (e.g. .bin buffer for GLTF)
// Download companion files, preserving the relative path from the API
// (e.g. "textures/foo_diff_4k.jpg" → destDir/textures/foo_diff_4k.jpg)
var destDir2 = System.IO.Path.GetDirectoryName(destPath)!;
foreach (var companionUrl in fmt.CompanionUrls)
foreach (var (relativePath, companionUrl) in fmt.CompanionFiles)
{
try
{
var companionFileName = System.IO.Path.GetFileName(new Uri(companionUrl).LocalPath);
var companionDest = System.IO.Path.Combine(destDir2, companionFileName);
var companionDest = System.IO.Path.Combine(
destDir2,
relativePath.Replace('/', System.IO.Path.DirectorySeparatorChar));
Directory.CreateDirectory(System.IO.Path.GetDirectoryName(companionDest)!);
await DownloadFileWithProgressAsync(companionUrl, companionDest, _ => Task.CompletedTask);
}
catch { /* non-fatal */ }
Expand Down Expand Up @@ -997,6 +1001,49 @@ private void ScanLocalAssets()
RefreshDownloadedStates();
}

private async Task MigrateAssetFoldersAsync()
{
var root = Models.AppPaths.Assets;
if (!Directory.Exists(root)) return;

string[] imageExts = ["jpg", "jpeg", "png", "webp", "hdr", "exr"];

// Collect all flat image files that need moving
var toMove = new List<(string Src, string Dest)>();
foreach (var assetDir in Directory.EnumerateDirectories(root))
foreach (var resDir in Directory.EnumerateDirectories(assetDir))
{
foreach (var file in Directory.EnumerateFiles(resDir))
{
var ext = Path.GetExtension(file).TrimStart('.').ToLowerInvariant();
if (!imageExts.Contains(ext)) continue;
var dest = Path.Combine(resDir, "textures", Path.GetFileName(file));
if (!File.Exists(dest))
toMove.Add((file, dest));
}
}

if (toMove.Count == 0) return;

await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
_ = ShowToastAsync($"Migrating {toMove.Count} texture file(s) into textures/ folders…"));

var moved = 0;
foreach (var (src, dest) in toMove)
{
try
{
Directory.CreateDirectory(Path.GetDirectoryName(dest)!);
File.Move(src, dest, overwrite: true);
moved++;
}
catch { /* non-fatal — leave file in place */ }
}

await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
_ = ShowToastAsync($"Asset folders updated — {moved} texture(s) moved to textures/"));
}

private void RefreshDownloadedStates()
{
var ids = LocalAssets.Select(a => a.AssetId)
Expand Down
2 changes: 1 addition & 1 deletion Views/MainWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ mc:Ignorable="d" d:DesignWidth="1500" d:DesignHeight="800"

<Grid Grid.Row="0" Height="56" ColumnDefinitions="*, Auto" Margin="4,8,4,0">
<TextBlock Grid.Column="0"
Text="Panzerfaust"
Text="Zodiac Hub"
FontWeight="DemiBold" FontSize="15"
VerticalAlignment="Center" Margin="12,0,0,0"
IsVisible="{Binding IsSidebarExpanded}"/>
Expand Down
Loading