Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
9ca1e05
docs: add README with features, downloads, system requirements and bu…
JeanPhilippeKernel Jul 29, 2026
f92afae
ci: enable single-file publish across all platform build jobs (#13)
JeanPhilippeKernel Jul 29, 2026
5315617
feat: show app release version in status bar (#14)
JeanPhilippeKernel Jul 29, 2026
e08d69c
feat: configure VS Code for cross-platform debugging and fix binding …
JeanPhilippeKernel Jul 29, 2026
ae27d32
feat: assets page redesign, local asset grouping, project card modern…
JeanPhilippeKernel Jul 30, 2026
f3b3555
docs: update README with current screenshots (#17)
JeanPhilippeKernel Jul 30, 2026
da5cbe0
chore: release 1.3.0 (#19)
github-actions[bot] Jul 30, 2026
3091b91
Revert "chore: release 1.3.0 (#19)" (#20)
JeanPhilippeKernel Jul 30, 2026
a1b5ba9
chore: release 1.3.0 (#23)
github-actions[bot] Jul 30, 2026
d4638a2
docs(roadmap): add roadmap with planned features and current implemen…
JeanPhilippeKernel Jul 31, 2026
7846204
fix: restore Windows caption buttons and fix app version display (#25)
JeanPhilippeKernel Jul 31, 2026
4895674
Fix/startup perf and native titlebar (#26)
JeanPhilippeKernel Aug 1, 2026
7fada50
fix: bump version to trigger RC build with orange border indicator (#27)
JeanPhilippeKernel Aug 1, 2026
ec34bcb
feat: RC build indicator with orange bloom border and version tag (#28)
JeanPhilippeKernel Aug 1, 2026
2d9c5db
fix: surface engine crash errors and resolve stale rpath for local bu…
JeanPhilippeKernel Aug 1, 2026
cf79d5e
fix: pin Tmds.DBus.Protocol to 0.20.0 to fix Linux startup crash (#31)
JeanPhilippeKernel Aug 1, 2026
d41dae2
feat: engine UX improvements and Linux startup fixes (#32)
JeanPhilippeKernel Aug 3, 2026
347fad9
chore: resolve conflicts merging main into develop (#34)
JeanPhilippeKernel Aug 3, 2026
014357a
chore: release 1.4.0 (#37)
github-actions[bot] Aug 3, 2026
d11d44f
chore: sync develop with main after 1.4.0 release (#38)
JeanPhilippeKernel Aug 3, 2026
38aada5
ci: restore commitlint check for all PRs (#39)
JeanPhilippeKernel Aug 3, 2026
60340d4
ci: ignore legacy non-conventional commits in commitlint (#40)
JeanPhilippeKernel Aug 3, 2026
3c2b2e9
chore: release 1.4.0 (#42)
github-actions[bot] Aug 3, 2026
7371102
Chore/sync develop post release workflow (#43)
JeanPhilippeKernel Aug 3, 2026
eaf213c
ci: drop macOS x64 build from all workflows (#44)
JeanPhilippeKernel Aug 4, 2026
bb35a0e
ci: skip build for non-source file changes (#45)
JeanPhilippeKernel Aug 4, 2026
90c8faf
feat(project): standardize asset directories under Assets/ and add sk…
JeanPhilippeKernel Aug 11, 2026
284b92b
project config standardize (#47)
JeanPhilippeKernel Aug 11, 2026
7e816f8
feat(project): remove SceneData directory from project layout (#48)
JeanPhilippeKernel Aug 17, 2026
52a0bea
feat(ui): add ZodiacEngineHub app icon (#49)
JeanPhilippeKernel Aug 17, 2026
0e6bada
chore: resolve merge conflicts with main (#51)
JeanPhilippeKernel Aug 22, 2026
028b27c
ci: set target-branch to main in release-please config (#53)
JeanPhilippeKernel Aug 22, 2026
74e140b
chore: sync develop with main after 1.5.0 release (#63)
JeanPhilippeKernel Aug 22, 2026
ddf004c
fix(assets): preserve companion file paths and migrate existing flat …
JeanPhilippeKernel Aug 24, 2026
092c270
chore: merge develop into main for 1.6.0 release
JeanPhilippeKernel Aug 24, 2026
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 / linux / build-release / build-linux-x64-Release

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 / windows / build-release / build-windows-x64-Release

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-release (arm64) / build-macOS-arm64-Release

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