主题
客户端环境能力
GameCore.ClientEnvironment 提供客户端代码访问本地设备和平台环境的统一入口,适合实现打开外部链接、读写剪贴板、读取或切换本地化语言、查看网络状态、电量状态和只读诊断信息。
显示模式、窗口与移动端 Surface、独立帧调度、扫码、手柄及原生即时诊断使用客户端原生服务,要求 ClientRuntimeFeature.NativeClientServices,最低客户端能力版本为 9。
使用边界
- 仅客户端可用。相关代码应放在
#if CLIENT内。 - 这些信息描述当前玩家的本地客户端,不同步到服务端,也不应作为玩法权威数据。
- 剪贴板、打开链接、电量和网络信息可能受平台、权限、系统版本或用户设置影响;项目代码需要处理失败或不可用的情况。
- 打开链接受项目 URL 白名单限制。默认白名单非常有限,主要覆盖常见 QQ 群加群链接;其他网站或应用链接需要先申请或配置白名单。
入口
常用入口在 GameCore.ClientEnvironment 命名空间下:
csharp
#if CLIENT
using GameCore.ClientEnvironment;
using System.Globalization;
ClientEnvironment.TryOpenUrl("https://qm.qq.com/q/xxxx");
ClientEnvironment.Clipboard.Text = "invite-code";
var systemCulture = ClientEnvironment.Localization.SystemCulture;
ClientEnvironment.Localization.CurrentCulture = CultureInfo.GetCultureInfo("zh-CN");
bool isWifi = ClientEnvironment.Network.IsWifi;
var power = ClientEnvironment.Power.Current;
var diagnostics = ClientEnvironment.Diagnostics.Current;
#endifClientEnvironment 分为六组:
| 入口 | 用途 |
|---|---|
ClientEnvironment.TryOpenUrl(...) | 请求客户端打开允许的外部 URL 或应用链接 |
ClientEnvironment.Clipboard | 读写本地剪贴板文本 |
ClientEnvironment.Localization | 读取默认语言、系统语言,并切换当前客户端本地化语言 |
ClientEnvironment.Network | 读取当前网络状态,例如是否为 Wi-Fi |
ClientEnvironment.Power | 读取电源和电池状态 |
ClientEnvironment.Diagnostics | 读取 FPS、ping、内存等诊断快照,或由玩家主动请求上传客户端日志 |
ClientEnvironment.Runtime | 读取客户端构建号,并判断客户端二进制是否支持可选运行时能力 |
打开外部链接
使用 TryOpenUrl(Uri) 或 TryOpenUrl(string) 请求客户端打开外部链接:
csharp
#if CLIENT
using GameCore.ClientEnvironment;
bool opened = ClientEnvironment.TryOpenUrl("https://qm.qq.com/q/xxxx");
if (!opened)
{
Game.Logger.LogWarning("未能打开 QQ 群加群链接");
}
#endif返回值表示客户端是否接受了打开请求,不代表目标页面、App 或浏览器一定已经加载完成。传入字符串不是绝对 URL / 应用链接,或链接未通过白名单检查时,会返回 false。
QQ 群加群链接
打开 QQ 群加群页时,使用 QQ 群分享功能生成的邀请链接,例如:
text
https://qm.qq.com/q/xxxx这里的 xxxx 是 QQ 生成的分享码,不是群号本身。比如群号是 1021737313 时,不应直接写成 https://qm.qq.com/q/1021737313;需要先在 QQ 群资料页或群管理后台生成实际的加群邀请链接,再把完整链接传给 TryOpenUrl。
默认白名单只覆盖非常有限的常见 QQ 群加群链接格式。如果项目使用的是旧版 QQ 群邀请链接,也应传入 QQ 实际生成的完整链接。
其他链接
游戏官网、问卷、活动页、客服页、社区页、应用协议链接等,都需要先申请或配置项目 URL 白名单。未加入白名单前,TryOpenUrl 会返回 false,客户端也可能提示无法跳转。
建议 UI 上为失败情况准备兜底文案,例如提示玩家稍后重试、复制链接,或引导到游戏内公告 / 客服入口。
剪贴板
ClientEnvironment.Clipboard.Text 读写本地剪贴板文本,Clear() 清空文本:
csharp
#if CLIENT
using GameCore.ClientEnvironment;
ClientEnvironment.Clipboard.Text = "ABC-123";
var copiedText = ClientEnvironment.Clipboard.Text;
ClientEnvironment.Clipboard.Clear();
#endif剪贴板适合复制房间码、兑换码、邀请文本等短文本。不要把账号凭据、支付状态、背包进度或其他敏感数据写入剪贴板。
语言与本地化
本地化入口使用 .NET 的 CultureInfo,而不是裸字符串:
csharp
#if CLIENT
using GameCore.ClientEnvironment;
using System.Globalization;
CultureInfo defaultCulture = ClientEnvironment.Localization.DefaultCulture;
CultureInfo systemCulture = ClientEnvironment.Localization.SystemCulture;
ClientEnvironment.Localization.CurrentCulture = CultureInfo.GetCultureInfo("en-US");
var currentName = ClientEnvironment.Localization.CurrentCulture.Name;
#endif常见 CultureInfo.Name 形如 zh-CN、en-US。大小写形式按 .NET 和平台返回为准;如果要和配置字符串比较,建议使用大小写不敏感比较,或统一转换后再比较。
| 属性 | 含义 |
|---|---|
DefaultCulture | 当前项目在客户端上的默认语言 / 区域性 |
SystemCulture | 玩家设备系统或平台账号报告的语言 / 区域性 |
CurrentCulture | 当前客户端本地化使用的语言 / 区域性,可写入以切换 |
网络、电量与电池
网络入口用于读取本地网络状态:
csharp
#if CLIENT
using GameCore.ClientEnvironment;
if (ClientEnvironment.Network.IsWifi)
{
Game.Logger.LogInformation("当前网络为 Wi-Fi");
}
#endif电源和电池入口返回结构化快照:
csharp
#if CLIENT
using GameCore.ClientEnvironment;
var power = ClientEnvironment.Power.Current;
if (power.BatteryPercent is { } percent && percent < 20)
{
Game.Logger.LogInformation("当前电量较低: {Percent}%", percent);
}
var battery = ClientEnvironment.Power.Battery;
var temperatureCelsius = battery.TemperatureTenthsCelsius / 10f;
#endifBatteryPercent、LevelPercent、TimeRemaining 为可空类型;当平台无法提供该值时返回 null。其他数值字段在不可用时可能为 0,状态枚举会返回 Unknown。
只读诊断
ClientEnvironment.Diagnostics.Current 返回当前客户端只读诊断快照:
csharp
#if CLIENT
using GameCore.ClientEnvironment;
var diagnostics = ClientEnvironment.Diagnostics.Current;
Game.Logger.LogInformation(
"FPS={Fps}, Ping={Ping}ms, DrawCalls={DrawCalls}, Jank={Jank}",
diagnostics.FramesPerSecond,
diagnostics.PingMilliseconds,
diagnostics.DrawCalls,
diagnostics.JankCount);
#endif这些值适合做项目内调试面板、性能提示或问题上报辅助信息。不要用 FPS、ping、电量或网络类型来裁决服务端玩法结果;如果玩法需要公平性或反作弊判断,应由服务端逻辑完成。
游戏内上传客户端日志
游戏设置页可以提供“上传日志”按钮,让玩家主动提交本地客户端日志:
csharp
#if CLIENT
using GameCore.ClientEnvironment;
if (ClientEnvironment.Runtime.Supports(ClientRuntimeFeature.ClientLogUpload))
{
bool accepted = ClientEnvironment.Diagnostics.TryUploadLogs();
// accepted 为 false 时,提示玩家稍后重试。
}
#endif此请求沿用客户端现有的日志打包和上传流程,自动关联当前游戏项目。true 仅表示客户端接受请求,不表示打包或网络上传成功;当前 API 不提供完成事件,界面不要在返回 true 后立即显示“上传成功”。仅客户端可调用,旧客户端需要先检查 ClientLogUpload 能力。
客户端版本与可选能力
ClientEnvironment.Runtime 提供客户端二进制的诊断版本和可选能力判断:
客户端契约版本、当前能力表和“旧客户端”的具体边界见客户端二进制兼容与能力版本。本节保留最常用的 API 入口和客户端环境信息边界。
csharp
#if CLIENT
using GameCore.ClientEnvironment;
using GameCore.GameSystem;
long clientBuild = ClientEnvironment.Runtime.BinaryVersion;
bool supportsDisconnectEvent = ClientEnvironment.Runtime.Supports(
ClientRuntimeFeature.HostDisconnectedEvent);
Game.OnServerDisconnected += () =>
{
Game.Logger.LogWarning("与游戏服务端的连接已断开");
};
#endifBinaryVersion是精确客户端构建号,只用于日志、问题上报或显示。不要通过比较构建号判断功能。CapabilityVersion是高级诊断信息。项目代码应使用Supports(ClientRuntimeFeature...),不要直接比较能力版本数字。Game.OnServerDisconnected已由框架完成旧客户端兼容判断,项目可以直接订阅;不支持该事件的旧客户端不会触发它。- 能力值在运行期间不会变化,并由框架缓存。选择可选实现时仍建议在初始化阶段判断一次,不要把能力判断散落到每帧或每条消息的逻辑中。
推荐模式
- 打开设置、分享、反馈或调试面板时读取一次环境信息。
- 对可能失败的能力使用
Try...返回值或兜底 UI,不要假设所有平台都能成功。 - 打开外部链接前先确认目标链接属于项目允许范围;新增非 QQ 群链接时,先走白名单申请 / 配置流程。
- 对语言字符串做比较时使用
StringComparison.OrdinalIgnoreCase,或把CultureInfo.Name统一规范化。 - 只把诊断数据作为观察和上报辅助,不作为服务端权威输入。
- 用
Runtime.Supports(...)判断可选客户端能力;不要用BinaryVersion推断功能。
验证
powershell
dotnet build src\GameEntry.csproj -c Client-Debug运行客户端后验证:
- QQ 群邀请链接可以正常打开;未加入白名单的普通网站链接会按预期失败或提示。
- 剪贴板复制 / 清空符合目标平台预期。
SystemCulture、CurrentCulture与本地化 UI 显示一致。- 网络、电量、电池和诊断快照在目标平台上能安全读取,并能处理不可用值。