Skip to content

New project file system#3

Merged
coconutbird merged 12 commits intomainfrom
dev/projfile
Jan 31, 2026
Merged

New project file system#3
coconutbird merged 12 commits intomainfrom
dev/projfile

Conversation

@coconutbird
Copy link
Copy Markdown
Owner

  • Fix project file relative pathing
  • Support direct .bnk editing
  • More

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a significant architectural refactoring to support direct BNK file editing alongside PCK package files. It implements a unified IAudioFile interface that abstracts over both file types, enabling commands and batch operations to work seamlessly with either format.

Changes:

  • Introduced IAudioFile and IAudioFileFactory abstractions to unify PCK and BNK file handling
  • Created BnkFile wrapper class enabling standalone BNK files to be edited directly
  • Refactored batch project system with improved relative path handling (input files relative to game directory, action source files relative to project file)
  • Updated all CLI commands to use the new unified audio file factory
  • Added comprehensive test coverage for new BNK file functionality
  • Added Native AOT/trimming support attributes (DynamicallyAccessedMembers)
  • Changed batch project file extension from .batchproj to .json
  • Added GitHub Actions CI/CD workflows
  • Enabled NuGet package lock files for reproducible builds
  • Updated .NET SDK version to 10.0.100

Reviewed changes

Copilot reviewed 47 out of 47 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
PckTool.Abstractions/IAudioFile.cs New unified interface for PCK and BNK files
PckTool.Abstractions/IAudioFileFactory.cs New factory interface for creating audio file instances
PckTool.Core/WWise/AudioFileFactory.cs Implementation of audio file factory with automatic type detection
PckTool.Core/WWise/Bnk/BnkFile.cs New wrapper class for standalone BNK files implementing IAudioFile
PckTool.Core/WWise/Bnk/Collections/* Moved collection classes to dedicated Collections namespace
PckTool.Core/WWise/Bnk/Entries/BnkFileSoundBankEntry.cs Entry wrapper for BNK soundbank in standalone files
PckTool.Core/WWise/Pck/PckFile.cs Updated to implement IAudioFile alongside existing interfaces
PckTool.Core/Services/Batch/BatchProjectExecutor.cs Refactored to use IAudioFileFactory and improved path resolution
PckTool.Core/Services/Batch/BatchProject.cs Enhanced validation with separate game directory handling
PckTool.Core/Services/PackageBrowser.cs Updated to use IAudioFileFactory for unified file loading
PckTool/Services/ServiceProvider.cs Replaced PckFileFactory with AudioFileFactory
PckTool/Commands/*.cs All commands updated to use IAudioFileFactory and added AOT attributes
PckTool/Program.cs Added comprehensive command examples and aliases
tests/PckTool.Core.Tests/BnkFileTests.cs New comprehensive tests for BNK file operations
tests/PckTool.Core.Tests/SoundBankTests.cs Tests moved from other files and organized
tests/PckTool.Core.Tests/PckFileTests.cs PCK-specific tests reorganized
global.json SDK version updated to 10.0.100
.github/workflows/* New CI/CD workflows for build, test, and release
Directory.Build.props Enabled package lock files globally
**/packages.lock.json New lock files for reproducible builds

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +41 to +65
public void ReplaceWith(byte[] data)
{
// For standalone BNK, we need to re-parse the data into the soundbank
// This is a bit unusual but maintains consistency with the interface
var newBank = SoundBank.Parse(data);

if (newBank is null)
{
throw new InvalidDataException("Failed to parse replacement BNK data.");
}

// Copy properties from new bank to existing bank
// Note: This is a simplified approach - in practice you might want to
// replace the entire soundbank reference
_soundBank.Media.Clear();

foreach (var kvp in newBank.Media)
{
_soundBank.Media.Add(kvp.Key, kvp.Value);
}

_soundBank.Items.Clear();
_soundBank.Items.AddRange(newBank.Items);

_parent.MarkModified();
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

The ReplaceWith method only copies Media and Items from the new bank but doesn't copy other important properties like Id, LanguageId, Version, ProjectId, and FeedbackInBank. This could lead to inconsistencies where the soundbank's metadata doesn't match its actual content.

Consider copying all properties from newBank to _soundBank, or document why only Media and Items should be replaced while preserving the original metadata.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

This is intentional. We're replacing the soundbank's content (Media and Items), not its identity. The metadata (Id, LanguageId, etc.) should remain unchanged so the soundbank stays in the same slot within the parent file. Added a clarifying comment to the code.

Comment on lines +25 to +26
/// <inheritdoc />
public uint Size => (uint) _soundBank.ToByteArray().Length;
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

The Size property calls ToByteArray() on every access, which serializes the entire soundbank. This could be a performance issue if Size is accessed frequently (e.g., in loops or UI binding).

Consider caching the size value and invalidating it when the soundbank is modified, or computing the size differently without full serialization.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

For a CLI tool, Size is typically accessed once per entry during listing/display operations, not in tight loops. The overhead is negligible in this context. If this becomes a hot path in the future, we can add caching then.

{
// Dispose all loaded files
foreach (var pck in loadedFiles.Values)
foreach (var audioFile in loadedFiles.Values)
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

This variable is manually disposed in a finally block - consider a C# using statement as a preferable resource management technique.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

The dictionary is built up incrementally during execution, so a using statement isn't practical here. The try/finally pattern is appropriate for this use case where we're managing a collection of disposables that are created at different points in the method.

{
// Arrange
var tempPath = Path.GetTempFileName();
PckFile? loaded = null;
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

This variable is manually disposed in a finally block - consider a C# using statement as a preferable resource management technique.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

This is test code cleaning up a temp file. The try/finally is clear and appropriate here - using a using statement for a file path string wouldn't make sense, and wrapping the temp file in a disposable helper would be overkill for a test.

@coconutbird coconutbird merged commit dfb178f into main Jan 31, 2026
1 check passed
@coconutbird coconutbird deleted the dev/projfile branch January 31, 2026 22:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants