Skip to content

Commit

Permalink
Merge pull request #3 from GoatG33k/master
Browse files Browse the repository at this point in the history
v1.5.0 - Performance improvements & rewrite
  • Loading branch information
DevBlocky authored Apr 18, 2021
2 parents 585708b + d31d5d3 commit c9daaf8
Show file tree
Hide file tree
Showing 9 changed files with 320 additions and 259 deletions.
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Nearest Postals

This script displays a nearest postal next to where PLD would go and also has a command to draw a route to a specific postal
This script displays the nearest postal next to map, and allows you to navigate to specific postal codes with `/postal`

## Installation

Expand All @@ -23,6 +23,15 @@ It will automatically remove the route when within 100m of the destination

## Updates

### 1.5

- Major performance improvements
- Added the `refreshRate` configuration option
- Simplified distance calculation logic
- Separated code into separate files
- Prebuild the postal list with vectors at startup
- Use FiveM Lua 5.4

### 1.4

- Performance Improvements
Expand Down Expand Up @@ -58,8 +67,8 @@ It will automatically remove the route when within 100m of the destination

This script provides a simple way of working on a new postal map

1. In the script, enabled the local variable `dev` near the bottom
2. Restart the script into game
1. In the resource `fxmanifest.lua` file, uncomment the `cl_dev.lua` requirement line
2. Do `refresh` and `restart nearest-postal` in-game
3. Teleport to the first postal code in numerical order
4. Type `/setnext [postalCode]` where postalCode is the postal that you are at
5. Type `/next` to insert it
Expand Down
222 changes: 22 additions & 200 deletions cl.lua
Original file line number Diff line number Diff line change
@@ -1,200 +1,22 @@
local raw = LoadResourceFile(GetCurrentResourceName(), GetResourceMetadata(GetCurrentResourceName(), 'postal_file'))
local postals = json.decode(raw)

local nearest = nil
local pBlip = nil

-- thread for nearest and blip
Citizen.CreateThread(
function()
while true do
local x, y = table.unpack(GetEntityCoords(GetPlayerPed(-1)))

local ndm = -1 -- nearest distance magnitude
local ni = -1 -- nearest index
for i, p in ipairs(postals) do
local dm = (x - p.x) ^ 2 + (y - p.y) ^ 2 -- distance magnitude
if ndm == -1 or dm < ndm then
ni = i
ndm = dm
end
end

--setting the nearest
if ni ~= -1 then
local nd = math.sqrt(ndm) -- nearest distance
nearest = {i = ni, d = nd}
end

-- if blip exists
if pBlip then
local b = {x = pBlip.p.x, y = pBlip.p.y} -- blip coords
local dm = (b.x - x) ^ 2 + (b.y - y) ^ 2 -- distance magnitude
if dm < config.blip.distToDelete ^ 2 then
-- delete blip if close
RemoveBlip(pBlip.hndl)
pBlip = nil
end
end

Wait(100)
end
end
)
-- text display thread
Citizen.CreateThread(
function()
while true do
if nearest and not IsHudHidden() then
local text = config.text.format:format(postals[nearest.i].code, nearest.d)
SetTextScale(0.42, 0.42)
SetTextFont(4)
SetTextOutline()
BeginTextCommandDisplayText('STRING')
AddTextComponentSubstringPlayerName(text)
EndTextCommandDisplayText(config.text.posX, config.text.posY)
end
Wait(0)
end
end
)

RegisterCommand(
'postal',
function(source, args, raw)
if #args < 1 then
if pBlip then
RemoveBlip(pBlip.hndl)
pBlip = nil
TriggerEvent(
'chat:addMessage',
{
color = {255, 0, 0},
args = {
'Postals',
config.blip.deleteText
}
}
)
end
return
end
local n = string.upper(args[1])

local fp = nil
for _, p in ipairs(postals) do
if string.upper(p.code) == n then
fp = p
end
end

if fp then
if pBlip then
RemoveBlip(pBlip.hndl)
end
pBlip = {hndl = AddBlipForCoord(fp.x, fp.y, 0.0), p = fp}
SetBlipRoute(pBlip.hndl, true)
SetBlipSprite(pBlip.hndl, config.blip.sprite)
SetBlipColour(pBlip.hndl, config.blip.color)
SetBlipRouteColour(pBlip.hndl, config.blip.color)
BeginTextCommandSetBlipName('STRING')
AddTextComponentSubstringPlayerName(config.blip.blipText:format(pBlip.p.code))
EndTextCommandSetBlipName(pBlip.hndl)

TriggerEvent(
'chat:addMessage',
{
color = {255, 0, 0},
args = {
'Postals',
config.blip.drawRouteText:format(fp.code)
}
}
)
else
TriggerEvent(
'chat:addMessage',
{
color = {255, 0, 0},
args = {
'Postals',
config.blip.notExistText
}
}
)
end
end
)

--[[Development shit]]
local dev = false
if dev then
local devLocal = json.decode(raw)
local next = 0

RegisterCommand(
'setnext',
function(src, args, raw)
local n = tonumber(args[1])
if n ~= nil then
next = n
print('next ' .. next)
return
end
print('invalid ' .. n)
end
)
RegisterCommand(
'next',
function(src, args, raw)
for i, d in ipairs(devLocal) do
if d.code == tostring(next) then
print('duplicate ' .. next)
return
end
end
local coords = GetEntityCoords(GetPlayerPed(-1))
table.insert(devLocal, {code = tostring(next), x = coords.x, y = coords.y})
print('insert ' .. next)
next = next + 1
end
)
RegisterCommand(
'rl',
function(src, args, raw)
if #devLocal > 0 then
local data = table.remove(devLocal, #devLocal)
print('remove ' .. data.code)
print('next ' .. next)
next = next - 1
else
print('invalid')
end
end
)
RegisterCommand(
'remove',
function(src, args, raw)
if #args < 1 then
print('invalid')
else
for i, d in ipairs(devLocal) do
if d.code == args[1] then
table.remove(devLocal, i)
print('remove ' .. d.code)
return
end
end
print('invalid')
end
end
)
RegisterCommand(
'json',
function(src, args, raw)
print(json.encode(devLocal))
end
)
end

exports('getPostal', function() if nearest ~= nil then return postals[nearest.i].code else return nil end end)
---@class PostalData : table<number, vec>
---@field code string
---@type table<number, PostalData>
postals = nil
CreateThread(function()
postals = LoadResourceFile(GetCurrentResourceName(), GetResourceMetadata(GetCurrentResourceName(), 'postal_file'))
postals = json.decode(postals)
for i, postal in ipairs(postals) do postals[i] = { vec(postal.x, postal.y), code = postal.code } end
end)

---@class NearestResult
---@field code string
---@field dist number
nearest = nil

---@class PostalBlip
---@field 1 vec
---@field p PostalData
---@field hndl number
pBlip = nil

exports('getPostal', function() return nearest and nearest.code or nil end)
69 changes: 69 additions & 0 deletions cl_commands.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
-- optimizations
local ipairs = ipairs
local upper = string.upper
local format = string.format
-- end optimizations

---
--- [[ Nearest Postal Commands ]] ---
---

TriggerEvent('chat:addSuggestion', '/postal', 'Set the GPS to a specific postal',
{ { name = 'Postal Code', help = 'The postal code you would like to go to' } })

RegisterCommand('postal', function(_, args)
if #args < 1 then
if pBlip then
RemoveBlip(pBlip.hndl)
pBlip = nil
TriggerEvent('chat:addMessage', {
color = { 255, 0, 0 },
args = {
'Postals',
config.blip.deleteText
}
})
end
return
end

local userPostal = upper(args[1])
local foundPostal

for _, p in ipairs(postals) do
if upper(p.code) == userPostal then
foundPostal = p
break
end
end

if foundPostal then
if pBlip then RemoveBlip(pBlip.hndl) end
local blip = AddBlipForCoord(foundPostal[1][1], foundPostal[1][2], 0.0)
pBlip = { hndl = blip, p = foundPostal }
SetBlipRoute(blip, true)
SetBlipSprite(blip, config.blip.sprite)
SetBlipColour(blip, config.blip.color)
SetBlipRouteColour(blip, config.blip.color)
BeginTextCommandSetBlipName('STRING')
AddTextComponentSubstringPlayerName(format(config.blip.blipText, pBlip.p.code))
EndTextCommandSetBlipName(blip)

TriggerEvent('chat:addMessage', {
color = { 255, 0, 0 },
args = {
'Postals',
format(config.blip.drawRouteText, foundPostal.code)
}
})
else
TriggerEvent('chat:addMessage', {
color = { 255, 0, 0 },
args = {
'Postals',
config.blip.notExistText
}
})
end
end)

57 changes: 57 additions & 0 deletions cl_dev.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
--- [[ Development shit ]]

local devLocal = json.decode(raw)
local next = 0

RegisterCommand('setnext', function(_, args)
local n = tonumber(args[1])
if n ~= nil then
next = n
print('next ' .. next)
return
end
print('invalid ' .. n)
end)

RegisterCommand('next', function()
for _, d in ipairs(devLocal) do
if d.code == tostring(next) then
print('duplicate ' .. next)
return
end
end
local coords = GetEntityCoords(PlayerPedId())
insert(devLocal, { code = tostring(next), x = coords.x, y = coords.y })
print('insert ' .. next)
next = next + 1
end)

RegisterCommand('rl', function()
if #devLocal > 0 then
local data = remove(devLocal, #devLocal)
print('remove ' .. data.code)
print('next ' .. next)
next = next - 1
else
print('invalid')
end
end)

RegisterCommand('remove', function(_, args)
if #args < 1 then
print('invalid')
else
for i, d in ipairs(devLocal) do
if d.code == args[1] then
table.remove(devLocal, i)
print('remove ' .. d.code)
return
end
end
print('invalid')
end
end)

RegisterCommand('json', function()
print(json.encode(devLocal))
end)
Loading

0 comments on commit c9daaf8

Please sign in to comment.