diff --git a/README.md b/README.md index 3fbecd1..feec039 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,28 @@ Radial Menu Used With qbx_Core :arrows_counterclockwise: **Supports FontAwesome Icons!** Get the name from [FontAwesome](https://fontawesome.com/v5.0/icons?d=gallery&p=2&s=brands,light,regular,solid&m=free) (v5) and use the icon's name in the config.lua for the icon (no `fa-` or `#` just the name like `arrow-right`) + + +## Blip Usage + +## toggleBlip +```lua +exports.qbx_radialmenu:toggleBlip(category) +``` +### Parameters +- `category` (string): The unique category of the blip to toggle + + +## registerToggleableBlip +```lua +exports.qbx_radialmenu:registerToggleableBlip(blipId, category) +``` +### Parameters +- `blipId` (number): The blip handle to register +- `category` (string): The unique category of the blip + +### Example +```lua +local blipHandle = AddBlipForCoord(0.0, 0.0, 0.0) +exports.qbx_radialmenu:registerToggleableBlip(blipHandle, "shops") +``` \ No newline at end of file diff --git a/client/main.lua b/client/main.lua index 638c541..1581482 100644 --- a/client/main.lua +++ b/client/main.lua @@ -1,9 +1,29 @@ local config = require 'config.client' +local lastOutSideVehicle = false +local lastNearVehicle = false +local onVehicle = false +local lastNearPlayer = false +local vehicleFlipped = false + +local toggleableBlips = {} +local categoryVisible = {} +local metadataLoaded = false + ----------------------- ------- Events -------- ----------------------- +lib.onCache('vehicle', function(vehicle) + if vehicle then + onVehicle = true + setupVehicleMenu(true) + else + onVehicle = false + setupVehicleMenu(false) + end +end) + if config.vehicleSeats then lib.onCache('vehicle', function(vehicle) if vehicle then @@ -52,11 +72,27 @@ end ----------------------- local function convert(tbl) + if tbl.onVehicleOnly and not onVehicle then + return + end + if tbl.outSideVehicleOnly and not lastOutSideVehicle then + return + end + if tbl.nearByVehicleOnly and not lastNearVehicle then + return + end + if tbl.nearByPlayerOnly and not lastNearPlayer then + return + end if tbl.items then local items = {} for _, v in pairs(tbl.items) do - items[#items + 1] = convert(v) + local converted = convert(v) + if converted then + items[#items + 1] = converted + end end + if #items == 0 then return end lib.registerRadial({ id = tbl.id .. 'Menu', @@ -97,7 +133,11 @@ local function convert(tbl) action() end end, - keepOpen = tbl.keepOpen + keepOpen = tbl.keepOpen, + onVehicleOnly = tbl.onVehicleOnly, + outSideVehicleOnly = tbl.outSideVehicleOnly, + nearByVehicleOnly = tbl.nearByVehicleOnly, + nearByPlayerOnly = tbl.nearByPlayerOnly } end @@ -109,19 +149,32 @@ function setupVehicleMenu(seat) menu = 'vehicleMenu' } - local vehicleItems = {{ - id = 'vehicle-flip', - label = locale('options.flip'), - icon = 'car-burst', - onSelect = function() - TriggerEvent('radialmenu:flipVehicle') - lib.hideRadial() + local vehicleItems = {} + if vehicleFlipped then + vehicleItems[#vehicleItems + 1] = { + id = 'vehicle-flip', + label = locale('options.flip'), + icon = 'car-burst', + onSelect = function() + TriggerEvent('radialmenu:flipVehicle') + lib.hideRadial() + end + } + end + + if config.vehicleItems then + for i = 1, #config.vehicleItems do + vehicleItems[#vehicleItems + 1] = convert(config.vehicleItems[i]) end - }} + end - vehicleItems[#vehicleItems + 1] = convert(config.vehicleDoors) + if config.vehicleWindows then + vehicleItems[#vehicleItems + 1] = convert(config.vehicleWindows) + end - vehicleItems[#vehicleItems + 1] = convert(config.vehicleWindows) + if config.vehicleDoors then + vehicleItems[#vehicleItems + 1] = convert(config.vehicleDoors) + end if config.enableExtraMenu then vehicleItems[#vehicleItems + 1] = convert(config.vehicleExtras) @@ -143,7 +196,10 @@ local function setupRadialMenu() setupVehicleMenu() for _, v in pairs(config.menuItems) do - lib.addRadialItem(convert(v)) + local converted = convert(v) + if converted then + lib.addRadialItem(converted) + end end if config.gangItems[QBX.PlayerData.gang.name] then @@ -175,6 +231,29 @@ local function isEMS() return QBX.PlayerData.job.type == 'ems' and QBX.PlayerData.job.onduty end +local loadBlipPreferences = function() + if metadataLoaded then return end + + local playerData = QBX.PlayerData + if playerData and playerData.metadata then + local blipPreferences = playerData.metadata.blipPreferences or {} + + for category, isVisible in pairs(blipPreferences) do + categoryVisible[category] = isVisible + + if toggleableBlips[category] then + for blipId, _ in pairs(toggleableBlips[category]) do + if DoesBlipExist(blipId) then + SetBlipAlpha(blipId, isVisible and 255 or 0) + end + end + end + end + + metadataLoaded = true + end +end + -- Events RegisterNetEvent('radialmenu:client:deadradial', function(isDead) if isDead then @@ -366,6 +445,7 @@ end) -- Sets the metadata when the player spawns AddEventHandler('QBCore:Client:OnPlayerLoaded', function() setupRadialMenu() + loadBlipPreferences() end) RegisterNetEvent('QBCore:Client:OnJobUpdate', function(job) @@ -397,6 +477,117 @@ RegisterNetEvent('QBCore:Client:OnGangUpdate', function(gang) end end) +local saveBlipPreferences = function () + TriggerServerEvent('radialmenu:server:saveBlipPreferences', categoryVisible) +end + +---@param category string +local toggleBlipsForCategory = function(category) + if not category then + lib.print.warn("No category provided for toggling blips.") + return + end + local toggledCount = 0 + local blipCategoryName = string.gsub(category, "_", " ") -- Replaces underscores with spaces + blipCategoryName = blipCategoryName:sub(1,1):upper() .. blipCategoryName:sub(2) -- Capitalizes the first letter + + if categoryVisible[category] == nil then + categoryVisible[category] = true -- Default to visible + else + categoryVisible[category] = not categoryVisible[category] + end + local isVisible = categoryVisible[category] + + if toggleableBlips[category] then + for blipId, _ in pairs(toggleableBlips[category]) do + if DoesBlipExist(blipId) then + if isVisible then + SetBlipAlpha(blipId, 255) -- Show blip + else + SetBlipAlpha(blipId, 0) -- Hide blip + end + toggledCount = toggledCount + 1 + else + if toggleableBlips[category] then + toggleableBlips[category][blipId] = nil + end + end + end + end + + saveBlipPreferences() + + local status = isVisible and locale('general.blip_shown') or locale('general.blip_hidden') + exports.qbx_core:Notify(("%s %s"):format(blipCategoryName, status), 'info') + return isVisible +end + +---@param blipHandle number +---@param category string +local registerToggleableBlip = function(blipHandle, category) + if not category then + lib.print.error(("No category provided when registering blipId: %s"):format(tostring(blipHandle))) + return + end + if not blipHandle then + lib.print.error(("No blipId provided for registration in category: %s"):format(category)) + return + end + + if DoesBlipExist(blipHandle) then + if not toggleableBlips[category] then + toggleableBlips[category] = {} + end + toggleableBlips[category][blipHandle] = true + + if not metadataLoaded then + loadBlipPreferences() + end + + local isCurrentlyVisible = categoryVisible[category] + if isCurrentlyVisible == nil then + isCurrentlyVisible = true -- default new categories/blips to visible + categoryVisible[category] = true + saveBlipPreferences() + end + + if isCurrentlyVisible then + SetBlipAlpha(blipHandle, 255) + else + SetBlipAlpha(blipHandle, 0) + end + else + lib.print.warn(("Attempted to register non-existent blip %s for category: %s"):format(tostring(blipHandle), category)) + end +end + + +CreateThread(function() + while true do + local outSideVehicle = lib.getClosestVehicle(GetEntityCoords(cache.ped), 5.0, false) ~= nil + local nearByVehicle = lib.getClosestVehicle(GetEntityCoords(cache.ped), 5.0, true) ~= nil + local closestPlayer, _ = lib.getClosestPlayer(GetEntityCoords(cache.ped)) + local nearPlayer = closestPlayer ~= nil + + local playerCoords = GetEntityCoords(cache.ped) + local closestVehicle = lib.getClosestVehicle(playerCoords, 3.0) + local flipableVehicle = closestVehicle and not IsVehicleOnAllWheels(closestVehicle) + + local outsideStatusChanged = outSideVehicle ~= lastOutSideVehicle + local nearByVehicleChanged = nearByVehicle ~= lastNearVehicle + local nearPlayerChanged = nearPlayer ~= lastNearPlayer + local vehicleFlipStateChanged = IsVehicleOnAllWheels(closestVehicle) ~= flipableVehicle + if outsideStatusChanged or nearByVehicleChanged or nearPlayerChanged or closestVehicle and not vehicleFlipStateChanged then + lastOutSideVehicle = outSideVehicle + lastNearVehicle = nearByVehicle + lastNearPlayer = nearPlayer + vehicleFlipped = flipableVehicle + setupRadialMenu() + end + Wait(1500) + end +end) + local function createQBExport(name, cb) AddEventHandler(('__cfx_export_qb-radialmenu_%s'):format(name), function(setCB) setCB(cb) @@ -418,3 +609,6 @@ end exports('RemoveOption', removeOption) createQBExport('RemoveOption', removeOption) + +exports('toggleBlip', toggleBlipsForCategory) +exports('registerToggleableBlip', registerToggleableBlip) \ No newline at end of file diff --git a/config/client.lua b/config/client.lua index d9a051e..802b8f4 100644 --- a/config/client.lua +++ b/config/client.lua @@ -4,6 +4,17 @@ return { enableExtraMenu = true, flipTime = 15000, + vehicleItems = { + { + id = 'quickgivevehkeys', + icon = 'key', + label = locale('options.quickgivekeys'), + serverEvent = 'qbx_vehiclekeys:server:quickgivekeys', + outSideVehicleOnly = true, + nearByPlayerOnly = true + }, + }, + menuItems = { { id = 'citizen', @@ -14,13 +25,15 @@ return { id = 'givenum', icon = 'address-book', label = 'Give Contact Details', - event = 'qb-phone:client:GiveContactDetails' + event = 'qb-phone:client:GiveContactDetails', + nearByPlayerOnly = true }, { id = 'getintrunk', icon = 'car', label = 'Get In Trunk', - event = 'qb-trunk:client:GetIn' + event = 'qb-trunk:client:GetIn', + outSideVehicleOnly = true }, { id = 'cornerselling', @@ -50,6 +63,7 @@ return { icon = 'car-side', label = 'Take Out Vehicle', event = 'police:client:SetPlayerOutVehicle', + nearByVehicleOnly = true }, { id = 'stealPlayer', @@ -366,6 +380,7 @@ return { icon = 'eye-slash', label = 'Show/Hide Meter', event = 'qb-taxi:client:toggleMeter', + onVehicleOnly = true }, { id = 'togglemouse', diff --git a/fxmanifest.lua b/fxmanifest.lua index df15db9..2116562 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -3,7 +3,7 @@ game 'gta5' description 'qbx_radialmenu' repository 'https://github.com/Qbox-project/qbx_radialmenu' -version '0.1.0' +version '0.3.0' ox_lib 'locale' diff --git a/locales/en.json b/locales/en.json index a5ee086..2547fc5 100644 --- a/locales/en.json +++ b/locales/en.json @@ -42,7 +42,9 @@ "getintrunk_command_desc": "Enter the Trunk", "putintrunk_command_desc": "Put the Player in the Trunk", "gang_radial": "Gang", - "job_radial": "Job" + "job_radial": "Job", + "blip_shown": "Blip shown", + "blip_hidden": "Blip hidden" }, "options": { "flip": "Flip the Vehicle", @@ -52,6 +54,7 @@ "passenger_seat": "Passenger Seat", "other_seats": "Other Seat", "rear_left_seat": "Rear Left Seat", - "rear_right_seat": "Rear Right Seat" + "rear_right_seat": "Rear Right Seat", + "quickgivekeys": "Quick Give Keys" } } diff --git a/server/main.lua b/server/main.lua index 35865be..e886400 100644 --- a/server/main.lua +++ b/server/main.lua @@ -7,3 +7,11 @@ end) RegisterNetEvent('hospital:server:SetDeathStatus', function(isDead) TriggerClientEvent('radialmenu:client:deadradial', source, isDead) end) + +RegisterNetEvent('qbx_radialmenu:server:saveBlipPreferences', function(blipPreferences) + local playerData = exports.qbx_core:GetPlayer(source) + + if playerData then + playerData.Functions.SetMetaData("blipPreferences", blipPreferences) + end +end) \ No newline at end of file