Entity improvements
•Pathfinder improvements •Fixes #1217 •Fixes #1933 Merge remote-tracking branch 'SafwatHalaby/water2' into fixes
This commit is contained in:
parent
f96f9dae66
commit
a509cf00ef
@ -247,7 +247,6 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R
|
|||||||
if (a_Attacker != nullptr)
|
if (a_Attacker != nullptr)
|
||||||
{
|
{
|
||||||
Heading = a_Attacker->GetLookVector() * (a_Attacker->IsSprinting() ? 16 : 11);
|
Heading = a_Attacker->GetLookVector() * (a_Attacker->IsSprinting() ? 16 : 11);
|
||||||
Heading.y = 1.6;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TDI.Knockback = Heading * a_KnockbackAmount;
|
TDI.Knockback = Heading * a_KnockbackAmount;
|
||||||
|
@ -122,7 +122,7 @@ public:
|
|||||||
double GetEyeHeight(void) const; // tolua_export
|
double GetEyeHeight(void) const; // tolua_export
|
||||||
Vector3d GetEyePosition(void) const; // tolua_export
|
Vector3d GetEyePosition(void) const; // tolua_export
|
||||||
virtual bool IsOnGround(void) const override { return m_bTouchGround; }
|
virtual bool IsOnGround(void) const override { return m_bTouchGround; }
|
||||||
inline double GetStance(void) const { return GetPosY() + 1.62; } // tolua_export // TODO: Proper stance when crouching etc.
|
inline double GetStance(void) const { return m_Stance; } // tolua_export
|
||||||
inline cInventory & GetInventory(void) { return m_Inventory; } // tolua_export
|
inline cInventory & GetInventory(void) { return m_Inventory; } // tolua_export
|
||||||
inline const cInventory & GetInventory(void) const { return m_Inventory; }
|
inline const cInventory & GetInventory(void) const { return m_Inventory; }
|
||||||
|
|
||||||
|
@ -75,10 +75,8 @@ cMonster::cMonster(const AString & a_ConfigName, eMonsterType a_MobType, const A
|
|||||||
, m_EMPersonality(AGGRESSIVE)
|
, m_EMPersonality(AGGRESSIVE)
|
||||||
, m_Target(nullptr)
|
, m_Target(nullptr)
|
||||||
, m_Path(nullptr)
|
, m_Path(nullptr)
|
||||||
, m_PathStatus(ePathFinderStatus::PATH_NOT_FOUND)
|
|
||||||
, m_IsFollowingPath(false)
|
, m_IsFollowingPath(false)
|
||||||
, m_GiveUpCounter(0)
|
, m_GiveUpCounter(0)
|
||||||
, m_bMovingToDestination(false)
|
|
||||||
, m_LastGroundHeight(POSY_TOINT)
|
, m_LastGroundHeight(POSY_TOINT)
|
||||||
, m_JumpCoolDown(0)
|
, m_JumpCoolDown(0)
|
||||||
, m_IdleInterval(0)
|
, m_IdleInterval(0)
|
||||||
@ -122,67 +120,125 @@ void cMonster::SpawnOn(cClientHandle & a_Client)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cMonster::TickPathFinding(cChunk & a_Chunk)
|
bool cMonster::TickPathFinding(cChunk & a_Chunk)
|
||||||
{
|
{
|
||||||
|
if (!m_IsFollowingPath)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReachedFinalDestination())
|
||||||
|
{
|
||||||
|
StopMovingToPosition();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_Path == nullptr)
|
if (m_Path == nullptr)
|
||||||
{
|
{
|
||||||
Vector3d position = GetPosition();
|
m_Path = new cPath(a_Chunk, GetPosition().Floor(), m_FinalDestination.Floor(), 20);
|
||||||
Vector3d Dest = m_FinalDestination;
|
|
||||||
|
|
||||||
// Can someone explain why are these two NOT THE SAME???
|
|
||||||
// m_Path = new cPath(GetWorld(), GetPosition(), m_FinalDestination, 30);
|
|
||||||
m_Path = new cPath(a_Chunk, Vector3d(floor(position.x), floor(position.y), floor(position.z)), Vector3d(floor(Dest.x), floor(Dest.y), floor(Dest.z)), 20);
|
|
||||||
|
|
||||||
|
|
||||||
m_IsFollowingPath = false;
|
|
||||||
}
|
}
|
||||||
m_PathStatus = m_Path->Step(a_Chunk);
|
|
||||||
switch (m_PathStatus)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
switch (m_Path->Step(a_Chunk))
|
||||||
|
{
|
||||||
case ePathFinderStatus::PATH_NOT_FOUND:
|
case ePathFinderStatus::PATH_NOT_FOUND:
|
||||||
{
|
{
|
||||||
ResetPathFinding();
|
StopMovingToPosition(); // Give up pathfinding to that destination
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
case ePathFinderStatus::CALCULATING:
|
case ePathFinderStatus::CALCULATING:
|
||||||
{
|
{
|
||||||
m_Destination = GetPosition();
|
// Pathfinder needs more time
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
case ePathFinderStatus::PATH_FOUND:
|
case ePathFinderStatus::PATH_FOUND:
|
||||||
{
|
{
|
||||||
if (ReachedDestination() || !m_IsFollowingPath)
|
if (--m_GiveUpCounter == 0)
|
||||||
{
|
{
|
||||||
m_Destination = m_Path->GetNextPoint();
|
ResetPathFinding(); // Try to calculate a path again
|
||||||
m_IsFollowingPath = true;
|
return false;
|
||||||
m_GiveUpCounter = 40; // Give up after 40 ticks (2 seconds) if failed to reach m_Dest.
|
|
||||||
}
|
}
|
||||||
if (m_Path->IsLastPoint())
|
else if (!m_Path->IsLastPoint() && (m_Path->IsFirstPoint() || ReachedDestination())) // Have we arrived at the next cell, as denoted by m_Destination?
|
||||||
{
|
{
|
||||||
ResetPathFinding();
|
m_Destination = Vector3d(0.5, 0, 0.5) + m_Path->GetNextPoint();
|
||||||
|
m_GiveUpCounter = 40; // Give up after 40 ticks (2 seconds) if failed to reach m_Destination.
|
||||||
}
|
}
|
||||||
break;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cMonster::MoveToWayPoint(cChunk & a_Chunk)
|
||||||
|
{
|
||||||
|
if (m_JumpCoolDown == 0)
|
||||||
|
{
|
||||||
|
// We're not moving and waypoint is above us, it means we are hitting something and we should jump.
|
||||||
|
if ((GetSpeedX() < 0.1) && (GetSpeedY() < 0.1) && DoesPosYRequireJump(FloorC(m_Destination.y)))
|
||||||
|
{
|
||||||
|
if (IsOnGround() || IsSwimming())
|
||||||
|
{
|
||||||
|
m_bOnGround = false;
|
||||||
|
m_JumpCoolDown = 20;
|
||||||
|
// TODO: Change to AddSpeedY once collision detection is fixed - currently, mobs will go into blocks attempting to jump without a teleport
|
||||||
|
AddPosY(1.6); // Jump!!
|
||||||
|
SetSpeedX(3.2 * (m_Destination.x - GetPosition().x)); // Move forward in a preset speed.
|
||||||
|
SetSpeedZ(3.2 * (m_Destination.z - GetPosition().z)); // The numbers were picked based on trial and error and 1.6 and 3.2 are perfect.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
--m_JumpCoolDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3d Distance = m_Destination - GetPosition();
|
||||||
|
if ((Distance.x != 0) || (Distance.z != 0))
|
||||||
|
{
|
||||||
|
Distance.y = 0;
|
||||||
|
Distance.Normalize();
|
||||||
|
|
||||||
|
if (m_bOnGround)
|
||||||
|
{
|
||||||
|
Distance *= 2.5f;
|
||||||
|
}
|
||||||
|
else if (IsSwimming())
|
||||||
|
{
|
||||||
|
Distance *= 1.3f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Don't let the mob move too much if he's falling.
|
||||||
|
Distance *= 0.25f;
|
||||||
|
}
|
||||||
|
// Apply walk speed:
|
||||||
|
Distance *= m_RelativeWalkSpeed;
|
||||||
|
/* Reduced default speed.
|
||||||
|
Close to Vanilla, easier for mobs to follow m_Destinations, hence
|
||||||
|
better pathfinding. */
|
||||||
|
Distance *= 0.5;
|
||||||
|
AddSpeedX(Distance.x);
|
||||||
|
AddSpeedZ(Distance.z);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Currently, the mob will only start moving to a new position after the position it is
|
|
||||||
currently going to is reached. */
|
|
||||||
void cMonster::MoveToPosition(const Vector3d & a_Position)
|
void cMonster::MoveToPosition(const Vector3d & a_Position)
|
||||||
{
|
{
|
||||||
m_FinalDestination = a_Position;
|
if ((m_FinalDestination - a_Position).Length() > 0.25)
|
||||||
m_bMovingToDestination = true;
|
{
|
||||||
|
ResetPathFinding();
|
||||||
|
|
||||||
|
m_FinalDestination = a_Position;
|
||||||
|
m_IsFollowingPath = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -191,7 +247,7 @@ void cMonster::MoveToPosition(const Vector3d & a_Position)
|
|||||||
|
|
||||||
void cMonster::StopMovingToPosition()
|
void cMonster::StopMovingToPosition()
|
||||||
{
|
{
|
||||||
m_bMovingToDestination = false;
|
m_IsFollowingPath = false;
|
||||||
ResetPathFinding();
|
ResetPathFinding();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,24 +255,12 @@ void cMonster::StopMovingToPosition()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cMonster::IsCoordinateInTraversedList(Vector3i a_Coords)
|
|
||||||
{
|
|
||||||
return (std::find(m_TraversedCoordinates.begin(), m_TraversedCoordinates.end(), a_Coords) != m_TraversedCoordinates.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* No one should call this except the pathfinder orthe monster tick or StopMovingToPosition.
|
|
||||||
Resets the pathfinder, usually starting a brand new path, unless called from StopMovingToPosition. */
|
|
||||||
void cMonster::ResetPathFinding(void)
|
void cMonster::ResetPathFinding(void)
|
||||||
{
|
{
|
||||||
if (m_Path != nullptr)
|
if (m_Path != nullptr)
|
||||||
{
|
{
|
||||||
delete m_Path;
|
delete m_Path;
|
||||||
m_Path = nullptr;
|
m_Path = nullptr;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,34 +268,6 @@ void cMonster::ResetPathFinding(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cMonster::ReachedDestination()
|
|
||||||
{
|
|
||||||
if ((m_Destination - GetPosition()).Length() < 0.5f)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cMonster::ReachedFinalDestination()
|
|
||||||
{
|
|
||||||
if ((GetPosition() - m_FinalDestination).Length() <= m_AttackRange)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||||
{
|
{
|
||||||
super::Tick(a_Dt, a_Chunk);
|
super::Tick(a_Dt, a_Chunk);
|
||||||
@ -277,84 +293,19 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
|||||||
m_Target = nullptr;
|
m_Target = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Burning in daylight
|
// Process the undead burning in daylight
|
||||||
bool WouldBurnRightNow = WouldBurnAt(GetPosition(), *Chunk); // cached so that we use it twice, spares some cycles.
|
HandleDaylightBurning(*Chunk, WouldBurnAt(GetPosition(), *Chunk));
|
||||||
HandleDaylightBurning(*Chunk, WouldBurnRightNow);
|
if (TickPathFinding(*Chunk))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (m_bMovingToDestination)
|
|
||||||
{
|
{
|
||||||
if (m_bOnGround)
|
if (m_BurnsInDaylight && WouldBurnAt(m_Destination, *Chunk->GetNeighborChunk(FloorC(m_Destination.x), FloorC(m_Destination.z))) && !IsOnFire() && (m_TicksSinceLastDamaged == 100))
|
||||||
{
|
|
||||||
if (m_JumpCoolDown == 0)
|
|
||||||
{
|
|
||||||
if (DoesPosYRequireJump(static_cast<int>(floor(m_Destination.y))))
|
|
||||||
{
|
|
||||||
m_bOnGround = false;
|
|
||||||
m_JumpCoolDown = 20;
|
|
||||||
// TODO: Change to AddSpeedY once collision detection is fixed - currently, mobs will go into blocks attempting to jump without a teleport
|
|
||||||
AddPosY(1.6); // Jump!!
|
|
||||||
SetSpeedX(3.2 * (m_Destination.x - GetPosition().x)); // Move forward in a preset speed.
|
|
||||||
SetSpeedZ(3.2 * (m_Destination.z - GetPosition().z)); // The numbers were picked based on trial and error and 1.6 and 3.2 are perfect.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
--m_JumpCoolDown;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TickPathFinding(a_Chunk);
|
|
||||||
|
|
||||||
Vector3d Distance = m_Destination - GetPosition();
|
|
||||||
if (!ReachedDestination() && !ReachedFinalDestination()) // If we haven't reached any sort of destination, move
|
|
||||||
{
|
|
||||||
if (--m_GiveUpCounter == 0)
|
|
||||||
{
|
|
||||||
ResetPathFinding(); // Not to be confused with StopMovingToPosition, this just discards the current path and calculates another.
|
|
||||||
}
|
|
||||||
else if (m_BurnsInDaylight && WouldBurnAt(m_Destination, *Chunk) && !WouldBurnRightNow && (m_TicksSinceLastDamaged == 100))
|
|
||||||
{
|
|
||||||
// If we burn in daylight, and we would burn at the next step, and we won't burn where we are right now, and we weren't provoked recently:
|
|
||||||
StopMovingToPosition();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Distance.y = 0;
|
|
||||||
Distance.Normalize();
|
|
||||||
|
|
||||||
if (m_bOnGround)
|
|
||||||
{
|
|
||||||
Distance *= 2.5f;
|
|
||||||
}
|
|
||||||
else if (IsSwimming())
|
|
||||||
{
|
|
||||||
Distance *= 1.3f;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Don't let the mob move too much if he's falling.
|
|
||||||
Distance *= 0.25f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply walk speed:
|
|
||||||
Distance *= m_RelativeWalkSpeed;
|
|
||||||
|
|
||||||
/* Reduced default speed.
|
|
||||||
Close to Vanilla, easier for mobs to follow m_Destinations, hence
|
|
||||||
better pathfinding. */
|
|
||||||
Distance *= 0.5;
|
|
||||||
|
|
||||||
AddSpeedX(Distance.x);
|
|
||||||
AddSpeedZ(Distance.z);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (ReachedFinalDestination())
|
|
||||||
{
|
{
|
||||||
|
// If we burn in daylight, and we would burn at the next step, and we won't burn where we are right now, and we weren't provoked recently:
|
||||||
StopMovingToPosition();
|
StopMovingToPosition();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MoveToWayPoint(*Chunk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetPitchAndYawFromDestination();
|
SetPitchAndYawFromDestination();
|
||||||
@ -379,12 +330,11 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
|||||||
InStateEscaping(a_Dt);
|
InStateEscaping(a_Dt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ATTACKING: break;
|
case ATTACKING: break;
|
||||||
} // switch (m_EMState)
|
} // switch (m_EMState)
|
||||||
|
|
||||||
BroadcastMovementUpdate();
|
BroadcastMovementUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -397,32 +347,29 @@ void cMonster::SetPitchAndYawFromDestination()
|
|||||||
{
|
{
|
||||||
if (m_Target->IsPlayer())
|
if (m_Target->IsPlayer())
|
||||||
{
|
{
|
||||||
FinalDestination.y = ((cPlayer *)m_Target)->GetStance();
|
FinalDestination.y = static_cast<cPlayer *>(m_Target)->GetStance() - 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FinalDestination.y = GetHeight();
|
FinalDestination.y = m_Target->GetPosY() + GetHeight();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3d Distance = FinalDestination - GetPosition();
|
Vector3d Distance = FinalDestination - GetPosition();
|
||||||
if (Distance.SqrLength() > 0.1f)
|
|
||||||
{
|
{
|
||||||
{
|
double Rotation, Pitch;
|
||||||
double Rotation, Pitch;
|
Distance.Normalize();
|
||||||
Distance.Normalize();
|
VectorToEuler(Distance.x, Distance.y, Distance.z, Rotation, Pitch);
|
||||||
VectorToEuler(Distance.x, Distance.y, Distance.z, Rotation, Pitch);
|
SetHeadYaw(Rotation);
|
||||||
SetHeadYaw(Rotation);
|
SetPitch(-Pitch);
|
||||||
SetPitch(-Pitch);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
Vector3d BodyDistance = m_Destination - GetPosition();
|
Vector3d BodyDistance = m_Destination - GetPosition();
|
||||||
double Rotation, Pitch;
|
double Rotation, Pitch;
|
||||||
Distance.Normalize();
|
BodyDistance.Normalize();
|
||||||
VectorToEuler(BodyDistance.x, BodyDistance.y, BodyDistance.z, Rotation, Pitch);
|
VectorToEuler(BodyDistance.x, BodyDistance.y, BodyDistance.z, Rotation, Pitch);
|
||||||
SetYaw(Rotation);
|
SetYaw(Rotation);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -662,7 +609,7 @@ void cMonster::EventLosePlayer(void)
|
|||||||
|
|
||||||
void cMonster::InStateIdle(std::chrono::milliseconds a_Dt)
|
void cMonster::InStateIdle(std::chrono::milliseconds a_Dt)
|
||||||
{
|
{
|
||||||
if (m_bMovingToDestination)
|
if (m_IsFollowingPath)
|
||||||
{
|
{
|
||||||
return; // Still getting there
|
return; // Still getting there
|
||||||
}
|
}
|
||||||
@ -682,14 +629,8 @@ void cMonster::InStateIdle(std::chrono::milliseconds a_Dt)
|
|||||||
if ((Dist.SqrLength() > 2) && (rem >= 3))
|
if ((Dist.SqrLength() > 2) && (rem >= 3))
|
||||||
{
|
{
|
||||||
Vector3d Destination(GetPosX() + Dist.x, 0, GetPosZ() + Dist.z);
|
Vector3d Destination(GetPosX() + Dist.x, 0, GetPosZ() + Dist.z);
|
||||||
|
Destination.y = FindFirstNonAirBlockPosition(Destination.x, Destination.z);
|
||||||
int NextHeight = FindFirstNonAirBlockPosition(Destination.x, Destination.z);
|
MoveToPosition(Destination);
|
||||||
|
|
||||||
if (IsNextYPosReachable(NextHeight))
|
|
||||||
{
|
|
||||||
Destination.y = NextHeight;
|
|
||||||
MoveToPosition(Destination);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,9 +61,9 @@ public:
|
|||||||
|
|
||||||
virtual void OnRightClicked(cPlayer & a_Player) override;
|
virtual void OnRightClicked(cPlayer & a_Player) override;
|
||||||
|
|
||||||
|
/** Engage pathfinder and tell it to calculate a path to a given position, and move the mobile accordingly
|
||||||
|
Currently, the mob will only start moving to a new position after the position it is currently going to is reached. */
|
||||||
virtual void MoveToPosition(const Vector3d & a_Position); // tolua_export
|
virtual void MoveToPosition(const Vector3d & a_Position); // tolua_export
|
||||||
virtual void StopMovingToPosition();
|
|
||||||
virtual bool ReachedDestination(void);
|
|
||||||
|
|
||||||
// tolua_begin
|
// tolua_begin
|
||||||
eMonsterType GetMobType(void) const { return m_MobType; }
|
eMonsterType GetMobType(void) const { return m_MobType; }
|
||||||
@ -160,24 +160,21 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/* ======= PATHFINDING ======= */
|
|
||||||
|
|
||||||
/** A pointer to the entity this mobile is aiming to reach */
|
/** A pointer to the entity this mobile is aiming to reach */
|
||||||
cEntity * m_Target;
|
cEntity * m_Target;
|
||||||
cPath * m_Path; // TODO unique ptr
|
cPath * m_Path; // TODO unique ptr
|
||||||
ePathFinderStatus m_PathStatus;
|
|
||||||
bool m_IsFollowingPath;
|
|
||||||
/* If 0, will give up reaching the next m_Dest and will re-compute path. */
|
|
||||||
int m_GiveUpCounter;
|
|
||||||
/** Coordinates of the next position that should be reached */
|
|
||||||
Vector3d m_Destination;
|
|
||||||
/** Coordinates for the ultimate, final destination. */
|
|
||||||
Vector3d m_FinalDestination;
|
|
||||||
/** Returns if the ultimate, final destination has been reached */
|
|
||||||
bool ReachedFinalDestination(void);
|
|
||||||
|
|
||||||
/** Stores if mobile is currently moving towards the ultimate, final destination */
|
/** Stores if mobile is currently moving towards the ultimate, final destination */
|
||||||
bool m_bMovingToDestination;
|
bool m_IsFollowingPath;
|
||||||
|
|
||||||
|
/* If 0, will give up reaching the next m_Destination and will re-compute path. */
|
||||||
|
int m_GiveUpCounter;
|
||||||
|
|
||||||
|
/** Coordinates of the next position that should be reached */
|
||||||
|
Vector3d m_Destination;
|
||||||
|
|
||||||
|
/** Coordinates for the ultimate, final destination. */
|
||||||
|
Vector3d m_FinalDestination;
|
||||||
|
|
||||||
/** Finds the lowest non-air block position (not the highest, as cWorld::GetHeight does)
|
/** Finds the lowest non-air block position (not the highest, as cWorld::GetHeight does)
|
||||||
If current Y is nonsolid, goes down to try to find a solid block, then returns that + 1
|
If current Y is nonsolid, goes down to try to find a solid block, then returns that + 1
|
||||||
@ -185,42 +182,41 @@ protected:
|
|||||||
If no suitable position is found, returns cChunkDef::Height. */
|
If no suitable position is found, returns cChunkDef::Height. */
|
||||||
int FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ);
|
int FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ);
|
||||||
|
|
||||||
/** Returns if a monster can actually reach a given height by jumping or walking */
|
/** Returns if the ultimate, final destination has been reached */
|
||||||
inline bool IsNextYPosReachable(int a_PosY)
|
bool ReachedFinalDestination(void) { return ((m_FinalDestination - GetPosition()).SqrLength() < (m_AttackRange * m_AttackRange)); }
|
||||||
{
|
|
||||||
return (
|
/** Returns if the intermediate waypoint of m_Destination has been reached */
|
||||||
(a_PosY <= POSY_TOINT) ||
|
bool ReachedDestination(void) { return ((m_Destination - GetPosition()).SqrLength() < 0.25); }
|
||||||
DoesPosYRequireJump(a_PosY)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
/** Returns if a monster can reach a given height by jumping */
|
/** Returns if a monster can reach a given height by jumping */
|
||||||
inline bool DoesPosYRequireJump(int a_PosY)
|
inline bool DoesPosYRequireJump(int a_PosY)
|
||||||
{
|
{
|
||||||
return ((a_PosY > POSY_TOINT) && (a_PosY == POSY_TOINT + 1));
|
return ((a_PosY > POSY_TOINT) && (a_PosY == POSY_TOINT + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A semi-temporary list to store the traversed coordinates during active pathfinding so we don't visit them again */
|
/** Finds the next place to go by calculating a path and setting the m_Destination variable for the next block to head to
|
||||||
std::vector<Vector3i> m_TraversedCoordinates;
|
This is based on the ultimate, final destination and the current position, as well as the A* algorithm, and any environmental hazards
|
||||||
/** Returns if coordinate is in the traversed list */
|
Returns if a path is ready, and therefore if the mob should move to m_Destination
|
||||||
bool IsCoordinateInTraversedList(Vector3i a_Coords);
|
*/
|
||||||
|
bool TickPathFinding(cChunk & a_Chunk);
|
||||||
|
void MoveToWayPoint(cChunk & a_Chunk);
|
||||||
|
|
||||||
/** Finds the next place to go
|
/** Resets a pathfinding task, be it due to failure or something else
|
||||||
This is based on the ultimate, final destination and the current position, as well as the traversed coordinates, and any environmental hazards */
|
Resets the pathfinder. If m_IsFollowingPath is true, TickPathFinding starts a brand new path.
|
||||||
void TickPathFinding(cChunk & a_Chunk);
|
Should only be called by the pathfinder, cMonster::Tick or StopMovingToPosition. */
|
||||||
/** Finishes a pathfinding task, be it due to failure or something else */
|
|
||||||
void ResetPathFinding(void);
|
void ResetPathFinding(void);
|
||||||
|
|
||||||
|
/** Stops pathfinding
|
||||||
|
Calls ResetPathFinding and sets m_IsFollowingPath to false */
|
||||||
|
void StopMovingToPosition();
|
||||||
|
|
||||||
/** Sets the body yaw and head yaw/pitch based on next/ultimate destinations */
|
/** Sets the body yaw and head yaw/pitch based on next/ultimate destinations */
|
||||||
void SetPitchAndYawFromDestination(void);
|
void SetPitchAndYawFromDestination(void);
|
||||||
|
|
||||||
/* =========================== */
|
|
||||||
/* ========= FALLING ========= */
|
|
||||||
|
|
||||||
virtual void HandleFalling(void);
|
virtual void HandleFalling(void);
|
||||||
int m_LastGroundHeight;
|
int m_LastGroundHeight;
|
||||||
int m_JumpCoolDown;
|
int m_JumpCoolDown;
|
||||||
|
|
||||||
/* =========================== */
|
|
||||||
|
|
||||||
std::chrono::milliseconds m_IdleInterval;
|
std::chrono::milliseconds m_IdleInterval;
|
||||||
std::chrono::milliseconds m_DestroyTimer;
|
std::chrono::milliseconds m_DestroyTimer;
|
||||||
|
|
||||||
|
@ -7,13 +7,13 @@
|
|||||||
|
|
||||||
#define DISTANCE_MANHATTAN 0 // 1: More speed, a bit less accuracy 0: Max accuracy, less speed.
|
#define DISTANCE_MANHATTAN 0 // 1: More speed, a bit less accuracy 0: Max accuracy, less speed.
|
||||||
#define HEURISTICS_ONLY 0 // 1: Much more speed, much less accurate.
|
#define HEURISTICS_ONLY 0 // 1: Much more speed, much less accurate.
|
||||||
#define CALCULATIONS_PER_STEP 5 // Higher means more CPU load but faster path calculations.
|
#define CALCULATIONS_PER_STEP 60 // Higher means more CPU load but faster path calculations.
|
||||||
// The only version which guarantees the shortest path is 0, 0.
|
// The only version which guarantees the shortest path is 0, 0.
|
||||||
|
|
||||||
enum class eCellStatus {OPENLIST, CLOSEDLIST, NOLIST};
|
enum class eCellStatus {OPENLIST, CLOSEDLIST, NOLIST};
|
||||||
struct cPathCell
|
struct cPathCell
|
||||||
{
|
{
|
||||||
Vector3d m_Location; // Location of the cell in the world.
|
Vector3i m_Location; // Location of the cell in the world.
|
||||||
int m_F, m_G, m_H; // F, G, H as defined in regular A*.
|
int m_F, m_G, m_H; // F, G, H as defined in regular A*.
|
||||||
eCellStatus m_Status; // Which list is the cell in? Either non, open, or closed.
|
eCellStatus m_Status; // Which list is the cell in? Either non, open, or closed.
|
||||||
cPathCell * m_Parent; // Cell's parent, as defined in regular A*.
|
cPathCell * m_Parent; // Cell's parent, as defined in regular A*.
|
||||||
@ -36,28 +36,51 @@ bool compareHeuristics::operator()(cPathCell * & a_Cell1, cPathCell * & a_Cell2)
|
|||||||
/* cPath implementation */
|
/* cPath implementation */
|
||||||
cPath::cPath(
|
cPath::cPath(
|
||||||
cChunk & a_Chunk,
|
cChunk & a_Chunk,
|
||||||
const Vector3d & a_StartingPoint, const Vector3d & a_EndingPoint, int a_MaxSteps,
|
const Vector3i & a_StartingPoint, const Vector3i & a_EndingPoint, int a_MaxSteps,
|
||||||
double a_BoundingBoxWidth, double a_BoundingBoxHeight,
|
double a_BoundingBoxWidth, double a_BoundingBoxHeight,
|
||||||
int a_MaxUp, int a_MaxDown
|
int a_MaxUp, int a_MaxDown
|
||||||
)
|
) :
|
||||||
|
m_Destination(a_EndingPoint.Floor()),
|
||||||
|
m_Source(a_StartingPoint.Floor()),
|
||||||
|
m_CurrentPoint(0), // GetNextPoint increments this to 1, but that's fine, since the first cell is always a_StartingPoint
|
||||||
|
m_Chunk(&a_Chunk)
|
||||||
{
|
{
|
||||||
// TODO: if src not walkable OR dest not walkable, then abort.
|
// TODO: if src not walkable OR dest not walkable, then abort.
|
||||||
// Borrow a new "isWalkable" from ProcessIfWalkable, make ProcessIfWalkable also call isWalkable
|
// Borrow a new "isWalkable" from ProcessIfWalkable, make ProcessIfWalkable also call isWalkable
|
||||||
|
|
||||||
m_Chunk = &a_Chunk;
|
|
||||||
m_Source = a_StartingPoint.Floor();
|
|
||||||
m_Destination = a_EndingPoint.Floor();
|
|
||||||
|
|
||||||
if (GetCell(m_Source)->m_IsSolid || GetCell(m_Destination)->m_IsSolid)
|
if (GetCell(m_Source)->m_IsSolid || GetCell(m_Destination)->m_IsSolid)
|
||||||
{
|
{
|
||||||
m_Status = ePathFinderStatus::PATH_NOT_FOUND;
|
m_Status = ePathFinderStatus::PATH_NOT_FOUND;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Status = ePathFinderStatus::CALCULATING;
|
// If destination in water, set water surface as destination.
|
||||||
|
cChunk * Chunk = m_Chunk->GetNeighborChunk(m_Destination.x, m_Destination.z);
|
||||||
|
if ((Chunk != nullptr) && Chunk->IsValid())
|
||||||
|
{
|
||||||
|
BLOCKTYPE BlockType;
|
||||||
|
NIBBLETYPE BlockMeta;
|
||||||
|
int RelX = m_Destination.x - m_Chunk->GetPosX() * cChunkDef::Width;
|
||||||
|
int RelZ = m_Destination.z - m_Chunk->GetPosZ() * cChunkDef::Width;
|
||||||
|
bool inwater = false;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
m_Chunk->GetBlockTypeMeta(RelX, m_Destination.y, RelZ, BlockType, BlockMeta);
|
||||||
|
if (BlockType != E_BLOCK_STATIONARY_WATER)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
inwater = true;
|
||||||
|
m_Destination+=Vector3d(0, 1, 0);
|
||||||
|
}
|
||||||
|
if (inwater)
|
||||||
|
{
|
||||||
|
m_Destination+=Vector3d(0, -1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Status = ePathFinderStatus::CALCULATING;
|
||||||
m_StepsLeft = a_MaxSteps;
|
m_StepsLeft = a_MaxSteps;
|
||||||
m_PointCount = 0;
|
|
||||||
|
|
||||||
ProcessCell(GetCell(a_StartingPoint), nullptr, 0);
|
ProcessCell(GetCell(a_StartingPoint), nullptr, 0);
|
||||||
m_Chunk = nullptr;
|
m_Chunk = nullptr;
|
||||||
@ -82,6 +105,7 @@ cPath::~cPath()
|
|||||||
ePathFinderStatus cPath::Step(cChunk & a_Chunk)
|
ePathFinderStatus cPath::Step(cChunk & a_Chunk)
|
||||||
{
|
{
|
||||||
m_Chunk = &a_Chunk;
|
m_Chunk = &a_Chunk;
|
||||||
|
|
||||||
if (m_Status != ePathFinderStatus::CALCULATING)
|
if (m_Status != ePathFinderStatus::CALCULATING)
|
||||||
{
|
{
|
||||||
return m_Status;
|
return m_Status;
|
||||||
@ -103,6 +127,7 @@ ePathFinderStatus cPath::Step(cChunk & a_Chunk)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Chunk = nullptr;
|
m_Chunk = nullptr;
|
||||||
return m_Status;
|
return m_Status;
|
||||||
}
|
}
|
||||||
@ -111,23 +136,32 @@ ePathFinderStatus cPath::Step(cChunk & a_Chunk)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cPath::IsSolid(const Vector3d & a_Location)
|
bool cPath::IsSolid(const Vector3i & a_Location)
|
||||||
{
|
{
|
||||||
ASSERT(m_Chunk != nullptr);
|
ASSERT(m_Chunk != nullptr);
|
||||||
m_Chunk = m_Chunk->GetNeighborChunk(a_Location.x, a_Location.z);
|
|
||||||
if (!m_Chunk->IsValid())
|
auto Chunk = m_Chunk->GetNeighborChunk(a_Location.x, a_Location.z);
|
||||||
|
if ((Chunk == nullptr) || !Chunk->IsValid())
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
m_Chunk = Chunk;
|
||||||
|
|
||||||
BLOCKTYPE BlockType;
|
BLOCKTYPE BlockType;
|
||||||
NIBBLETYPE BlockMeta;
|
NIBBLETYPE BlockMeta;
|
||||||
int RelX = a_Location.x - m_Chunk->GetPosX() * cChunkDef::Width;
|
int RelX = a_Location.x - m_Chunk->GetPosX() * cChunkDef::Width;
|
||||||
int RelZ = a_Location.z - m_Chunk->GetPosZ() * cChunkDef::Width;
|
int RelZ = a_Location.z - m_Chunk->GetPosZ() * cChunkDef::Width;
|
||||||
|
|
||||||
m_Chunk->GetBlockTypeMeta(RelX, a_Location.y, RelZ, BlockType, BlockMeta);
|
m_Chunk->GetBlockTypeMeta(RelX, a_Location.y, RelZ, BlockType, BlockMeta);
|
||||||
if ((BlockType == E_BLOCK_FENCE) || (BlockType == E_BLOCK_FENCE_GATE))
|
if ((BlockType == E_BLOCK_FENCE) || (BlockType == E_BLOCK_FENCE_GATE))
|
||||||
{
|
{
|
||||||
GetCell(a_Location + Vector3d(0, 1, 0))->m_IsSolid = true; // Mobs will always think that the fence is 2 blocks high and therefore won't jump over.
|
GetCell(a_Location + Vector3i(0, 1, 0))->m_IsSolid = true; // Mobs will always think that the fence is 2 blocks high and therefore won't jump over.
|
||||||
}
|
}
|
||||||
|
if (BlockType == E_BLOCK_STATIONARY_WATER)
|
||||||
|
{
|
||||||
|
GetCell(a_Location + Vector3i(0, -1, 0))->m_IsSolid = true; // Mobs will always think that the fence is 2 blocks high and therefore won't jump over.
|
||||||
|
}
|
||||||
|
|
||||||
return cBlockInfo::IsSolid(BlockType);
|
return cBlockInfo::IsSolid(BlockType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,11 +186,10 @@ bool cPath::Step_Internal()
|
|||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
AddPoint(CurrentCell->m_Location + Vector3d(0.5, 0, 0.5)); // Populate the cPath with points.
|
m_PathPoints.push_back(CurrentCell->m_Location); // Populate the cPath with points.
|
||||||
CurrentCell = CurrentCell->m_Parent;
|
CurrentCell = CurrentCell->m_Parent;
|
||||||
} while (CurrentCell != nullptr);
|
} while (CurrentCell != nullptr);
|
||||||
|
|
||||||
m_CurrentPoint = -1;
|
|
||||||
FinishCalculation(ePathFinderStatus::PATH_FOUND);
|
FinishCalculation(ePathFinderStatus::PATH_FOUND);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -167,10 +200,10 @@ bool cPath::Step_Internal()
|
|||||||
int i;
|
int i;
|
||||||
for (i = -1; i <= 1; ++i)
|
for (i = -1; i <= 1; ++i)
|
||||||
{
|
{
|
||||||
ProcessIfWalkable(CurrentCell->m_Location + Vector3d(1, i, 0), CurrentCell, 10);
|
ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, i, 0), CurrentCell, 10);
|
||||||
ProcessIfWalkable(CurrentCell->m_Location + Vector3d(-1, i, 0), CurrentCell, 10);
|
ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, i, 0), CurrentCell, 10);
|
||||||
ProcessIfWalkable(CurrentCell->m_Location + Vector3d(0, i, 1), CurrentCell, 10);
|
ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, i, 1), CurrentCell, 10);
|
||||||
ProcessIfWalkable(CurrentCell->m_Location + Vector3d(0, i, -1), CurrentCell, 10);
|
ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, i, -1), CurrentCell, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check diagonals on mob's height only.
|
// Check diagonals on mob's height only.
|
||||||
@ -180,18 +213,17 @@ bool cPath::Step_Internal()
|
|||||||
for (z = -1; z <= 1; z += 2)
|
for (z = -1; z <= 1; z += 2)
|
||||||
{
|
{
|
||||||
// This condition prevents diagonal corner cutting.
|
// This condition prevents diagonal corner cutting.
|
||||||
if (!GetCell(CurrentCell->m_Location + Vector3d(x, 0, 0))->m_IsSolid && !GetCell(CurrentCell->m_Location + Vector3d(0, 0, z))->m_IsSolid)
|
if (!GetCell(CurrentCell->m_Location + Vector3i(x, 0, 0))->m_IsSolid && !GetCell(CurrentCell->m_Location + Vector3i(0, 0, z))->m_IsSolid)
|
||||||
{
|
{
|
||||||
// This prevents falling of "sharp turns" e.g. a 1x1x20 rectangle in the air which breaks in a right angle suddenly.
|
// This prevents falling of "sharp turns" e.g. a 1x1x20 rectangle in the air which breaks in a right angle suddenly.
|
||||||
if (GetCell(CurrentCell->m_Location + Vector3d(x, -1, 0))->m_IsSolid && GetCell(CurrentCell->m_Location + Vector3d(0, -1, z))->m_IsSolid)
|
if (GetCell(CurrentCell->m_Location + Vector3i(x, -1, 0))->m_IsSolid && GetCell(CurrentCell->m_Location + Vector3i(0, -1, z))->m_IsSolid)
|
||||||
{
|
{
|
||||||
ProcessIfWalkable(CurrentCell->m_Location + Vector3d(x, 0, z), CurrentCell, 14); // 14 is a good enough approximation of sqrt(10 + 10).
|
ProcessIfWalkable(CurrentCell->m_Location + Vector3i(x, 0, z), CurrentCell, 14); // 14 is a good enough approximation of sqrt(10 + 10).
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,10 +289,10 @@ si::setBlock((Ret)->m_Location.x, (Ret)->m_Location.y, (Ret)->m_Location.z, debu
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cPath::ProcessIfWalkable(const Vector3d & a_Location, cPathCell * a_Parent, int a_Cost)
|
void cPath::ProcessIfWalkable(const Vector3i & a_Location, cPathCell * a_Parent, int a_Cost)
|
||||||
{
|
{
|
||||||
cPathCell * cell = GetCell(a_Location);
|
cPathCell * cell = GetCell(a_Location);
|
||||||
if (!cell->m_IsSolid && GetCell(a_Location + Vector3d(0, -1, 0))->m_IsSolid && !GetCell(a_Location + Vector3d(0, 1, 0))->m_IsSolid)
|
if (!cell->m_IsSolid && GetCell(a_Location + Vector3i(0, -1, 0))->m_IsSolid && !GetCell(a_Location + Vector3i(0, 1, 0))->m_IsSolid)
|
||||||
{
|
{
|
||||||
ProcessCell(cell, a_Parent, a_Cost);
|
ProcessCell(cell, a_Parent, a_Cost);
|
||||||
}
|
}
|
||||||
@ -298,7 +330,7 @@ void cPath::ProcessCell(cPathCell * a_Cell, cPathCell * a_Caller, int a_GDelta)
|
|||||||
a_Cell->m_H = 10 * (abs(a_Cell->m_Location.x-m_Destination.x) + abs(a_Cell->m_Location.y-m_Destination.y) + abs(a_Cell->m_Location.z-m_Destination.z));
|
a_Cell->m_H = 10 * (abs(a_Cell->m_Location.x-m_Destination.x) + abs(a_Cell->m_Location.y-m_Destination.y) + abs(a_Cell->m_Location.z-m_Destination.z));
|
||||||
#else
|
#else
|
||||||
// Euclidian distance. sqrt(DeltaX^2 + DeltaY^2 + DeltaZ^2), more precise.
|
// Euclidian distance. sqrt(DeltaX^2 + DeltaY^2 + DeltaZ^2), more precise.
|
||||||
a_Cell->m_H = std::sqrt((a_Cell->m_Location.x - m_Destination.x) * (a_Cell->m_Location.x - m_Destination.x) * 100 + (a_Cell->m_Location.y - m_Destination.y) * (a_Cell->m_Location.y - m_Destination.y) * 100 + (a_Cell->m_Location.z - m_Destination.z) * (a_Cell->m_Location.z - m_Destination.z) * 100);
|
a_Cell->m_H = static_cast<decltype(a_Cell->m_H)>((a_Cell->m_Location - m_Destination).Length() * 10);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if HEURISTICS_ONLY == 1
|
#if HEURISTICS_ONLY == 1
|
||||||
@ -326,7 +358,7 @@ void cPath::ProcessCell(cPathCell * a_Cell, cPathCell * a_Caller, int a_GDelta)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
cPathCell * cPath::GetCell(const Vector3d & a_Location)
|
cPathCell * cPath::GetCell(const Vector3i & a_Location)
|
||||||
{
|
{
|
||||||
// Create the cell in the hash table if it's not already there.
|
// Create the cell in the hash table if it's not already there.
|
||||||
cPathCell * Cell;
|
cPathCell * Cell;
|
||||||
@ -349,14 +381,3 @@ cPathCell * cPath::GetCell(const Vector3d & a_Location)
|
|||||||
return m_Map[a_Location];
|
return m_Map[a_Location];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Add the next point in the final path.
|
|
||||||
void cPath::AddPoint(Vector3d a_Vector)
|
|
||||||
{
|
|
||||||
m_PathPoints.push_back(a_Vector);
|
|
||||||
++m_PointCount;
|
|
||||||
}
|
|
||||||
|
@ -53,7 +53,7 @@ public:
|
|||||||
@param a_MaxSteps The maximum steps before giving up. */
|
@param a_MaxSteps The maximum steps before giving up. */
|
||||||
cPath(
|
cPath(
|
||||||
cChunk & a_Chunk,
|
cChunk & a_Chunk,
|
||||||
const Vector3d & a_StartingPoint, const Vector3d & a_EndingPoint, int a_MaxSteps,
|
const Vector3i & a_StartingPoint, const Vector3i & a_EndingPoint, int a_MaxSteps,
|
||||||
double a_BoundingBoxWidth = 1, double a_BoundingBoxHeight = 2,
|
double a_BoundingBoxWidth = 1, double a_BoundingBoxHeight = 2,
|
||||||
int a_MaxUp = 1, int a_MaxDown = 1
|
int a_MaxUp = 1, int a_MaxDown = 1
|
||||||
);
|
);
|
||||||
@ -66,35 +66,39 @@ public:
|
|||||||
|
|
||||||
/* Point retrieval functions, inlined for performance. */
|
/* Point retrieval functions, inlined for performance. */
|
||||||
/** Returns the next point in the path. */
|
/** Returns the next point in the path. */
|
||||||
inline Vector3d GetNextPoint()
|
inline Vector3i GetNextPoint()
|
||||||
{
|
{
|
||||||
ASSERT(m_Status == ePathFinderStatus::PATH_FOUND);
|
ASSERT(m_Status == ePathFinderStatus::PATH_FOUND);
|
||||||
return m_PathPoints[m_PointCount - 1 - (++m_CurrentPoint)];
|
return m_PathPoints[m_PathPoints.size() - 1 - (++m_CurrentPoint)];
|
||||||
}
|
}
|
||||||
/** Checks whether this is the last point or not. Never call getnextPoint when this is true. */
|
/** Checks whether this is the last point or not. Never call getnextPoint when this is true. */
|
||||||
inline bool IsLastPoint()
|
inline bool IsLastPoint()
|
||||||
{
|
{
|
||||||
ASSERT(m_Status == ePathFinderStatus::PATH_FOUND);
|
ASSERT(m_Status == ePathFinderStatus::PATH_FOUND);
|
||||||
ASSERT(m_CurrentPoint != -1); // You must call getFirstPoint at least once before calling this.
|
return (m_CurrentPoint == m_PathPoints.size() - 1);
|
||||||
return (m_CurrentPoint == m_PointCount - 1);
|
|
||||||
}
|
}
|
||||||
/** Get the point at a_index. Remark: Internally, the indexes are reversed. */
|
inline bool IsFirstPoint()
|
||||||
inline Vector3d GetPoint(int a_index)
|
|
||||||
{
|
{
|
||||||
ASSERT(m_Status == ePathFinderStatus::PATH_FOUND);
|
ASSERT(m_Status == ePathFinderStatus::PATH_FOUND);
|
||||||
ASSERT(a_index < m_PointCount);
|
return (m_CurrentPoint == 0);
|
||||||
return m_PathPoints[m_PointCount - 1 - a_index];
|
}
|
||||||
|
/** Get the point at a_index. Remark: Internally, the indexes are reversed. */
|
||||||
|
inline Vector3i GetPoint(size_t a_index)
|
||||||
|
{
|
||||||
|
ASSERT(m_Status == ePathFinderStatus::PATH_FOUND);
|
||||||
|
ASSERT(a_index < m_PathPoints.size());
|
||||||
|
return m_PathPoints[m_PathPoints.size() - 1 - a_index];
|
||||||
}
|
}
|
||||||
/** Returns the total number of points this path has. */
|
/** Returns the total number of points this path has. */
|
||||||
inline int GetPointCount()
|
inline int GetPointCount()
|
||||||
{
|
{
|
||||||
ASSERT(m_Status == ePathFinderStatus::PATH_FOUND);
|
ASSERT(m_Status == ePathFinderStatus::PATH_FOUND);
|
||||||
return m_PointCount;
|
return m_PathPoints.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VectorHasher
|
struct VectorHasher
|
||||||
{
|
{
|
||||||
std::size_t operator()(const Vector3d & a_Vector) const
|
std::size_t operator()(const Vector3i & a_Vector) const
|
||||||
{
|
{
|
||||||
// Guaranteed to have no hash collisions for any 128x128x128 area. Suitable for pathfinding.
|
// Guaranteed to have no hash collisions for any 128x128x128 area. Suitable for pathfinding.
|
||||||
int32_t t = 0;
|
int32_t t = 0;
|
||||||
@ -110,7 +114,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
/* General */
|
/* General */
|
||||||
bool IsSolid(const Vector3d & a_Location); // Query our hosting world and ask it if there's a solid at a_location.
|
bool IsSolid(const Vector3i & a_Location); // Query our hosting world and ask it if there's a solid at a_location.
|
||||||
bool Step_Internal(); // The public version just calls this version * CALCULATIONS_PER_CALL times.
|
bool Step_Internal(); // The public version just calls this version * CALCULATIONS_PER_CALL times.
|
||||||
void FinishCalculation(); // Clears the memory used for calculating the path.
|
void FinishCalculation(); // Clears the memory used for calculating the path.
|
||||||
void FinishCalculation(ePathFinderStatus a_NewStatus); // Clears the memory used for calculating the path and changes the status.
|
void FinishCalculation(ePathFinderStatus a_NewStatus); // Clears the memory used for calculating the path and changes the status.
|
||||||
@ -118,27 +122,25 @@ private:
|
|||||||
/* Openlist and closedlist management */
|
/* Openlist and closedlist management */
|
||||||
void OpenListAdd(cPathCell * a_Cell);
|
void OpenListAdd(cPathCell * a_Cell);
|
||||||
cPathCell * OpenListPop();
|
cPathCell * OpenListPop();
|
||||||
void ProcessIfWalkable(const Vector3d &a_Location, cPathCell * a_Parent, int a_Cost);
|
void ProcessIfWalkable(const Vector3i &a_Location, cPathCell * a_Parent, int a_Cost);
|
||||||
|
|
||||||
/* Map management */
|
/* Map management */
|
||||||
void ProcessCell(cPathCell * a_Cell, cPathCell * a_Caller, int a_GDelta);
|
void ProcessCell(cPathCell * a_Cell, cPathCell * a_Caller, int a_GDelta);
|
||||||
cPathCell * GetCell(const Vector3d & a_location);
|
cPathCell * GetCell(const Vector3i & a_location);
|
||||||
|
|
||||||
/* Pathfinding fields */
|
/* Pathfinding fields */
|
||||||
std::priority_queue<cPathCell *, std::vector<cPathCell *>, compareHeuristics> m_OpenList;
|
std::priority_queue<cPathCell *, std::vector<cPathCell *>, compareHeuristics> m_OpenList;
|
||||||
std::unordered_map<Vector3d, cPathCell *, VectorHasher> m_Map;
|
std::unordered_map<Vector3i, cPathCell *, VectorHasher> m_Map;
|
||||||
Vector3d m_Destination;
|
Vector3i m_Destination;
|
||||||
Vector3d m_Source;
|
Vector3i m_Source;
|
||||||
int m_StepsLeft;
|
int m_StepsLeft;
|
||||||
|
|
||||||
/* Control fields */
|
/* Control fields */
|
||||||
ePathFinderStatus m_Status;
|
ePathFinderStatus m_Status;
|
||||||
|
|
||||||
/* Final path fields */
|
/* Final path fields */
|
||||||
int m_PointCount;
|
size_t m_CurrentPoint;
|
||||||
int m_CurrentPoint;
|
std::vector<Vector3i> m_PathPoints;
|
||||||
std::vector<Vector3d> m_PathPoints;
|
|
||||||
void AddPoint(Vector3d a_Vector);
|
|
||||||
|
|
||||||
/* Interfacing with the world */
|
/* Interfacing with the world */
|
||||||
cChunk * m_Chunk; // Only valid inside Step()!
|
cChunk * m_Chunk; // Only valid inside Step()!
|
||||||
|
@ -156,7 +156,7 @@ void cVillager::HandleFarmerPrepareFarmCrops()
|
|||||||
void cVillager::HandleFarmerTryHarvestCrops()
|
void cVillager::HandleFarmerTryHarvestCrops()
|
||||||
{
|
{
|
||||||
// Harvest the crops if the villager isn't moving and if the crops are closer then 2 blocks.
|
// Harvest the crops if the villager isn't moving and if the crops are closer then 2 blocks.
|
||||||
if (!m_bMovingToDestination && (GetPosition() - m_CropsPos).Length() < 2)
|
if (!m_IsFollowingPath && (GetPosition() - m_CropsPos).Length() < 2)
|
||||||
{
|
{
|
||||||
// Check if the blocks didn't change while the villager was walking to the coordinates.
|
// Check if the blocks didn't change while the villager was walking to the coordinates.
|
||||||
BLOCKTYPE CropBlock = m_World->GetBlock(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z);
|
BLOCKTYPE CropBlock = m_World->GetBlock(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z);
|
||||||
|
@ -2310,7 +2310,7 @@ void cProtocol180::HandlePacketPlayerPos(cByteBuffer & a_ByteBuffer)
|
|||||||
HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosY);
|
HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosY);
|
||||||
HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosZ);
|
HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosZ);
|
||||||
HANDLE_READ(a_ByteBuffer, ReadBool, bool, IsOnGround);
|
HANDLE_READ(a_ByteBuffer, ReadBool, bool, IsOnGround);
|
||||||
m_Client->HandlePlayerPos(PosX, PosY, PosZ, PosY + 1.62, IsOnGround);
|
m_Client->HandlePlayerPos(PosX, PosY, PosZ, PosY + (m_Client->GetPlayer()->IsCrouched() ? 1.54 : 1.62), IsOnGround);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user