Skip to content

Commit

Permalink
Minor performance improvements for navigational mesh (FAForever#4922)
Browse files Browse the repository at this point in the history
  • Loading branch information
Garanas authored May 18, 2023
1 parent 3a608a1 commit 6dca464
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 73 deletions.
7 changes: 1 addition & 6 deletions lua/sim/NavDatastructures.lua
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,6 @@ NavPathToHeap = ClassSimple {

---@param self NavPathToHeap
Clear = function(self)
local heap = self.Heap

for k = 1, self.HeapSize do
heap[k] = nil
end
self.HeapSize = 0
end,

Expand Down Expand Up @@ -129,7 +124,7 @@ NavPathToHeap = ClassSimple {

-- if there is a right child, compare its value with the left one
-- if right is smaller, then assign min = right. Else, keep min on left.
if heap[right] and (heap[right].TotalCosts < heap[left].TotalCosts) then
if right <= heapSize and (heap[right].TotalCosts < heap[left].TotalCosts) then
min = right
end

Expand Down
99 changes: 32 additions & 67 deletions lua/sim/NavUtils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ local Colors = import("/lua/shared/color.lua")
local NavGenerator = import("/lua/sim/navgenerator.lua")
local NavDatastructures = import("/lua/sim/navdatastructures.lua")

-- upvalue scope for performance
local TableGetn = table.getn

-------------------------------------------------------------------------------
-- Debugging functionality

Expand All @@ -51,7 +54,7 @@ function DebugRegisterPath(type, path, origin, destination)
---@type { Tick: number, Path: Vector[], Origin: Vector, Destination: Vector }[]
local cache = paths[type]
if cache then
local n = table.getn(cache)
local n = TableGetn(cache)
cache[n + 1] = {
Tick = GetGameTick(),
Path = path,
Expand All @@ -66,7 +69,7 @@ function DebugPathRender()
local DrawCircle = DrawCircle
local DrawLinePop = DrawLinePop
local GetGameTick = GetGameTick
local TableGetn = table.getn
local TableGetn = TableGetn
local ColorsRGB = Colors.ColorRGB

local duration = 150
Expand Down Expand Up @@ -141,20 +144,10 @@ function Generate()
end
end

--- Produces various warning messages in the logs to inform the developer
local function WarnNoNavMesh()
WARN("Navigational utilities are used without a generated navigational mesh")
WARN("For AI development: ")
WARN(" - Add in the field `requiresNavMesh = true` to each of your AI entries in `lua/AI/CustomAIs_v2`")
WARN("For map or regular mod development: ")
WARN(" - Call the Generate function of NavUtils before calling any other function")
end

---@param layer NavLayers
---@return NavGrid?
---@return 'InvalidLayer'?
local function FindGrid(layer)
-- check layer argument
local grid = NavGenerator.NavGrids[layer] --[[@as NavGrid]]
if not grid then
return nil, 'InvalidLayer'
Expand All @@ -181,7 +174,7 @@ local function FindLeaf(grid, position)
local pz = position[3]

-- try and find nearest valid neighbor
for k = 1, table.getn(leaf) do
for k = 1, TableGetn(leaf) do

---@type CompressedLabelTreeLeaf
local neighbor = leaf[k]
Expand Down Expand Up @@ -214,7 +207,6 @@ end
function CanPathTo(layer, origin, destination)
-- check if generated
if not NavGenerator.IsGenerated() then
WarnNoNavMesh()
return nil, 'NotGenerated'
end

Expand Down Expand Up @@ -271,22 +263,6 @@ local function PathToGetUniqueIdentifier()
return PathToIdentifier
end

---@class NavPathToOptions
local PathToOptions = {
UseCache = false
}

--- Retrieves a shallow copy of the default options
---@return NavPathToOptions
function PathToDefaultOptions()
PathToOptions.StepSize = 0
PathToOptions.IncludeOrigin = false
PathToOptions.IncludeDestination = true
PathToOptions.Simplify = true

return PathToOptions
end

---@param layer NavLayers
---@param origin Vector
---@param destination Vector
Expand All @@ -296,7 +272,6 @@ end
function PathTo(layer, origin, destination)
-- check if generated
if not NavGenerator.IsGenerated() then
WarnNoNavMesh()
return nil, 'NotGenerated'
end

Expand All @@ -317,6 +292,9 @@ function PathTo(layer, origin, destination)
originLeaf.AcquiredCosts = 0
originLeaf.TotalCosts = originLeaf:DistanceTo(destinationLeaf)
originLeaf.Seen = seenIdentifier

-- start using the navigational heap
PathToHeap:Clear()
PathToHeap:Insert(originLeaf)

destinationLeaf.From = nil
Expand All @@ -335,7 +313,7 @@ function PathTo(layer, origin, destination)
end

-- continue state
for k = 1, table.getn(leaf) do
for k = 1, TableGetn(leaf) do
local neighbor = leaf[k]
if neighbor.Label > 0 and neighbor.Seen != seenIdentifier then
local preferLargeNeighbor = 0
Expand Down Expand Up @@ -393,9 +371,6 @@ function PathTo(layer, origin, destination)
-- add destination to the path
path[head] = destination

-- clear up after ourselves
PathToHeap:Clear()

DebugRegisterPath('PathTo', path, origin, destination)

-- return all the goodies!!
Expand All @@ -417,7 +392,6 @@ ThreatFunctions = Shared.ThreatFunctions
function PathToWithThreatThreshold(layer, origin, destination, aibrain, threatFunc, threatThreshold, threatRadius)
-- check if generated
if not NavGenerator.IsGenerated() then
WarnNoNavMesh()
return nil, 'NotGenerated'
end

Expand All @@ -438,6 +412,9 @@ function PathToWithThreatThreshold(layer, origin, destination, aibrain, threatFu
originLeaf.AcquiredCosts = 0
originLeaf.TotalCosts = originLeaf:DistanceTo(destinationLeaf)
originLeaf.Seen = seenIdentifier

-- start using the navigational heap
PathToHeap:Clear()
PathToHeap:Insert(originLeaf)

destinationLeaf.From = nil
Expand All @@ -456,7 +433,7 @@ function PathToWithThreatThreshold(layer, origin, destination, aibrain, threatFu
end

-- search through neighbors
for k = 1, table.getn(leaf) do
for k = 1, TableGetn(leaf) do
local neighbor = leaf[k]
if neighbor.Label > 0 and neighbor.Seen != seenIdentifier then
local preferLargeNeighbor = 0
Expand Down Expand Up @@ -521,9 +498,6 @@ function PathToWithThreatThreshold(layer, origin, destination, aibrain, threatFu
-- add destination to the path
path[head] = destination

-- clear up after ourselves
PathToHeap:Clear()

DebugRegisterPath('PathToWithThreatThreshold', path, origin, destination)

-- return all the goodies!!
Expand All @@ -539,7 +513,6 @@ end
function GetLabel(layer, position)
-- check if generated
if not NavGenerator.IsGenerated() then
WarnNoNavMesh()
return nil, 'NotGenerated'
end

Expand Down Expand Up @@ -575,7 +548,6 @@ end
function GetTerrainLabel(layer, position)
-- check if generated
if not NavGenerator.IsGenerated() then
WarnNoNavMesh()
return nil, 'NotGenerated'
end

Expand Down Expand Up @@ -609,7 +581,6 @@ end
function GetLabelMetadata(id)
-- check if generated
if not NavGenerator.IsGenerated() then
WarnNoNavMesh()
return nil, 'NotGenerated'
end

Expand Down Expand Up @@ -643,7 +614,6 @@ function DirectionsFrom(layer, origin, distance, sizeThreshold)

-- check if generated
if not NavGenerator.IsGenerated() then
WarnNoNavMesh()
return nil, 'NotGenerated'
end

Expand All @@ -669,6 +639,9 @@ function DirectionsFrom(layer, origin, distance, sizeThreshold)
originLeaf.AcquiredCosts = 0
originLeaf.TotalCosts = distance
originLeaf.Seen = seenIdentifier

-- start using the navigational heap
PathToHeap:Clear()
PathToHeap:Insert(originLeaf)

while not PathToHeap:IsEmpty() do
Expand Down Expand Up @@ -699,7 +672,7 @@ function DirectionsFrom(layer, origin, distance, sizeThreshold)
end

-- search neighbors for more leafs
for k = 1, table.getn(leaf) do
for k = 1, TableGetn(leaf) do
local neighbor = leaf[k]
if neighbor.Label > 0 and neighbor.Seen != seenIdentifier then
neighbor.From = leaf
Expand Down Expand Up @@ -739,9 +712,6 @@ function DirectionsFrom(layer, origin, distance, sizeThreshold)
}
end

-- clean up after ourselves
PathToHeap:Clear()

for k, _ in found do
found[k] = nil
end
Expand All @@ -766,7 +736,6 @@ function RandomDirectionFrom(layer, origin, distance, sizeThreshold)

-- check if generated
if not NavGenerator.IsGenerated() then
WarnNoNavMesh()
return nil, 'NotGenerated'
end

Expand All @@ -792,6 +761,9 @@ function RandomDirectionFrom(layer, origin, distance, sizeThreshold)
originLeaf.AcquiredCosts = 0
originLeaf.TotalCosts = distance
originLeaf.Seen = seenIdentifier

-- start using the navigational heap
PathToHeap:Clear()
PathToHeap:Insert(originLeaf)

while not PathToHeap:IsEmpty() do
Expand Down Expand Up @@ -822,7 +794,7 @@ function RandomDirectionFrom(layer, origin, distance, sizeThreshold)
end

-- search neighbors for more leafs
for k = 1, table.getn(leaf) do
for k = 1, TableGetn(leaf) do
local neighbor = leaf[k]
if neighbor.Label > 0 and neighbor.Seen != seenIdentifier then
neighbor.From = leaf
Expand All @@ -841,7 +813,7 @@ function RandomDirectionFrom(layer, origin, distance, sizeThreshold)
end

-- retrieve a random candidate
local candidate = candidates[Random(1, table.getn(candidates))]
local candidate = candidates[Random(1, TableGetn(candidates))]

local px = candidate.px
local pz = candidate.pz
Expand All @@ -860,9 +832,6 @@ function RandomDirectionFrom(layer, origin, distance, sizeThreshold)
z
}

-- clean up after ourselves
PathToHeap:Clear()

for k, _ in found do
found[k] = nil
end
Expand All @@ -888,7 +857,6 @@ function RetreatDirectionFrom(layer, origin, threat, distance)

-- check if generated
if not NavGenerator.IsGenerated() then
WarnNoNavMesh()
return nil, 'NotGenerated'
end

Expand Down Expand Up @@ -921,6 +889,9 @@ function RetreatDirectionFrom(layer, origin, threat, distance)
originLeaf.AcquiredCosts = 0
originLeaf.TotalCosts = distance
originLeaf.Seen = seenIdentifier

-- start using the navigational heap
PathToHeap:Clear()
PathToHeap:Insert(originLeaf)

while not PathToHeap:IsEmpty() do
Expand Down Expand Up @@ -951,7 +922,7 @@ function RetreatDirectionFrom(layer, origin, threat, distance)
end

-- add neighbors of leaf that is too close to the origin
for k = 1, table.getn(leaf) do
for k = 1, TableGetn(leaf) do
local neighbor = leaf[k]
if neighbor.Label > 0 and neighbor.Seen != seenIdentifier then

Expand All @@ -977,7 +948,7 @@ function RetreatDirectionFrom(layer, origin, threat, distance)
end

-- retrieve a random candidate
local candidate = candidates[Random(1, table.getn(candidates))]
local candidate = candidates[Random(1, TableGetn(candidates))]

local px = candidate.px
local pz = candidate.pz
Expand All @@ -996,9 +967,6 @@ function RetreatDirectionFrom(layer, origin, threat, distance)
z
}

-- clean up after ourselves
PathToHeap:Clear()

for k, _ in found do
found[k] = nil
end
Expand All @@ -1021,7 +989,6 @@ local DirectionToPath = { }
function DirectionTo(layer, origin, destination, distance)
-- check if generated
if not NavGenerator.IsGenerated() then
WarnNoNavMesh()
return nil, 'NotGenerated'
end

Expand All @@ -1042,6 +1009,9 @@ function DirectionTo(layer, origin, destination, distance)
originLeaf.AcquiredCosts = 0
originLeaf.TotalCosts = originLeaf:DistanceTo(destinationLeaf)
originLeaf.Seen = seenIdentifier

-- start using the navigational heap
PathToHeap:Clear()
PathToHeap:Insert(originLeaf)

destinationLeaf.From = nil
Expand All @@ -1060,7 +1030,7 @@ function DirectionTo(layer, origin, destination, distance)
end

-- continue state
for k = 1, table.getn(leaf) do
for k = 1, TableGetn(leaf) do
local neighbor = leaf[k]
if neighbor.Label > 0 and neighbor.Seen != seenIdentifier then
local preferLargeNeighbor = 0
Expand All @@ -1077,16 +1047,11 @@ function DirectionTo(layer, origin, destination, distance)
end
end

-- clear up after ourselves
PathToHeap:Clear()

-- check if we found a path
if not destinationLeaf.Seen == seenIdentifier then
return nil, 'SystemError'
end

-- construct

-- construct current path
local head = 1
local path = DirectionToPath
Expand Down

0 comments on commit 6dca464

Please sign in to comment.