bugfix(radar): Fix incorrect 2D distance calculation in Radar::tryEvent#2368
bugfix(radar): Fix incorrect 2D distance calculation in Radar::tryEvent#2368johnneijzen wants to merge 2 commits intoTheSuperHackers:mainfrom
Conversation
|
| Filename | Overview |
|---|---|
| Core/GameEngine/Source/Common/System/Radar.cpp | Fixed critical operator precedence bug in 2D distance calculation; minor style inconsistency with array indexing spacing |
Last reviewed commit: 0ddd87b
|
Nice find. We'll need to check if this needs to go behind the retail compatibility macro. |
Caball009
left a comment
There was a problem hiding this comment.
Looks ok.
AFAICT this is only affects local stuff; e.g. control bar, game ui, audio and eva.
|
so far i can see i don't think we need to add retail compatibility macro because since this affects only player base ui behavior when comes to radar event and spacebar key for example if player discovered stealth unit or "we're under attack" event when player been attacked |
xezon
left a comment
There was a problem hiding this comment.
Can be simplified in one line.
What was the user facing bug with this?
| { | ||
|
|
||
| // get distance from our new event location to this event location in 2D | ||
| Real distSquared = m_event[ i ].worldLoc.x - pos->x * m_event[ i ].worldLoc.x - pos->x + |
There was a problem hiding this comment.
Real distSquared = sqr(m_event[ i ].worldLoc.x - pos->x) + sqr(m_event[ i ].worldLoc.y - pos->y);
There was a problem hiding this comment.
if want one line solution i could rewrite as. removing need of sqr macro/function
const Real distSquared =
(m_event[i].worldLoc.x - pos->x) * (m_event[i].worldLoc.x - pos->x) +
(m_event[i].worldLoc.y - pos->y) * (m_event[i].worldLoc.y - pos->y);There was a problem hiding this comment.
The one line solution look slightly more efficient in Godbolt. Although it has one instruction more, it saves on memory 4 store/reload pairs.
There was a problem hiding this comment.
sqr(m_event[i].worldLoc.x - pos->x)
is identical to
(m_event[i].worldLoc.x - pos->x) * (m_event[i].worldLoc.x - pos->x)
Not really. The only thing this code would fix is the distance check required for a radar event to be triggered. In most cases, the old formula would just spam events. However, in this particular case, the condition was almost always true because closeEnoughDistanceSq = 250.0f * 250.0f. You probably wont notice it because framesBetweenEvents = LOGICFRAMES_PER_SECOND * 10, so spamming was mostly prevented by the time interval. The reason I wrote it as three lines is that this is the most common style used when developers calculate distances, for example in Core\GameEngine\Source\GameClient\FXList.cpp and GeneralsMD\Code\Tools\WorldBuilder\src\WaterOptions.cpp. // get distance from our new event location to this event location in 2D
Real distSquared = m_event[ i ].worldLoc.x - pos->x * m_event[ i ].worldLoc.x - pos->x +
m_event[ i ].worldLoc.y - pos->y * m_event[ i ].worldLoc.y - pos->y;
if( distSquared <= closeEnoughDistanceSq )
{
// finally only reject making a new event of this existing one is "recent enough"
if( currentFrame - m_event[ i ].createFrame < framesBetweenEvents )
return FALSE; // reject it
} |
Summary
The 2D distance calculation in
Radar::tryEventwas incorrect due to operator precedence.The previous implementation:
Real distSquared = m_event[i].worldLoc.x - pos->x * m_event[i].worldLoc.x - pos->x + m_event[i].worldLoc.y - pos->y * m_event[i].worldLoc.y - pos->y;does not compute the squared distance:
Because multiplication has higher precedence than subtraction, the expression is evaluated as:
This can produce incorrect values, including negative results, which are invalid for squared distance.
Example
Using:
Expected result (correct formula)
Previous implementation result
Squared distance should never be negative, which demonstrates the calculation was incorrect.
Fix
Replaced the calculation with the proper squared distance formula: