From 8fd69445b71c8e9be99661d719b694f6b2aa4880 Mon Sep 17 00:00:00 2001 From: Laith <96451713+L1iith@users.noreply.github.com> Date: Tue, 7 Oct 2025 20:50:39 +0300 Subject: [PATCH 1/2] Add showIf filtering to targeting options Introduces filtering of options and zones using their showIf function before sending data to the UI. This ensures only relevant options are displayed based on dynamic conditions. --- client/main.lua | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/client/main.lua b/client/main.lua index 5ab090e..fa606ee 100644 --- a/client/main.lua +++ b/client/main.lua @@ -288,6 +288,7 @@ local function startTargeting() end end + if newOptions then if hasTarget == 1 and (totalOptions - hidden) > 1 then hasTarget = true @@ -312,10 +313,37 @@ local function startTargeting() }) end + -- Filter options with showIf (only when showing the menu) + local function filterShowIf(tbl) + if not tbl then return nil end + local filtered = {} + for k, v in pairs(tbl) do + if type(v) == 'table' then + local skip = false + if v.showIf then + local ok, res = pcall(v.showIf, currentTarget.entity, currentTarget.distance, currentTarget.coords, v.name) + if not ok or not res then skip = true end + end + if not skip then filtered[k] = v end + end + end + return filtered + end + + local filteredOptions = {} + for k, v in pairs(options) do + filteredOptions[k] = filterShowIf(v) + end + + local filteredZones = {} + for i = 1, #zones do + filteredZones[i] = filterShowIf(zones[i]) + end + SendNuiMessage(json.encode({ event = 'setTarget', - options = options, - zones = zones, + options = filteredOptions, + zones = filteredZones, }, { sort_keys = true })) end From 5cfb886772d42cb3bb9dda2567a6b6e6d196ff36 Mon Sep 17 00:00:00 2001 From: Laith <96451713+L1iith@users.noreply.github.com> Date: Sun, 12 Oct 2025 02:18:37 +0300 Subject: [PATCH 2/2] Add unique option IDs for reliable selection add unique IDs for target options in Lua and passes them to the NUI frontend ensuring correct option selection even when filtering or reordering occurs. Updates both Lua and JS to use and transmit these IDs improving robustness of option handling. --- client/main.lua | 40 +++++++++++++++++++++++++++++++--------- web/js/createOptions.js | 6 ++++-- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/client/main.lua b/client/main.lua index fa606ee..ccc167f 100644 --- a/client/main.lua +++ b/client/main.lua @@ -315,16 +315,23 @@ local function startTargeting() -- Filter options with showIf (only when showing the menu) local function filterShowIf(tbl) - if not tbl then return nil end + if not tbl then return {} end local filtered = {} - for k, v in pairs(tbl) do + for i = 1, #tbl do + local v = tbl[i] if type(v) == 'table' then - local skip = false + -- Assign a unique id if not present + if not v.id then + v.id = v.name or (v.label .. '_' .. tostring(i)) + end + local include = true if v.showIf then local ok, res = pcall(v.showIf, currentTarget.entity, currentTarget.distance, currentTarget.coords, v.name) - if not ok or not res then skip = true end + if not ok or not res then include = false end + end + if include then + table.insert(filtered, v) end - if not skip then filtered[k] = v end end end return filtered @@ -340,6 +347,7 @@ local function startTargeting() filteredZones[i] = filterShowIf(zones[i]) end + -- Send filtered options with their ids to NUI SendNuiMessage(json.encode({ event = 'setTarget', options = filteredOptions, @@ -434,9 +442,23 @@ RegisterNUICallback('select', function(data, cb) cb(1) local zone = data[3] and nearbyZones[data[3]] + local optionId = data[4] -- expects NUI to send the option id as the 4th element + + local function findOptionById(tbl, id) + for i = 1, #tbl do + if tbl[i] and tbl[i].id == id then + return tbl[i] + end + end + end ---@type OxTargetOption? - local option = zone and zone.options[data[2]] or options[data[1]][data[2]] + local option = nil + if zone then + option = findOptionById(zone.options, optionId) + else + option = findOptionById(options[data[1]], optionId) + end if option then if option.openMenu then @@ -461,12 +483,12 @@ RegisterNUICallback('select', function(data, cb) state.setNuiFocus(false) end - currentTarget.zone = zone?.id + currentTarget.zone = zone and zone.id or nil if option.onSelect then option.onSelect(option.qtarget and currentTarget.entity or getResponse(option)) elseif option.export then - exports[option.resource or zone.resource][option.export](nil, getResponse(option)) + exports[option.resource or (zone and zone.resource)][option.export](nil, getResponse(option)) elseif option.event then TriggerEvent(option.event, getResponse(option)) elseif option.serverEvent then @@ -478,7 +500,7 @@ RegisterNUICallback('select', function(data, cb) if option.menuName == 'home' then return end end - if not option?.openMenu and IsNuiFocused() then + if not (option and option.openMenu) and IsNuiFocused() then state.setActive(false) end end) diff --git a/web/js/createOptions.js b/web/js/createOptions.js index 193f25a..e4d89aa 100644 --- a/web/js/createOptions.js +++ b/web/js/createOptions.js @@ -6,7 +6,8 @@ function onClick() { // when nuifocus is disabled after a click, the hover event is never released this.style.pointerEvents = "none"; - fetchNui("select", [this.targetType, this.targetId, this.zoneId]); + // Send the unique id as the 4th element + fetchNui("select", [this.targetType, this.targetId, this.zoneId, this.optionId]); // is there a better way to handle this? probably setTimeout(() => (this.style.pointerEvents = "auto"), 100); } @@ -24,7 +25,8 @@ export function createOptions(type, data, id, zoneId) { option.targetType = type; option.targetId = id; option.zoneId = zoneId; + option.optionId = data.id; // Pass the unique id from Lua option.addEventListener("click", onClick); optionsWrapper.appendChild(option); -} +} \ No newline at end of file