输入与网络

自动关联目录:输入与网络

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. 作弊?→ 命中判定与数值是否在服务端

参考