Skip to main content

Migration

This page is written against the family of mounting systems built around three components — one on the rider, one on the mount, one on the controller — with seats described as arrays of relative offsets. If yours is shaped differently, the concept table is still the useful part.

Concepts

ThereHereNote
Mount rider component (on the pawn)UEDRiderComponentSame place, much smaller.
Mountable actor componentUEDMountableComponentSame place.
Rider controller component(usually none)See The third component.
A seat struct in an array on the mountableUEDMountPointComponent, one per seatA scene component you drag.
A side plus an offsetFEDEntryPoint — a transform, a tag and a clearance capsuleValidated against the world.
Seat index / seat id / seat nameFEDSeatHandleOne way, not three.
A relative-direction enumMount.Entry.* gameplay tagsExtensible; games can add sides.
An action-state enum plus six booleansEEDMountPhase, one enumCannot contradict itself.
bool return plus an out-parameter response structFEDMountResult with a named failureEvery refusal names itself.
Five AnimNotify classesOne notify with a tagPlus a windowed variant for doors.
(nothing)UEDMountAnimationSetWhich animation plays is data, not code.
(nothing)Obstruction checks on entry and exitThe framework will not put you in a wall.
(nothing)The procedural transitionIt works before you have animations.

Functions

ThereHere
MountPawn(Actor, LinkedActor, Response)RequestMount(Actor)
MountPawnToSeat(Actor, LinkedActor, SeatId, Response)RequestMountWithOptions({Actor, DesiredSeat})
DismountPawn(Actor, Response)RequestDismount()
ChangeSeatToIndex / ChangeSeatByIdRequestChangeSeat(Handle)
IsMounted / IsSeated / IsAttachedToMountGetMountPhase(), or IsMounted() / IsSeated()
IsMounting / IsDismounting / IsChangingSeatsIsTransitioning(), or compare the phase
GetCurrentMount()GetMountActor()
GetSeatId()GetSeatHandle()
GetRiderBySeatId / AtIndex / ByNameGetOccupant(Handle)
SetSeatOccupiedById / AtIndex / ByNameRequestMount — see the note below
FindAvailableMountingPosition(...)FindBestSeatFor(Rider, Request, OutFailure)
HasAvailableSeats()HasFreeSeat()
GetNumSeats() / GetNumRiders()GetNumSeats() / GetNumOccupiedSeats()
PawnFinishedMounting() and friends, from notifiesHandleMountEvent(Mount.Event.Attach) and friends
On the occupancy setters

OccupySeat, ReserveSeat and ReleaseSeat exist and are public C++, but they are how the rider component talks to the mountable — not an API for gameplay. Where the old system expected you to call SetSeatOccupied yourself, here you call RequestMount and the framework does the bookkeeping, including the reservation that stops two players taking one seat.

The third component

The old shape needs a component on the controller because when the controller possesses the vehicle, the character's component is no longer on the possessed pawn, so something has to remember the way back.

Here that is a per-seat setting. Keep Possessing the Rider — the default — never possesses the mount at all: the controller stays on the character and driving input is forwarded. There is nothing to remember. Possess the Mount gives you the old behaviour, and the rider component itself stores the controller, so the way back is one object rather than three.

See Camera and possession.

Setting up a seat, before and after

Before: add a seat struct to the array on the mountable; type a socket name; add one mounting-data entry per side; type an FVector offset for each; run the game to see where they went.

After: add a seat component; drag it. Press Generate Entry Points; drag those. The capsules are green when a rider fits and red when they do not, live, while you drag.

Things this framework deliberately does not do

  • No "linked mountable actor" concept. The old system carries a second actor through every call to support a mount whose seats live on a different actor. Here a seat is a component, and a component can be parented to anything — so the case is handled by attachment rather than by a parallel pointer in nineteen signatures.
  • No custom-status byte on the result. Failures are a typed enum with localised text. A game that needs its own reason uses CanAcceptRider and its own state.
  • No root-motion validation toggle. Root motion is the animation's business; the attach moment is a notify, and the watchdog covers a montage that never reaches it.
  • No mounting AI. FindBestEntryPoint will tell you where to stand. Walking there is your movement system's job.

A practical order

  1. Replace the seat arrays with seat components. This is the bulk of the work and it is mostly dragging. Do one vehicle, look at it with ED.Mounting.DrawSeats 1, then do the rest.
  2. Replace the mount/dismount calls with the Request* equivalents, and handle FEDMountResult where you previously ignored a bool.
  3. Replace index/id/name lookups with one FindSeatByName at setup, held as a handle.
  4. Delete your notify classes and put ED Mount Event on the same frames.
  5. Build an animation set from whatever branching your old code did to pick animations.
  6. Decide per seat between Keep Possessing the Rider and Possess the Mount, and delete the controller component if every seat says the former.