Skip to content

add server-side and client-side entity spawn wrappers and shared helper#762

Open
TGIANN wants to merge 2 commits into
overextended:mainfrom
TGIANN:main
Open

add server-side and client-side entity spawn wrappers and shared helper#762
TGIANN wants to merge 2 commits into
overextended:mainfrom
TGIANN:main

Conversation

@TGIANN
Copy link
Copy Markdown
Contributor

@TGIANN TGIANN commented May 2, 2026

Add lib.createObject, lib.createPed, and lib.createVehicle for the server, plus a shared lib.spawnEntity helper used by both client and server wrappers. Each wrapper splits its body at module load time based on cache.game so that the correct CREATE_OBJECT/PED/VEHICLE native signature is used on FiveM vs RedM.

Server wrappers default orphanMode to 2 (KeepEntity). Server createVehicle uses CreateVehicleServerSetter (with vehicleType) on FiveM and the CFX CreateVehicle native on RedM, where vehicleType, properties, and seat are not exposed.

Existing client wrappers were refactored to delegate model loading to lib.spawnEntity, with a few client-side fixes folded in:

  • pass heading as the float arg in SetEntityHeading for createObject
  • replace undefined netMissionEntity with isNetwork in createPed
  • drop duplicate isNetwork assert in createPed
  • mark isNetwork, netMissionEntity, and doorFlag as optional in the type annotations to match runtime behavior

Add `lib.createObject`, `lib.createPed`, and `lib.createVehicle` for the
server, plus a shared `lib.spawnEntity` helper used by both client and
server wrappers. Each wrapper splits its body at module load time based
on `cache.game` so that the correct CREATE_OBJECT/PED/VEHICLE native
signature is used on FiveM vs RedM.

Server wrappers default `orphanMode` to 2 (KeepEntity). Server
`createVehicle` uses `CreateVehicleServerSetter` (with `vehicleType`)
on FiveM and the CFX `CreateVehicle` native on RedM, where
`vehicleType`, `properties`, and `seat` are not exposed.

Existing client wrappers were refactored to delegate model loading to
`lib.spawnEntity`, with a few client-side fixes folded in:
- pass heading as the float arg in `SetEntityHeading` for createObject
- replace undefined `netMissionEntity` with `isNetwork` in createPed
- drop duplicate `isNetwork` assert in createPed
- mark `isNetwork`, `netMissionEntity`, and `doorFlag` as optional in
  the type annotations to match runtime behavior
@TGIANN
Copy link
Copy Markdown
Contributor Author

TGIANN commented May 2, 2026

Comment thread fxmanifest.lua Outdated
Comment on lines +46 to +49
'imports/spawnEntity/server.lua',
'imports/createObject/server.lua',
'imports/createPed/server.lua',
'imports/createVehicle/server.lua',
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are unnecessary.

Comment thread imports/createVehicle/client.lua Outdated
Comment on lines +9 to +18
---@alias SeatPosition
---| -2 # SF_ANY
---| -1 # SF_FrontDriverSide
---| 0 # SF_FrontPassengerSide
---| 1 # SF_BackDriverSide
---| 2 # SF_BackPassengerSide
---| 3 # SF_AltFrontDriverSide
---| 4 # SF_AltFrontPassengerSide
---| 5 # SF_AltBackDriverSide
---| 6 # SF_AltBackPassengerSide
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be best to have a types file or have game types like this defined as part of fivem-lls-addon.

@thelindat
Copy link
Copy Markdown
Member

thelindat commented May 2, 2026

My biggest issues with this are

  • code duplication
  • type disparity (i.e. function declarations differ greatly between fivem/redm/fxserver)
  • uses RPCs in some cases (almost never good)

I'd personally want to see classes used for any entity wrappers, e.g.

lib.entity as a base class inherited by lib.object, lib.ped, lib.vehicle with some common methods across server and client.

Networked entities from clients are also somewhat discouraged and potentially disabled on many servers, so focusing on server-created entities is more important.

@TGIANN
Copy link
Copy Markdown
Contributor Author

TGIANN commented May 2, 2026

My biggest issues with this are

  • code duplication
  • type disparity (i.e. function declarations differ greatly between fivem/redm/fxserver)
  • uses RPCs in some cases (almost never good)

I'd personally want to see classes used for any entity wrappers, e.g.

lib.entity as a base class inherited by lib.object, lib.ped, lib.vehicle with some common methods across server and client.

Networked entities from clients are also somewhat discouraged and potentially disabled on many servers, so focusing on server-created entities is more important.

I've re edit everything. If everything is as you want and there are no issues, I can prepare the docs

test script
tgiann-test.zip

@unitysync unitysync requested a review from thelindat May 12, 2026 08:09
Copy link
Copy Markdown
Member

@thelindat thelindat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is usable but I might need to do some planning for a future implementation to ensure its fully fit for purpose. This can also work into a proposal for a custom statebag interface and would need a solid TS implementation too.

Things like resource management/cleanup, grid handling, etc. would probably be necessary for any (local) client entities too.

Comment thread imports/entity/shared.lua
---@class Entity : OxClass
---@field handle number Native entity handle.
---@field script string Resource that created or wrapped this entity.
local Entity = lib.class('Entity')
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll need to use lib.entity from the start. Assigning the value later results in private and protected fields giving errors. Same applies to the other classes of course.

Comment thread imports/entity/shared.lua
---to wrap any pre-existing entity, or as the parent of `lib.object`, `lib.ped`, and
---`lib.vehicle` for typed spawn wrappers.
---@class Entity : OxClass
---@field handle number Native entity handle.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately there's no readonly annotation, but always good to tell people not to mess with values.

Comment thread imports/entity/shared.lua
assert(handleType == 'number' and handle ~= 0, ('expected non-zero entity handle, got %s (%s)'):format(handleType, tostring(handle)))

self.handle = handle
self.script = GetInvokingResource() or cache.resource
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this for exactly?

Comment thread imports/entity/shared.lua
Comment on lines +80 to +83
---Returns the entity's state bag.
function Entity:getState()
return getEntityStateBag(self.handle).state
end
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd scrap this for now, in case we do our own statebag handling (#778)

Comment thread imports/entity/shared.lua
Comment on lines +122 to +124
if IS_SERVER and cache.game ~= 'redm' then
self:setOrphanMode(data.orphanMode or 2)
end
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cache.game on the server will be 'fxserver'.

Comment thread imports/entity/shared.lua
function Entity:onAfterRespawn(data) end

if IS_SERVER then
local allowClientServerEntityCreation = GetConvarInt('ox:allowClientServerEntityCreation', 0) == 1
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now let's just focus solely on class wrappers and not implementing RPCs.

Comment thread imports/object/server.lua
Comment on lines +53 to +57
return CreateObject(modelHash, data.coords.x, data.coords.y, data.coords.z,
true, data.bScriptHostObj or false, data.dynamic or false, data.p7 or false, data.p8 or false)
end

return CreateObject(modelHash, data.coords.x, data.coords.y, data.coords.z, true, true, data.doorFlag or false)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CreateObject is an RPC; the server needs to use CreateObjectNoOffset.

Comment thread imports/entity/shared.lua
---Base class wrapping a CFX entity handle. Used directly via `lib.entity:new(handle)`
---to wrap any pre-existing entity, or as the parent of `lib.object`, `lib.ped`, and
---`lib.vehicle` for typed spawn wrappers.
---@class Entity : OxClass
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be GameEntity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants