Elements
Everything a resource can point at in the world is an element: players, vehicles, pickups, objects and the rest. The server holds every element; a resource holds only handles to them. This page describes which elements exist, who owns them, what a handle is and what happens to handles and events when an element goes away. The functions of each family are in the API reference, dlmp.lua.
The element tree
Events are addressed through a tree of elements (Events):
root dlmp.root
├── resource:<id> dlmp.resource (of that resource)
│ └── resource_root:<id> dlmp.resource_root
│ ├── vehicle:<id> created by this resource
│ ├── pickup:<id>
│ ├── object:<id>
│ ├── checkpoint:<id>
│ ├── colshape:<id>
│ └── gang_zone:<id>
└── player:<id>- An element a resource created hangs under that resource's
dlmp.resource_root, so a handler attached there hears the events of the resource's own elements and nothing else. - Players belong to no resource and hang directly under the root.
- Only the elements in the tree raise events. Labels, blips, markers and teams have handles but raise none.
These tree nodes reach Lua as Element handles: dlmp.root, dlmp.resource, dlmp.resource_root, and dlmp.source while an event is being dispatched. An Element only addresses events; reading and acting go through the family handles below.
Families
| Family | Created by | Removed by | Handle |
|---|---|---|---|
| player | a connection joining the server (once the auth resource accepts it, when one is configured) | its departure: quit, timeout, kick or ban | Player |
| vehicle | dlmp.create_vehicle; a train engine model creates the whole train as one vehicle | dlmp.destroy_vehicle; the owner's stop | Vehicle |
| pickup | dlmp.create_pickup | dlmp.destroy_pickup; dlmp.collect_pickup of a collectible without respawn_ms; the owner's stop | Pickup |
| object | dlmp.create_object | dlmp.destroy_object (with everything attached to it); the owner's stop; the removal of its parent; the departure of the only player who sees it | Object |
| label | dlmp.create_label | dlmp.destroy_label; the owner's stop; the removal of the player or vehicle it is attached to; the departure of the only player who sees it | Label |
| blip | dlmp.create_blip | as a label | Blip |
| marker | dlmp.create_marker | dlmp.destroy_marker; otherwise as a label | Marker |
| gang zone | dlmp.create_gang_zone | dlmp.destroy_gang_zone; the owner's stop | GangZone |
| checkpoint | dlmp.create_checkpoint | dlmp.destroy_checkpoint; the owner's stop; the departure of its player | Checkpoint |
| colshape | dlmp.create_colshape | dlmp.destroy_colshape; the owner's stop | Colshape |
| team | dlmp.create_team | dlmp.destroy_team; the owner's stop; its members go teamless | Team |
The ids of created elements count up and are not reused while the server runs. A player id is a slot: the next connection may get the id of a player who left (Players).
A respawn (dlmp.respawn_vehicle) keeps the vehicle, its id and its handles. A vehicle that blew up or drowned stays a wreck until it is respawned or destroyed. A collectible pickup collected with respawn_ms is not removed: until it respawns, dlmp.collect_pickup returns nil, err, and dlmp.destroy_pickup still removes it.
Other state a resource holds
Some things are not elements but still belong to the resource that made them and end with its stop:
- the dialog, passive table, menu and offer a resource shows a player (one of each per player), and an edit session;
- views (
dlmp.open_view) and the resource's client files; - what a map placed (
dlmp.load_map;map:unload()removes it earlier); - HUD entries (announcements, countdowns, status lines, the kill feed, progress bars, notifications, gauges, the speedometer, action prompts) the resource wrote last;
- declared actions (
dlmp.register_action) and platform key overrides; - the UI theme (
dlmp.set_ui_theme) and the server list's mode text (dlmp.set_mode_text), when this resource set them.
Server-wide settings are no one's: the spawn point, vehicle jacking, the RC range, the player list scope, garage doors, weapon properties and allowances, damage multipliers, the drive-by interval and the server password stay as they were set after the resource that set them stops. Explosions, fires and projectiles are effects, not elements: there is nothing to hold or remove.
Ownership
- The resource that creates an element owns it. Ownership means two things: the stop of the resource removes the element, and the element's events are sourced under the resource's
dlmp.resource_root. - Ownership is not access control. Any resource may read, change and destroy an element another resource created, for example any vehicle in
dlmp.vehicles(). A destroy by another resource removes the element for its owner too. - A stop removes the resource's elements after its
resource_stophandlers ran, so the elements those handlers created go as well; elements already gone are skipped. Aresource_startthat fails removes what it created the same way. - A reload is a stop and a start: the elements of the old run are removed, and the old VM's handles go with it.
- Each family has its own typed
dlmp.create_<family>anddlmp.destroy_<family>; there is no generic destroy, since each family checks and cleans up in its own way (destroying a vehicle lets go of its RC driver, its trailer and what its winch carries, and takes the labels, blips, markers and objects attached to it along). - A destroy raises no events: no
player_exit_vehicle,trailer_detach,winch_detach,colshape_leaveorcheckpoint_leavecomes from it.
Handles
A handle holds only the element's family and id; a player handle also remembers the connection it belongs to. Every read and every action goes through the server at the moment of the call, so a handle kept across server steps never returns stale data.
- An event gives each handler fresh handles. Handles of the same element compare equal with
==;tostringnames the family and the id ("vehicle:5"). - A handle is a Lua value, and two equal handles are still two different table keys. Key per-element state by
handle:id(). - A handle belongs to the VM that made it: it cannot cross into another resource (Calling other resources). Pass the id and look the element up on the other side (
dlmp.get_player(id)). - A handle of the wrong family where another is expected (
dlmp.destroy_vehicle(pickup)) raises an error.
Handles after removal
| Call | A player that left | A removed vehicle, pickup or other element | A timer that ended |
|---|---|---|---|
id(), ==, tostring | work | work | — |
| reads | nil, err | nil, err | is_active() is false |
actions, dlmp.destroy_*, passing it to another function | nil, err | nil, err | cancel() does nothing |
| after its id is taken again | remains bound to the disconnected player | ids are not reused | — |
A timer ends after its last repeat, on cancel() and with the stop of its resource; it is not an element.
Players
- A player comes into being when a connection joins, and lives from
player_connectuntilplayer_disconnect. With an auth resource configured, a connection is first aPendingthat only the auth resource sees; it becomes a player when that resource accepts it (ADR 0052). - Players have no owner and hang under the root. Player events therefore reach
dlmp.roothandlers, neverdlmp.resource_rootones, and the stop of a resource does nothing to the players. - Every departure goes through one removal path (ADR 0021) and raises
player_disconnect(player, reason)withreason"quit","timeout","kicked"or"overflow"(Disconnect). It also comes after a kick from a timer or from another handler. Inside its handlers the player is already removed:id()works, reads and actions returnnil, err. - A player id is a slot that a later connection reuses, but never before
player_disconnectof the previous player has been delivered. A handle belongs to one connection: afterplayer_disconnectit can no longer act on any player, even if another player now holds the id, and it equals only handles of its own connection. - Keep per-player state in a table keyed by
player:id()and clear the entry inplayer_disconnect. dlmp.sourceof a player event is the player's tree node, and the tree knows players by id. A handler attached to a saved playerdlmp.sourcestays until the resource stops and fires for the next player of that id too, so attach player handlers todlmp.rootand filter there.
local kills = {}
dlmp.add_event_handler("player_connect", dlmp.root, function(player)
kills[player:id()] = 0
end)
dlmp.add_event_handler("player_death", dlmp.root, function(victim, killer)
if killer and kills[killer:id()] then
kills[killer:id()] = kills[killer:id()] + 1
end
end)
dlmp.add_event_handler("player_disconnect", dlmp.root, function(player)
kills[player:id()] = nil
end)Events with a removed source
Events reach the resources one at a time in the order the server committed them (ADR 0048), so an element may be gone by the time an event about it is delivered: a handler of an earlier event in the same server step may have removed it.
- Removed inside a dispatch. When a handler removes the source of the event it is handling, the remaining handlers of that event still run with the same source; their reads of it return
nil, err. - Vehicles, objects, checkpoints and colshapes removed after the event was raised take the event with them: it is dropped. A refusable event about a removed vehicle counts as refused, and the server decides the request against the current state.
colshape_enterandcolshape_leaveare also dropped when the player or vehicle crossing was removed.vehicle_syncernames only players who are still there; one who left isnil. - Events that need a live player leave with a player who was removed after they were raised:
player_action, offer answers,player_stream_inandplayer_stream_out, checkpoint and colshape crossings, view callbacks,player_key_change,player_weapon_reloadandplayer_suspicion. - Facts the server already committed about a removed player are still delivered: damage, death (with the killer for scoring), chat, commands and the rest. Their player handles read
nil, err, andplayer_disconnectof that player follows in the same step. pickup_interactis delivered even when an earlier handler removed the pickup; actions on the pickup then returnnil, err.- Removal raises nothing on its own: destroying an object raises no
object_move_end, destroying a colshape or checkpoint raises no leave, and a player leaving raises onlyplayer_disconnect.
