diff --git a/code/components/citizen-server-impl/src/state/ServerGameState_Scripting.cpp b/code/components/citizen-server-impl/src/state/ServerGameState_Scripting.cpp index bb64bc2953..691e0fe091 100644 --- a/code/components/citizen-server-impl/src/state/ServerGameState_Scripting.cpp +++ b/code/components/citizen-server-impl/src/state/ServerGameState_Scripting.cpp @@ -242,6 +242,45 @@ static void Init() return retval; })); + + fx::ScriptEngine::RegisterNativeHandler("NETWORK_SET_FIRST_ENTITY_OWNER", makeEntityFunction([](fx::ScriptContext& context, const fx::sync::SyncEntityPtr& entity) + { + auto resourceManager = fx::ResourceManager::GetCurrent(); + auto instance = resourceManager->GetComponent()->Get(); + auto clientRegistry = instance->GetComponent(); + + auto playerSrc = context.GetArgument(1); + + int playerNetId = atoi(playerSrc); + if (playerNetId == 0) + { + throw std::runtime_error(va("NETWORK_SET_FIRST_ENTITY_OWNER: invalid player: %s", playerSrc)); + } + + bool firstOwnerExists = !!entity->GetFirstOwner(); + bool hasClient = !!entity->GetClient(); + + // We only allow this to be set whenever we don't have an initial owner and the entity isn't already sync'd to clients + if (firstOwnerExists || hasClient) + { + fx::scripting::Warningf("net", "Tried to set the first owner for entity: %u but it already had an owner or client, hasFirstOwner: %d, hasClient: %d", context.GetArgument(0), firstOwnerExists, hasClient); + return false; + } + + auto client = clientRegistry->GetClientByNetID(playerNetId); + if (!client) + { + return false; + } + + // set all of the owner fields that are expected, this is safe since this shouldn't be broadcasted yet if we just created the entity. + entity->GetFirstOwnerUnsafe() = client; + entity->GetLastOwnerUnsafe() = client; + entity->GetClientUnsafe() = client; + + return true; + })); + fx::ScriptEngine::RegisterNativeHandler("SET_ENTITY_ORPHAN_MODE", [](fx::ScriptContext& context) { // get the current resource manager diff --git a/ext/native-decls/NetworkSetFirstEntityOwner.md b/ext/native-decls/NetworkSetFirstEntityOwner.md new file mode 100644 index 0000000000..c0794eb5e2 --- /dev/null +++ b/ext/native-decls/NetworkSetFirstEntityOwner.md @@ -0,0 +1,37 @@ +--- +ns: CFX +apiset: server +--- +## NETWORK_SET_FIRST_ENTITY_OWNER + +```c +void NETWORK_SET_FIRST_ENTITY_OWNER(Entity entity, char* playerSrc); +``` + +**WARNING**: This native is not planned to be ported to Enhanced. You should make sure this native exists before calling it. + +In Lua you can do this by doing `if NetworkSetFirstEntityOwner then` in JS you can do this by checking that `typeof globalThis.NetworkGetFirstEntityOwner === "function"`. + +If you fail to do this when enhanced is released, it is likely that native will error and you will be expected to fix it. + +**NOTE**: This only works for server created entities, and only work in the same tick that the server-created entity was made, trying to call this after an owner has been assigned will do nothing. + +This native sets the first entity owner for server-created entitys in order to reduce the migration the server might do with the entity. + +## Parameters +* **entity**: The entity to set the first owner for. +* **playerSrc**: The player to set as the owner + +## Examples +```lua +-- for this example we just get the first player +local player = GetPlayers()[1] + +-- create the helicopter +local heli = CreateVehicleServerSetter(`seasparrow`, 'heli', GetEntityCoords(GetPlayerPed(player)) + vector3(0, 0, 15), 0.0) + +-- and set the first entity owner to the player +if NetworkSetFirstEntityOwner then + NetworkSetFirstEntityOwner(heli, player) +end +```