Skip to content

Commit

Permalink
fix #1968
Browse files Browse the repository at this point in the history
  • Loading branch information
rt committed Nov 1, 2018
1 parent 1406116 commit deaf660
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 84 deletions.
7 changes: 4 additions & 3 deletions doc/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -154,19 +154,20 @@ Misc:
by either nested tables or 'parent' key.
- IME editing support for those with the proper SDL2 version/IME tool combination
! Made lockluaui.txt obsolete: no longer necessary for it to exists in order to enable VFS for LuaUI
- use SHA2 content hashes rather than CRC32
- use SHA2 rather than CRC32 content hashes

Fixes:
- fix #1968 (units not moving in direction of next queued [build-]command if current order blocked)
- fix #6060 (Max{Nano}Particles=0 still allowing 1 {nano}particle to spawn)
- fix #6059 (units with high turnRate/brakeRate/acceleration moving unexpectedly)
- fix #4268 (add Spring.AddObjectDecal)
- fix #4755 (wrong usage of addr2line on FreeBSD)
- fix #4945 (add Spring.GetMapStartPositions)
- fix #4724 (Spring.SetUnitNeutral not informing any attackers)
- fix #5864 (gunships not limited by maxVelocity when climbing)
- fix #5864 (gunships not limited by maxVelocity when colliding with terrain)
- fix #4515 (aircraft jitter when moving and turning)
- fix #6048 (falling features shaking on the ground instead of fully stopping)
- fix #6046 #5326 #5222 #4663 (false camera movement if entering MMB mode while moving cursor)
- fix #6046 #5326 #5222 #4663 (spurious camera position change if entering MMB mode while moving cursor)
- fix #6019 (Spring.IsAABBInView bug)
- fix #6038 (noExplode weapons not obeying SetUnitWeaponState("range"))
- fix #6036 (no method to detect MMB camera-pan mode)
Expand Down
58 changes: 37 additions & 21 deletions rts/Sim/MoveTypes/GroundMoveType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,8 +495,12 @@ bool CGroundMoveType::FollowPath()
ASSERT_SYNCED(nextWayPoint);
ASSERT_SYNCED(owner->pos);

const float3& opos = owner->pos;
const float3& ovel = owner->speed;
const float3& ffd = flatFrontDir;

prevWayPointDist = currWayPointDist;
currWayPointDist = currWayPoint.distance2D(owner->pos);
currWayPointDist = currWayPoint.distance2D(opos);

{
// NOTE:
Expand All @@ -505,12 +509,19 @@ bool CGroundMoveType::FollowPath()
// if our first command is a build-order, then goal-radius is set to our build-range
// and we cannot increase tolerance safely (otherwise the unit might stop when still
// outside its range and fail to start construction)
const float curGoalDistSq = (owner->pos - goalPos).SqLength2D();
//
// units moving faster than <minGoalDist> elmos per frame might overshoot their goal
// the last two atGoal conditions will just cause flatFrontDir to be selected as the
// "wanted" direction when this happens
const float curGoalDistSq = (opos - goalPos).SqLength2D();
const float minGoalDistSq = (UNIT_HAS_MOVE_CMD(owner))?
Square((goalRadius + extraRadius) * (numIdlingSlowUpdates + 1)):
Square((goalRadius + extraRadius) );
const float spdGoalDistSq = Square(currentSpeed * 1.05f);

atGoal |= (curGoalDistSq <= minGoalDistSq);
atGoal |= ((curGoalDistSq <= spdGoalDistSq) && !reversing && (ffd.dot(goalPos - opos) > 0.0f && ffd.dot(goalPos - (opos + ovel)) <= 0.0f));
atGoal |= ((curGoalDistSq <= spdGoalDistSq) && reversing && (ffd.dot(goalPos - opos) < 0.0f && ffd.dot(goalPos - (opos + ovel)) >= 0.0f));
}

if (!atGoal) {
Expand All @@ -532,22 +543,23 @@ bool CGroundMoveType::FollowPath()

// set direction to waypoint AFTER requesting it; should not be a null-vector
float3 waypointVec;
float2 wpProjDists;
// float3 wpProjDists;

if (currWayPoint != owner->pos) {
waypointVec = (currWayPoint - owner->pos) * XZVector;
if (currWayPoint != opos) {
waypointVec = (currWayPoint - opos) * XZVector;
waypointDir = waypointVec / waypointVec.Length();
wpProjDists = {math::fabs(waypointVec.dot(flatFrontDir)), 1.0f};
// wpProjDists = {math::fabs(waypointVec.dot(ffd)), 1.0f, math::fabs(waypointDir.dot(ffd))};
}

ASSERT_SYNCED(waypointVec);
ASSERT_SYNCED(waypointDir);

wantReverse = WantReverse(waypointDir, flatFrontDir);
wantReverse = WantReverse(waypointDir, ffd);

// apply obstacle avoidance (steering), prevent unit from chasing its own tail if very close to waypoint
// apply obstacle avoidance (steering), prevent unit from chasing its own tail if already at goal
const float3 rawWantedDir = waypointDir * Sign(int(!wantReverse));
const float3& modWantedDir = GetObstacleAvoidanceDir(mix(flatFrontDir, rawWantedDir, (wpProjDists.x > wpProjDists.y) && (!atGoal)));
const float3& modWantedDir = GetObstacleAvoidanceDir(mix(ffd, rawWantedDir, !atGoal));
// const float3& modWantedDir = GetObstacleAvoidanceDir(mix(ffd, rawWantedDir, (!atGoal) && (wpProjDists.x > wpProjDists.y || wpProjDists.z < 0.995f)));

ChangeHeading(GetHeadingFromVector(modWantedDir.x, modWantedDir.z));
ChangeSpeed(maxWantedSpeed, wantReverse);
Expand Down Expand Up @@ -628,7 +640,7 @@ void CGroundMoveType::ChangeSpeed(float newWantedSpeed, bool wantReverse, bool f
// at this point, Update() will no longer call SetNextWayPoint()
// and we must slow down to prevent entering an infinite circle
#if (MODEL_TURN_INERTIA == 0)
const float absTurnSpeed = turnRate;
const float absTurnSpeed = turnSpeed;
#else
const float absTurnSpeed = std::max(0.0001f, math::fabs(turnSpeed));
#endif
Expand Down Expand Up @@ -1350,7 +1362,7 @@ bool CGroundMoveType::CanSetNextWayPoint() {
const int dirSign = Sign(int(!reversing));

#if (MODEL_TURN_INERTIA == 0)
const float absTurnSpeed = turnRate;
const float absTurnSpeed = turnSpeed;
#else
const float absTurnSpeed = std::max(0.0001f, math::fabs(turnSpeed));
#endif
Expand Down Expand Up @@ -1694,12 +1706,15 @@ bool CGroundMoveType::HandleStaticObjectCollision(
float3 sqrSumPosition; // .y is always 0
float2 sqrPenDistance; // .x = sum, .y = count

const float3& pos = collider->pos;
const float3& vel = collider->speed;

const float3 rightDir2D = (collider->rightdir * XZVector).SafeNormalize();
const float3 speedDir2D = (collider->speed * XZVector).SafeNormalize();


const int xmid = (collider->pos.x + collider->speed.x) / SQUARE_SIZE;
const int zmid = (collider->pos.z + collider->speed.z) / SQUARE_SIZE;
const int xmid = (pos.x + vel.x) / SQUARE_SIZE;
const int zmid = (pos.z + vel.z) / SQUARE_SIZE;

// mantis{3614,4217}
// we cannot nicely bounce off terrain when checking only the center square
Expand All @@ -1713,7 +1728,7 @@ bool CGroundMoveType::HandleStaticObjectCollision(
const int zmin = std::min(-1, -zsh), zmax = std::max(1, zsh);

if (DEBUG_DRAWING_ENABLED)
geometricObjects->AddLine(collider->pos + (UpVector * 25.0f), collider->pos + (UpVector * 100.0f), 3, 1, 4);
geometricObjects->AddLine(pos + (UpVector * 25.0f), pos + (UpVector * 100.0f), 3, 1, 4);

// check for blocked squares inside collider's MoveDef footprint zone
// interpret each square as a "collidee" and sum up separation vectors
Expand Down Expand Up @@ -1742,18 +1757,18 @@ bool CGroundMoveType::HandleStaticObjectCollision(
continue;
}

const float3 squarePos = float3(xabs * SQUARE_SIZE + (SQUARE_SIZE >> 1), collider->pos.y, zabs * SQUARE_SIZE + (SQUARE_SIZE >> 1));
const float3 squareVec = collider->pos - squarePos;
const float3 squarePos = float3(xabs * SQUARE_SIZE + (SQUARE_SIZE >> 1), pos.y, zabs * SQUARE_SIZE + (SQUARE_SIZE >> 1));
const float3 squareVec = pos - squarePos;

// ignore squares behind us (relative to velocity vector)
if (squareVec.dot(collider->speed) > 0.0f)
if (squareVec.dot(vel) > 0.0f)
continue;

// RHS magic constant is the radius of a square (sqrt(2*(SQUARE_SIZE>>1)*(SQUARE_SIZE>>1)))
const float squareColRadiusSum = colliderRadius + 5.656854249492381f;
const float squareSepDistance = squareVec.Length2D() + 0.1f;
const float squarePenDistance = std::min(squareSepDistance - squareColRadiusSum, 0.0f);
// const float squareColSlideSign = -Sign(squarePos.dot(rightDir2D) - (collider->pos).dot(rightDir2D));
// const float squareColSlideSign = -Sign(squarePos.dot(rightDir2D) - pos.dot(rightDir2D));

// this tends to cancel out too much on average
// strafeVec += (rightDir2D * sqColSlideSign);
Expand All @@ -1768,7 +1783,7 @@ bool CGroundMoveType::HandleStaticObjectCollision(
sqrSumPosition *= (1.0f / sqrPenDistance.y);
sqrPenDistance *= (1.0f / sqrPenDistance.y);

const float strafeSign = -Sign(sqrSumPosition.dot(rightDir2D) - (collider->pos).dot(rightDir2D));
const float strafeSign = -Sign(sqrSumPosition.dot(rightDir2D) - pos.dot(rightDir2D));
const float bounceSign = Sign(rightDir2D.dot(bounceVec));
const float strafeScale = std::min(std::max(currentSpeed*0.0f, maxSpeedDef), std::max(0.1f, -sqrPenDistance.x * 0.5f));
const float bounceScale = std::min(std::max(currentSpeed*0.0f, maxSpeedDef), std::max(0.1f, -sqrPenDistance.x * 0.5f));
Expand All @@ -1785,15 +1800,16 @@ bool CGroundMoveType::HandleStaticObjectCollision(
summedVec = strafeVec + bounceVec;

// if checkTerrain is true, test only the center square
if (colliderMD->TestMoveSquare(collider, collider->pos + summedVec, collider->speed, checkTerrain, checkYardMap, checkTerrain)) {
if (colliderMD->TestMoveSquare(collider, pos + summedVec, vel, checkTerrain, checkYardMap, checkTerrain)) {
collider->Move(summedVec, true);

// minimal hack to make FollowPath work at all turn-rates
// since waypointDir will undergo a (large) discontinuity
currWayPoint += summedVec;
nextWayPoint += summedVec;
} else {
collider->Move(oldPos - collider->pos, true);
// never move fully back to oldPos when dealing with yardmaps
collider->Move((oldPos - pos) + summedVec * 0.25f * checkYardMap, true);
}
}

Expand Down
85 changes: 30 additions & 55 deletions rts/Sim/Units/CommandAI/MobileCAI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,6 @@
#include <assert.h>

#define AUTO_GENERATE_ATTACK_ORDERS 1
#define BUGGER_OFF_TTL 200
#define MAX_CLOSE_IN_RETRY_TICKS 30
#define MAX_USERGOAL_TOLERANCE_DIST 100.0f

#define AIRTRANSPORT_DOCKING_RADIUS 16
#define AIRTRANSPORT_DOCKING_ANGLE 50
#define UNLOAD_LAND 0
#define UNLOAD_DROP 1
#define UNLOAD_LANDFLOOD 2

// MobileCAI is not always assigned to aircraft
static AAirMoveType* GetAirMoveType(const CUnit* owner) {
Expand Down Expand Up @@ -82,6 +73,7 @@ CR_REG_METADATA(CMobileCAI, (
CR_MEMBER(lastCommandFrame),
CR_MEMBER(lastCloseInTry),
CR_MEMBER(lastBuggerOffTime),
CR_MEMBER(numNonMovingCalls),
CR_MEMBER(lastIdleCheck)
))

Expand All @@ -96,14 +88,7 @@ CMobileCAI::CMobileCAI():

tempOrder(false),
slowGuard(false),
moveDir(gsRNG.NextFloat() > 0.5f),

cancelDistance(1024),

lastCommandFrame(-1),
lastCloseInTry(-1),
lastBuggerOffTime(-BUGGER_OFF_TTL),
lastIdleCheck(0)
moveDir(gsRNG.NextFloat() > 0.5f)
{}


Expand All @@ -118,14 +103,7 @@ CMobileCAI::CMobileCAI(CUnit* owner):

tempOrder(false),
slowGuard(false),
moveDir(gsRNG.NextFloat() > 0.5f),

cancelDistance(1024),

lastCommandFrame(-1),
lastCloseInTry(-1),
lastBuggerOffTime(-BUGGER_OFF_TTL),
lastIdleCheck(0)
moveDir(gsRNG.NextFloat() > 0.5f)
{
CalculateCancelDistance();

Expand Down Expand Up @@ -1009,67 +987,64 @@ void CMobileCAI::StopMoveAndKeepPointing(const float3& p, const float r, bool b)
void CMobileCAI::BuggerOff(const float3& pos, float radius)
{
if (radius < 0.0f) {
// AttachUnit call
lastBuggerOffTime = gs->frameNum - BUGGER_OFF_TTL;
return;
}

lastBuggerOffTime = gs->frameNum;
// numNonMovingCalls = 0;

buggerOffPos = pos;
buggerOffRadius = radius + owner->radius;
}

void CMobileCAI::NonMoving()
{
if (owner->UsingScriptMoveType())
// wait one SlowUpdate for more commands to enter the queue
// (so the bugger-off dir can be chosen more intelligently)
if (!commandQue.empty() && (++numNonMovingCalls) <= 1)
return;

if (lastBuggerOffTime <= (gs->frameNum - BUGGER_OFF_TTL))
if (owner->UsingScriptMoveType())
return;

#if 0
float3 deltaPos = (owner->pos - buggerOffPos) * XZVector;
float3 buggerPos;

float buggerDist = deltaPos.Length();

if (buggerDist < 0.001f)
deltaPos = RgtVector * (buggerDist = 0.1f);
if (buggerDist >= buggerOffRadius)
if (lastBuggerOffTime <= (gs->frameNum - BUGGER_OFF_TTL))
return;
#endif

if (((owner->pos - buggerOffPos) * XZVector).SqLength() >= Square(buggerOffRadius * 1.5f))
return;

// pick a perimeter point and hope for the best
float3 buggerVec;
float3 buggerPos = -OnesVector;

for (int i = 0; i < 16 && !buggerPos.IsInMap(); i++) {
buggerVec = gsRNG.NextVector2D();
buggerPos = buggerOffPos + buggerVec.Normalize() * buggerOffRadius * 1.5f;
}
if (HasMoreMoveCommands()) {
size_t i = 0;
size_t j = 0;

#if 0
if ((buggerPos.x == lastBuggerGoalPos.x) && (buggerPos.z == lastBuggerGoalPos.z)) {
// randomize; gradually increase the amplitude of the random factor (radius)
lastBuggerGoalPos.y += 32.0f;
lastBuggerGoalPos.x = buggerPos.x;
lastBuggerGoalPos.z = buggerPos.z;
for (i = 0; (i < commandQue.size() && !commandQue[i].IsMoveCommand()); i++) {}
for (j = i + 1; (j < commandQue.size() && !commandQue[j].IsMoveCommand()); j++) {}

buggerPos.x += (2.0f * lastBuggerGoalPos.y) * gsRNG.NextFloat() - lastBuggerGoalPos.y;
buggerPos.z += (2.0f * lastBuggerGoalPos.y) * gsRNG.NextFloat() - lastBuggerGoalPos.y;
} else {
lastBuggerGoalPos.y = 0.0f;
lastBuggerGoalPos.x = buggerPos.x;
lastBuggerGoalPos.z = buggerPos.z;
if (i < commandQue.size() && j < commandQue.size()) {
buggerVec = commandQue[j].GetPos(0) - commandQue[i].GetPos(0);
buggerPos = buggerOffPos + buggerVec.Normalize() * buggerOffRadius * 1.25f;
}
}

if (buggerPos.x == -1.0f) {
// pick a random perimeter point and hope for the best
for (int i = 0; i < 16 && !buggerPos.IsInMap(); i++) {
buggerVec = gsRNG.NextVector2D();
buggerPos = buggerOffPos + buggerVec.Normalize() * buggerOffRadius * 1.5f;
}
}
#endif

Command c(CMD_MOVE, buggerPos);
// c.SetOpts(INTERNAL_ORDER);
c.SetTimeOut(gs->frameNum + BUGGER_OFF_TTL);
commandQue.push_front(c);

numNonMovingCalls = 0;
}

void CMobileCAI::FinishCommand()
Expand Down
24 changes: 19 additions & 5 deletions rts/Sim/Units/CommandAI/MobileCAI.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,27 @@ class CMobileCAI : public CCommandAI
bool slowGuard;
bool moveDir;

int cancelDistance;
int cancelDistance = 1024;

/// last frame certain types of area-commands were handled, helps avoid infinite loops
int lastCommandFrame;
int lastCloseInTry;
int lastBuggerOffTime;
int lastIdleCheck;
int lastCommandFrame = -1;
int lastCloseInTry = -1;
int lastBuggerOffTime = -BUGGER_OFF_TTL;
int lastIdleCheck = 0;
int numNonMovingCalls = 0;

static constexpr int MAX_CLOSE_IN_RETRY_TICKS = 30;
static constexpr int BUGGER_OFF_TTL = 200;

static constexpr float MAX_USERGOAL_TOLERANCE_DIST = 100.0f;
static constexpr float AIRTRANSPORT_DOCKING_RADIUS = 16.0f;
static constexpr float AIRTRANSPORT_DOCKING_ANGLE = 50.0f;

enum {
UNLOAD_LAND = 0,
UNLOAD_DROP = 1,
UNLOAD_LANDFLOOD = 2,
};

void PushOrUpdateReturnFight() {
CCommandAI::PushOrUpdateReturnFight(commandPos1, commandPos2);
Expand Down

0 comments on commit deaf660

Please sign in to comment.