Skip to content
7 changes: 7 additions & 0 deletions GenHub/GenHub.Core/Constants/FileTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,11 @@ public static class FileTypes
/// File extension for user data manifest files.
/// </summary>
public const string UserDataManifestExtension = ".userdata.json";

/// <summary>
/// Filename used to store the source directory path mapping for a manifest's content.
/// This file is written inside the manifest's data directory and contains the path
/// to the original source directory (e.g., local installation folder).
/// </summary>
public const string SourcePathFileName = "source.path";
}
Original file line number Diff line number Diff line change
Expand Up @@ -161,38 +161,6 @@ public static class GenPatcherContentRegistry
Variants = ResolutionVariants,
},

// Camera Modifications
["crgn"] = new GenPatcherContentMetadata
{
ContentCode = "crgn",
DisplayName = "Camera Mod - Generals",
Description = "Camera modification for Generals",
ContentType = ContentType.Addon,
TargetGame = GameType.Generals,
Category = GenPatcherContentCategory.Camera,
InstallTarget = ContentInstallTarget.Workspace,
},
["crzh"] = new GenPatcherContentMetadata
{
ContentCode = "crzh",
DisplayName = "Camera Mod - Zero Hour",
Description = "Camera modification for Zero Hour",
ContentType = ContentType.Addon,
TargetGame = GameType.ZeroHour,
Category = GenPatcherContentCategory.Camera,
InstallTarget = ContentInstallTarget.Workspace,
},
["dczh"] = new GenPatcherContentMetadata
{
ContentCode = "dczh",
DisplayName = "D-Control - Zero Hour",
Description = "D-Control camera for Zero Hour",
ContentType = ContentType.Addon,
TargetGame = GameType.ZeroHour,
Category = GenPatcherContentCategory.Camera,
InstallTarget = ContentInstallTarget.Workspace,
},

// Hotkeys
Comment thread
undead2146 marked this conversation as resolved.
["ewba"] = new GenPatcherContentMetadata
{
Expand Down
25 changes: 24 additions & 1 deletion GenHub/GenHub.Core/Models/Workspace/ContentTypePriority.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using GenHub.Core.Models.Enums;

namespace GenHub.Core.Models.Workspace;
Expand All @@ -14,16 +15,38 @@
/// </summary>
/// <param name="contentType">The content type.</param>
/// <returns>Priority value (0-100).</returns>
/// <exception cref="ArgumentException">Thrown when the content type should not be in a workspace.</exception>
public static int GetPriority(ContentType contentType)
{
return contentType switch
{
ContentType.Mod => 100, // Highest: User mods override everything
ContentType.Patch => 90, // Patches override base content
ContentType.GameClient => 50, // Community executables override official
ContentType.ModdingTool => 45, // Modding tools (between Addon and GameClient)
ContentType.Executable => 45, // Executables (between Addon and GameClient)
ContentType.Addon => 40, // Addons (maps, etc.)
ContentType.LanguagePack => 35, // Language packs
ContentType.MapPack => 30, // Map packs (between GameInstallation and Addon)
ContentType.Map => 30, // Individual maps
ContentType.Mission => 30, // Missions
ContentType.Skin => 20, // Skins
ContentType.Video => 20, // Videos
ContentType.Replay => 20, // Replays
ContentType.Screensaver => 20, // Screensavers
ContentType.GameInstallation => 10, // Lowest: Base game files
_ => 0, // Unknown/undefined types

// These types should not be in workspaces
ContentType.ContentBundle => throw new ArgumentException($"ContentType {contentType} should not be used in workspace priority resolution"),
ContentType.PublisherReferral => throw new ArgumentException($"ContentType {contentType} should not be used in workspace priority resolution"),
ContentType.ContentReferral => throw new ArgumentException($"ContentType {contentType} should not be used in workspace priority resolution"),
ContentType.UnknownContentType => throw new ArgumentException($"ContentType {contentType} should not be used in workspace priority resolution"),

_ => throw new ArgumentOutOfRangeException(

Check warning on line 45 in GenHub/GenHub.Core/Models/Workspace/ContentTypePriority.cs

View workflow job for this annotation

GitHub Actions / Build Linux

Check warning on line 45 in GenHub/GenHub.Core/Models/Workspace/ContentTypePriority.cs

View workflow job for this annotation

GitHub Actions / Build Linux

Check warning on line 45 in GenHub/GenHub.Core/Models/Workspace/ContentTypePriority.cs

View workflow job for this annotation

GitHub Actions / Build Windows

Check warning on line 45 in GenHub/GenHub.Core/Models/Workspace/ContentTypePriority.cs

View workflow job for this annotation

GitHub Actions / Build Windows

nameof(contentType),
contentType,
$"ContentType '{contentType}' is not mapped in {nameof(ContentTypePriority)}. " +

Check warning on line 48 in GenHub/GenHub.Core/Models/Workspace/ContentTypePriority.cs

View workflow job for this annotation

GitHub Actions / Build Linux

Check warning on line 48 in GenHub/GenHub.Core/Models/Workspace/ContentTypePriority.cs

View workflow job for this annotation

GitHub Actions / Build Linux

Check warning on line 48 in GenHub/GenHub.Core/Models/Workspace/ContentTypePriority.cs

View workflow job for this annotation

GitHub Actions / Build Windows

Check warning on line 48 in GenHub/GenHub.Core/Models/Workspace/ContentTypePriority.cs

View workflow job for this annotation

GitHub Actions / Build Windows

"Add an explicit priority entry for this type.")
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Outdated
Comment thread
undead2146 marked this conversation as resolved.
Outdated
};
}

Expand Down
33 changes: 33 additions & 0 deletions GenHub/GenHub/Common/ViewModels/MainViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using GenHub.Common.ViewModels.Dialogs;
using GenHub.Core.Constants;
using GenHub.Core.Interfaces.Common;
using GenHub.Core.Interfaces.Notifications;
using GenHub.Core.Messages;
Expand Down Expand Up @@ -416,4 +420,33 @@ partial void OnSelectedTabChanged(NavigationTab value)

SaveSelectedTab(value);
}

/// <summary>
/// Copies the application version to the clipboard.
/// </summary>
[RelayCommand]
private async Task CopyVersionToClipboard()
{
try
{
var lifetime = Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime;
var mainWindow = lifetime?.MainWindow;
var topLevel = mainWindow != null ? TopLevel.GetTopLevel(mainWindow) : null;

if (topLevel?.Clipboard != null)
{
await topLevel.Clipboard.SetTextAsync(AppConstants.FullDisplayVersion);
notificationService.ShowSuccess("Copied", "Version copied to clipboard.", 3000);
}
else
{
notificationService.ShowError("Error", "Clipboard not available.", 3000);
}
}
catch (Exception ex)
{
logger?.LogError(ex, "Failed to copy version to clipboard");
notificationService.ShowError("Error", "Failed to copy version to clipboard.", 3000);
}
}
}
27 changes: 21 additions & 6 deletions GenHub/GenHub/Common/Views/MainView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -212,12 +212,27 @@
<Grid Grid.Row="1">
<ContentControl Content="{Binding CurrentTabViewModel}" />
<!-- Version label in bottom right corner -->
<TextBlock Text="{x:Static constants:AppConstants.DisplayVersion}"
FontSize="9"
Foreground="#808080"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Margin="0,0,10,5" />
<Button Command="{Binding CopyVersionToClipboardCommand}"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Margin="0,0,10,5"
Padding="0"
Background="Transparent"
BorderThickness="0"
Cursor="Hand"
ToolTip.Tip="Click to copy full version (including git hash) to clipboard">
<Button.Styles>
<Style Selector="Button:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="Transparent" />
</Style>
<Style Selector="Button:pressed /template/ ContentPresenter">
<Setter Property="Background" Value="Transparent" />
</Style>
</Button.Styles>
<TextBlock Text="{x:Static constants:AppConstants.DisplayVersion}"
Comment thread
undead2146 marked this conversation as resolved.
Outdated
FontSize="9"
Foreground="#808080" />
</Button>
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Comment thread
undead2146 marked this conversation as resolved.
</Grid>
</Grid>
</UserControl>
Original file line number Diff line number Diff line change
Expand Up @@ -524,14 +524,12 @@ private async Task<OperationResult<ReconciliationResult>> ReconcileBulkManifestR
}
else
{
var error = $"Failed to update profile '{profile.Name}': {updateResult.FirstError}";
logger.LogWarning("Failed to update profile '{ProfileName}': {Error}", profile.Name, updateResult.FirstError);
failedProfiles.Add(profile.Name);
}
}
catch (Exception ex)
{
var error = $"Error reconciling profile '{profile.Name}': {ex.Message}";
logger.LogError(ex, "Error reconciling profile '{ProfileName}': {Message}", profile.Name, ex.Message);
failedProfiles.Add(profile.Name);
}
Expand Down Expand Up @@ -608,14 +606,12 @@ private async Task<OperationResult<ReconciliationResult>> ReconcileManifestRemov
}
else
{
var error = $"Failed to update profile '{profile.Name}': {updateResult.FirstError}";
logger.LogWarning("Failed to update profile '{ProfileName}': {Error}", profile.Name, updateResult.FirstError);
failedProfiles.Add(profile.Name);
}
}
catch (Exception ex)
{
var error = $"Error removing manifest from profile '{profile.Name}': {ex.Message}";
logger.LogError(ex, "Error removing manifest from profile '{ProfileName}': {Message}", profile.Name, ex.Message);
failedProfiles.Add(profile.Name);
}
Expand Down
46 changes: 44 additions & 2 deletions GenHub/GenHub/Features/Content/Services/ContentStorageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,13 @@
var manifestJson = JsonSerializer.Serialize(updatedManifest, JsonOptions);
await File.WriteAllTextAsync(manifestPath, manifestJson, cancellationToken);

// Create source.path marker for CAS-stored content
// This prevents "Could not resolve source path" warnings when GetContentDirectoryAsync is called
var contentDir = Path.Combine(_storageRoot, DirectoryNames.Data, updatedManifest.Id.Value);
Directory.CreateDirectory(contentDir);
var sourcePathFile = Path.Combine(contentDir, FileTypes.SourcePathFileName);
await File.WriteAllTextAsync(sourcePathFile, "CAS-ONLY", cancellationToken);

Comment on lines +291 to +297

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don’t make marker-file write failure abort successful CAS storage.

source.path (CAS-ONLY) is auxiliary metadata, but currently any exception here triggers full rollback in the outer catch. That can convert a successful CAS+manifest write into a failed operation unnecessarily.

Suggested containment
-            var contentDir = Path.Combine(_storageRoot, DirectoryNames.Data, updatedManifest.Id.Value);
-            Directory.CreateDirectory(contentDir);
-            var sourcePathFile = Path.Combine(contentDir, FileTypes.SourcePathFileName);
-            await File.WriteAllTextAsync(sourcePathFile, "CAS-ONLY", cancellationToken);
+            try
+            {
+                var contentDir = Path.Combine(_storageRoot, DirectoryNames.Data, updatedManifest.Id.Value);
+                Directory.CreateDirectory(contentDir);
+                var sourcePathFile = Path.Combine(contentDir, FileTypes.SourcePathFileName);
+                await File.WriteAllTextAsync(sourcePathFile, "CAS-ONLY", cancellationToken);
+            }
+            catch (Exception markerEx)
+            {
+                _logger.LogWarning(markerEx, "Stored manifest {ManifestId} but failed to write CAS source-path marker", updatedManifest.Id);
+            }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@GenHub/GenHub/Features/Content/Services/ContentStorageService.cs` around
lines 291 - 297, The write of the auxiliary marker file (creating contentDir and
writing FileTypes.SourcePathFileName with "CAS-ONLY") must not cause the outer
operation to fail; wrap Directory.CreateDirectory and File.WriteAllTextAsync for
the marker (using _storageRoot, DirectoryNames.Data, updatedManifest.Id.Value,
FileTypes.SourcePathFileName) in a small try/catch that logs the exception
(using the service's logger, e.g. _logger) and swallows it (do not rethrow), so
CAS+manifest success isn't rolled back if the marker write fails; preserve
cancellationToken handling when calling WriteAllTextAsync.

_logger.LogInformation("Successfully stored content for manifest {ManifestId}", manifest.Id);
return OperationResult<ContentManifest>.CreateSuccess(updatedManifest);
}
Expand Down Expand Up @@ -408,7 +415,7 @@

// Remove source.path mapping file if it exists
var contentDir = Path.Combine(_storageRoot, DirectoryNames.Data, manifestId.Value);
var sourcePathFile = Path.Combine(contentDir, "source.path");
var sourcePathFile = Path.Combine(contentDir, FileTypes.SourcePathFileName);
FileOperationsService.DeleteFileIfExists(sourcePathFile);

// Clean up the data directory if empty
Expand Down Expand Up @@ -495,13 +502,24 @@

// Create source.path mapping if we have a valid source directory
// This allows GetContentDirectoryAsync to resolve the content location
bool contentDirCreatedByThisCall = false;
bool sourcePathWrittenByThisCall = false;

Check warning on line 506 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Linux

The variable 'sourcePathWrittenByThisCall' is assigned but its value is never used

Check warning on line 506 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Linux

The variable 'sourcePathWrittenByThisCall' is assigned but its value is never used

Check warning on line 506 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Windows

The variable 'sourcePathWrittenByThisCall' is assigned but its value is never used

Check warning on line 506 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Windows

The variable 'sourcePathWrittenByThisCall' is assigned but its value is never used

Check warning on line 506 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Windows

The variable 'sourcePathWrittenByThisCall' is assigned but its value is never used

Check warning on line 506 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Windows

The variable 'sourcePathWrittenByThisCall' is assigned but its value is never used
string? previousSourcePathContent = null;
if (!string.IsNullOrWhiteSpace(sourceDirectory) && Directory.Exists(sourceDirectory))
{
var contentDir = Path.Combine(_storageRoot, DirectoryNames.Data, manifest.Id.Value);
bool dirAlreadyExisted = Directory.Exists(contentDir);
Directory.CreateDirectory(contentDir);
contentDirCreatedByThisCall = !dirAlreadyExisted;

var sourcePathFile = Path.Combine(contentDir, FileTypes.SourcePathFileName);

// Backup existing source.path content before overwriting
if (File.Exists(sourcePathFile))
previousSourcePathContent = await File.ReadAllTextAsync(sourcePathFile, cancellationToken);

var sourcePathFile = Path.Combine(contentDir, "source.path");
await File.WriteAllTextAsync(sourcePathFile, sourceDirectory, cancellationToken);
sourcePathWrittenByThisCall = true;

_logger.LogInformation(
"Created source path mapping for {ManifestId}: {SourcePath}",
Expand Down Expand Up @@ -534,6 +552,30 @@
{
FileOperationsService.DeleteFileIfExists(manifestPath);

// Clean up the content dir created for source.path mapping
var contentDir = Path.Combine(_storageRoot, DirectoryNames.Data, manifest.Id.Value);
if (contentDirCreatedByThisCall)

Check failure on line 557 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Linux

The name 'contentDirCreatedByThisCall' does not exist in the current context

Check failure on line 557 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Linux

The name 'contentDirCreatedByThisCall' does not exist in the current context

Check failure on line 557 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Windows

The name 'contentDirCreatedByThisCall' does not exist in the current context

Check failure on line 557 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Windows

The name 'contentDirCreatedByThisCall' does not exist in the current context

Check failure on line 557 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Windows

The name 'contentDirCreatedByThisCall' does not exist in the current context
{
// We created this directory in the current call — safe to remove entirely.
if (Directory.Exists(contentDir))
Directory.Delete(contentDir, recursive: true);
}
else if (sourcePathWrittenByThisCall && Directory.Exists(contentDir))

Check failure on line 563 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Linux

The name 'sourcePathWrittenByThisCall' does not exist in the current context

Check failure on line 563 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Linux

The name 'sourcePathWrittenByThisCall' does not exist in the current context

Check failure on line 563 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Windows

The name 'sourcePathWrittenByThisCall' does not exist in the current context

Check failure on line 563 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Windows

The name 'sourcePathWrittenByThisCall' does not exist in the current context

Check failure on line 563 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Windows

The name 'sourcePathWrittenByThisCall' does not exist in the current context
{
// We overwrote an existing source.path file - restore it or delete if it was new
var sourcePathFile = Path.Combine(contentDir, FileTypes.SourcePathFileName);
if (previousSourcePathContent != null)

Check failure on line 567 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Linux

The name 'previousSourcePathContent' does not exist in the current context

Check failure on line 567 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Linux

The name 'previousSourcePathContent' does not exist in the current context

Check failure on line 567 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Windows

The name 'previousSourcePathContent' does not exist in the current context

Check failure on line 567 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Windows

The name 'previousSourcePathContent' does not exist in the current context
{
// Restore the previous content
await File.WriteAllTextAsync(sourcePathFile, previousSourcePathContent, CancellationToken.None);

Check failure on line 570 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Linux

The name 'previousSourcePathContent' does not exist in the current context

Check failure on line 570 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Linux

The name 'previousSourcePathContent' does not exist in the current context

Check failure on line 570 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Windows

The name 'previousSourcePathContent' does not exist in the current context

Check failure on line 570 in GenHub/GenHub/Features/Content/Services/ContentStorageService.cs

View workflow job for this annotation

GitHub Actions / Build Windows

The name 'previousSourcePathContent' does not exist in the current context
}
else
{
// We created a new file, safe to delete
FileOperationsService.DeleteFileIfExists(sourcePathFile);
}
}
Comment thread
undead2146 marked this conversation as resolved.

Comment thread
undead2146 marked this conversation as resolved.
// Untrack manifest if we failed to save its metadata but had already tracked/refreshed references.
await _referenceTracker.UntrackManifestAsync(manifest.Id, CancellationToken.None);
}
Expand Down
10 changes: 9 additions & 1 deletion GenHub/GenHub/Features/Manifest/ContentManifestPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -294,12 +294,20 @@ public async Task<OperationResult<bool>> IsManifestAcquiredAsync(ManifestId mani
var contentDir = Path.Combine(storageService.GetContentStorageRoot(), DirectoryNames.Data, manifestId.Value);

// If a mapping file exists, return its value (this points to the original source directory)
var mappingFile = Path.Combine(contentDir, "source.path");
var mappingFile = Path.Combine(contentDir, FileTypes.SourcePathFileName);
if (File.Exists(mappingFile))
{
var sourcePath = await File.ReadAllTextAsync(mappingFile, cancellationToken);
if (!string.IsNullOrWhiteSpace(sourcePath))
{
// Handle CAS-only content gracefully - return null without warnings
if (sourcePath.Trim().Equals("CAS-ONLY", StringComparison.OrdinalIgnoreCase))
{
return OperationResult<string?>.CreateSuccess(null);
}

return OperationResult<string?>.CreateSuccess(sourcePath);
}
}

var result = Directory.Exists(contentDir) ? contentDir : null;
Expand Down
50 changes: 25 additions & 25 deletions GenHub/GenHub/Features/Settings/Views/SettingsView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -409,31 +409,6 @@
<TextBlock Text="Select application color theme (More coming soon)"
Classes="setting-description" />
</StackPanel>

<!-- Auto Update Check -->
<StackPanel Spacing="8">
<CheckBox Content="Check for updates on startup"
IsChecked="{Binding AutoCheckForUpdatesOnStartup}" />
<TextBlock Text="Automatically check for GenHub updates when the application starts"
Classes="setting-description" Margin="24,0,0,0" />
</StackPanel>

<!-- Settings File Path -->
<StackPanel Spacing="8">
<TextBlock Text="Settings File Location" Classes="setting-label" />
<Grid ColumnDefinitions="*,Auto">
<TextBox Grid.Column="0"
Text="{Binding SettingsFilePath}"
Watermark="Default (platform-dependent)"
LostFocus="OnTextBoxLostFocus" />
<Button Grid.Column="1"
Content="Browse"
Command="{Binding BrowseSettingsFilePathCommand}"
Classes="browse-button" />
</Grid>
<TextBlock Text="Specify a custom location for your settings file. Leave empty for auto-detection."
Classes="setting-description" />
</StackPanel>
</StackPanel>
</Border>
</Expander>
Expand Down Expand Up @@ -480,6 +455,23 @@
Command="{Binding OpenCasPoolDirectoryCommand}"
Classes="secondary-button" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"/>
</Grid>

<!-- Settings File Path -->
<StackPanel Spacing="8">
<TextBlock Text="Settings File Location" Classes="setting-label" />
<Grid ColumnDefinitions="*,Auto">
<TextBox Grid.Column="0"
Text="{Binding SettingsFilePath}"
Watermark="Default (platform-dependent)"
LostFocus="OnTextBoxLostFocus" />
<Button Grid.Column="1"
Content="Browse"
Command="{Binding BrowseSettingsFilePathCommand}"
Classes="browse-button" />
</Grid>
<TextBlock Text="Specify a custom location for your settings file. Leave empty for auto-detection."
Classes="setting-description" />
</StackPanel>
</StackPanel>
</Border>
</Expander>
Expand Down Expand Up @@ -734,6 +726,14 @@
ToolTip.Tip="Browse available updates and subscribe to Pull Requests" />


<!-- Auto Update Check -->
<StackPanel Spacing="8">
<CheckBox Content="Check for updates on startup"
IsChecked="{Binding AutoCheckForUpdatesOnStartup}" />
<TextBlock Text="Automatically check for GenHub updates when the application starts"
Classes="setting-description" Margin="24,0,0,0" />
</StackPanel>

<!-- GitHub PAT for Artifact Access -->
<Border Background="#1E1E1E" CornerRadius="4" Padding="15" BorderBrush="#4E4E4E" BorderThickness="1">
<StackPanel Spacing="12">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,10 @@ await Parallel.ForEachAsync(
async (fileGroup, ct) =>
{
// For each destination path, process files in priority order (lowest to highest)
// Priority: GameInstallation (0) < GameClient (1) < Mod (2)
// Priority: GameInstallation (10) < Addon (40) < GameClient (50) < Patch (90) < Mod (100)
// This ensures higher priority content overwrites lower priority
var orderedFiles = fileGroup
.OrderBy(item => item.Manifest.ContentType)
.OrderBy(item => ContentTypePriority.GetPriority(item.Manifest.ContentType))
.ToList();
Comment thread
undead2146 marked this conversation as resolved.

// Process all versions of this file in priority order
Expand Down
Loading