输入与网络
自动关联目录:输入与网络
1. 定位
输入只在"拥有者客户端"产生,但结果必须由服务端裁决。这条边界决定了所有网络输入的设计。
一句话定位:输入是意图,不是结果——玩家按下开火,客户端只发"我开火了",能不能开、打中谁,全由服务端算。
2. 数据流
本地输入(Enhanced Input,见 [输入映射与触发](/55778ed2.html))
│
├─ 本地预测:立刻演算(手感)
│
└─ Server RPC:把意图发给服务端
│
服务端校验(能否开火?冷却?弹药?)
│
├─ 通过 → 服务端执行 → 复制结果 / 下发纠正
└─ 拒绝 → 通知客户端回滚| 层 | 在哪 | 做什么 |
|---|---|---|
| 输入采集 | 拥有者客户端 | Enhanced Input → 回调 |
| 本地预测 | 拥有者客户端 | 先演算一遍(见 网络预测与回滚) |
| 权威执行 | 服务端 | 校验 + 真正执行 |
| 结果同步 | 服务端 → 各端 | 属性复制 / GameplayCue |
3. 三种常见写法
| 写法 | 适用 | 问题 |
|---|---|---|
| 输入 → Server RPC → 服务端执行 | 权威型(默认推荐) | 有 RTT 延迟,靠预测补 |
| 输入 → 本地执行 + Server RPC | 需要手感的动作 | 必须能回滚 |
| 输入 → 本地执行(不上报) | 纯表现 | 可作弊,不能影响他人 |
void AMyCharacter::OnFire(const FInputActionValue& Value)
{
ServerFire(GetControlRotation().Vector()); // 只发意图
// 本地预测的表现(必须可回滚)
}
UFUNCTION(Server, Unreliable, WithValidation)
void ServerFire(FVector_NetQuantizeNormal Dir);4. 校验放哪
| 校验类型 | 放哪 | 理由 |
|---|---|---|
| 数值越界、状态机非法 | WithValidation(返回 false 会断开连接) | 明显不可能的输入 |
| 冷却、弹药、能否行动 | _Implementation 里 | 业务上不允许 ≠ 作弊;否则玩家会掉线 |
| 命中判定 | 服务端 | 绝不能信客户端 |
把业务校验放进 WithValidation 是典型事故:玩家在冷却期间点一下就掉线。
5. 与 GAS 的配合
| 层 | 机制 |
|---|---|
| 激活 | 输入 → TryActivateAbility(见 UGameplayAbility) |
| 网络策略 | Net Execution Policy = LocalPredicted |
| 预测 | FPredictionKey,预测失败回滚 |
| 消耗/冷却 | CommitAbility,服务端权威 |
| 表现 | GameplayCue,可丢可延迟 |
GAS 已经把"输入 → 预测 → 权威 → 回滚"这条链做完了,自己用 RPC 重写一遍通常会漏掉回滚。
6. 代价与权衡
| 设计 | 收益 | 代价 | 什么时候不该用 |
|---|---|---|---|
| 纯权威(不预测) | 实现简单、绝对一致 | 有 RTT 延迟,手感差 | 快节奏动作不可用 |
| 本地预测 | 手感好 | 必须可回滚;不可逆表现会穿帮 | 纯服务端逻辑不该预测 |
| 本地执行不上报 | 最快 | 可作弊(见 Security) | 绝不能影响他人或数值 |
WithValidation 严格 | 拦异常输入 | 误伤即掉线 | 只用于"明显不可能" |
7. 踩坑与排查
| 坑 | 现象 | 怎么验证 |
|---|---|---|
| 客户端直接改属性 | 不权威、被覆盖产生抖动 | 应 Apply GE 走预测 |
| 命中判定在客户端 | 可作弊 | 必须服务端 |
业务校验写进 WithValidation | 玩家行为异常就掉线 | 移到 _Implementation |
| 预测路径播了不可逆表现 | 回滚时闪一下就没 | 表现走服务端下发的 Cue |
| 每帧发输入 RPC | 带宽爆炸 | 用属性复制或移动组件的输入机制 |
| 输入只在本地测 | 服务端行为不一致 | PIE 多端测 |
| 依赖本地时间/随机 | 预测两端结果不同 | 预测代码必须确定性 |
| 蓄力计时在客户端 | 服务端不认 | 服务端也要算,或用预测 key |
8. 排查顺序
1. 延迟感?→ 有没有本地预测
2. 被拉回/回滚穿帮?→ 预测路径是否有不可逆表现(见网络预测篇)
3. 掉线?→ WithValidation 是不是做了业务校验
4. 数值抖动?→ 是不是客户端直接改了属性
5. 带宽高?→ 是不是每帧发 RPC
6. 作弊?→ 命中判定与数值是否在服务端参考
许可协议:CC BY
作者:Davids
本文链接:https://hustjjd.github.io/5bfc4a0a.html
更新于:2026年10月10日