Overview
The vehicle_spawner_war_bus_device is a concrete specialisation of vehicle_spawner_device — the shared base class for every vehicle spawner in UEFN. It manages one War Bus instance: you can spawn or destroy it at any moment, forcibly seat a player as the driver, enable or disable the spawner entirely, and subscribe to rich lifecycle events that tell you when the bus appears, when players hop on or off, and when the bus is destroyed.
When to reach for it:
- A game-start sequence where the War Bus appears only after a countdown finishes.
- An escort mission where Verse auto-assigns the host as driver and respawns the bus if it's destroyed.
- A scoring system that awards points every second a player stays on the bus.
- A wave-based mode that disables the spawner between rounds so the bus can't be called early.
The device inherits every method and event from vehicle_spawner_device, so the patterns here apply to all other vehicle spawner types too.
API Reference
vehicle_spawner_war_bus_device
Specialized
vehicle_spawner_devicethat allows a war bus to be configured and spawned.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse). Inherited members are merged from vehicle_spawner_device.
vehicle_spawner_war_bus_device<public> := class<concrete><final>(vehicle_spawner_device):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
AgentEntersVehicleEvent |
AgentEntersVehicleEvent<public>:listenable(agent) |
Signaled when an agent enters the vehicle. Sends the agent that entered the vehicle. |
AgentExitsVehicleEvent |
AgentExitsVehicleEvent<public>:listenable(agent) |
Signaled when an agent exits the vehicle. Sends the agent that exited the vehicle. |
SpawnedEvent |
SpawnedEvent<public>:listenable(fort_vehicle) |
Signaled when a vehicle is spawned or respawned by this device. Sends the fort_vehicle who was spawned. |
VehicleSpawnedEvent |
VehicleSpawnedEvent<public>:listenable(tuple()) |
Signaled when a vehicle is spawned or respawned by this device. Deprecated, use SpawnedEvent instead. |
VehicleDestroyedEvent |
VehicleDestroyedEvent<public>:listenable(tuple()) |
Signaled when a vehicle is destroyed. Deprecated, use DestroyedEvent instead. |
DestroyedEvent |
DestroyedEvent<public>:listenable(tuple()) |
Signaled when a vehicle is destroyed. |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Enable |
Enable<public>():void |
Enables this device. |
Disable |
Disable<public>():void |
Disables this device. |
AssignDriver |
AssignDriver<public>(Agent:agent):void |
Sets agent as the vehicle's driver. |
DestroyVehicle |
DestroyVehicle<public>():void |
Destroys the vehicle if it exists. |
RespawnVehicle |
RespawnVehicle<public>():void |
Spawns a new vehicle. The previous vehicle will be destroyed before a new vehicle spawns. |
vehicle_spawner_device
Base class for various specialized vehicle spawners which allow specific vehicle types to be spawned and configured with specialized options.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
vehicle_spawner_device<public> := class<abstract><epic_internal>(creative_device_base):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
AgentEntersVehicleEvent |
AgentEntersVehicleEvent<public>:listenable(agent) |
Signaled when an agent enters the vehicle. Sends the agent that entered the vehicle. |
AgentExitsVehicleEvent |
AgentExitsVehicleEvent<public>:listenable(agent) |
Signaled when an agent exits the vehicle. Sends the agent that exited the vehicle. |
SpawnedEvent |
SpawnedEvent<public>:listenable(fort_vehicle) |
Signaled when a vehicle is spawned or respawned by this device. Sends the fort_vehicle who was spawned. |
VehicleSpawnedEvent |
VehicleSpawnedEvent<public>:listenable(tuple()) |
Signaled when a vehicle is spawned or respawned by this device. Deprecated, use SpawnedEvent instead. |
VehicleDestroyedEvent |
VehicleDestroyedEvent<public>:listenable(tuple()) |
Signaled when a vehicle is destroyed. Deprecated, use DestroyedEvent instead. |
DestroyedEvent |
DestroyedEvent<public>:listenable(tuple()) |
Signaled when a vehicle is destroyed. |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Enable |
Enable<public>():void |
Enables this device. |
Disable |
Disable<public>():void |
Disables this device. |
AssignDriver |
AssignDriver<public>(Agent:agent):void |
Sets agent as the vehicle's driver. |
DestroyVehicle |
DestroyVehicle<public>():void |
Destroys the vehicle if it exists. |
RespawnVehicle |
RespawnVehicle<public>():void |
Spawns a new vehicle. The previous vehicle will be destroyed before a new vehicle spawns. |
Walkthrough
Scenario: Escort the War Bus
A trigger plate starts the round. The War Bus spawns, the first player to step on the plate is auto-assigned as driver, and a score widget tracks how many times the bus has been respawned after destruction. When the bus is destroyed the device waits three seconds and respawns it automatically.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Fortnite.com/Vehicles }
# Place this Verse device in your level, then wire up the editable fields
# in the Details panel.
escort_manager_device := class(creative_device):
# The War Bus spawner placed in the level.
@editable
WarBusSpawner : vehicle_spawner_war_bus_device = vehicle_spawner_war_bus_device{}
# A trigger plate the first player steps on to start the round.
@editable
StartPlate : trigger_device = trigger_device{}
# Tracks how many times the bus has been respawned this round.
var RespawnCount : int = 0
# Localised helper so we can pass text to Print (diagnostic only).
BusRespawnedMsg<localizes>(N : int) : message = "Bus respawned {N} time(s)."
BusDestroyedMsg<localizes>() : message = "War Bus destroyed! Respawning in 3 seconds..."
RoundStartMsg<localizes>() : message = "Round started — War Bus incoming!"
OnBegin<override>()<suspends> : void =
# Disable the spawner until the round officially starts.
WarBusSpawner.Disable()
# Subscribe to the start plate.
StartPlate.TriggeredEvent.Subscribe(OnRoundStart)
# Subscribe to War Bus lifecycle events.
WarBusSpawner.AgentEntersVehicleEvent.Subscribe(OnAgentEnters)
WarBusSpawner.AgentExitsVehicleEvent.Subscribe(OnAgentExits)
WarBusSpawner.SpawnedEvent.Subscribe(OnBusSpawned)
WarBusSpawner.DestroyedEvent.Subscribe(OnBusDestroyed)
# Called when a player steps on the start plate.
OnRoundStart(Agent : ?agent) : void =
Print(RoundStartMsg())
# Enable the spawner and immediately spawn the bus.
WarBusSpawner.Enable()
WarBusSpawner.RespawnVehicle()
# Auto-assign the triggering player as driver if we can unwrap them.
if (A := Agent?):
WarBusSpawner.AssignDriver(A)
# SpawnedEvent sends a fort_vehicle — useful for future extension.
OnBusSpawned(Vehicle : fort_vehicle) : void =
Print(BusRespawnedMsg(RespawnCount))
# DestroyedEvent sends tuple() — no payload to unwrap.
OnBusDestroyed(_Void : tuple()) : void =
Print(BusDestroyedMsg())
# Spawn a task so we can Sleep without blocking the event thread.
spawn { RespawnAfterDelay() }
RespawnAfterDelay()<suspends> : void =
Sleep(3.0)
set RespawnCount = RespawnCount + 1
WarBusSpawner.RespawnVehicle()
OnAgentEnters(Agent : agent) : void =
# Agent is already a concrete agent here — no unwrap needed.
# (AgentEntersVehicleEvent is listenable(agent), not listenable(?agent))
WarBusSpawner.AssignDriver(Agent)
OnAgentExits(Agent : agent) : void =
# Could trigger a UI update, award points, etc.
Print(BusDestroyedMsg()) # reusing localised message as placeholder```
**Line-by-line highlights:**
| Lines | What's happening |
|---|---|
| `WarBusSpawner.Disable()` | Prevents the bus from appearing before the round starts. |
| `StartPlate.TriggeredEvent.Subscribe(OnRoundStart)` | `TriggeredEvent` is `listenable(?agent)` so the handler receives `?agent`. |
| `if (A := Agent?)` | Safely unwraps the optional agent before passing to `AssignDriver`. |
| `WarBusSpawner.RespawnVehicle()` | Destroys any existing bus and spawns a fresh one. |
| `WarBusSpawner.AssignDriver(A)` | Puts the unwrapped agent in the driver's seat immediately. |
| `SpawnedEvent.Subscribe(OnBusSpawned)` | Uses the **non-deprecated** event that delivers the `fort_vehicle`. |
| `DestroyedEvent.Subscribe(OnBusDestroyed)` | Uses the **non-deprecated** replacement for `VehicleDestroyedEvent`. |
| `spawn { RespawnAfterDelay() }` | Launches a concurrent task so `Sleep` doesn't block the event handler. |
| `AgentEntersVehicleEvent` handler receives `agent` directly | This event is `listenable(agent)`, **not** `listenable(?agent)`, so no unwrap is needed. |
---
## Common patterns
### Pattern 1 — Enable / Disable on a timer (gate the spawner between waves)
```verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
wave_gate_device := class(creative_device):
@editable
WarBusSpawner : vehicle_spawner_war_bus_device = vehicle_spawner_war_bus_device{}
# How long each wave lasts before the bus is recalled.
WaveDuration : float = 60.0
# Gap between waves.
CooldownDuration : float = 15.0
GateOpenMsg<localizes>() : message = "War Bus is available!"
GateClosedMsg<localizes>() : message = "War Bus recalled for cooldown."
OnBegin<override>()<suspends> : void =
# Run wave loop forever.
loop:
# Open the gate — spawn the bus.
WarBusSpawner.Enable()
WarBusSpawner.RespawnVehicle()
Print(GateOpenMsg())
Sleep(WaveDuration)
# Close the gate — destroy the bus and disable spawning.
WarBusSpawner.DestroyVehicle()
WarBusSpawner.Disable()
Print(GateClosedMsg())
Sleep(CooldownDuration)
Key calls: Enable, Disable, RespawnVehicle, DestroyVehicle — the full spawn/destroy lifecycle in one loop.
Pattern 2 — React to the spawned fort_vehicle via SpawnedEvent
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
bus_tracker_device := class(creative_device):
@editable
WarBusSpawner : vehicle_spawner_war_bus_device = vehicle_spawner_war_bus_device{}
# Counts total spawns this session.
var SpawnCount : int = 0
SpawnCountMsg<localizes>(N : int) : message = "Total War Bus spawns this session: {N}"
OnBegin<override>()<suspends> : void =
# SpawnedEvent delivers the fort_vehicle — useful for future
# fort_vehicle API calls when Epic exposes more of that surface.
WarBusSpawner.SpawnedEvent.Subscribe(OnVehicleSpawned)
# Kick off the first spawn.
WarBusSpawner.RespawnVehicle()
OnVehicleSpawned(Vehicle : fort_vehicle) : void =
set SpawnCount += 1
Print(SpawnCountMsg(SpawnCount))
# Vehicle is the live fort_vehicle reference — store or pass it
# to other systems that accept fort_vehicle parameters.
Key call: SpawnedEvent (the modern, non-deprecated event) delivers a fort_vehicle value you can store and pass to other APIs.
Pattern 3 — Force a specific player into the driver seat on entry
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Fortnite.com/Characters }
driver_enforcer_device := class(creative_device):
@editable
WarBusSpawner : vehicle_spawner_war_bus_device = vehicle_spawner_war_bus_device{}
# A button that a designated player presses to claim the driver seat.
@editable
ClaimButton : button_device = button_device{}
DriverClaimedMsg<localizes>() : message = "You are now the War Bus driver!"
NoDriverMsg<localizes>() : message = "No eligible driver found."
OnBegin<override>()<suspends> : void =
WarBusSpawner.RespawnVehicle()
ClaimButton.InteractedWithEvent.Subscribe(OnClaimPressed)
# InteractedWithEvent is listenable(agent) — no optional unwrap needed.
OnClaimPressed(Agent : agent) : void =
# Assign the interacting player as driver immediately.
WarBusSpawner.AssignDriver(Agent)
Print(DriverClaimedMsg())
Key call: AssignDriver(Agent) — takes a concrete agent, so no unwrapping is required when the event already delivers agent (not ?agent).
Gotchas
1. listenable(agent) vs listenable(?agent) — know which you're handling
AgentEntersVehicleEvent and AgentExitsVehicleEvent are listenable(agent) — the handler receives a concrete agent, no if unwrap needed. Contrast this with many trigger/plate events that deliver ?agent (optional). Getting this wrong causes a compile error.
2. DestroyedEvent and SpawnedEvent — use these, not the deprecated ones
VehicleDestroyedEvent and VehicleSpawnedEvent both send tuple() and are deprecated as of the 25.00 release notes. Use DestroyedEvent (also tuple()) and SpawnedEvent (delivers fort_vehicle) instead. The fort_vehicle payload from SpawnedEvent is the main reason to upgrade.
3. RespawnVehicle destroys the old bus first
Calling RespawnVehicle() when a bus already exists will destroy it before spawning the new one. This fires DestroyedEvent, which will trigger your destruction handler — make sure your respawn logic is idempotent (e.g. guard with a flag) or you'll get an infinite respawn loop.
4. AssignDriver requires the bus to exist
Calling AssignDriver before the bus has spawned (i.e. before SpawnedEvent fires or before RespawnVehicle completes) has no effect. Subscribe to SpawnedEvent and call AssignDriver inside that handler if you need a guaranteed driver.
5. Sleep inside event handlers requires spawn {}
Event handler methods are not <suspends>, so you cannot call Sleep directly inside them. Always launch a new coroutine with spawn { MyAsyncFunction() } when you need to delay inside a handler.
6. Localised text for Print
Verse's Print accepts a message, not a raw string. Declare a helper function with <localizes> and an interpolated body: MyMsg<localizes>(S : string) : message = "{S}". There is no StringToMessage function in the API.
7. The device must be @editable — you cannot construct it in code
vehicle_spawner_war_bus_device is <concrete><final> but it's a placed device. You must declare it as an @editable field and wire it in the UEFN Details panel. A bare vehicle_spawner_war_bus_device{} in your logic will compile but will not be connected to any placed actor in the level.