Skip to main content

Access rules

Two layers. Use either, or both.

Tags, for the common case

Put a query in the seat's Required Rider Tags, and answer GetRiderTags from wherever your game already keeps them:

void AMyCharacter::GetRiderTags_Implementation(FGameplayTagContainer& OutTags) const
{
if (const UAbilitySystemComponent* ASC = GetAbilitySystemComponent())
{
ASC->GetOwnedGameplayTags(OutTags);
}
}

An ability system, an inventory, a faction enum — the framework does not care, deliberately. Requiring one of those systems would make the plugin depend on it.

A rider who fails the query is refused with SeatLocked, which your UI can turn into a rattle and a message rather than silence.

Declare your own tags

The framework ships Mount.Access as a root only. Whether a seat is locked to a faction, a key item or a quest state is a question only your game can answer, so declare Mount.Access.PoliceVehicle, Mount.Access.HasKeys and so on in a game module or in Config/DefaultGameplayTags.ini.

Temporary access

FEDMountRequest::ContextTags are appended to the rider's tags for one request only, without changing anything about the pawn. That is the path for an ability that lets you hotwire a locked car:

FEDMountRequest Request;
Request.MountActor = LockedCar;
Request.ContextTags.AddTag(MyTags::Mount_Access_Hotwired);

Rider->RequestMountWithOptions(Request);

Code, for everything else

Implement CanAcceptRider on the mount:

bool AMyVehicle::CanAcceptRider_Implementation(APawn* Rider, FEDSeatHandle Seat,
const FGameplayTagContainer& ContextTags) const
{
return !bEngineOnFire && GetTeamOf(Rider) == OwningTeam;
}

It runs after the framework's own checks and on the server as well as the predicting client, so a rule written here is authoritative rather than cosmetic. A client that predicts past it is rolled back. Return false and the request fails with Denied.

Available in Blueprint through the ED Mountable Interface.

Keep it cheap and keep it pure

It is called once per seat when a rider asks for "any seat", and again during the query that drives your interaction prompt — which may run every frame. Do not trace in it, and do not change state in it.

Taking a mount out of service

Three levels, from coarse to fine:

WhatEffect
Mountable->SetMountable(false)Nobody may get in at all. Replicated, so client UI can grey out a wreck.
Seat->bEnabled = falseOne seat out of service. Others still work.
EntryPoint.bAllowEntry = falseOne door closed. The seat is still reachable from its other doors.

SetMountable(false) does not eject anyone. EjectAllRiders() does, and is what bEjectRidersOnDestroy calls when the mount is destroyed — because attached actors are destroyed with their parent by default, and a car exploding should not silently delete the passengers unless your game meant it to.

Order of checks

For completeness, this is what runs and in what order. The first failure wins, and its name is what you get back:

  1. Is the mount enabled? → MountDisabled
  2. Does the seat exist and is it enabled? → NoSeat
  3. Is it free — neither occupied nor reserved? → SeatOccupied
  4. Does the rider satisfy Required Rider Tags? → SeatLocked
  5. Does CanAcceptRider agree? → Denied
  6. Is there a usable entry point? → NoEntryPoint
  7. Is the rider close enough? → TooFar

Steps 1 to 5 run inside CanRiderUseSeat, which is also what the mount query calls when scoring seats — so a locked seat is never offered by "mount nearest" in the first place.