Areas

Many systems ask “what is at this place”: the water zone a boat is in, the temperature of a valley, the music of a town, the territory of a faction, a safe zone. A Pulse Area (UPulseAreaComponent, Add Component > Pulse Area) is one component for all of them, and systems ask for areas by tag instead of building their own volumes.

Setting What it does
Shape Box (Box Extent), Sphere (Sphere Radius), Spline Area (the area inside the first spline of the actor seen from above, or Area Points, between Area Bottom and Area Top) or Everywhere
Area Tags What the area is (Area.Safe, Biome.Snow, Music.Town); queries filter by them, a parent tag finds its children
Priority Where areas overlap, the higher priority comes first
Edge Falloff Width of the edge (cm) over which the weight fades from 1 to 0; 0: weight 1 everywhere inside
Conditions Only players that pass them count as inside (events, In Area)
Events None (only asked), Server (Entered and Left on the server for every player) or Everywhere (also on every machine for its local players)

Ids

Every registered area has an id (FPulseAreaId, Get Area Id), so hits, messages and saves can name it without a pointer to the component:

  • Areas of placed actors get the same id on every machine and in every session: it is made from the level (the long package name of a sublevel or level instance, else the map), the actor and the component name, without case. Level instances need a deterministic instance name for ids that match across machines (PulseWorld places have one).
  • Fixed Area Name (advanced) gives the id from a name instead (“Town.Market”); Make Pulse Area Id From Name makes the same id in Blueprints. Copies of an actor copy the name: give each its own (Data Validation reports two areas of one level with the same name).
  • Actors spawned while playing, and area components added at runtime, have names that differ between machines: call Set Area Id with an id from their own replicated state (Make Pulse Area Id From Guid) when other machines need the id. A component added at runtime to a placed actor without Fixed Area Name logs this once.
  • Two areas that ask for the same id are an error: the second gets another id and a warning.

Blueprint helpers: Equal (Pulse Area Id), Is Valid (Pulse Area Id), To String (Pulse Area Id).

Asking

Function What it gives
Find Pulse Areas (Location, Tag) Every area at the place with its id and weight, highest priority first, then the highest weight, then the id
Get Pulse Area At (Location, Tag) The area that decides there (the first)
Get Pulse Area Id At (Location, Tag) Its id
Find Pulse Area By Id (Id) The area registered under an id
Is Player In Pulse Area (Player, Tag) Whether the player’s pawn is in such an area and passes its conditions
Contains Point, Get Weight At One area

The condition In Area (category Area) passes when the pawn of the player (else the instigator, else the target) is in an area with a tag, for quests, dialogs and interactions. Queries use a grid of 50 m cells, so many areas cost little; very large areas and Everywhere are checked for every query. A moved area finds its cells again by itself.

The areas are plain data in the subsystem (UPulseAreaSubsystem::GetIndex, Pulse::Area::FAreaIndex), copied from the component when it registers. After changing Area Tags, Priority, Edge Falloff or Events at runtime from C++, or adding the first or removing the last condition, call Refresh Area; the conditions themselves are read live from the component.

Entering and leaving

Areas with Events check the pawns of the players five times a second and send:

Channel Payload When
Pulse.Message.Area.Entered FPulseAreaMessage (area id, area, its tags) A player entered
Pulse.Message.Area.Left FPulseAreaMessage A player left, or the area went (after it is removed)

Context: the pawn is Player and Instigator, the actor of the area is Target, the area is Source, its tags are the Tags. The context names the player id too (Ids), also when a handler of On Player Left (or of OnAreaPlayerNative) destroys the pawn; a pawn that is gone before the pointer events sends no Left message. The component has the same as On Player Entered and On Player Left, C++ listeners UPulseAreaSubsystem::OnAreaPlayerNative. Areas without events cost nothing per frame.

Players are counted twice:

  • By player (OnAreaOccupantNative, GetPlayersInside): a player is one key (its net id, else its player state), whatever pawn it has. A new pawn within one check (a vehicle, a respawn that has the new pawn at the next check) neither leaves nor enters. A respawn with a gap longer than one check leaves and enters. A pawn that is gone leaves with a null pawn.
  • By pawn (the messages, the component events, OnAreaPlayerNative): paired per pawn as before. A new pawn of a player inside sends Left with the old pawn and Entered with the new one; a pawn that is gone leaves silently.

Both stay paired when a listener removes or adds areas in any handler: every Entered gets its Left. An area whose actor went away without unregistering leaves the index at the next check, with Left by player only.

Debugging

The Pulse Debugger and PulseDebugDump Area list the areas with their tags, priority and the players inside, and draw their bounds.


PulseFoundation plugin documentation.

This site uses Just the Docs, a documentation theme for Jekyll.