From d705a743205ee473e32224d3d09b9a48eac48086 Mon Sep 17 00:00:00 2001 From: xThrasherrr <101474430+xThrasherrr@users.noreply.github.com> Date: Thu, 10 Jul 2025 23:16:34 -0600 Subject: [PATCH 01/10] feat(config): add config for list of shells --- configs/shells.lua | 21 +++++++++++++++++++++ fxmanifest.lua | 4 ++++ 2 files changed, 25 insertions(+) create mode 100644 configs/shells.lua diff --git a/configs/shells.lua b/configs/shells.lua new file mode 100644 index 0000000..39d1e3e --- /dev/null +++ b/configs/shells.lua @@ -0,0 +1,21 @@ +--[[ + ['shell_model'] = 'Shell Label' +]] + +return { + ['furnitured_midapart'] = 'Furnished Mid Apartment', + ['shell_v16low'] = 'K4MBI Low End', + ['shell_v16mid'] = 'K4MBI Mid', + ['shell_trevor'] = 'Trevor\'s House', + ['shell_trailer'] = 'Trailer', + ['shell_lester'] = 'Lester\'s House', + ['shell_ranch'] = 'Ranch', + ['container_shell'] = 'Container', + ['modernhotel_shell'] = 'Modern Hotel', + ['shell_frankaunt'] = 'Franklin\'s Aunt', + ['shell_garagemed'] = 'Medium Garage', + ['shell_michael'] = 'Michael\'s House', + ['shell_office1'] = 'Office', + ['shell_store1'] = 'Store', + ['shell_warehouse1'] = 'Warehouse' +} \ No newline at end of file diff --git a/fxmanifest.lua b/fxmanifest.lua index c61e720..4adbe98 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -17,4 +17,8 @@ shared_scripts { '@ox_lib/init.lua' } +files { + 'configs/shells.lua', +} + lua54 'yes' From e46e3f269a4810321d8ce959e93997b200813360 Mon Sep 17 00:00:00 2001 From: xThrasherrr <101474430+xThrasherrr@users.noreply.github.com> Date: Thu, 10 Jul 2025 23:16:52 -0600 Subject: [PATCH 02/10] feat(utils): create utils module --- client/utils.lua | 119 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 client/utils.lua diff --git a/client/utils.lua b/client/utils.lua new file mode 100644 index 0000000..cbec37f --- /dev/null +++ b/client/utils.lua @@ -0,0 +1,119 @@ +local INTERIORS = lib.require('configs.shells') + +local shellHandle +local lastCoords + +local utils = {} + +-- remove object by handle +function utils.removeObject(object) + if DoesEntityExist(object) then + DeleteEntity(object) + end +end + +-- create object/shell +function utils.createObject(model, coords) + if not IsModelInCdimage(model) then + return utils.notify(("The object \"%s\" is not in cd image"):format(model), 'error') + end + + lib.requestModel(model) + + local object = CreateObject(model, coords.x, coords.y, coords.z, true, true, false) + FreezeEntityPosition(object, true) + SetEntityHeading(object, 0.0) + + return object +end + +-- remove shell, remove placed objects and teleport player to last coords +function utils.removeShell() + if shellHandle and DoesEntityExist(shellHandle) then + DeleteEntity(shellHandle) + shellHandle = nil + end + + lib.hideTextUI() + + if lastCoords then + SetEntityCoordsNoOffset(cache.ped, lastCoords.x, lastCoords.y, lastCoords.z, true, true, true) + lastCoords = nil + end +end + +-- create shell object and teleport player inside +function utils.createShell(shell) + if not IsModelInCdimage(shell) then + return utils.notify(("The shell \"%s\" is not in cd image, did you start the shell?"):format(shell), 'error') + end + + utils.removeShell() + + lastCoords = GetEntityCoords(cache.ped) + local newCoords = lastCoords - vec3(0, 0, 240) + + shellHandle = utils.createObject(shell, newCoords) + + while not DoesEntityExist(shellHandle) or not HasCollisionForModelLoaded(shell) do + Wait(100) + end + + SetEntityCollision(shellHandle, true, true) + + -- teleport player into shell + local z = newCoords.z + local success, groundZ, _ = GetGroundZAndNormalFor_3dCoord(newCoords.x, newCoords.y, newCoords.z) + while not success do + success, groundZ, _ = GetGroundZAndNormalFor_3dCoord(newCoords.x, newCoords.y, z) + z = z + 0.5 -- increment z until found + Wait(10) + end + + SetEntityCoordsNoOffset(cache.ped, newCoords.x, newCoords.y, groundZ + 1.0, true, true, true) + + return shellHandle +end + +-- select shell model input +function utils.selectShell() + local options = {} + + for shell, label in pairs(INTERIORS) do + options[#options + 1] = { + value = shell, + label = label + } + end + + local shellSelect = lib.inputDialog('Select Interior', { + { type = 'select', label = 'Interior', required = true, options = options }, + }) + + return shellSelect and shellSelect[1] or false +end + +-- copy offset to clipboard +function utils.copyOffset(coordsToCompare, heading) + local offset = GetOffsetFromEntityGivenWorldCoords(shellHandle, coordsToCompare.x, coordsToCompare.y, coordsToCompare.z) + + lib.setClipboard(('vec4(%f, %f, %f, %f)'):format(offset.x, offset.y, offset.z, heading)) + + utils.notify("Copied offset to clipboard.", 'success') +end + +function utils.notify(message, messageType) + lib.notify({ + title = 'Offset Finder', + description = message, + type = messageType + }) +end + +function utils.showControls(string) + lib.showTextUI(string, { + position = 'top-center' + }) +end + +return utils \ No newline at end of file From 27889c5133639100a4b9c17a84336dc7bd875038 Mon Sep 17 00:00:00 2001 From: xThrasherrr <101474430+xThrasherrr@users.noreply.github.com> Date: Thu, 10 Jul 2025 23:17:10 -0600 Subject: [PATCH 03/10] tweak(server): change command/remove command --- server/main.lua | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/server/main.lua b/server/main.lua index 174b0c1..fc82fd2 100644 --- a/server/main.lua +++ b/server/main.lua @@ -1,20 +1,7 @@ -lib.addCommand('findoffsets', { +lib.addCommand('offsets', { help = 'Find offets for a shell', - params = { - { - name = 'shell', - type = 'string', - help = 'name of the shell to test', - }, - }, + params = {}, restricted = 'group.admin' }, function(source, args, raw) - TriggerClientEvent('qw-offset:client:testShell', source, args.shell) -end) - -lib.addCommand('findoffsets:object', { - help = 'Find object / prop offets for a shell', - restricted = 'group.admin' -}, function(source, args, raw) - TriggerClientEvent('qw-offset:client:objectOffsetMode', source) + TriggerClientEvent('qw-offset:client:offsetFinder', source) end) \ No newline at end of file From a30fa0fac627b037e837c3cc83d2de0e0b80af18 Mon Sep 17 00:00:00 2001 From: xThrasherrr <101474430+xThrasherrr@users.noreply.github.com> Date: Thu, 10 Jul 2025 23:17:31 -0600 Subject: [PATCH 04/10] refactor(client): single event for shell/objects --- client/main.lua | 250 ++++++++++++++++-------------------------------- 1 file changed, 82 insertions(+), 168 deletions(-) diff --git a/client/main.lua b/client/main.lua index 6fbb418..b67a41a 100644 --- a/client/main.lua +++ b/client/main.lua @@ -1,206 +1,120 @@ -local shellHandle = nil -local objectHandle = nil -local oldCoords = nil +local UTILS = lib.require('client.utils') + +local controlsString = '[E] - Copy Offset \n [Q] - Remove Shell' local testingShell = false local inObjectPreview = false -local placedPreviews = {} - -local function Notify(msg) - lib.notify({ - title = 'Offset Finder', - description = msg, - type = 'success' - }) -end - -local function removePlaceholderObjects() - for i = 1, #placedPreviews do - local preview = placedPreviews[i] - - if DoesEntityExist(preview) then - DeleteEntity(preview) - end - end - - placedPreviews = {} -end - -local function RemoveShell() - if not shellHandle then - return - end - - testingShell = false - lib.hideTextUI() - DeleteEntity(shellHandle) - shellHandle = nil - - if objectHandle and DoesEntityExist(objectHandle) then - inObjectPreview = false - DeleteEntity(objectHandle) - objectHandle = nil - end +local tempObject, tempObjectModel, tempObjectSnapToGround, tempCoords - removePlaceholderObjects() +RegisterNetEvent("qw-offset:client:offsetFinder", function() + if GetInvokingResource() then return end - SetEntityCoordsNoOffset(cache.ped, oldCoords) - oldCoords = nil - - Notify("Deleted shell") -end - -RegisterNetEvent("qw-offset:client:testShell", function(shellName) - local shellModel = shellName and GetHashKey(shellName) - - if not shellName then - return Notify(("No such shell \"%s\"."):format(shellName or "")) - elseif not IsModelInCdimage(shellModel) then - return Notify(("The shell \"%s\" is not in cd image, did you start the shell?"):format(shellName)) - end - - if DoesEntityExist(shellHandle) then - DeleteEntity(shellHandle) - shellHandle = nil - else - oldCoords = GetEntityCoords(cache.ped) - end - - local input = lib.inputDialog('Shell Z Coord', { - { - type = 'number', - label = 'Z Coord Offset', - description = 'How High or Low to Spawn the Shell', - icon = 'hashtag', - required = true, - default = 0.0 - }, - }) - - if not input then - return - end - - shellHandle = CreateObject(shellModel, oldCoords + vec3(0.0, 0.0, input[1]), true, true) - FreezeEntityPosition(shellHandle, true) - SetEntityHeading(shellHandle, 0.0) - - SetEntityCoordsNoOffset(cache.ped, GetEntityCoords(shellHandle)) - - testingShell = true - - lib.showTextUI('[E] - Copy Offset \n [Q] - Remove Shell', { - position = "left-center", - }) - - CreateThread(function() - while testingShell do - Wait(0) - - if IsControlJustPressed(0, 44) then RemoveShell() end - - if IsControlJustPressed(0, 38) then - if not shellHandle then - return - end - - local coords = GetEntityCoords(PlayerPedId()) - - local coordsToCompare = inObjectPreview and GetEntityCoords(objectHandle) or coords - - local offset = GetOffsetFromEntityGivenWorldCoords(shellHandle, coordsToCompare) - - lib.setClipboard(('vec4(%f, %f, %f, %f)'):format(offset.x, offset.y, offset.z, - GetEntityHeading(inObjectPreview and objectHandle or cache.ped))) - Notify("Copied offset to clipboard.") - end + if not testingShell then + local selectedShell = UTILS.selectShell() + if not selectedShell then + return end - end) -end) -RegisterNetEvent('qw-offset:client:objectOffsetMode', function() - - if not testingShell then return end - if not inObjectPreview then + local createdShell = UTILS.createShell(selectedShell) + if not createdShell then + return + end - local input = lib.inputDialog('Object Model Preview', { + testingShell = true + else + local objectModel = lib.inputDialog('Object Model Preview', { { type = 'input', label = 'Object Name', required = true, }, + { + type = 'checkbox', + label = 'Snap To Ground?' + } }) - - if not input then + if not objectModel or not objectModel[1] then + UTILS.notify('No object model provided', 'error') return end - local object = tostring(input[1]) - - local objectModel = object and GetHashKey(object) + tempObjectModel = objectModel[1] + tempObjectSnapToGround = objectModel[2] - if not IsModelInCdimage(objectModel) then - return Notify(("The object \"%s\" is not in cd image, are you sure this exists?"):format(objectModel)) + if tempObject and DoesEntityExist(tempObject) then + DeleteEntity(tempObject) end + controlsString = controlsString .. ' \n[L/R Arrow] Rotate Object \n[X] Cancel Object Offset Finder' + + local coords = GetEntityCoords(cache.ped) + + tempObject = UTILS.createObject(tempObjectModel, coords) + + SetEntityAlpha(tempObject, 150, false) + SetEntityCollision(tempObject, false, false) + inObjectPreview = true + end + + UTILS.showControls(controlsString) - lib.requestModel(objectModel, 1000) + CreateThread(function() + while testingShell do + Wait(0) - objectHandle = CreateObject(objectModel, GetEntityCoords(cache.ped), true, true, false) + -- press Q to remove shell + if IsControlJustPressed(0, 44) then + UTILS.removeShell() + testingShell = false + inObjectPreview = false + tempObjectModel = nil + tempObjectSnapToGround = nil + end - SetEntityAlpha(objectHandle, 150, false) - SetEntityCollision(objectHandle, false, false) - FreezeEntityPosition(objectHandle, true) + -- press E to copy offset off current object or current coords + if IsControlJustPressed(0, 38) then + local coords = GetEntityCoords(cache.ped) + local coordsToCompare = inObjectPreview and GetEntityCoords(tempObject) or coords + local heading = GetEntityHeading(inObjectPreview and tempObject or cache.ped) - lib.hideTextUI() - lib.showTextUI('[E] - Copy Offset \n [Q] - Remove Shell \n [L/R Arrow] Rotate Object', { - position = "left-center", - }) + UTILS.copyOffset(coordsToCompare, heading) + end - CreateThread(function() - while inObjectPreview do - local hit, _, coords, _, _ = lib.raycast.cam(1, 4) + if inObjectPreview then + local hit, _, tempCoords, _, _ = lib.raycast.cam(1, 4) if hit then - SetEntityCoords(objectHandle, coords.x, coords.y, coords.z) - PlaceObjectOnGroundProperly(objectHandle) + SetEntityCoords(tempObject, tempCoords.x, tempCoords.y, tempCoords.z, false, false, false, false) + if tempObjectSnapToGround then + PlaceObjectOnGroundProperly(tempObject) + end + -- left and right arrows for temp object heading changes if IsControlPressed(0, 174) then - SetEntityHeading(objectHandle, GetEntityHeading(objectHandle) - 1.0) + SetEntityHeading(tempObject, GetEntityHeading(tempObject) - 1.0) end if IsControlPressed(0, 175) then - SetEntityHeading(objectHandle, GetEntityHeading(objectHandle) + 1.0) + SetEntityHeading(tempObject, GetEntityHeading(tempObject) + 1.0) end + end - if IsControlJustPressed(0, 38) then - local placeholderObject = CreateObject(objectModel, coords.x, coords.y, coords.z, true, true, false) - SetEntityHeading(placeholderObject, GetEntityHeading(objectHandle)) - - PlaceObjectOnGroundProperly(placeholderObject) - SetEntityAlpha(placeholderObject, 150, false) - SetEntityCollision(placeholderObject, false, false) - FreezeEntityPosition(placeholderObject, true) - SetEntityDrawOutline(placeholderObject, true) - SetEntityDrawOutlineColor(0, 255, 0, 150) - + if IsControlJustPressed(0, 73) then -- press X to cancel object offset finder + UTILS.removeObject(tempObject) + inObjectPreview = false + tempObjectModel = nil - placedPreviews[#placedPreviews+1] = placeholderObject - end + -- return to default control string + controlsString = '[E] - Copy Offset \n [Q] - Remove Shell' + UTILS.showControls(controlsString) end - - Wait(0) end - end) - else - if objectHandle and DoesEntityExist(objectHandle) then - inObjectPreview = false - DeleteEntity(objectHandle) - objectHandle = nil end - - lib.hideTextUI() - lib.showTextUI('[E] - Copy Offset \n [Q] - Remove Shell', { - position = "left-center", - }) - end + end) end) + +-- remove shell on stop +AddEventHandler('onResourceStop', function(resource) + if resource ~= GetCurrentResourceName() then return end + + UTILS.removeShell() +end) \ No newline at end of file From 50c86ef8beeb40a883bc2d8c2c05b5735b474d07 Mon Sep 17 00:00:00 2001 From: xThrasherrr <101474430+xThrasherrr@users.noreply.github.com> Date: Thu, 10 Jul 2025 23:36:07 -0600 Subject: [PATCH 05/10] feat(client): temp objects w/ target --- client/main.lua | 14 +++++++++++++- client/utils.lua | 42 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/client/main.lua b/client/main.lua index b67a41a..e694191 100644 --- a/client/main.lua +++ b/client/main.lua @@ -44,7 +44,7 @@ RegisterNetEvent("qw-offset:client:offsetFinder", function() DeleteEntity(tempObject) end - controlsString = controlsString .. ' \n[L/R Arrow] Rotate Object \n[X] Cancel Object Offset Finder' + controlsString = controlsString .. ' \n[L/R Arrow] Rotate Object \n[Z] Place Object \n[X] Cancel Object Offset Finder' local coords = GetEntityCoords(cache.ped) @@ -107,6 +107,18 @@ RegisterNetEvent("qw-offset:client:offsetFinder", function() controlsString = '[E] - Copy Offset \n [Q] - Remove Shell' UTILS.showControls(controlsString) end + + if IsControlJustPressed(0, 20) then -- press Z to create temp objects + local vec4Coords = vec4(tempCoords.x, tempCoords.y, tempCoords.z, GetEntityHeading(tempObject)) + + UTILS.createTempObject(tempObjectModel, vec4Coords) + inObjectPreview = false + tempObjectModel = nil + + -- return to default control string + controlsString = '[E] - Copy Offset \n [Q] - Remove Shell' + UTILS.showControls(controlsString) + end end end end) diff --git a/client/utils.lua b/client/utils.lua index cbec37f..4b45e9a 100644 --- a/client/utils.lua +++ b/client/utils.lua @@ -2,9 +2,32 @@ local INTERIORS = lib.require('configs.shells') local shellHandle local lastCoords +local tempObjects = {} local utils = {} +-- creates temp object +function utils.createTempObject(model, coords) + local tempObject = utils.createObject(model, coords) + SetEntityDrawOutline(tempObject, true) + + exports.ox_target:addLocalEntity(tempObject, { + { + icon = 'fas fa-copy', + label = 'Copy Offset', + onSelect = function() + local heading = GetEntityHeading(tempObject) + + utils.copyOffset(coords, heading) + end + } + }) + + tempObjects[#tempObjects + 1] = tempObject + + return tempObject +end + -- remove object by handle function utils.removeObject(object) if DoesEntityExist(object) then @@ -22,7 +45,11 @@ function utils.createObject(model, coords) local object = CreateObject(model, coords.x, coords.y, coords.z, true, true, false) FreezeEntityPosition(object, true) - SetEntityHeading(object, 0.0) + SetEntityHeading(object, coords.w or 0.0) + + while not DoesEntityExist(object) do + Wait(10) + end return object end @@ -36,6 +63,15 @@ function utils.removeShell() lib.hideTextUI() + if tempObjects and next(tempObjects) then + for x = 1, #tempObjects do + utils.removeObject(tempObjects[x]) + exports.ox_target:removeLocalEntity(tempObjects[x]) + + tempObjects[x] = nil + end + end + if lastCoords then SetEntityCoordsNoOffset(cache.ped, lastCoords.x, lastCoords.y, lastCoords.z, true, true, true) lastCoords = nil @@ -55,8 +91,8 @@ function utils.createShell(shell) shellHandle = utils.createObject(shell, newCoords) - while not DoesEntityExist(shellHandle) or not HasCollisionForModelLoaded(shell) do - Wait(100) + while not HasCollisionForModelLoaded(shell) do + Wait(10) end SetEntityCollision(shellHandle, true, true) From bbbe6421c14a2785eb83ce9ed564c297d16e39cd Mon Sep 17 00:00:00 2001 From: xThrasherrr <101474430+xThrasherrr@users.noreply.github.com> Date: Thu, 10 Jul 2025 23:36:51 -0600 Subject: [PATCH 06/10] bump version --- fxmanifest.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fxmanifest.lua b/fxmanifest.lua index 4adbe98..fd0c0a3 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -3,7 +3,7 @@ game 'gta5' description 'offset finder for FiveM' author 'qw-scripts' -version '1.0.0' +version '2.0.0' client_scripts { 'client/**/*' From 34b8f8307f96da6f0db0312882ce8e8009496312 Mon Sep 17 00:00:00 2001 From: xThrasherrr <101474430+xThrasherrr@users.noreply.github.com> Date: Thu, 10 Jul 2025 23:38:31 -0600 Subject: [PATCH 07/10] tweak(client): reset controls string function --- client/main.lua | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/client/main.lua b/client/main.lua index e694191..a9d8e90 100644 --- a/client/main.lua +++ b/client/main.lua @@ -5,6 +5,11 @@ local testingShell = false local inObjectPreview = false local tempObject, tempObjectModel, tempObjectSnapToGround, tempCoords +local function __resetControlsString() + controlsString = '[E] - Copy Offset \n [Q] - Remove Shell' + UTILS.showControls(controlsString) +end + RegisterNetEvent("qw-offset:client:offsetFinder", function() if GetInvokingResource() then return end @@ -103,9 +108,7 @@ RegisterNetEvent("qw-offset:client:offsetFinder", function() inObjectPreview = false tempObjectModel = nil - -- return to default control string - controlsString = '[E] - Copy Offset \n [Q] - Remove Shell' - UTILS.showControls(controlsString) + __resetControlsString() end if IsControlJustPressed(0, 20) then -- press Z to create temp objects @@ -115,9 +118,7 @@ RegisterNetEvent("qw-offset:client:offsetFinder", function() inObjectPreview = false tempObjectModel = nil - -- return to default control string - controlsString = '[E] - Copy Offset \n [Q] - Remove Shell' - UTILS.showControls(controlsString) + __resetControlsString() end end end From 8a95353b77157bb985c3fa8a48b003cbf7b2dfd5 Mon Sep 17 00:00:00 2001 From: xThrasherrr <101474430+xThrasherrr@users.noreply.github.com> Date: Thu, 10 Jul 2025 23:49:36 -0600 Subject: [PATCH 08/10] fix(client): remove temp object before placing --- client/main.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/client/main.lua b/client/main.lua index a9d8e90..16c027d 100644 --- a/client/main.lua +++ b/client/main.lua @@ -114,6 +114,7 @@ RegisterNetEvent("qw-offset:client:offsetFinder", function() if IsControlJustPressed(0, 20) then -- press Z to create temp objects local vec4Coords = vec4(tempCoords.x, tempCoords.y, tempCoords.z, GetEntityHeading(tempObject)) + UTILS.removeObject(tempObject) UTILS.createTempObject(tempObjectModel, vec4Coords) inObjectPreview = false tempObjectModel = nil From 881261a5da5c2a4095ca7e4c04f4b18c67be9343 Mon Sep 17 00:00:00 2001 From: xThrasherrr <101474430+xThrasherrr@users.noreply.github.com> Date: Thu, 10 Jul 2025 23:49:47 -0600 Subject: [PATCH 09/10] Update README.md --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 53ce8c8..381573f 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,17 @@ # Offset finder for FiveM -supports Player offsets and Object offsets +Supports Player offsets and Object offsets ## Commands Available: -`findoffsets` - -`findoffsets:object` +`offsets` ## Links [Co-Authored by Zoo](https://github.com/Renewed-Scripts) - I am very much so brain dead so Zoo helped me get the offsets working correctly +[Reworked by xT](https://github.com/xT-Development) -[preview](https://streamable.com/my3fd6) +[preview](https://streamable.com/ereyap) ## Warning From e7fd1ea0c11a2fe5085609efbb43676f986c4ab8 Mon Sep 17 00:00:00 2001 From: xThrasherrr <101474430+xThrasherrr@users.noreply.github.com> Date: Thu, 10 Jul 2025 23:54:08 -0600 Subject: [PATCH 10/10] tweak(client): check if ox_target is started --- client/utils.lua | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/client/utils.lua b/client/utils.lua index 4b45e9a..3aa5e09 100644 --- a/client/utils.lua +++ b/client/utils.lua @@ -1,4 +1,5 @@ local INTERIORS = lib.require('configs.shells') +local ox_target = GetResourceState('ox_target') == 'started' local shellHandle local lastCoords @@ -11,17 +12,19 @@ function utils.createTempObject(model, coords) local tempObject = utils.createObject(model, coords) SetEntityDrawOutline(tempObject, true) - exports.ox_target:addLocalEntity(tempObject, { - { - icon = 'fas fa-copy', - label = 'Copy Offset', - onSelect = function() - local heading = GetEntityHeading(tempObject) - - utils.copyOffset(coords, heading) - end - } - }) + if ox_target then + exports.ox_target:addLocalEntity(tempObject, { + { + icon = 'fas fa-copy', + label = 'Copy Offset', + onSelect = function() + local heading = GetEntityHeading(tempObject) + + utils.copyOffset(coords, heading) + end + } + }) + end tempObjects[#tempObjects + 1] = tempObject