├── README.md ├── client └── cl_main.lua ├── fxmanifest.lua └── ui ├── index.html ├── script.js └── style.css /README.md: -------------------------------------------------------------------------------- 1 | # Blip Manager: Blips with info popups 2 | 3 | #### ⭐ Check out our other resources on [gamzkystore.com](https://gamzkystore.com/) or in our [Discord](https://discord.com/invite/sjFP3HrWc3). 4 | #### 📼 Preview video: [Streamable](https://streamable.com/la3460) 5 | 6 | ## Features 7 | - Create blips with properties such as coordinates, sprite, label, and more. 8 | - Update and delete existing blips. 9 | - Handle blip overlays that provide additional information when hovering over or selecting blips. 10 | - Automatically clean up blips when the resource is stopped. 11 | - Assign blips to categories to group them together. (Max 2 unique categories, as per limit of GTA 5) 12 | 13 | ## Installation 14 | 1. Place the script in your resource directory. 15 | 2. Ensure your resource is started in the server configuration. 16 | 3. Use the provided exports to interact with the blip system in your other scripts. 17 | 18 | ## Documentation 19 | 20 | ### `exports.gs_blips:CreateBlip(params)` 21 | Creates a new blip on the map. 22 | #### Parameters 23 | - `params`: A table containing: 24 | - `coords` (required): Coordinates for the blip. Preferably a vector3, but any coordinate type will work. 25 | - `sprite` (required): The sprite ID for the blip. See [here](https://docs.fivem.net/game-references/blips/) for a list of sprites. 26 | - `label` (required): The label for the blip. 27 | - `scale` (optional): The scale of the blip (default is `1.0`). 28 | - `color` (optional): The color of the blip (default is `0`). See [here](https://docs.fivem.net/docs/game-references/blips/#blip-colors) for a list of colors. 29 | - `category` (optional): The category label of the blip. 30 | - `data` (optional): A table containing additional data for the blip. 31 | - `title` (optional): The title of the blip. 32 | - `description` (optional): The description of the blip. 33 | - `display` (optional): Display option for the blip (default is `4`). 34 | 35 | #### Returns 36 | A blip object with methods to modify or delete the blip. 37 | 38 | ### Methods of Blip Object 39 | - `setData(newData)`: Updates the data associated with the blip. 40 | - `setTitle(title)`: Sets the title of the blip. 41 | - `setDescription(description)`: Sets the description of the blip. 42 | - `setDisplayHandler(fn)`: Sets a custom display function for the blip. 43 | - `delete()`: Deletes the blip from the map. 44 | 45 | ## Usage Examples 46 | ```lua 47 | -- Example blip with default properties 48 | exports.gs_blips:CreateBlip({ 49 | coords = vector3(436.28, -993.07, 43.69), 50 | sprite = 60, 51 | scale = 1.3, 52 | color = 38, 53 | label = 'Police Station', 54 | data = { 55 | title = '👮🏽 Police Station', 56 | description = 'Mission Row Police Station is a key center for city police operations, equipped with holding cells, offices, and an impound lot.', 57 | }, 58 | }) 59 | ``` 60 | 61 | ```lua 62 | -- Example blip with display handler 63 | local blip = exports.gs_blips:CreateBlip({ 64 | coords = vector3(189.69, -937.84, 30.69), 65 | sprite = 306, 66 | scale = 1.5, 67 | color = 5, 68 | label = 'Example blip', 69 | data = { 70 | title = 'Example blip', 71 | description = '', 72 | }, 73 | }) 74 | 75 | -- Example: Sets a random number each time the info box is opened 76 | blip.setDisplayHandler(function() 77 | blip.setDescription('Random number: ' .. math.random(1, 100)) 78 | end) 79 | 80 | -- Example: Delete the blip 81 | blip.delete() 82 | ``` 83 | 84 | ```lua 85 | -- Example: Create blips with a category 86 | for i = 1, 10 do 87 | exports.gs_blips:CreateBlip({ 88 | coords = vector3(i * 50, i * 50, i * 50), 89 | sprite = 1, 90 | scale = 1.0, 91 | color = 0, 92 | label = 'Example blip: #' .. i, 93 | category = 'Example category', 94 | data = { 95 | title = 'Example blip', 96 | description = 'This blip is grouped under the "Example category" category.', 97 | }, 98 | }) 99 | end 100 | ``` 101 | 102 | ```lua 103 | -- Delete a blip created with the CreateBlip export 104 | exports.gs_blips:DeleteBlip(blipHandle) 105 | 106 | -- Example: Get a blip object 107 | local blip = exports.gs_blips:GetBlip(blipHandle) 108 | ``` 109 | -------------------------------------------------------------------------------- /client/cl_main.lua: -------------------------------------------------------------------------------- 1 | local createdBlips = {} 2 | local blipData = {} 3 | local currentBlip = nil 4 | local isOverlayOpen = false 5 | local blipIndex = 0 6 | 7 | local blipCategories = { 8 | { id = 'BLIP_PROPCAT', index = 10, label = nil }, 9 | { id = 'BLIP_APARTCAT', index = 11, label = nil }, 10 | } 11 | 12 | function CreateBlip(params) 13 | local invokingResource = GetInvokingResource() 14 | 15 | -- Validate params 16 | if not params.coords then 17 | print(('^1[%s] Error while creating blip: coords is required'):format(invokingResource)) 18 | return 19 | end 20 | if not params.sprite then 21 | print(('^1[%s] Error while creating blip: sprite is required'):format(invokingResource)) 22 | return 23 | end 24 | if not params.label then 25 | print(('^1[%s] Error while creating blip: label is required'):format(invokingResource)) 26 | return 27 | end 28 | 29 | local coords = ParseCoords(params.coords) 30 | local sprite = params.sprite 31 | local scale = params.scale or 1.0 32 | local color = params.color or 0 33 | local label = params.label 34 | local data = params.data or { title = label } 35 | local display = params.display or 4 36 | 37 | local blipHandle = AddBlipForCoord(coords.x, coords.y, coords.z) 38 | 39 | SetBlipSprite(blipHandle, sprite) 40 | SetBlipScale(blipHandle, scale) 41 | SetBlipColour(blipHandle, color) 42 | SetBlipDisplay(blipHandle, display) 43 | SetBlipAsShortRange(blipHandle, true) 44 | SetBlipHighDetail(blipHandle, true) 45 | SetBlipAsMissionCreatorBlip(blipHandle, true) 46 | 47 | -- Set blip category 48 | if params.category then 49 | local categoryIndex = AssignLabelToCategory(params.category) 50 | if categoryIndex then 51 | SetBlipCategory(blipHandle, categoryIndex) 52 | else 53 | print(('^1[%s] Error while creating blip: No available category for label %s'):format(invokingResource, params.category)) 54 | end 55 | end 56 | 57 | blipIndex = blipIndex + 1 58 | local blipTextEntry = 'GS_BLIP_' .. blipIndex 59 | AddTextEntry(blipTextEntry, label) 60 | BeginTextCommandSetBlipName(blipTextEntry) 61 | AddTextComponentSubstringPlayerName('me') 62 | EndTextCommandSetBlipName(blipHandle) 63 | 64 | if data then 65 | blipData[blipHandle] = data 66 | end 67 | 68 | createdBlips[invokingResource] = createdBlips[invokingResource] or {} 69 | table.insert(createdBlips[invokingResource], blipHandle) 70 | 71 | local blipObject = { 72 | handle = blipHandle, 73 | 74 | setData = function(newData) 75 | blipData[blipHandle] = newData 76 | UpdateBlipOverlay(blipHandle) 77 | end, 78 | 79 | setTitle = function(title) 80 | blipData[blipHandle].title = title 81 | UpdateBlipOverlay(blipHandle) 82 | end, 83 | 84 | setDescription = function(description) 85 | blipData[blipHandle].description = description 86 | UpdateBlipOverlay(blipHandle) 87 | end, 88 | 89 | setDisplayHandler = function(fn) 90 | blipData[blipHandle].onDisplay = fn 91 | end, 92 | 93 | delete = function() 94 | DeleteBlip(blipHandle) 95 | end, 96 | } 97 | 98 | return blipObject 99 | end 100 | 101 | function DeleteBlip(blipHandle) 102 | if blipData[blipHandle] then 103 | blipData[blipHandle] = nil 104 | end 105 | if DoesBlipExist(blipHandle) then 106 | RemoveBlip(blipHandle) 107 | end 108 | end 109 | 110 | function GetBlip(blipHandle) 111 | return blipData[blipHandle] 112 | end 113 | 114 | function ParseCoords(input) 115 | local inputType = type(input) 116 | 117 | -- Convert table to vector3 118 | if (inputType == 'table') then 119 | if input.x and input.y and input.z then 120 | return vector3(input.x, input.y, input.z) 121 | else 122 | return vector3(input[1], input[2], input[3]) 123 | end 124 | end 125 | 126 | return input 127 | end 128 | 129 | function AssignLabelToCategory(label) 130 | for _, category in ipairs(blipCategories) do 131 | if (category.label == label) then 132 | -- If the label already matches, use this category 133 | return category.index 134 | elseif (category.label == nil) then 135 | -- If the category is available (no label assigned), use it and set the label 136 | category.label = label 137 | AddTextEntry(category.id, label) 138 | return category.index 139 | end 140 | end 141 | 142 | -- No available category 143 | return nil 144 | end 145 | 146 | CreateThread(function() 147 | while true do 148 | Wait(100) 149 | if IsFrontendReadyForControl() then 150 | if IsHoveringOverMissionCreatorBlip() then 151 | local blipHandle = GetNewSelectedMissionCreatorBlip() 152 | if DoesBlipExist(blipHandle) then 153 | if currentBlip ~= blipHandle then 154 | currentBlip = blipHandle 155 | if blipData[blipHandle] then 156 | ShowBlipOverlay(blipHandle) 157 | if blipData[blipHandle].onDisplay then 158 | blipData[blipHandle].onDisplay() 159 | end 160 | else 161 | HideBlipOverlay() 162 | end 163 | end 164 | end 165 | else 166 | if currentBlip then currentBlip = nil end 167 | if isOverlayOpen then HideBlipOverlay() end 168 | end 169 | end 170 | end 171 | end) 172 | 173 | AddEventHandler('onClientResourceStop', function(resourceName) 174 | if resourceName == GetCurrentResourceName() then return end 175 | 176 | if createdBlips[resourceName] then 177 | -- Delete blips created by this resource 178 | for i = 1, #createdBlips[resourceName] do 179 | local blipHandle = createdBlips[resourceName][i] 180 | if DoesBlipExist(blipHandle) then 181 | RemoveBlip(blipHandle) 182 | end 183 | end 184 | 185 | createdBlips[resourceName] = nil 186 | end 187 | end) 188 | 189 | function ShowBlipOverlay(blipHandle) 190 | isOverlayOpen = true 191 | SendNUIMessage({ action = 'show', data = blipData[blipHandle] }) 192 | end 193 | 194 | function HideBlipOverlay() 195 | isOverlayOpen = false 196 | SendNUIMessage({ action = 'hide' }) 197 | end 198 | 199 | function UpdateBlipOverlay(blip) 200 | SendNUIMessage({ action = 'update', data = blipData[blip] }) 201 | end 202 | 203 | -- Exports 204 | exports('CreateBlip', CreateBlip) 205 | exports('DeleteBlip', DeleteBlip) 206 | exports('GetBlip', GetBlip) 207 | -------------------------------------------------------------------------------- /fxmanifest.lua: -------------------------------------------------------------------------------- 1 | fx_version 'cerulean' 2 | game 'gta5' 3 | 4 | author 'Gamzky' 5 | description 'Helper script to easily create and manage blips' 6 | version '1.1.0' 7 | 8 | ui_page 'ui/index.html' 9 | 10 | files { 11 | 'ui/index.html', 12 | 'ui/style.css', 13 | 'ui/script.js', 14 | } 15 | 16 | client_scripts { 17 | 'client/cl_main.lua', 18 | } 19 | -------------------------------------------------------------------------------- /ui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |