Files
LlamaCasty/ytLive.csproj
T
gramps 1fe84be64a build(steam): stage steam_api64.dll beside the exe — one file, not the whole SDK
The SDK zip is 24 MB of headers, examples and tools we never build. The runtime
dependency is one native library, so scripts/steam-sdk.sh extracts exactly
sdk/redistributable_bin/win64/steam_api64.dll into steam/ (gitignored, like ffmpeg/ —
the script is the audit trail) and writes steam_appid.txt = 480, Valve's Spacewar app,
so SteamAPI.Init() resolves an app id locally before LlamaCasty has one of its own.

Two csproj details that would have cost a debugging session:
- Link="steam_api64.dll" puts it BESIDE the exe; without Link, None items keep their
  relative path and it lands in steam/, where the loader does not look.
- ExcludeFromSingleFile, for the same reason ffmpeg needed it: a native DLL otherwise
  gets swallowed into the single-file bundle and cannot be loaded at runtime.

steam_appid.txt is Debug-only — Valve's guidance is not to ship it — and the publish
output confirms it: dll present at the root, no appid file, exe still 127 MB (proof the
DLL was not bundled).

Also queued, as asked: preview undo (Ctrl+Z / Ctrl+Shift+Z) in edit mode, noted as the
partner to the defaults-vs-current split — undo covers the slip, defaults cover the mess.
2026-11-01 07:23:29 -08:00

183 lines
11 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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="&quot;C:\Program Files\Git\cmd\git.exe&quot; 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="// &lt;auto-generated&gt; 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 = &quot;#$(BuildNumber)&quot;%3B public const string Id = &quot;$(BuildStampId)&quot;%3B public const string BuiltLocal = &quot;$(BuildStampTime)&quot;%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" />
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="8.0.0" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2903.40" />
</ItemGroup>
</Project>