diff --git a/bridge/esx/client.lua b/bridge/esx/client.lua index 139ab56..d682f31 100644 --- a/bridge/esx/client.lua +++ b/bridge/esx/client.lua @@ -26,7 +26,6 @@ end) RegisterNetEvent('esx:onPlayerLogout', function() Player = table.wipe(Player) - TriggerEvent('interact:groupsChanged', {}) -end) -return Bridge \ No newline at end of file + TriggerEvent('interact:groupsChanged', {}) +end) \ No newline at end of file diff --git a/bridge/ox/client.lua b/bridge/ox/client.lua index 91e2836..93008e8 100644 --- a/bridge/ox/client.lua +++ b/bridge/ox/client.lua @@ -20,6 +20,7 @@ end) AddEventHandler('ox:playerLogout', function() table.wipe(Player) + TriggerEvent('interact:groupsChanged', {}) end) diff --git a/bridge/qb/client.lua b/bridge/qb/client.lua index 8425b60..2652078 100644 --- a/bridge/qb/client.lua +++ b/bridge/qb/client.lua @@ -24,6 +24,7 @@ end) RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() local PlayerData = QBCore.Functions.GetPlayerData() + Player = { Group = { [PlayerData.job.name] = PlayerData.job.grade.level, @@ -38,6 +39,6 @@ end) RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() Player = table.wipe(Player) - TriggerEvent('interact:groupsChanged', {}) -end) + TriggerEvent('interact:groupsChanged', {}) +end) \ No newline at end of file diff --git a/client/defaults.lua b/client/defaults.lua index 1464391..0b50558 100644 --- a/client/defaults.lua +++ b/client/defaults.lua @@ -1,6 +1,4 @@ -if GetConvar('interact_disabledefault', 'false') == 'true' then - return -end +if GetConvar('interact_disabledefault', 'false') == 'true' then return end local api = require 'client.interactions' @@ -23,12 +21,11 @@ api.addGlobalVehicleInteraction({ end local plate = GetVehicleNumberPlateText(entity) - local invId = 'trunk'..plate local coords = GetEntityCoords(entity) TaskTurnPedToFaceCoord(cache.ped, coords.x, coords.y, coords.z, 0) - if not exports.ox_inventory:openInventory('trunk', { id = invId, netid = NetworkGetNetworkIdFromEntity(entity), entityid = entity, door = 5 }) then return end + if not exports.ox_inventory:openInventory('trunk', { id = ('trunk%s'):format(plate), netid = NetworkGetNetworkIdFromEntity(entity), entityid = entity, door = 5 }) then return end end, } }) \ No newline at end of file diff --git a/client/entities.lua b/client/entities.lua index 0d144f7..d744693 100644 --- a/client/entities.lua +++ b/client/entities.lua @@ -9,6 +9,7 @@ local subCache = {} function entities.isNetIdNearby(netID) local entity = netIds[netID] + return entity and entity.entity end @@ -31,24 +32,25 @@ function entities.getEntitiesByType(type) for k, v in pairs(localEnties) do if v.type == type then - amount = amount + 1 + amount += 1 entityTable[amount] = k end end for _, v in pairs(netIds) do if v.type == type then - amount = amount + 1 + amount += 1 entityTable[amount] = v.entity end end - if type == "players" then - for k, v in pairs(playersTable) do - amount = amount + 1 + if type == 'players' then + for _, v in pairs(playersTable) do + amount += 1 entityTable[amount] = v.entity serverIds[amount] = v.serverId end + return amount, entityTable, serverIds end @@ -112,6 +114,7 @@ end CreateThread(function() while true do local playerCoords = GetEntityCoords(cache.ped) + clearTables() buildEntities('CVehicle', playerCoords) @@ -131,36 +134,42 @@ RegisterNetEvent('onPlayerJoining', function(serverId) local ent = lib.waitFor(function() local ped = GetPlayerPed(playerId) - if ped > 0 then return ped end + + if ped > 0 then + return ped + end end, '', 10000) - + playersTable[serverId] = { entity = ent, serverId = serverId, - type = "players", + type = 'players', } end) -AddEventHandler('onResourceStart', function(name) - if name == GetCurrentResourceName() then - local players = GetActivePlayers() - - for i = 1, #players do - local playerId = players[i] - local serverId = GetPlayerServerId(playerId) - if serverId ~= cache.serverId then - - local ent = lib.waitFor(function() - local ped = GetPlayerPed(playerId) - if ped > 0 then return ped end - end, '', 10000) - - playersTable[serverId] = { - entity = ent, - serverId = serverId, - type = "players", - } - end +AddEventHandler('onResourceStart', function(resource) + if resource ~= cache.resource then return end + + local players = GetActivePlayers() + + for i = 1, #players do + local playerId = players[i] + local serverId = GetPlayerServerId(playerId) + + if serverId ~= cache.serverId then + local ent = lib.waitFor(function() + local ped = GetPlayerPed(playerId) + + if ped > 0 then + return ped + end + end, '', 10000) + + playersTable[serverId] = { + entity = ent, + serverId = serverId, + type = 'players', + } end end end) diff --git a/client/interactions.lua b/client/interactions.lua index 183b818..2a9a322 100644 --- a/client/interactions.lua +++ b/client/interactions.lua @@ -8,7 +8,6 @@ local table_type = table.type -- CACHE. local api = {} - local entityInteractions = {} local modelInteractions = {} local netInteractions = {} @@ -20,7 +19,8 @@ local myGroups = {} local function generateUUID() return ('xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'):gsub('[xy]', function(c) local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb) - return string.format('%x', v) + + return ('%x'):format(v) end) end @@ -34,14 +34,14 @@ local function verifyInteraction(interaction) end -- makes it so you can send a singular object instead of an array - if table_type(interaction.options) ~= 'array' then + if table.type(interaction.options) ~= 'array' then interaction.options = { interaction.options } end -- Translates types of groups into a key value pair for easier checking if interaction.groups then if type(interaction.groups) == 'string' then - interaction.groups = { [interaction.groups] = 0, } + interaction.groups = { [interaction.groups] = 0 } elseif table_type(interaction.groups) == 'array' then for i = 1, #interaction.groups do interaction.groups[interaction.groups[i]] = 0 @@ -121,9 +121,7 @@ end) ---@return string | nil : The id of the interaction -- Add an interaction point at a set of coords function api.addInteraction(data) - if not verifyInteraction(data) then - return - end + if not verifyInteraction(data) then return end local id = data.id or generateUUID() @@ -148,7 +146,8 @@ function api.addInteraction(data) end return id -end exports('AddInteraction', api.addInteraction) +end +exports('AddInteraction', api.addInteraction) ---@param data table : { name, entity, options, distance, interactDst, groups } ---@return string | nil : The id of the interaction @@ -162,9 +161,7 @@ function api.addLocalEntityInteraction(data) return log:error('Invalid entity') end - if not verifyInteraction(data) then - return - end + if not verifyInteraction(data) then return end if not entityInteractions[entity] then entityInteractions[entity] = {} @@ -192,7 +189,8 @@ function api.addLocalEntityInteraction(data) entityInteractions[entity][#entityInteractions[entity] + 1] = tableData return id -end exports('AddLocalEntityInteraction', api.addLocalEntityInteraction) +end +exports('AddLocalEntityInteraction', api.addLocalEntityInteraction) ---@param data table : { name, netId, options, distance, interactDst, groups } ---@return string | nil : The id of the interaction @@ -203,8 +201,10 @@ function api.addEntityInteraction(data) -- If the netId does not exist, we assume it is an entity if not netId or not NetworkDoesNetworkIdExist(netId) then local entity = data.entity or data.netId + if DoesEntityExist(entity) then data.entity = entity + return api.addLocalEntityInteraction(data) end end @@ -215,9 +215,7 @@ function api.addEntityInteraction(data) end end - if not verifyInteraction(data) then - return - end + if not verifyInteraction(data) then return end local id = data.id or generateUUID() @@ -247,12 +245,11 @@ function api.addEntityInteraction(data) netInteractions[netId][#netInteractions[netId]+1] = dataTable return id -end exports('AddEntityInteraction', api.addEntityInteraction) +end +exports('AddEntityInteraction', api.addEntityInteraction) function api.addGlobalVehicleInteraction(data) - if not verifyInteraction(data) then - return - end + if not verifyInteraction(data) then return end local id = data.id or generateUUID() @@ -278,12 +275,11 @@ function api.addGlobalVehicleInteraction(data) end return id -end exports('AddGlobalVehicleInteraction', api.addGlobalVehicleInteraction) +end +exports('AddGlobalVehicleInteraction', api.addGlobalVehicleInteraction) function api.addGlobalPlayerInteraction(data) - if not verifyInteraction(data) then - return - end + if not verifyInteraction(data) then return end local id = data.id or generateUUID() @@ -310,7 +306,8 @@ function api.addGlobalPlayerInteraction(data) end return id -end exports('addGlobalPlayerInteraction', api.addGlobalPlayerInteraction) +end +exports('addGlobalPlayerInteraction', api.addGlobalPlayerInteraction) ---@param data table : { name, entity[number|string], bone[string], options, distance, interactDst, groups } @@ -318,7 +315,8 @@ end exports('addGlobalPlayerInteraction', api.addGlobalPlayerInteraction) -- Add an interaction point on a networked entity's bone function api.addEntityBoneInteraction() lib.print.warn('addEntityBoneInteraction is deprecated, use AddEntityInteraction or AddLocalEntityInteraction instead') -end exports('AddEntityBoneInteraction', api.addEntityBoneInteraction) +end +exports('AddEntityBoneInteraction', api.addEntityBoneInteraction) ---@param data table : { name, modelData table : { model[string], offset[vec3] }, options, distance, interactDst, groups } -- Add interaction(s) to a list of models @@ -359,11 +357,13 @@ function api.addModelInteraction(data) modelInteractions[model][#modelInteractions[model] + 1] = tableData return id -end exports('AddModelInteraction', api.addModelInteraction) +end +exports('AddModelInteraction', api.addModelInteraction) local function removeFilteredInteraction(interaction) if not interaction.groups or hasGroup(interaction.groups) then local id = interaction.id + for i = #filteredInteractions, 1, -1 do if filteredInteractions[i].id == id then table.remove(filteredInteractions, i) @@ -393,7 +393,8 @@ exports('RemoveInteraction', api.removeInteraction) -- Remove an interaction point by entity. function api.removeInteractionByEntity() lib.print.warn('removeInteractionByEntity is deprecated, use RemoveLocalEntityInteraction instead') -end exports('RemoveInteractionByEntity', api.removeInteractionByEntity) +end +exports('RemoveInteractionByEntity', api.removeInteractionByEntity) function api.removeLocalEntityInteraction(entity, id) if entity and id and entityInteractions[entity] then @@ -407,7 +408,8 @@ function api.removeLocalEntityInteraction(entity, id) end end end -end exports('RemoveLocalEntityInteraction', api.removeLocalEntityInteraction) +end +exports('RemoveLocalEntityInteraction', api.removeLocalEntityInteraction) function api.removeModelInteraction(model, id) if model and id and modelInteractions[model] then @@ -421,7 +423,8 @@ function api.removeModelInteraction(model, id) end end end -end exports('RemoveModelInteraction', api.removeModelInteraction) +end +exports('RemoveModelInteraction', api.removeModelInteraction) function api.removeEntityInteraction(netId, id) if netId and id and netInteractions[netId] then @@ -435,7 +438,8 @@ function api.removeEntityInteraction(netId, id) end end end -end exports('RemoveEntityInteraction', api.removeEntityInteraction) +end +exports('RemoveEntityInteraction', api.removeEntityInteraction) RegisterNetEvent('interact:removeEntity', function(data) for i = 1, #data do @@ -461,7 +465,8 @@ function api.removeGlobalVehicleInteraction(id) end end end -end exports('RemoveGlobalVehicleInteraction', api.removeGlobalVehicleInteraction) +end +exports('RemoveGlobalVehicleInteraction', api.removeGlobalVehicleInteraction) function api.removeGlobalPlayerInteraction(id) if id then @@ -475,7 +480,9 @@ function api.removeGlobalPlayerInteraction(id) end end end -end exports('RemoveGlobalPlayerInteraction', api.removeGlobalPlayerInteraction) +end +exports('RemoveGlobalPlayerInteraction', api.removeGlobalPlayerInteraction) + ---@param id number : The id of the interaction to remove the option from ---@param name? string : The name of the option to remove -- Remove an option from an interaction point by id. @@ -499,7 +506,8 @@ function api.removeInteractionOption(id, name) log:debug('Removed option %s from interaction %s', name, id) end end -end exports('RemoveInteractionOption', api.removeInteractionOption) +end +exports('RemoveInteractionOption', api.removeInteractionOption) ---@param id number : The id of the interaction to update ---@param options table : The new options to update the interaction with @@ -518,7 +526,8 @@ function api.updateInteraction(id, options) interactions[id].options = options filterInteractions() end -end exports('UpdateInteraction', api.updateInteraction) +end +exports('UpdateInteraction', api.updateInteraction) local function canInteract(option, interaction) return not option.canInteract or option.canInteract(interaction.entity, interaction.coords, interaction.args) @@ -537,8 +546,8 @@ local function getInteractionOptions(interaction) if success and result then if not option.job or hasGroup(option.job) then - added += 1 - currentOptions[added] = option + added += 1 + currentOptions[added] = option end end end @@ -589,6 +598,7 @@ end local function addGlobalPlayerData(interaction, options, playercoords) local playerAmount, players, serverIds = entities.getEntitiesByType('players') + if playerAmount > 0 then local amount = #options @@ -692,7 +702,7 @@ function api.getNearbyInteractions() end if amount > 1 then - table_sort(options, function(a, b) + table.sort(options, function(a, b) return a.curDist < b.curDist end) end @@ -702,7 +712,8 @@ end function api.disable(state) LocalPlayer.state:set('interactionsDisabled', state, false) -end exports('Disable', api.disable) +end +exports('Disable', api.disable) AddEventHandler('onClientResourceStop', function(resource) for i = #interactions, 1, -1 do @@ -761,4 +772,4 @@ AddEventHandler('onClientResourceStop', function(resource) filterInteractions() end) -return api +return api \ No newline at end of file diff --git a/client/interacts.lua b/client/interacts.lua index f534d91..8597bfa 100644 --- a/client/interacts.lua +++ b/client/interacts.lua @@ -32,6 +32,7 @@ local math_max = math.max local math_min = math.min local nearby, nearbyAmount = {}, 0 + local function CreateInteractions() for i = 1, nearbyAmount do local interaction = nearby[i] @@ -49,9 +50,9 @@ local function CreateInteractions() if GetScreenCoordFromWorldCoord(coords.x, coords.y, coords.z) then local isClose = isPrimary and (interaction.curDist <= interaction.interactDst) and (not interaction.entity or interaction.ignoreLos or interaction.entity == CurrentTarget) + if isPrimary and currentAlpha < 0 then local options = interaction.options - local alpha = currentAlpha * -1 SetScriptGfxAlignParams(0.0, 0.0, 0.0, 0.0) @@ -61,6 +62,7 @@ local function CreateInteractions() local optionAmount = #options local showDot = optionAmount > 1 + for j = 1, optionAmount do createOption(coords, options[j], j, interaction.width, showDot, alpha) end @@ -136,12 +138,15 @@ end -- Fast thread CreateThread(function () lib.requestStreamedTextureDict('interactions_txd') + while true do local wait = 500 + if nearbyAmount > 0 and not disableInteraction then wait = 0 CreateInteractions() end + Wait(wait) end end) @@ -149,9 +154,11 @@ end) -- Slow checker thread local getCurrentTarget = require 'client.raycast' local threadTimer = GetConvarInt('interact_thread', 250) + CreateThread(function() while true do disableInteraction = isDisabled() + if disableInteraction then nearby, nearbyAmount = table.wipe(nearby), 0 CurrentTarget = 0 @@ -162,4 +169,4 @@ CreateThread(function() Wait(threadTimer) end -end) +end) \ No newline at end of file diff --git a/client/raycast.lua b/client/raycast.lua index 3da6d5d..9c04c3c 100644 --- a/client/raycast.lua +++ b/client/raycast.lua @@ -1,10 +1,12 @@ local function getForwardVector(rotation) local rot = (math.pi / 180.0) * rotation - return vector3(-math.sin(rot.z) * math.abs(math.cos(rot.x)), math.cos(rot.z) * math.abs(math.cos(rot.x)), math.sin(rot.x)) + + return vec3(-math.sin(rot.z) * math.abs(math.cos(rot.x)), math.cos(rot.z) * math.abs(math.cos(rot.x)), math.sin(rot.x)) end local function rayCast(origin, target, options, ignoreEntity, radius) local handle = StartShapeTestSweptSphere(origin.x, origin.y, origin.z, target.x, target.y, target.z, radius, options, ignoreEntity, 0) + return GetShapeTestResult(handle) end @@ -26,7 +28,10 @@ end return function() local entity, entityType - pcall(function() entity, entityType = entityInFrontOfPlayer(3.0, 0.2, cache.ped) end) + + pcall(function() + entity, entityType = entityInFrontOfPlayer(3.0, 0.2, cache.ped) + end) return entity and entityType ~= 0 and entity or nil end \ No newline at end of file diff --git a/client/textures.lua b/client/textures.lua index 1d83b46..1f66021 100644 --- a/client/textures.lua +++ b/client/textures.lua @@ -3,5 +3,5 @@ local textures = settings.Textures local txd = CreateRuntimeTxd('interactions_txd') for _, v in pairs(textures) do - CreateRuntimeTextureFromImage(txd, tostring(v), "assets/"..settings.Style.."/"..v..".png") + CreateRuntimeTextureFromImage(txd, tostring(v), 'assets/'..settings.Style..'/'..v..'.png') end \ No newline at end of file diff --git a/client/utils.lua b/client/utils.lua index dfa5668..88dafbb 100644 --- a/client/utils.lua +++ b/client/utils.lua @@ -33,6 +33,7 @@ end function utils.getTrunkOffset(entity) local min, _ = GetModelDimensions(GetEntityModel(entity)) + return GetOffsetFromEntityInWorldCoords(entity, 0.0, min.y - 0.5, 0.0) end @@ -64,9 +65,11 @@ function utils.getCoordsFromInteract(interaction) if DoesEntityExist(interaction.entity) then if interaction.bone then local pos = GetEntityBonePosition_2(interaction.entity, GetEntityBoneIndexByName(interaction.entity, interaction.bone)) + if interaction.offset then pos = GetEntityBonePosition_2(interaction.entity, GetEntityBoneIndexByName(interaction.entity, interaction.bone)) + interaction.offset end + return pos elseif interaction.model then local offset = interaction.offset or vec3(0.0, 0.0, 0.0) @@ -77,6 +80,7 @@ function utils.getCoordsFromInteract(interaction) if interaction.offset then return GetOffsetFromEntityInWorldCoords(interaction.entity, 0.0 + interaction.offset.x, 0.0 + interaction.offset.y, 0.0 + interaction.offset.z) end + return GetEntityBonePosition_2(interaction.entity, 0) -- SKEL_ROOT else if interaction.offset then @@ -97,7 +101,7 @@ function utils.drawOption(coords, text, spriteDict, spriteName, row, width, show SetTextScale(0, 0.3) SetTextFont(4) SetTextColour(255, 255, 255, alpha) - BeginTextCommandDisplayText("STRING") + BeginTextCommandDisplayText('STRING') SetTextCentre(true) AddTextComponentSubstringPlayerName(text) SetDrawOrigin(coords.x, coords.y, coords.z, 0) diff --git a/fxmanifest.lua b/fxmanifest.lua index 717a438..6e97a8b 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -30,7 +30,9 @@ client_scripts { 'client/raycast.lua', 'client/defaults.lua', } + server_scripts { 'server/main.lua', } -dependency 'ox_lib' + +dependency 'ox_lib' \ No newline at end of file diff --git a/server/main.lua b/server/main.lua index add5a29..6d6536b 100644 --- a/server/main.lua +++ b/server/main.lua @@ -6,6 +6,7 @@ local entityStates = {} RegisterNetEvent('interact:setEntityHasOptions', function(netId) local entity = Entity(NetworkGetEntityFromNetworkId(netId)) + entity.state.hasInteractOptions = true entityStates[netId] = entity end) @@ -21,7 +22,6 @@ CreateThread(function() if not DoesEntityExist(entity.__data) or not entity.state.hasInteractOptions then entityStates[netId] = nil num += 1 - arr[num] = netId end end diff --git a/shared/log.lua b/shared/log.lua index 483cab1..9307eee 100644 --- a/shared/log.lua +++ b/shared/log.lua @@ -1,11 +1,12 @@ -local settings = 'shared.settings' - -return { - debug = function(self, message, ...) - if not settings.Debug then return end - print(('[%s] %s'):format('DEBUG', message:format(...))) - end, - error = function(self, message, ...) - print(('[%s] %s'):format('ERROR', message:format(...))) - end +local settings = require 'shared.settings' + +return { + debug = function(self, message, ...) + if not settings.Debug then return end + + print(('[%s] %s'):format('DEBUG', message:format(...))) + end, + error = function(self, message, ...) + print(('[%s] %s'):format('ERROR', message:format(...))) + end } \ No newline at end of file