Dev Building from Source - FitzDegenhub/UltimateCameraMod GitHub Wiki
This document covers prerequisites, solution structure, project references, NuGet dependencies, build commands, and publish configuration for UCM.
| Requirement | Version | Notes |
|---|---|---|
| .NET SDK | 6.0+ | The projects target net6.0 / net6.0-windows. Any 6.0+ SDK will work. |
| OS | Windows 10/11 | WPF is Windows-only. Linux/macOS cannot build the V3 app. |
| Visual Studio | 2022+ (optional) | For IDE-based development. VS Code with C# Dev Kit also works. |
| Git | Any recent version | For cloning the repository. |
WPF and Windows Forms support is required. The .NET SDK's Windows Desktop workload must be installed. If you installed the SDK via Visual Studio, this is included by default. For standalone SDK installs:
dotnet workload install microsoft-net-sdk-windowsdesktopThe repository contains two projects under src/:
src/
UltimateCameraMod/ # Shared library (v2 legacy + shared services)
UltimateCameraMod.csproj
Models/
AdvancedRow.cs
CameraParamDocs.cs
CameraRules.cs
PresetCodec.cs
Services/
CameraMod.cs
GameDetector.cs
GameInstallBaselineTracker.cs
JsonModExporter.cs
Paz/
ArchiveWriter.cs
AssetCodec.cs
CompressionUtils.cs
NameHasher.cs
PamtReader.cs
PazEntry.cs
StreamTransform.cs
MainWindow.xaml.cs # v2 app entry (legacy)
...
UltimateCameraMod.V3/ # V3 WPF application
UltimateCameraMod.V3.csproj
MainWindow.xaml
MainWindow.xaml.cs
MainWindow.Presets.cs
MainWindow.Editors.cs
MainWindow.FineTune.cs
MainWindow.GodMode.cs
MainWindow.Import.cs
MainWindow.Export.cs
MainWindow.Community.cs
MainWindow.Taskbar.cs
Controls/
CameraPreview.cs
FovPreview.cs
Models/
PresetManagerItem.cs
ImportedPreset.cs
Assets/
ucm.ico
ucm-app-icon.png
ShippedPresets/
*.json
...
The shared library (UltimateCameraMod/) was originally the v2 application. When v3 was developed as a new WPF app, the core services (camera modification engine, PAZ archive handling, game detection) were kept in the original project to allow potential reuse. The V3 project references shared source files via <Compile Include> links rather than a project reference.
The V3 .csproj includes shared source files using linked compile items:
<ItemGroup>
<Compile Include="..\UltimateCameraMod\Models\AdvancedRow.cs">
<Link>Shared\Models\AdvancedRow.cs</Link>
</Compile>
<Compile Include="..\UltimateCameraMod\Models\CameraParamDocs.cs">
<Link>Shared\Models\CameraParamDocs.cs</Link>
</Compile>
<Compile Include="..\UltimateCameraMod\Models\CameraRules.cs">
<Link>Shared\Models\CameraRules.cs</Link>
</Compile>
<Compile Include="..\UltimateCameraMod\Models\PresetCodec.cs">
<Link>Shared\Models\PresetCodec.cs</Link>
</Compile>
<Compile Include="..\UltimateCameraMod\Services\CameraMod.cs">
<Link>Shared\Services\CameraMod.cs</Link>
</Compile>
<Compile Include="..\UltimateCameraMod\Services\GameDetector.cs">
<Link>Shared\Services\GameDetector.cs</Link>
</Compile>
<Compile Include="..\UltimateCameraMod\Services\GameInstallBaselineTracker.cs">
<Link>Shared\Services\GameInstallBaselineTracker.cs</Link>
</Compile>
<Compile Include="..\UltimateCameraMod\Services\JsonModExporter.cs">
<Link>Shared\Services\JsonModExporter.cs</Link>
</Compile>
<Compile Include="..\UltimateCameraMod\Paz\*.cs">
<Link>Shared\Paz\%(Filename)%(Extension)</Link>
</Compile>
</ItemGroup>This means the shared .cs files are compiled directly into the V3 assembly. There is no separate DLL output for the shared library when building V3. The <Link> elements control how these files appear in the Solution Explorer (under a virtual Shared/ folder).
| Package | Version | Used By | Purpose |
|---|---|---|---|
K4os.Compression.LZ4 |
1.3.8 | Both projects | LZ4 compression/decompression for PAZ archive entries |
This is the only external NuGet dependency. It is referenced in both .csproj files:
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.8" />All other functionality uses .NET BCL types (System.Text.Json, System.Security.Cryptography, System.Net.Http, etc.).
Key properties from UltimateCameraMod.V3.csproj:
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>false</ImplicitUsings>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<AssemblyName>UltimateCameraMod.V3</AssemblyName>
<RootNamespace>UltimateCameraMod.V3</RootNamespace>
<Version>3.0.1-beta</Version>
<Authors>0xFitz</Authors>
<Description>Export-first camera workflow for Crimson Desert Mod Manager</Description>
<ApplicationIcon>Assets\ucm.ico</ApplicationIcon>
</PropertyGroup>Notable settings:
-
ImplicitUsingsis disabled in V3 (explicitusingstatements throughout). The shared library project has it enabled. -
UseWindowsFormsis enabled forFolderBrowserDialogusage (WPF does not have a native folder picker). -
OutputTypeisWinExe(notExe), which suppresses the console window.
Shipped presets are embedded as resources:
<ItemGroup>
<EmbeddedResource Include="ShippedPresets\*.json" />
</ItemGroup>The .csproj includes a custom target to copy the icon to the output directory:
<Target Name="CopyUcmIcoToOutput" AfterTargets="Build">
<Copy SourceFiles="$(MSBuildProjectDirectory)\Assets\ucm.ico"
DestinationFolder="$(OutputPath)Assets"
SkipUnchangedFiles="true" />
<Copy SourceFiles="$(MSBuildProjectDirectory)\Assets\ucm.ico"
DestinationFiles="$(OutputPath)ucm.ico"
SkipUnchangedFiles="true" />
</Target>The icon is copied to both Assets/ucm.ico (standard location) and the output root ucm.ico (fallback for LoadImage(LR_LOADFROMFILE) when the Windows shell probes for the icon before the Assets directory exists).
Key properties from UltimateCameraMod.csproj:
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AssemblyName>UltimateCameraMod</AssemblyName>
<RootNamespace>UltimateCameraMod</RootNamespace>
<Version>2.5.0</Version>
<!-- Publishing: single-file self-contained -->
<PublishSingleFile>true</PublishSingleFile>
<SelfContained>true</SelfContained>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
</PropertyGroup>This project is the v2 application. It has OutputType=WinExe because it was originally a standalone app. The publish properties are for the v2 distribution and are not used when building V3.
dotnet build src/UltimateCameraMod.V3/UltimateCameraMod.V3.csprojOutput: src/UltimateCameraMod.V3/bin/Debug/net6.0-windows/
dotnet build src/UltimateCameraMod.V3/UltimateCameraMod.V3.csproj -c ReleaseOutput: src/UltimateCameraMod.V3/bin/Release/net6.0-windows/
If a solution file exists:
dotnet build src/UltimateCameraMod.slnOr build individually (the V3 project does not have a <ProjectReference> to the shared library, so they are independent build targets).
Happens automatically on build, but can be triggered explicitly:
dotnet restore src/UltimateCameraMod.V3/UltimateCameraMod.V3.csprojFor distribution, UCM is published as a single-file, self-contained executable.
dotnet publish src/UltimateCameraMod.V3/UltimateCameraMod.V3.csproj \
-c Release \
-r win-x64 \
--self-contained true \
-p:PublishSingleFile=true \
-p:EnableCompressionInSingleFile=trueOutput: src/UltimateCameraMod.V3/bin/Release/net6.0-windows/win-x64/publish/
| Property | Value | Purpose |
|---|---|---|
PublishSingleFile |
true |
Bundles all assemblies, resources, and native libraries into a single .exe
|
SelfContained |
true |
Includes the .NET runtime so users do not need to install .NET separately |
RuntimeIdentifier |
win-x64 |
Targets 64-bit Windows |
EnableCompressionInSingleFile |
true |
Compresses the bundled assemblies to reduce file size |
The resulting executable is standalone and can be distributed as a single file (plus the Assets/ucm.ico that is copied alongside).
After publish, the distribution package typically contains:
UltimateCameraMod.V3.exe # Single-file self-contained executable
Assets/
ucm.ico # Application icon
ucm.ico # Shell fallback icon
The preset directories (ucm_presets/, my_presets/, etc.) and sidecar files (.catalog_state.json, advanced_overrides.json, install_trace.txt) are created at runtime.
There is no automated test project. Testing is performed manually through the application. The key verification points are:
- Export/install pipeline: Use
install_trace.txtandpayload_changedfield to verify writes - Binary diff:
VerifyPatchesRoundTrip()inJsonModExporterprovides runtime verification during JSON export - Size matching:
ArchiveWriter.MatchCompressedSizethrows if it cannot hit the target size, preventing silent corruption
If contributing, manual testing should cover:
- Fresh launch (no presets, no game detected)
- Game detection and vanilla backup creation
- Quick tab slider changes and preview updates
- Fine Tune slider generation and sync from Quick
- God Mode DataGrid editing
- All four export formats
- Install to Game and Restore
- Preset download, update detection, and update flow
- Import from each supported format (XML, PAZ, JSON, UCM preset)
"UseWPF is not supported": You are building on Linux or macOS. WPF requires Windows.
Missing .NET SDK: Install the .NET 6.0 SDK from https://dotnet.microsoft.com/download. The dotnet command must be on your PATH.
NuGet restore failure: Check network connectivity. The only external package is K4os.Compression.LZ4 from NuGet.org.
Icon not found at runtime: The CopyUcmIcoToOutput target runs after build. If you are running from a non-standard output directory, the icon may not be present. The app handles this gracefully with fallback behavior.
| File | Role |
|---|---|
src/UltimateCameraMod.V3/UltimateCameraMod.V3.csproj |
V3 app project file |
src/UltimateCameraMod/UltimateCameraMod.csproj |
Shared library / v2 project file |
src/UltimateCameraMod.V3/GlobalUsings.cs |
Global using directives for V3 |
src/UltimateCameraMod/GlobalUsings.cs |
Global using directives for shared library |
src/UltimateCameraMod.V3/AssemblyInfo.cs |
Assembly metadata |