The first half of surge day 1. One question, "may this session emit Pro output?", with one method on the interface so nothing downstream knows which rail proved it. SteamEntitlement reads the lifetime SKU the way Valve intends: SteamAPI.Init() then SteamApps.BIsDlcInstalled(dlcAppId). Four different failure paths all resolve to the free tier rather than to Pro or to a crash — no DLC id configured, no Steam client, steam_api64.dll missing (a throw on first touch), and simply not owned. A copied folder run without Steam is the common case, not an exceptional one. NotConfigured() is the shipping default until Steamworks creates the DLC app; it answers false without ever touching the native library, so today's builds behave exactly as they did before this commit. HasProOutput is now IsPremium || DeveloperMode || rail, with an internal EntitlementOverride test seam (internal, because a public setter here is a licence bypass). Four tests: no id reads false, no client reads false without throwing, the fake reports what a test sets, and the view model takes its answer from the rail. Steamworks.NET 2024.8.0 added; the native DLL still comes from scripts/steam-sdk.sh, so the csproj change is three lines and no formatting churn.
186 lines
11 KiB
XML
186 lines
11 KiB
XML
<Project Sdk="Microsoft.NET.Sdk">
|
||
|
||
<PropertyGroup>
|
||
<OutputType>WinExe</OutputType>
|
||
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
|
||
<Nullable>enable</Nullable>
|
||
<ImplicitUsings>enable</ImplicitUsings>
|
||
<UseWPF>true</UseWPF>
|
||
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
||
<ApplicationIcon>Assets\llamacasty-icon.ico</ApplicationIcon>
|
||
<!-- The shipped exe is LlamaCasty.exe (renamed 2026-11-01, before the first Steam depot so
|
||
the store never sees the legacy name). RootNamespace stays `ytLive` — the C# namespaces
|
||
are not user-visible and renaming them would churn every file for no benefit. -->
|
||
<AssemblyName>LlamaCasty</AssemblyName>
|
||
<RootNamespace>ytLive</RootNamespace>
|
||
<!-- 64-bit Windows only (creator ruling 2026-10-09). The bundled ffmpeg is the win64 build
|
||
and ONNX Runtime ships no win-x86 native, so a 32-bit process could never stream; a
|
||
32-bit address space (2–4 GB) would also choke on 1080p frame buffers. x64 makes the
|
||
exe refuse to start on 32-bit Windows instead of failing at Go Live. -->
|
||
<PlatformTarget>x64</PlatformTarget>
|
||
</PropertyGroup>
|
||
|
||
<ItemGroup>
|
||
<Compile Remove="ytLive.Tests\**" />
|
||
<EmbeddedResource Remove="ytLive.Tests\**" />
|
||
<None Remove="ytLive.Tests\**" />
|
||
<Page Remove="ytLive.Tests\**" />
|
||
</ItemGroup>
|
||
|
||
<!-- Per-build identity stamp (2026-09-04): takes 1–6 could not be attributed to an
|
||
exact binary — render perf "fixes" were being judged against builds we could not
|
||
prove were running. A fresh GUID per build makes an incremental compile impossible
|
||
(that is the point: every exe you launch was compiled NOW), the wordmark shows the
|
||
id, and startup.log records id + build time. -->
|
||
<Target Name="GenerateBuildStamp" BeforeTargets="CoreCompile">
|
||
<PropertyGroup>
|
||
<BuildStampFile>$(IntermediateOutputPath)BuildStamp.g.cs</BuildStampFile>
|
||
<BuildStampId>$([System.Guid]::NewGuid().ToString('N').Substring(0,8))</BuildStampId>
|
||
<BuildStampTime>$([System.DateTime]::Now.ToString('yyyy-MM-dd HH:mm:ss'))</BuildStampTime>
|
||
<!-- RELEASE COUNTER (creator ruling 2026-09-04): the UI shows a sequential number that
|
||
ticks +1 per COMMIT, starting at 13 — a per-BUILD GUID changed on every launch and read
|
||
as noise (rightly). Derived from git rev-list count (stable per commit, no bookkeeping).
|
||
Baseline 241 = count at introduction, first display 13. Missing git or unparsed output
|
||
falls back to the start (build never breaks). GUID + compile time stay in startup.log,
|
||
where build-identity forensics actually live. -->
|
||
<BuildNumberBaseline>17</BuildNumberBaseline>
|
||
<BuildNumberStart>13</BuildNumberStart>
|
||
</PropertyGroup>
|
||
<Exec Command=""C:\Program Files\Git\cmd\git.exe" rev-list --count HEAD"
|
||
WorkingDirectory="$(ProjectDir)" ConsoleToMSBuild="true" IgnoreExitCode="true">
|
||
<Output TaskParameter="ConsoleOutput" PropertyName="CommitCountRaw" />
|
||
</Exec>
|
||
<PropertyGroup>
|
||
<CommitCount>$(CommitCountRaw.Trim())</CommitCount>
|
||
<BuildCounterFile>$(ProjectDir)BuildCounter.txt</BuildCounterFile>
|
||
<PriorBuildCount Condition="Exists('$(BuildCounterFile)')">$([System.IO.File]::ReadAllText('$(BuildCounterFile)').Trim())</PriorBuildCount>
|
||
<PriorBuildCount Condition="'$(PriorBuildCount)' == ''">423</PriorBuildCount>
|
||
<BuildNumber>$([MSBuild]::Add($(PriorBuildCount), 1))</BuildNumber>
|
||
</PropertyGroup>
|
||
<WriteLinesToFile File="$(BuildCounterFile)" Lines="$(BuildNumber)" Overwrite="true" WriteOnlyWhenDifferent="false" />
|
||
<PropertyGroup>
|
||
<BuildNumber Condition="! $([System.Text.RegularExpressions.Regex]::IsMatch('$(BuildNumber)', '^[0-9]+$'))">$(BuildNumberStart)</BuildNumber>
|
||
</PropertyGroup>
|
||
<ItemGroup>
|
||
<BuildStampLines Include="// <auto-generated> Per-build identity (ytLive.csproj GenerateBuildStamp)."/>
|
||
<BuildStampLines Include="// Release/Label = the sequential UI stamp (+1 per commit, started at 13)."/>
|
||
<BuildStampLines Include="// Id/BuiltLocal = per-build forensic identity, logged to startup.log only. Never edit by hand."/>
|
||
<BuildStampLines Include="namespace ytLive.Helpers%3B"/>
|
||
<BuildStampLines Include="public static class BuildStamp { public const int Release = $(BuildNumber)%3B public const string Label = "#$(BuildNumber)"%3B public const string Id = "$(BuildStampId)"%3B public const string BuiltLocal = "$(BuildStampTime)"%3B }"/>
|
||
</ItemGroup>
|
||
<WriteLinesToFile File="$(BuildStampFile)" Lines="@(BuildStampLines)" Overwrite="true" WriteOnlyWhenDifferent="false" />
|
||
<ItemGroup>
|
||
<Compile Include="$(BuildStampFile)" />
|
||
</ItemGroup>
|
||
</Target>
|
||
|
||
<ItemGroup>
|
||
<Resource Include="Assets\llamacasty-icon.png" />
|
||
<Resource Include="Assets\llamacasty-logo.jpg" />
|
||
<Resource Include="Assets\starting-background.jpg" />
|
||
<Resource Include="Assets\brb-background.jpg" />
|
||
<Resource Include="Assets\live-background.jpg" />
|
||
<Resource Include="Assets\ending-background.jpg" />
|
||
<Resource Include="Assets\chat-background.jpg" />
|
||
<Resource Include="Assets\alert-default.mp4" />
|
||
<!-- Design-standard typefaces (DESIGN.md): Inter + JetBrains Mono, OFL-1.1. -->
|
||
<Resource Include="Assets\Fonts\Inter-Regular.ttf" />
|
||
<Resource Include="Assets\Fonts\Inter-Medium.ttf" />
|
||
<Resource Include="Assets\Fonts\Inter-SemiBold.ttf" />
|
||
<Resource Include="Assets\Fonts\Inter-Bold.ttf" />
|
||
<Resource Include="Assets\Fonts\JetBrainsMono-Medium.ttf" />
|
||
<Resource Include="Assets\Fonts\JetBrainsMono-SemiBold.ttf" />
|
||
</ItemGroup>
|
||
|
||
<ItemGroup Condition="'$(Configuration)' != 'Debug'">
|
||
<!-- ⛔ Development-only UI never ships: no BAML, no code-behind, nothing to reveal.
|
||
OverlayHost adds the panel at runtime inside #if DEBUG, so a Release build has no
|
||
reference to it and compiles cleanly. -->
|
||
<Page Remove="Controls\DeveloperPanel.xaml" />
|
||
<Compile Remove="Controls\DeveloperPanel.xaml.cs" />
|
||
</ItemGroup>
|
||
|
||
<!-- Steamworks runtime (scripts/steam-sdk.sh extracts it; steam/ is gitignored).
|
||
⛔ Link puts it BESIDE the exe rather than under steam/, because the loader looks there.
|
||
⛔ ExcludeFromSingleFile matters for the same reason as ffmpeg: a native DLL otherwise
|
||
gets swallowed into the single-file bundle and the app cannot load it at runtime. -->
|
||
<ItemGroup>
|
||
<None Remove="steam\**" />
|
||
<None Include="steam\steam_api64.dll" Link="steam_api64.dll"
|
||
CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="Always"
|
||
ExcludeFromSingleFile="true" />
|
||
<!-- Local-only: lets SteamAPI.Init() resolve an app id outside the Steam client (480 =
|
||
Valve's Spacewar test app). Never published — Valve's guidance is to omit it. -->
|
||
<None Include="steam\steam_appid.txt" Link="steam_appid.txt" Condition="'$(Configuration)' == 'Debug'"
|
||
CopyToOutputDirectory="PreserveNewest" />
|
||
</ItemGroup>
|
||
|
||
<ItemGroup>
|
||
<None Include="THIRD-PARTY-NOTICES.txt" CopyToOutputDirectory="PreserveNewest" />
|
||
<!-- The EULA and privacy policy travel with every copy: they are what the About screen and
|
||
any store listing are checked against. -->
|
||
<None Include="LICENSE" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="Always" />
|
||
<None Include="PRIVACY.md" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="Always" />
|
||
</ItemGroup>
|
||
|
||
<!-- Webcam background effects (TASK 51): Google's MediaPipe Selfie Segmenter (landscape,
|
||
Apache-2.0), converted to ONNX by tools/selfie-seg/ and embedded in the assembly —
|
||
~430 KB, so it lives in git, ships inside the exe, and is never downloaded at runtime
|
||
(Store policy 10.2.2, same posture as the bundled ffmpeg). -->
|
||
<ItemGroup>
|
||
<EmbeddedResource Include="Assets\Models\selfie_segmenter_landscape.onnx" LogicalName="ytLive.Assets.Models.selfie_segmenter_landscape.onnx" />
|
||
</ItemGroup>
|
||
|
||
<!-- Bundled FFmpeg (TASK 48 item 1, Store policy 10.2.2 dynamic code inclusion).
|
||
The app used to DOWNLOAD an unsigned ffmpeg from GitHub at first run and execute
|
||
it; that 404'd on the creator's first real recording (2026-09-01) and is the one
|
||
hard certification gate. ffmpeg.exe + ffprobe.exe + the libav*.dll family now ship
|
||
in the output under a single ffmpeg/ folder — the shared build resolves its DLLs
|
||
from the exe's own directory, so they must stay siblings.
|
||
|
||
The binaries are NOT in git (135 MB). scripts/fetch-ffmpeg.sh populates ./ffmpeg
|
||
from a pinned URL, verifying SHA-256 first. CopyToPublishDirectory=Always is the
|
||
one that matters for the MSIX package. -->
|
||
<ItemGroup>
|
||
<!-- `Remove` first: the SDK's default None glob already matched ffmpeg\**, so an Include
|
||
without removing it produced DUPLICATE items — one carrying the copy metadata and one
|
||
with none. Harmless until PublishSingleFile + IncludeNativeLibrariesForSelfExtract came
|
||
along, where the bundler collapses the duplicate and the folder silently stops being
|
||
published (found 2026-11-01: a 9-file publish with no ffmpeg in it). -->
|
||
<!-- ⛔ ExcludeFromSingleFile is load-bearing. With PublishSingleFile +
|
||
IncludeNativeLibrariesForSelfExtract the bundler treats the libav*.dll family as native
|
||
libs and swallows them INTO the exe — a 182 MB exe with no ffmpeg\ folder beside it, so
|
||
the locator finds nothing and every stream fails at runtime. The metadata keeps the
|
||
folder a folder. (Found 2026-11-01 by diffing the publish output against a control
|
||
publish without the single-file flags.) -->
|
||
<None Remove="ffmpeg\**" />
|
||
<None Include="ffmpeg\**" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="Always" ExcludeFromSingleFile="true" />
|
||
</ItemGroup>
|
||
|
||
<Target Name="GuardBundledFfmpeg" BeforeTargets="CoreCompile">
|
||
<Error Condition="!Exists('$(MSBuildProjectDirectory)\ffmpeg\ffmpeg.exe')"
|
||
Text="Bundled FFmpeg is missing from ffmpeg\. Run scripts/fetch-ffmpeg.sh once before building (it pins the URL and verifies SHA-256). FFmpeg must be bundled, never downloaded at runtime — that is Windows Store policy 10.2.2, and the previous download path 404'd on 2026-09-01." />
|
||
</Target>
|
||
|
||
<ItemGroup>
|
||
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
||
<_Parameter1>ytLive.Tests</_Parameter1>
|
||
</AssemblyAttribute>
|
||
</ItemGroup>
|
||
|
||
<ItemGroup>
|
||
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.10" />
|
||
<PackageReference Include="Microsoft.ML.OnnxRuntime" Version="1.31.0" />
|
||
<PackageReference Include="NAudio.Wasapi" Version="2.2.1" />
|
||
<PackageReference Include="NAudio.WinMM" Version="2.2.1" />
|
||
<PackageReference Include="Notification.Wpf" Version="11.0.0" />
|
||
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.12" />
|
||
<!-- Steam's managed wrapper. The native steam_api64.dll comes from the SDK via
|
||
scripts/steam-sdk.sh; this package only provides the C# surface (SteamAPI, SteamApps). -->
|
||
<PackageReference Include="Steamworks.NET" Version="2024.8.0" />
|
||
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="8.0.0" />
|
||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2903.40" />
|
||
</ItemGroup>
|
||
|
||
</Project>
|