跳转到内容
CRUSHFORMV1.1.0
在 Fab 上获取

多人游戏复制与预测

复制与预测

每位玩家看到的损伤都是相同的。每辆车都由一端模拟并决定其损伤,其他端接收结果。驾驶端不会等待该结果:它会立即绘制自己的命中,服务器稍后会确认或拒绝这些命中。本页说明由谁决定、命中如何在端之间传递,以及复制了哪些内容。

一个客户端上的撞击会立即在该客户端上造成车身凹陷。服务器随后确认这一凹陷,并且其他每位玩家的屏幕上都会出现相同的凹陷。

两个并排的 Play In Editor 窗口。左侧,NetMode Client 1:轿车以 99 km/h 驶向一堵橙色墙壁。右侧,NetMode Server 0:远处的第二辆轿车停着,它的前保险杠掉在身旁的路上,而服务器自己的轿车在前景中等待,速度为 0 km/h。
驾驶端客户端(左)和服务器(右),位于两个 Play In Editor 窗口中。
两个窗口中的同一次撞击:客户端窗口中保险杠脱落,服务器窗口中也一样。

车辆适配器上的 Authority 决定由哪一端模拟车辆并判定其命中。两种模型和允许撞击的速度余量,参见核心概念;服务器对每份报告所应用的规则见下文。

在 Owning Client 模型下,驾驶端客户端会立即将每次命中应用到自己的晶格上。它应用的是它将要发送的报告,并按服务器解码的方式解码,因此两端最终得到相同的数值。超过客户端报告预算(Max Reports Per Second)的命中根本不会绘制,而不是先绘制再撤销。

客户端会以最多 Max Reports Per Batch 条为一批,将报告发送给服务器。服务器在应用每份报告之前都会进行检查:修复代数必须一致,撞击点必须位于晶格内部,速度和滑移必须在 Max Plausible Delta V 以及刮擦限制之内。宿主也可以拒绝该报告。被拒绝的报告会以拒绝通知的形式回传给客户端,客户端随即撤销这处凹陷。在 Pending Report Timeout 内既未被服务器确认也未被拒绝的预测会被丢弃。

端如果不再是撞击源(例如车辆现在归另一位玩家所有),会丢弃其尚未发送的预测。此后,新的撞击源的命中将以块的形式到达。

服务器持有真实的晶格,并将其以块的形式发送,正如核心概念所述。以下内容也会被复制:

  • 代数:修复的次数。不同代数的块和报告会被忽略。
  • 清洗次数:一次清洗会让每一端清除其污垢。污垢本身从不通过网络传输。
  • 已分离和摆动的部件:哪些铰接部件已脱落,以及模拟该车辆的一端让哪些部件开始摆动。每一端在收到这一决定时才放开部件,因此所有玩家会在同一时刻看到同一个部件松开。摆动本身仍是每一端自己的物理。
  • **玻璃裂纹、可破坏单元的等级以及近期的破坏事件,以及倒下的树木的状态。**关于之后才连接的端会收到什么,参见中途加入的玩家。
  • 撞击声音:撞击源播放命中并进行转发。其他每一端播放转发的副本。

轮胎、滚动声音和滚动 FX,以及发动机声音不会被复制。每一端各自运行自己的这些内容。

  1. 在 Content Browser 中打开 Settings,勾选 Plugin Content。依次打开 Plugins › Crushform Content › Blueprints › Sedan,将 BP_VehicleAdvSedan 复制到你的项目中,然后打开该副本。本页以轿车为例,但这些步骤适用于任何带有适配器的车辆。

  2. 在 Components 面板中选中 CF_Adapter,即 Chaos 车辆适配器(UCFChaosVehicleAdapterComponent)。它从基础适配器类继承 Authority。

  3. 在 Details 面板中,将 Authority 设为 Owning Client。

  4. Ram Allowance Mps 保持默认值 15;如果你的硬撞击被拒绝,可以提高它。它是服务器在近期峰值之上允许的速度余量。

    Crushform
    AuthorityOwning Client
    Ram Allowance Mps15.0 m/s
    Chaos 适配器的 Crushform 分类,其中 Authority 设为 Owning Client。
  5. 检查 Deform Profile 已设置。留空则使用项目的默认配置文件。

  6. 打开 Project Settings › Plugins › Crushform › Network。默认值适用于首次测试。下表列出了每项设置的作用。

  7. 将你所使用的 Game Mode 的 Default Pawn Class 设为你的副本。插件的 BP_VehicleAdvGameMode 会生成插件自带的轿车作为 Pawn,因此如果副本不是 Default Pawn Class,它就永远不会作为玩家的车辆生成,其 Owning Client 设置也不会生效。

  8. 保存蓝图。在 Play 设置中,将 Number of Players 设为 2,Net Mode 设为 Play As Listen Server,然后按 Play。编辑器会打开一个服务器窗口(NetMode: Server 0)和一个客户端窗口(NetMode: Client 1)。在客户端窗口中将车开向墙壁,并在服务器窗口中观察。

蓝图中的一项常见任务是在服务器上修复车辆。Repair 和 Wash 只在拥有权威的端上运行,它们清除的内容会复制到每一端上。图表中通过一个自定义事件调用 Repair,你可以从服务器上调用该事件,例如从你自己的服务器 RPC 中调用。

图表通过一个自定义事件调用 Repair,你从服务器上调用该事件。

C++ 中的相同调用:

// The vehicle actor that owns the adapter.
AActor* Vehicle = GetOwner();
if (UCFDeformComponent* Deform = Vehicle->FindComponentByClass<UCFDeformComponent>())
{
if (Vehicle->HasAuthority())
{
// Clears every dent and scratch, on every machine.
Deform->Repair();
}
// Hits this client sent that the server has not yet confirmed or refused.
const int32 Waiting = Deform->GetNumPendingReports();
// How many repairs the body has had.
const uint8 Generation = Deform->GetGeneration();
}
属性作用默认值
UCFVehicleAdapterComponent::Authority由哪一端模拟车辆并判定其命中:Server 或 Owning Client。Server
UCFVehicleAdapterComponent::RamAllowanceMps配合 Owning Client:上报的命中速度可以比近期峰值速度快多少,单位为米/秒。15
UCFProfile::MaxPlausibleDeltaV报告中允许携带的最猛烈的撞击,单位为米/秒。滑移同样受此限制。40
UCFSettings::MaxReportsPerBatch驾驶端客户端每帧在一批中发送的报告数。服务器会拒绝超出的部分。8
UCFSettings::MaxReportsPerSecond一个组件每秒接受的报告数。客户端的突发量相同;服务器的容量是它的 1.5 倍。60
UCFSettings::PendingReportTimeout客户端在服务器既未确认也未拒绝时,保留某次预测命中的秒数。10
UCFSettings::ScrapeReportInterval同一组件两次刮擦报告之间的秒数。0.1
UCFSettings::MaxScrapeDt一份刮擦报告所能代表的最长滑移,单位为秒。0.25

运行设置步骤中的双人测试。在编辑器控制台中输入一次 Crushform.Stats。它会为每个正在运行的世界中每辆可形变车辆输出一行。服务器副本那一行显示 server lattice,客户端副本那一行显示 client view。每行的格式如下:

<vehicle>: <server lattice or client view>, generation <n>, <n> pending, <n> chunks | hits <n>, sent <n>, accepted <n>, rejected <n>, published <n>, received <n>, bad <n>, expired <n>, parts off sent <n>, accepted <n>, rejected <n>, collision builds <n>, longest <ms> ms, collision waits <n>, parts held <n>, part hulls <n>, longest <ms> ms, most points <n>

在客户端撞击之后,其 pending 计数会上升,并在服务器确认凹陷后回落到 0;服务器的 accepted 计数则会上升。被拒绝的命中会在客户端显示为 rejected 计数。

原因。 服务器拒绝了该报告,客户端于是撤销了这处凹陷。当报告的速度或滑移高于 Max Plausible Delta V、撞击点位于晶格之外,或其修复代数已过期时,服务器会拒绝该报告。在 Owning Client 模式下,比近期峰值速度加上 Ram Allowance Mps 更猛烈的命中同样会被拒绝。

修复。 在 Crushform.Stats 中查看 rejected 计数。如果希望客户端判定自己的命中,请将 Authority 设为 Owning Client。如果真实的撞击比 Max Plausible Delta V 更猛烈,请在配置文件上提高它。

原因。 车辆的 Authority 为 Server。此时客户端不是撞击源,因此它不做任何预测,而是等待服务器的块。

修复。 将 Authority 设为 Owning Client,如设置步骤中所述。

原因。 服务器没有在 Pending Report Timeout(默认 10 秒)内确认客户端的报告,客户端于是丢弃了这次预测。

修复。 在 Crushform.Stats 中查找 rejected 和 expired。如果超时时间对你的网络来说太短,请在 Network 下提高 Pending Report Timeout。