Repository Wiki
BeyondDimension/SteamTools

解决方案组成与分层架构

WattToolkit(Steam++)仓库使用单一 XML 格式解决方案文件 WattToolkit.slnx 组织全部源代码,通过 7 个编号解决方案文件夹(/0.Root ~ /6.Tools)实现「根配置 → 宿主 → 参考程序集 → 测试 → 共享库 → 插件 → 工具」的分层组织,并由 src/Directory.Build.props 将编译属性、共享 AssemblyInfo 与隐式 global using 统一注入到解决方案内的每一个项目。

Purpose and Scope

本页是仓库顶层结构的权威参考,覆盖以下内容:

  • WattToolkit.slnx 解决方案的完整组成:解决方案文件夹、项目清单、目标平台(Any CPU / ARM / ARM64 / x64 / x86);
  • 分层架构与各层职责:/1.AppHost 宿主层、/4.Shared 共享层(含 Avalonia.Ref 与 ClientSDK 子层)、/5.Plugins 插件层、/2.Reference 参考程序集层(git 子模块)、/3.Test 测试层、/6.Tools 工具层;
  • 由 src/Directory.Build.props、src/TFM_NETX*.props 与 src/ImplicitUsings.*.cs 构成的统一构建约定与「配置注入」机制;
  • src/README.md 中记录的命名空间 / 文件夹约定(v3.X 时代沿用至今的分层语义)。

本页不覆盖(留给兄弟页面):各插件(Accelerator、Authenticator、ArchiSteamFarmPlus 等)的内部实现、Avalonia UI 层与视图模型细节、IPC 通信机制、反代加速实现、数据库实体设计等。本页只回答「解决方案由什么组成、如何分层、构建配置如何统一注入」。

Overview

解决方案文件:WattToolkit.slnx

仓库没有使用传统 .sln 文本格式,而是采用新的 XML 解决方案格式 .slnx。文件以 <Solution> 为根节点,先声明 5 个目标平台,再以嵌套 <Folder> / <Project> / <File> 节点描述整个目录树,最后在文件夹结构之外声明启动项目 src/BD.WTTS.Client.Avalonia.App:

xml
1<Solution> 2 <Configurations> 3 <Platform Name="Any CPU" /> 4 <Platform Name="ARM" /> 5 <Platform Name="ARM64" /> 6 <Platform Name="x64" /> 7 <Platform Name="x86" /> 8 </Configurations> 9 ... 10 <Project Path="src/BD.WTTS.Client.Avalonia.App/BD.WTTS.Client.Avalonia.App.csproj" /> 11</Solution>

Source: WattToolkit.slnx

选择 .slnx 的设计意图在于:XML 格式对合并冲突更友好、可被工具直接解析,并且天然支持「编号前缀文件夹」这种显式分层表达——文件夹编号即依赖方向(0 是被所有人依赖的配置层,1.AppHost 依赖 4.Shared,4.Shared 依赖 2.Reference)。

关键概念与术语

术语含义
解决方案文件夹(Solution Folder).slnx 中的逻辑分组(如 /5.Plugins/),不要求物理路径一致,仅用于在 IDE 中表达分层
AppHost(宿主)桌面应用宿主进程相关项目,负责进程模型与启动桥接
参考程序集层(ref/)通过 .gitmodules 引入的第三方 / 自维护 fork(git 子模块),以源码形式参与编译
Avalonia.Ref通过友元程序集或空程序集实现手动裁剪(trimming)的 Avalonia 兼容项目集
ClientSDK客户端调用云端微服务的 SDK 项目集(Models / ViewModels / Resources / Primitives)
插件(Plugins)按业务域拆分的功能模块(加速器、令牌验证器、挂卡等),编译期即集成进客户端
ImplicitUsings.*.cs按域拆分的隐式 global using 文件,通过 MSBuild Compile 项注入到各项目
CPM(Central Package Management)ManagePackageVersionsCentrally=true,NuGet 包版本统一由 Directory.Packages.props 管理

Architecture

下图展示解决方案的整体分层组成。图中实线表示「上层依赖下层」的分层方向(该方向遵循 src/README.md 记录的历史分层语义,具体项目间的 ProjectReference 以各 csproj 为准);虚线表示根配置层对全部项目的属性注入关系(由 src/Directory.Build.props 实现,见后文)。

Loading diagram...

各层职责说明:

  • /0.Root 根配置层:不产出程序集,而是承载 CI 工作流(.github/workflows/CI.yml)、nuget.config、.gitmodules、集中包版本(ref/DirectoryPackages/Directory.Packages.props)、src/.editorconfig、src/Directory.Build.props,以及 Source/(共享 AssemblyInfo*.cs、Utils.cs)、Source/ImplicitUsings/(31 个按域拆分的隐式 using 文件)、TFM/(6 个目标框架组合属性文件)与 Document/(含 doc/program-file-structure/ 下 Linux/macOS/Windows 三平台程序文件结构文档)。
  • /1.AppHost 宿主层:BD.WTTS.Client.AppHost 与 BD.WTTS.Client.AppHost.Bridge(注意:该项目文件名为 Steam++.csproj,属于历史命名遗留)。启动项目 BD.WTTS.Client.Avalonia.App 登记在文件夹结构之外。
  • /2.Reference 参考程序集层:全部位于 ref/ 下并以 git 子模块形式引入,分 6 组:AppCenter(崩溃/分析上报)、Avalonia(图像解码扩展 Avalonia.Gif、LibAPNG)、Common(BD.Common* 15 个基础类库:Essentials、Primitives、Mvvm(.ReactiveUI)、Pinyin(.TinyPinyin)、Security、Settings、Repositories.SQLitePCL、Area 等)、Ipc(dotnetCampus.Ipc + Analyzers)、Steam(BD.SteamClient、BD.SteamClient.Models.Protobuf、Facepunch.Steamworks.Posix/Win64、Steam4NET、Gameloop.Vdf、ValveKeyValue)、WinAuth(令牌验证算法)。
  • /3.Test 测试层:单一单元测试项目 BD.WTTS.UnitTest。
  • /4.Shared 共享层:客户端核心 BD.WTTS.Client、Avalonia View 层 BD.WTTS.Client.Avalonia、进程间通信 BD.WTTS.Client.IPC、图像兼容 BD.Avalonia8.Image2.Compat、共享代码项目 OSShuttingDownHelper.shproj(.shproj 直接以源码形式共享编译项),以及两个子层:Avalonia.Ref(10 个项目:Avalonia.Base(.Internals)、Avalonia.Controls.Internals、Avalonia.Desktop、Avalonia.Diagnostics、Avalonia.Native、Avalonia.Skia.Internals、Avalonia.WebView2、Avalonia.Win32、Avalonia.X11)与 ClientSDK(BD.WTTS.MicroServices.ClientSDK、BD.WTTS.MicroServices.Primitives(.Models/.ViewModels/.Resources)、BD.WTTS.Primitives(.Models/.ViewModels)、BD.WTTS.Primitives.Resources)。
  • /5.Plugins 插件层:8 个业务插件项目——Accelerator(网络加速)、Accelerator.ReverseProxy(反向代理实现)、ArchiSteamFarmPlus(ASF 挂卡)、Authenticator(令牌验证器)、GameAccount(账号切换)、GameList(游戏库存)、GameTools(游戏工具)、SteamIdleCard(挂卡)。
  • /6.Tools 工具层:构建/开发期工具——BD.Common.Settings.V4.SourceGenerator.Tools(设置源生成器工具)、BD.WTTS.Client.Avalonia.Designer.HostApp(设计器宿主)、BD.WTTS.Client.Tools.HostsTest、BD.WTTS.Client.Tools.OpenSourceLibraryList(开源许可清单生成)、BD.WTTS.Client.Tools.Publish(发布工具)。

核心机制:统一构建约定(src/Directory.Build.props)

src/Directory.Build.props 是分层架构中「配置即代码」的关键机制。MSBuild 会沿目录树向上查找该文件并自动应用到 src/ 下所有项目,从而让 40+ 个项目共享同一套编译语义,无需在每个 csproj 重复配置。

xml
1<Project> 2 <PropertyGroup> 3 <DotNet_Version>11.0</DotNet_Version> 4 <NoWarn>$(NoWarn);NU1507;1591;SA1612;IL2026;IL2091</NoWarn> 5 <LangVersion>latest</LangVersion> 6 <Nullable>enable</Nullable> 7 <GenerateAssemblyInfo>true</GenerateAssemblyInfo> 8 <GenerateDocumentationFile>false</GenerateDocumentationFile> 9 <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally> 10 <ImplicitUsings>enable</ImplicitUsings> 11 <IsTrimmable>true</IsTrimmable> 12 ... 13 <Deterministic>true</Deterministic> 14 <CETCompat>false</CETCompat> 15 </PropertyGroup> 16</Project>

Source: Directory.Build.props

关键属性的设计意图:

  • Nullable=enable + LangVersion=latest:全解决方案启用可空引用类型检查与最新语言特性,配合 ImplicitUsings=enable 消除样板 using;
  • ManagePackageVersionsCentrally=true:启用 CPM,所有 NuGet 包版本集中管理在 ref/DirectoryPackages/Directory.Packages.props(登记于 .slnx 的 /0.Root 文件夹),避免多项目版本漂移;
  • IsTrimmable=true + NoWarn 中的 IL2026;IL2091:客户端需要 AOT/裁剪发布(对应 TFM_NETX*.props 的多 TFM 矩阵),故声明程序集可裁剪,同时抑制裁剪警告以便逐步治理;
  • 关闭 GenerateAssemblyTitleAttribute 等 9 项程序集特性生成:因为程序集信息由 /0.Root/Source/ 下共享的 AssemblyInfo.cs、AssemblyInfo.Constants.cs、AssemblyInfo.Version.Max.cs 统一提供,避免双重定义。

共享源码注入

该文件还把根级源码文件以 Compile 项形式注入到每个项目,并通过 LinkBase=Properties 在 IDE 中归组:

xml
1<ItemGroup> 2 <Compile Include="..\AssemblyInfo.cs"> 3 <LinkBase>Properties</LinkBase> 4 </Compile> 5 <Compile Include="..\ImplicitUsings.BCL.cs"> 6 <LinkBase>Properties</LinkBase> 7 </Compile> 8 <Compile Include="..\ImplicitUsings.Common.cs"> 9 <LinkBase>Properties</LinkBase> 10 </Compile> 11</ItemGroup>

Source: Directory.Build.props

.slnx 的 /0.Root/Source/ImplicitUsings/ 文件夹中登记了 31 个 ImplicitUsings.*.cs 文件(ArchiSteamFarm、AspNetCore、AutoMapper、Avalonia、BCL、Common、Controllers、Data、EntityFrameworkCore、Identity、Jobs、JsonProperty、JWT、MessagePack、Models、MSEX、Nito、NLog、Plugins、Quartz、ReactiveUI、Repositories、Services、Settings、SQLite、Steam、UI、UI.ViewModels、UI.Views、UnitTest、WTTS)。这套设计让「按域组织的 global using」成为全局分层的一部分:任何项目引用到某一域(如 Services、Repositories、Steam)时无需手写 using。

目标框架矩阵(TFM props)

/0.Root/TFM/ 提供了 6 个目标框架组合文件,供不同项目按需导入以组成多目标矩阵:TFM_NETX.props、TFM_NETX_SINGLE.props、TFM_NETX_WINDOWS.props、TFM_NETX_WITH_ALL.props、TFM_NETX_WITH_DESKTOP.props、TFM_NETX_WITH_WINDOWS.props。这与 .slnx 中的 5 个平台(Any CPU、ARM、ARM64、x64、x86)共同支撑跨平台发布矩阵。此外 Directory.Build.props 对 net11.0 追加了 runtime-async=on 特性开关。

解决方案项目清单

下表汇总 .slnx 中登记的全部项目及其分层归属(共 41 个项目 + 1 个 .shproj):

解决方案文件夹项目职责
/1.AppHostBD.WTTS.Client.AppHost桌面客户端宿主进程
/1.AppHostBD.WTTS.Client.AppHost.Bridge(Steam++.csproj)宿主桥接(历史命名)
(根)BD.WTTS.Client.Avalonia.App启动项目(Avalonia 桌面应用)
/2.Reference/AppCenterBD.AppCenter.Any、BD.AppCenter.Analytics.Any崩溃与分析上报 SDK fork
/2.Reference/AvaloniaAvalonia.Gif、LibAPNGGIF/APNG 图像解码扩展
/2.Reference/CommonBD.Common + 14 个 BD.Common.*通用基础类库(Essentials/Primitives/Mvvm/Pinyin/Security/Settings/Repositories 等)
/2.Reference/IpcdotnetCampus.Ipc + dotnetCampus.Ipc.AnalyzersIPC 通信与代码分析器
/2.Reference/SteamBD.SteamClient、BD.SteamClient.Models.Protobuf、Facepunch.Steamworks.Posix/.Win64、Steam4NET、Gameloop.Vdf、ValveKeyValueSteam 互操作与 VDF/protobuf 解析
/2.Reference/WinAuthWinAuth令牌验证算法
/3.TestBD.WTTS.UnitTest单元测试
/4.SharedBD.WTTS.Client客户端核心类库
/4.SharedBD.WTTS.Client.AvaloniaAvalonia View 层
/4.SharedBD.WTTS.Client.IPC客户端 IPC
/4.SharedBD.Avalonia8.Image2.CompatAvalonia 8 图像兼容层
/4.SharedOSShuttingDownHelper.shproj共享编译项(关机辅助)
/4.Shared/Avalonia.RefAvalonia.Base(.Internals) 等 10 个项目通过友元程序集/空程序集手动裁剪
/4.Shared/ClientSDKBD.WTTS.MicroServices.ClientSDK 等 9 个项目云端微服务客户端 SDK
/5.PluginsAccelerator、Accelerator.ReverseProxy、ArchiSteamFarmPlus、Authenticator、GameAccount、GameList、GameTools、SteamIdleCard8 个业务功能插件
/6.ToolsSettings.V4.SourceGenerator.Tools、Avalonia.Designer.HostApp、Tools.HostsTest、Tools.OpenSourceLibraryList、Tools.Publish构建期与开发期工具

启动与加载流程(编译期视角)

从解决方案结构看,一次典型的桌面客户端启动在编译期表现为以下依赖传播顺序:

Loading diagram...

这一顺序解释了分层的设计动机:插件与 UI 都只依赖核心类库 BD.WTTS.Client,而所有对第三方 / 子模块的依赖收口在核心层与参考程序集层。新增一个插件时,只需在 /5.Plugins 增加一个项目并引用核心层,即可自动继承全部构建约定,不会触碰上层宿主代码。

历史分层语义(src/README.md)

src/README.md 记录了 v3.X 时代(当时的 ST.* 命名)的项目结构约定。虽然命名已演进为 BD.WTTS.*,其中描述的分层职责仍与当前 .slnx 结构一一对应,是理解该仓库分层的重要文档:

markdown
1- Lib 类库 2 - ST 业务通用类库 3 - ST.Client 客户端通用类库 4 - Platforms 5 - ST.Client.Windows 用于 Windows 的实现 6 - ST.Client.Mac 用于 macOS 的实现 7 - ST.Client.Linux 用于 GNU/Linux 的实现 8 - UI Framework 9 - ST.Client.Avalonia 使用 Avalonia 实现的 View 层 10 - Avalonia.Ref 通过友元程序集调用内部函数或空程序集实现手动裁剪 11 - Web API 12 - ST.Services.CloudService 客户端调用服务端 API 定义

Source: README.md

该文档同时记录了「命名空间/文件夹」约定,例如 Properties 下放置 AssemblyInfo.cs、InternalsVisibleTo.cs 与本地化资源 SR;Application 下按 Columns(模型实体列定义接口)、Converters(VM→V 值转换器)、Data(EFCore DbContext)、Entities(ORM 表实体)等子目录组织业务代码。.slnx 根文件夹对 src/AssemblyInfo*.cs 与 src/ImplicitUsings/* 的集中登记,正是这一约定在构建层的落地。

命名规范与演进

  • 前缀分层:BD.Common*(基础层)→ BD.WTTS.MicroServices* / BD.WTTS.Primitives*(云 SDK 层)→ BD.WTTS.Client*(客户端层)。前缀即命名空间层级,与解决方案文件夹编号对应。
  • 历史遗留:BD.WTTS.Client.AppHost.Bridge 的项目文件仍名为 Steam++.csproj;src/README.md 中的 ST.* 命名是 v3.X 的旧称,文档开头以 ~~删除线~~ 标记已废弃项(如 ST.Client.WPF、ST.Client.WinUI、ST.Tools.MinifyStaticSites 等)。
  • 特殊项目类型:OSShuttingDownHelper.shproj 使用共享项目(Shared Project)形式,向引用方直接贡献源码而非程序集引用——这是在多 TFM 下共享平台特定代码的常用手段。

Failure Modes、边界与运维注意

  • 子模块拉取失败:/2.Reference 全部来自 ref/ 下的 git 子模块(由 /0.Root 中的 .gitmodules 登记)。克隆仓库后若未执行 git submodule update --init,MSBuild 将报找不到 ref/Common/src/BD.Common/BD.Common.csproj 等项目文件——解决方案无法加载。
  • 集中包版本缺失:CPM 依赖 /0.Root 登记的 ref/DirectoryPackages/Directory.Packages.props。若该文件或其所在子模块缺失,NuGet 还原阶段即失败(NU1507 相关警告已在 NoWarn 中豁免多 TFM 包版本不一致告警)。
  • TFM 矩阵不一致:各项目通过导入不同 TFM_NETX*.props 组成目标框架集合,如果某项目导入的组合与依赖项目不兼容(例如依赖方不带 -windows 后缀 TFM),还原阶段会报 ValidateExecutableReferencesMatchSelfContained/TFM 不匹配错误。仓库将该属性显式置为 false 以放宽自包含发布校验。
  • 程序集特性冲突:由于 Directory.Build.props 注入了共享 AssemblyInfo.cs,任何项目若再启用程序集特性生成或自建 AssemblyInfo.cs 会产生重复定义编译错误——这就是为什么该文件显式关闭了 9 项 GenerateAssembly*Attribute。
  • Avalonia.Ref 的裁剪脆弱性:Avalonia.Ref 通过友元程序集访问 Avalonia 内部类型或以空程序集替代,属于对上游内部实现的强耦合。升级 Avalonia 版本时该子层需要优先验证。

Extension Points

  • 新增业务功能:在 /5.Plugins/ 下新建 BD.WTTS.Client.Plugins.<Name> 项目,引用 BD.WTTS.Client 即可。构建约定、隐式 using、可空检查与裁剪支持会通过 Directory.Build.props 自动生效,无需修改任何根配置。
  • 新增按域隐式 using:在 src/ 下增加 ImplicitUsings.<Domain>.cs,并在 .slnx 的 /0.Root/Source/ImplicitUsings/ 文件夹登记,必要时在 Directory.Build.props 的 Compile 项组中追加注入。
  • 新增跨平台 TFM 组合:在 /0.Root/TFM/ 增加新的 TFM_*.props 并在目标项目导入,.slnx 的 Configurations 平台列表无需变更。
  • 调整全局编译语义:所有对 Nullable、IsTrimmable、警告抑制、源链接(Microsoft.SourceLink.GitHub)的调整都应发生在 src/Directory.Build.props,而不是散落到各 csproj。