Networking & MP¶
PFC is built for dedicated servers - everything is networked. The model follows Reforger's ownership-transfer model: one peer is authoritative, the rest are interpolated proxies.
Authority¶
- The pilot's client owns the vehicle and is authoritative; when the aircraft is unmanned the server owns it.
PFC_FlightModel.EOnSimulatereturns immediately unless the peer is the owner or the server, so the aerodynamic integration runs in exactly one place.OnTicksOnRemoteProxy()returnstrueso the component still ticks on proxies - needed for local visual updates (propeller spin) and to read replicated signals.
Input relay¶
PFC_FlightController smooths input on the owning client, then relays it to the server:
- Sent on an interval (
m_fInputSendIntervalMs, default 16 ms) over an unreliable channel - it's a constantly-refreshed stream, so a dropped packet doesn't matter. - A non-owner client never overwrites the pilot's stick:
PollInputreturns early for non-owners, which read the cached relayed values instead.
Movement replication¶
PFC_NwkMovementComponent replicates the authoritative transform + velocity to proxies so remote viewers see
smooth motion. Proxies don't simulate aero; they interpolate this state and drive their own propeller visuals
from the replicated, normalized engine-RPM signal.
Instrument signals¶
The owner publishes gauge signals via SignalsManagerComponent; they replicate to all peers, so cockpit
instruments and HUDs on every client read them for free.
Use the right compression function
AddOrFindMPSignal(..., SignalCompressionFunc.X) - the compression must match the value range:
- Raw units (airspeed km/h, altitude m, climb m/s, pitch/bank/heading deg, G-load): use
None.Range01would clamp them to[0,1]over the wire, pinning every receiver's gauge at1. - Normalized 0..1 (throttle, normalized RPM):
Range01is fine. - Angles (control-surface deflection):
RotDEG.
Boot-window guard¶
Writing an MP signal - or firing an RPC - on an entity that isn't yet registered for replication spams
"unregistered item" errors every frame during the spawn window. PFC guards both:
- Signal publishing is gated on
m_RplComponent.Id().IsValid(). - The input RPC is sent only when
!Replication.IsServer()and the Rpl id is valid - if the server owns the plane (unmanned), there's no one to send to and it already holds the values locally.
Reuse these patterns in variants
Any per-tick RPC or MP-signal write you add in a variant should follow the same two guards (owner/server check + valid-Rpl-id check), or you'll reintroduce the boot-window log spam.