GetEnemyUnitsInSphere func not reporting units in a sphere?

Everything about mods can be found here.

Moderator: Morax

GetEnemyUnitsInSphere func not reporting units in a sphere?

Postby Nono06 » 03 Sep 2014, 21:27

Hi,

In priority markers mod, we are using the "GetEnemyUnitsInSphere" function to list the enemy around the units. But based on my trials and on how GetEnemyUnitsInSphere is coded, it seems that enemies that are not on the same layer, are not reported.
When looking closer to the function, we see that Y axis is not used therefore only a rectangle is used and not a sphere/cube.

Does someone know how to fix it?
Is there another function doing the same thing?
How a bomber detects units on the ground for example?

Thanks
Nono06
Crusader
 
Posts: 37
Joined: 19 Jun 2014, 10:07
Has liked: 0 time
Been liked: 8 times
FAF User Name: Nono06

Re: GetEnemyUnitsInSphere func not reporting units in a sphe

Postby IceDreamer » 03 Sep 2014, 23:46

Use this: CAiBrain:GetUnitsAroundPoint()

This is an excellent resource
http://supcom.wikia.com/wiki/LUADOC_1.5.3599
IceDreamer
Supreme Commander
 
Posts: 2607
Joined: 27 Dec 2011, 07:01
Has liked: 138 times
Been liked: 488 times

Re: GetEnemyUnitsInSphere func not reporting units in a sphe

Postby Sheeo » 04 Sep 2014, 03:15

Can a moderator move this thread somewhere apropriate?

Looking at the definition of GetEnemyUnitsInSphere in /lua/utilities.lua:

Code: Select all
function GetEnemyUnitsInSphere(unit, position, radius)
   local x1 = position.x - radius
   local y1 = position.y - radius
   local z1 = position.z - radius
   local x2 = position.x + radius
   local y2 = position.y + radius
   local z2 = position.z + radius
   local UnitsinRec = GetUnitsInRect( Rect(x1, z1, x2, z2) )
   #Check for empty rectangle
   if not UnitsinRec then
      return UnitsinRec
   end
   local RadEntities = {}
    for k, v in UnitsinRec do
      local dist = VDist3(position, v:GetPosition())
      if (unit:GetArmy() != v:GetArmy()) and (dist <= radius) then
         table.insert(RadEntities, v)
      end
   end
   return RadEntities
end


You see that it is indeed using GetUnitsInRect, but it does correct distance pruning to only return units within the given spherical radius.

From my testing, GetUnitsInRect works and using this function should work fine, but using CAiBrain:GetUnitsAroundPoint() is likely more efficient.
Support FAF on patreon: https://www.patreon.com/faf?ty=h

Peek at our continued development on github: https://github.com/FAForever
Sheeo
Councillor - Administrative
 
Posts: 1038
Joined: 17 Dec 2013, 18:57
Has liked: 109 times
Been liked: 233 times
FAF User Name: Sheeo

Re: GetEnemyUnitsInSphere func not reporting units in a sphe

Postby Nono06 » 04 Sep 2014, 10:44

Hi guys,

Thanks for the reply.
I know LUADOC page but we cannot really say it is a documentation since the functions are not explained :)

I thought that all CaiBrain functions were available only when playing with AI.
Good to know that we can use it anywhere.
What is the "coverage" of GetUnitsAroundPoint()? Is that covering the whole map?

Regarding GetEnemyUnitsInSphere. We are using it in a thread running on the opponent "priority" unit:
Code: Select all
      while not self:IsDead() and self:HasGlobalPriority() do
         local EnemyUnits = GetEnemyUnitsInSphere(self:GetArmy(), self:GetPosition(), 128)
         local GlobalPriority = self:GetGlobalPriority()
         
         if EnemyUnits and table.getn(EnemyUnits) > 0 then
            for j,k in EnemyUnits do
               if not k:IsPriorityTarget(GlobalPriority, self) then
                  local distance = GetDistanceBetweenTwoEntities(self, k)
                  if (distance <= k:GetMaxPriorityRange()) then
                     k:AddPriorityTarget(GlobalPriority, self)
                  end
               end
            end
         end
         WaitSeconds(1)
      end

If the priority unit is a land unit and a bomber is flying above that unit, the GetEnemyUnitsInSphere func is not reporting it unless the plane starts its landing approach.
I'm not exactly sure how X, Y, Z axis are used in FA but usually Y represents the height and I find strange that it is not used anywhere.
Does GetUnitsInRect actually represents a rectangular parallelepipedal? since Y axis is not present it does not seem to be the case except if the function consider the coordinates infinite on that axis.

Thanks
Nono06
Crusader
 
Posts: 37
Joined: 19 Jun 2014, 10:07
Has liked: 0 time
Been liked: 8 times
FAF User Name: Nono06

Re: GetEnemyUnitsInSphere func not reporting units in a sphe

Postby Sheeo » 04 Sep 2014, 11:23

Nono06 wrote:
Code: Select all
         local EnemyUnits = GetEnemyUnitsInSphere(self:GetArmy(), self:GetPosition(), 128)


This shouldn't work at all. GetEnemyUnitsInSphere(unit, position, radius) expects unit to be a table with function GetArmy() (I.e. an entity), not a number.

Nono06 wrote:If the priority unit is a land unit and a bomber is flying above that unit, the GetEnemyUnitsInSphere func is not reporting it unless the plane starts its landing approach.


I would like a replay showing this behavior, as I can't reproduce it myself.

Nono06 wrote:I'm not exactly sure how X, Y, Z axis are used in FA but usually Y represents the height and I find strange that it is not used anywhere.


The coordinate system in FA is indeed a normal cartesian coordinate system. It's not passed to the GetEntitiesInRect function, but it's relatively safe to assume (and my testing showed) that this function returns units from then entire y-axis, seemingly the implementor of this function also had this assumption. In your words the rectangle being infinite in the y-axis.

I still don't think using CAIBrain is going to fix anything, but I'll reiterate that it should be more efficient.
Support FAF on patreon: https://www.patreon.com/faf?ty=h

Peek at our continued development on github: https://github.com/FAForever
Sheeo
Councillor - Administrative
 
Posts: 1038
Joined: 17 Dec 2013, 18:57
Has liked: 109 times
Been liked: 233 times
FAF User Name: Sheeo

Re: GetEnemyUnitsInSphere func not reporting units in a sphe

Postby IceDreamer » 04 Sep 2014, 11:46

Is he right that it's not recognising units in the region which are assigned another layer though? If so, that's the problem; how might that be fixed?

Also, shouldn't the 'Unit' argument just be 'self'? That would tie up with every other place I've seen similar code, if it is wanting the unit doing the check for other units (self), the position of the centre of the sphere (The position of unit, in this case self), and the radius of the sphere...
IceDreamer
Supreme Commander
 
Posts: 2607
Joined: 27 Dec 2011, 07:01
Has liked: 138 times
Been liked: 488 times

Re: GetEnemyUnitsInSphere func not reporting units in a sphe

Postby Sheeo » 04 Sep 2014, 11:55

According to my tests, units in air layers and land layers are returned.

The function is defined in the global namespace, so using 'self' for the first argument would be confusing, since it's not attached to a class. Unit (the first argument) is only used to check if the units returned are in a different army than the given unit, it may as well be a number.

That logic is actually flawed as well, since a different army may well be an allied army.. It should be using the appropriate IsEnemy function :)

Since this whole functionality is duplicated engine side, I suggest we try and remove it to see what code actually uses it. We should then replace all calls in faf-code with the C-version, and update this to produce a deprecation warning the first time it's called.
Support FAF on patreon: https://www.patreon.com/faf?ty=h

Peek at our continued development on github: https://github.com/FAForever
Sheeo
Councillor - Administrative
 
Posts: 1038
Joined: 17 Dec 2013, 18:57
Has liked: 109 times
Been liked: 233 times
FAF User Name: Sheeo

Re: GetEnemyUnitsInSphere func not reporting units in a sphe

Postby Nono06 » 04 Sep 2014, 13:52

Thanks Sheeo,

But I just noticed that Domino redefined the function in his DMS part. (The mod was originally created by him but it was not working well, at least for me)
And he included the check for Enemy Army.

The discussion thread and source are here:
viewtopic.php?f=2&t=5866&start=90

Code: Select all
function GetUnitsInSphere(position, radius)
   local x1 = position.x - radius
   local y1 = position.y - radius
   local z1 = position.z - radius
   local x2 = position.x + radius
   local y2 = position.y + radius
   local z2 = position.z + radius
   local UnitsinRec = GetUnitsInRect( Rect(x1, z1, x2, z2) )

   if not UnitsinRec then
      return false
   end
   local RetEntities = {}
    for k, v in UnitsinRec do
      local dist = VDist3(position, v:GetPosition())
      if dist <= radius then
         table.insert(RetEntities, v)
      end
   end

   return RetEntities
end

function GetEnemyUnitsInSphere(army, position, radius)
   local UnitsinRec = GetUnitsInSphere(position, radius)
   
   army = army or GetFocusArmy()
   
   if not UnitsinRec then
      return false
   end
   
   local RetEntities = {}
   
   if army then
      for k, v in UnitsinRec do
         local dist = VDist3(position, v:GetPosition())
         if IsEnemy(v:GetArmy(), army) and dist <= radius then
            table.insert(RetEntities, v)
         end
      end
   end

   return RetEntities
end


But the GetUnitsInSphere function is using the same structure as the default GetEnemyUnitsInSphere.
Since it is working on your side, I guess I have to re-test it.

You are also referring to C-code that could be addressed directly. Is that already available in FAF?

Thanks
Nono06
Crusader
 
Posts: 37
Joined: 19 Jun 2014, 10:07
Has liked: 0 time
Been liked: 8 times
FAF User Name: Nono06

Re: GetEnemyUnitsInSphere func not reporting units in a sphe

Postby Nono06 » 08 Sep 2014, 11:17

Hi Sheeo,

you were right, GetEnemyUnitsInSphere is working correctly and reports all units independently of their layer.
The only issue is that it is not reporting enemy units only. Domino fixed that in his DMS library mod.

The issue I'm seeing is coming from another thread which prevents enemy to be detected.

Is there an easy way to know what was the last order a user gave to a unit? Moving, attacking, repair...
IsUnitState() return the current state but it is not necessarily an order provided by the user and I do not know how to use GetCommandQueue() function correctly.

Thanks
Nono06
Crusader
 
Posts: 37
Joined: 19 Jun 2014, 10:07
Has liked: 0 time
Been liked: 8 times
FAF User Name: Nono06

Re: GetEnemyUnitsInSphere func not reporting units in a sphe

Postby Sheeo » 08 Sep 2014, 11:57

Nono06 wrote:You are also referring to C-code that could be addressed directly. Is that already available in FAF?


Yes I'm referring to the CAiBrain.GetUnitsAroundPoint function that IceDreamer mentioned.

Nono06 wrote:The issue I'm seeing is coming from another thread which prevents enemy to be detected.

Is there an easy way to know what was the last order a user gave to a unit? Moving, attacking, repair...
IsUnitState() return the current state but it is not necessarily an order provided by the user and I do not know how to use GetCommandQueue() function correctly.


Afaik there is no easy way. But what eactly is it you want to do? And what issue from what thread is this? :)
Support FAF on patreon: https://www.patreon.com/faf?ty=h

Peek at our continued development on github: https://github.com/FAForever
Sheeo
Councillor - Administrative
 
Posts: 1038
Joined: 17 Dec 2013, 18:57
Has liked: 109 times
Been liked: 233 times
FAF User Name: Sheeo

Next

Return to Mods & Tools

Who is online

Users browsing this forum: No registered users and 1 guest