client runtime · Lua API
Open77.props
Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server.
On this page14 sections
attach
Open77.props.attach(propId, binding)Attach a resource-owned local prop to a rendered bone or vehicle.
Binding fields: parentType ('player' or 'vehicle'), parentId (canonical network ID, not an engine handle), bone (named slot, empty for root), offset {x,y,z} in metres (each ±20), rotation {x,y,z} in degrees (each ±360, local Z-Y-X composition). Unknown fields and non-finite numbers reject. Missing streamed parents are hidden, then rebound when available. See attachments.md. Requires world.props. This changes only this client's prop, not server authority. Physics uses a visual-only attachment host; arbitrary mesh paths without that host are refused.
Parameters 2
| Name | Type | Use | Default |
|---|---|---|---|
propId | integer | required | — |
binding | table | required | — |
Returns
- boolean success, reason on failure
Example
-- A local placement ghost held in the player's hand
Open77.props.attach(localPropId, { parentType = "player", parentId = Open77.players.localId(), bone = "RightHand" })Synchronized attachments guide · Registered in ResourceHost.cpp as LuaPropAttach (line 25501).
bones
Open77.props.bones(parentType, parentId)List available named attachment slots on a streamed parent.
Requires world.props. Returns sorted names from the current native slot components, not all skeleton bones. Parent IDs are canonical player/vehicle IDs. Empty array means unavailable or no slots; it does not establish that a different body/model supports a requested slot.
Parameters 2
| Name | Type | Use | Default |
|---|---|---|---|
parentType | string | required | — |
parentId | integer | required | — |
Returns
- string[] or nil, reason
Example
local slots, err = Open77.props.bones('player', playerId)
if slots then for _, slot in ipairs(slots) do print(slot) end endSynchronized attachments guide · Registered in ResourceHost.cpp as LuaPropAttachmentBones (line 25503).
clear
Open77.props.clear()Removes every local prop this resource created.
Called automatically when the resource stops or reloads, so a reloading gamemode never leaves orphaned decorations behind. It never touches another resource's props, nor server-owned ones.
Returns
- boolean
Example
-- Leaving build mode removes every placement ghost
AddEventHandler("build:exit", function()
Open77.props.clear()
end)Registered in ResourceHost.cpp as LuaPropClear (line 25507).
create
Open77.props.create(options)Creates a local, decorative prop owned by this resource.
Requires world.props. This is the client meaning of the name: the prop is never replicated and never visible to anyone else -- a placement ghost, a build cursor, a preview being dragged. It is charged against this resource's quota and released when the resource stops. The identically-named *server* function mints an authoritative, replicated prop instead; the two Open77 tables are different objects on different machines.
Parameters 1
| Name | Type | Use | Default |
|---|---|---|---|
options | table { model, position, yaw?, scale?, appearance?, kind?, physics?, collision?, visible?, light? } | required | — |
Returns
- decimal-string prop id, or nil
- reason
Example
local ghost = assert(Open77.props.create({
model = "crate.small",
position = { x = -1442.2, y = 127.4, z = 18.0 },
collision = false
}))Registered in ResourceHost.cpp as LuaPropCreate (line 25500).
detach
Open77.props.detach(propId)Detach a resource-owned local prop.
Requires world.props. Restores an independent host at the last locally rendered pose. Does not detach a server-owned network prop. Calling the server API is required for a replicated release.
Parameters 1
| Name | Type | Use | Default |
|---|---|---|---|
propId | integer | required | — |
Returns
- boolean success, reason on failure
Example
-- Drop the local ghost prop where it is
Open77.props.detach(localPropId)Synchronized attachments guide · Registered in ResourceHost.cpp as LuaPropDetach (line 25502).
list
Open77.props.list()Local props this resource owns, with what the renderer did with each.
Each entry carries the model, kind, physics, transform, scale, the back-end that drew it, and whether it rendered or failed. Scoped to the caller: it deliberately excludes server-owned props, which belong to the session rather than to any resource, so asking a resource-scoped question about them would return an empty table and read as "no props" rather than "wrong question". Use the open77_props resource's all export for those.
Returns
- array of prop snapshots
Example
-- Did every local prop actually render?
for _, prop in ipairs(Open77.props.list()) do
if not prop.rendered then print("prop failed to render:", prop.model) end
endRegistered in ResourceHost.cpp as LuaPropList (line 25508).
nearest
Open77.props.nearest(position, [radius])Finds the nearest local prop owned by this resource.
Requires world.props. Searches only the calling resource's local prop set, using a 10 metre default radius. A non-positive or non-finite radius is rejected; use list when an unbounded set is intended.
Parameters 2
| Name | Type | Use | Default |
|---|---|---|---|
position | table { x, y, z } | required | — |
radius | number | optional | 10 |
Returns
- prop snapshot and distance, or nil
- reason on validation failure
Example
-- Press E on the nearest of this resource's ghosts to confirm the placement
RegisterKeyMapping("build_confirm", "Confirm placement", "E", function()
local prop, distance = Open77.props.nearest(Open77.character.state().position, 3)
if prop then TriggerServerEvent("build:confirm", prop.model, prop.position) end
end)Registered in ResourceHost.cpp as LuaPropNearest (line 25510).
project
Open77.props.project(serverId, options)Upserts a server-owned prop into the world, keyed by the server id.
What the bundled open77_props projection resource drives; not the way a gamemode places objects. Because the native layer is keyed by the server's own id, a prop that only moved is transformed in place rather than destroyed and rebuilt, which is what stops it visibly popping. Projected props are owned by the session, survive a resource reload, and are not charged against any resource's quota.
Parameters 2
| Name | Type | Use | Default |
|---|---|---|---|
serverId | decimal string | required | — |
options | table, same fields as create | required | — |
Returns
- boolean
- reason
Example
-- The projection resource shows a server prop under the server's own id
RegisterNetEvent("props:sync", function(serverId, definition)
Open77.props.project(serverId, definition)
end)Registered in ResourceHost.cpp as LuaPropProject (line 25511).
projected
Open77.props.projected(serverPropId)Inspect a replicated prop by its server ID.
Requires world.props. Returns the current local projection snapshot, or nil if absent. Includes backend, rendered, failed and attachmentStatus. Native item projection reports rendered only after native attachment and visual spawning. hidden_first_person is explicitly not rendered. Read-only; does not create or take ownership of a server prop.
Parameters 1
| Name | Type | Use | Default |
|---|---|---|---|
serverPropId | integer|string | required | — |
Returns
- table snapshot, or nil
- reason on failure
Example
local prop = Open77.props.projected(serverPropId)
if prop then print(prop.backend, prop.attachmentStatus, prop.rendered) endRegistered in ResourceHost.cpp as LuaPropProjected (line 25509).
remove
Open77.props.remove(id)Removes a local prop this resource owns.
Removing a prop that is already gone succeeds: the caller asked for it not to be there, and it is not there. Another resource's prop answers owned_by_another_resource.
Parameters 1
| Name | Type | Use | Default |
|---|---|---|---|
id | decimal string | required | — |
Returns
- boolean
- reason
Example
-- The player cancelled the placement: remove the ghost
Open77.props.remove(ghostId)Registered in ResourceHost.cpp as LuaPropRemove (line 25506).
setTransform
Open77.props.setTransform(id, transform)Moves a local prop to a position and yaw.
The one mutation the engine accepts on a live entity, so it never respawns and never pops. Scale is deliberately not part of it: scale is read when the render proxy is built, so it goes through update and costs a respawn.
Parameters 2
| Name | Type | Use | Default |
|---|---|---|---|
id | decimal string | required | — |
transform | table { position, yaw? } | required | — |
Returns
- boolean
- reason
Example
-- Drag the placement ghost to wherever the reticle points
SetTick(function()
local ray = Open77.camera.aimRay(20)
if ray and ray.hit then Open77.props.setTransform(ghostId, { position = ray.position }) end
end)Registered in ResourceHost.cpp as LuaPropSetTransform (line 25505).
unproject
Open77.props.unproject(serverId)Stops projecting one server-owned prop.
Succeeds when the prop is already absent: the server is saying stop showing something, and it is not being shown.
Parameters 1
| Name | Type | Use | Default |
|---|---|---|---|
serverId | decimal string | required | — |
Returns
- boolean
- reason
Example
-- The server removed the prop: stop showing it
RegisterNetEvent("props:removed", function(serverId)
Open77.props.unproject(serverId)
end)Registered in ResourceHost.cpp as LuaPropUnproject (line 25512).
unprojectAll
Open77.props.unprojectAll()Stops projecting every server-owned prop.
Used on disconnect and when the projection resource restarts, so a stale world never survives into a new session.
Returns
- boolean
Example
-- Leaving the server: nothing stale survives into the next session
AddEventHandler("session:disconnected", function()
Open77.props.unprojectAll()
end)Registered in ResourceHost.cpp as LuaPropUnprojectAll (line 25513).
update
Open77.props.update(id, patch)Patches a local prop this resource owns.
Only the fields present in the patch are taken. Changing anything the render proxy reads when it is built -- model, scale, kind, physics, collision, visibility or the light parameters -- respawns the underlying entity rather than mutating it, because the engine offers no in-place path for those. Use setTransform to move a prop without that cost.
Parameters 2
| Name | Type | Use | Default |
|---|---|---|---|
id | decimal string | required | — |
patch | table, same fields as create | required | — |
Returns
- boolean
- reason
Example
-- The player chose a bigger crate: scale respawns the ghost
Open77.props.update(ghostId, { scale = 1.5 })Registered in ResourceHost.cpp as LuaPropUpdate (line 25504).
// For agents & LLMsthis page as Markdownllms.txtllms-full.txt
