Doors and locks
Module PulseLocks (depends on PulseAbility and PulseInventory). A door opens, closes, closes by itself and locks. Players open it with the interaction; a locked door opens only for a player with its key. The key is a Pulse condition list (“Has Item” with a key tag by default), a key that is used up is a Pulse cost (“Items”).
Overview
| Type | What it is |
|---|---|
UPulseDoorComponent | Pulse Door: the interactable of a door; moves a part of its actor, keeps the state, saves itself |
APulseDoor | A ready door: frame, hinge and panel (engine cubes) with a door component |
FPulseDoorState | The state as plain data: open, lock, direction, start of the last move and auto close on the server clock |
FPulseDoorMotion | How the part moves: rotate or slide, angle or offset, duration, easing, auto close |
UPulseLocksSettings | Project Settings > Pulse > Core > Locks: prompt texts, network update rate |
Setup
- Place a Pulse Door (
APulseDoor), or create a door Blueprint in the Pulse window (Create > Door) and give it your meshes. - Or add a Pulse Door component to an actor of your own: set Moving Part to the scene component that moves (Movable; its transform in the editor is the closed one). The actor must replicate.
- The player needs the interaction of PulseCore (
UPulseInteractAbilityorUPulseRepInteractAbility): the door is an interactable component and replicates its interaction to the server.
How a door works
Everything a rule decides is a pure function in Pulse::Locks (PulseLocksTypes.h), tested without a world (specs PulseLocks.Rules, PulseLocks.Keys, PulseLocks.Save):
| Function | What it does |
|---|---|
CheckAction | Whether Open, Close, Lock, Unlock or Pick can be done now (a locked door does not open, only a closed door that stands still locks, a picked lock cannot be locked again) |
ApplyAction | The state after an allowed action; a door turned back while it moves goes back from where it is |
GetOpenAlpha, GetMotionEnd, IsMoving | How far the door is open at a time, when its move ends |
GetMotionTransform | Where the moving part is: turned around the axis or moved by the offset |
IsReversedFor | The direction for an opener: a door swings away from who opens it |
IsAutoCloseDue | Whether an open door closes by itself now |
GetInteractAction, GetPrompt | What the interaction does and what the prompt says (“Open”, “Close”, “Unlock”, “Locked”) |
MakeKeyExchange | The key as an exchange: the key conditions, then the key costs, all or nothing |
ToSaveData, IsValidSaveData, FromSaveData | Save data |
- Interaction: the prompt shows Open, Close or, while the door is locked, Unlock for a player with the key and a greyed out “Locked” with the reason of the first failing key condition for the others. The interaction completes on the server (the interactable’s own conditions and costs come first) and calls
Interact. - Check, then apply (server):
TryDoorActionchecks the action first. Unlocking with a key runsMakeKeyExchangethroughPulse::Exchange::Run: if a condition fails or a cost cannot be paid nothing changes. Then the new state is set in one step: the dormant actor wakes up, the state is marked for replication, the auto close timer is set, the part moves, the events fire. - Motion (every machine): only
FPulseDoorStatereplicates (push model). Each machine computes where the part is from the state, the motion and the server clock, so the door moves the same on the server and every client without replicated movement. The component ticks only while the part moves. A placed door is dormant until it changes, so clients start from the values of the level (Start Open, Start Lock); every change of the server counts upRevision, so a changed state always reaches them. - Auto close (server): with Auto Close Delay a door closes by itself that many seconds after it is fully open, on a timer of the Pulse clock subsystem. Closing it by hand cancels it.
The interaction on a locked door unlocks it and then opens it (Open On Unlock). Locking with a key and picking a lock are TryDoorAction calls (Lock with Use Key, Pick); a script can open, close, lock and unlock without a key.
Keys
| Property | Default | What it is |
|---|---|---|
StartLock | Unlocked | The lock when the door begins play: Unlocked, Locked or Picked |
KeyConditions | Has Item with tag Pulse.Locks.Key | What a player needs to unlock or lock the door; set the tag of the door’s own key |
KeyCosts | none | Paid when unlocking: add an Items cost with the key to use it up |
bOpenOnUnlock | true | The interaction opens the door after it unlocked it |
“Has Item” counts child tags: a door that asks for Pulse.Locks.Key opens with every key, a door that asks for Pulse.Locks.Key.Cellar only with the cellar key. Any other Pulse condition works as well (a quest flag, a skill, a team). The conditions of the interactable itself (Conditions, Costs) apply to every interaction, also to an unlocked door.
Saving
The component is an IPulseByteSaveable with the save identity tag Pulse.Locks.Save.Door (the key starts with the door’s actor and its level). It saves open or closed, the lock (Unlocked, Locked, Picked) and the direction; a moving door is saved where it goes. Loading checks the bytes and the values first and sets nothing when one is broken; an open door that closes by itself waits its delay again. Save systems that keep IPulseByteSaveable objects (PulseSave) save doors without a bridge: the byte collector of Pulse Save collects them, and the save menus of Pulse Save use it by default, so Save in the pause menu (PulseCoreSaveBridge) saves every door.
Messages
| Channel | Payload | Context |
|---|---|---|
Pulse.Message.Locks.DoorChanged | FPulseDoorMessage (door, instigator, action, state) | player and instigator: who did it (none for a script or the auto close), target: the door’s actor, source: the door component, tags: Pulse.Locks.Action.Open, .Close, .Lock, .Unlock or .Pick |
It comes from the server.
Blueprint and C++
| Function | Where | What it does |
|---|---|---|
Interact | server | What the interaction does: unlock with the key and open, close or open |
Try Door Action | server | Open, Close, Lock, Unlock or Pick, with or without the key; returns the result (Pulse.Result.Failure.Locks.*) |
Set Door State | server | Replaces the state (a save of the game) |
Get Door State, Is Open, Get Lock State, Get Open Alpha | any | The state now |
Get Prompt | any | Action, text and availability for a player |
On Door Action | server event | An action changed the door, with the instigator |
On Door State Changed | event on every machine | The state changed (clients when it arrives) |
Settings
| Setting | Default | Description |
|---|---|---|
Texts | Open, Close, Unlock, Locked | Texts of the prompt; a door can override them (Override Texts) |
NetUpdateFrequency | 10 Hz | How often a changed door is sent at most |
Example
Behind the player start of the PulseCore example map stand two doors: Door closes by itself after 4 s, Locked Door needs the example key DA_PulseExample_Key (tag Pulse.Locks.Key.Example, in /PulseCore/Examples/Locks), which PulseCoreGrant and PulseLocksGrant give. Press E at a door; without the key the prompt says “Locked”. The doors and the key are built by Tools/make_locks_examples.py (headless editor Python).
Cheats
See Console.