From b8aa38b18d7f7ab78766d2be94e8738e503bacca Mon Sep 17 00:00:00 2001 From: wiseoldman95 Date: Wed, 6 May 2015 17:23:07 +0300 Subject: (duplicate) AI - Livestock escape fixed, water jumping fixed --- src/Mobs/Monster.cpp | 78 ++++++++++++++++++++++++++++++++++++++++++++++------ src/Mobs/Monster.h | 10 +++++++ src/Mobs/Path.cpp | 25 ----------------- 3 files changed, 79 insertions(+), 34 deletions(-) (limited to 'src/Mobs') diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 37774b08f..df9c1f390 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -156,6 +156,11 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) if (m_Path == nullptr) { + if (!EnsureProperDestination(a_Chunk)) + { + StopMovingToPosition(); // Invalid chunks, probably world is loading or something, cancel movement. + return false; + } m_PathFinderDestination = m_FinalDestination; m_Path = new cPath(a_Chunk, GetPosition().Floor(), m_PathFinderDestination.Floor(), 20); } @@ -199,10 +204,12 @@ void cMonster::MoveToWayPoint(cChunk & a_Chunk) { if (m_JumpCoolDown == 0) { - // We're not moving (or barely moving), and waypoint is above us, it means we are hitting something and we should jump. - if ((GetSpeedX() < 0.1) && (GetSpeedZ() < 0.1) && DoesPosYRequireJump(FloorC(m_NextWayPointPosition.y))) + if (DoesPosYRequireJump(FloorC(m_NextWayPointPosition.y))) { - if (IsOnGround() || IsSwimming()) + if ( + (IsOnGround() && (GetSpeedX() == 0) && (GetSpeedY() == 0)) || + (IsSwimming() && (m_GiveUpCounter < 15)) + ) { m_bOnGround = false; m_JumpCoolDown = 20; @@ -252,6 +259,63 @@ void cMonster::MoveToWayPoint(cChunk & a_Chunk) +bool cMonster::EnsureProperDestination(cChunk & a_Chunk) +{ + cChunk * Chunk = a_Chunk.GetNeighborChunk(m_FinalDestination.x, m_FinalDestination.z); + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + int RelX = m_FinalDestination.x - Chunk->GetPosX() * cChunkDef::Width; + int RelZ = m_FinalDestination.z - Chunk->GetPosZ() * cChunkDef::Width; + if ((Chunk == nullptr) || !Chunk->IsValid()) + { + return false; + } + + // If destination in the air, go down to the lowest air block. + while (m_FinalDestination.y > 0) + { + Chunk->GetBlockTypeMeta(RelX, m_FinalDestination.y - 1, RelZ, BlockType, BlockMeta); + if (cBlockInfo::IsSolid(BlockType)) + { + break; + } + m_FinalDestination.y -= 1; + } + + + // If destination in water, go up to the highest water block. + // If destination in solid, go up to first air block. + bool InWater = false; + while (m_FinalDestination.y < cChunkDef::Height) + { + Chunk->GetBlockTypeMeta(RelX, m_FinalDestination.y, RelZ, BlockType, BlockMeta); + if (BlockType == E_BLOCK_STATIONARY_WATER) + { + InWater = true; + } + else if (cBlockInfo::IsSolid(BlockType)) + { + InWater = false; + } + else + { + break; + } + m_FinalDestination.y += 1; + } + if (InWater) + { + m_FinalDestination.y -= 1; + } + + + return true; +} + + + + + void cMonster::MoveToPosition(const Vector3d & a_Position) { m_FinalDestination = a_Position; @@ -292,7 +356,7 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) if (m_Health <= 0) { - // The mob is dead, but we're still animating the "puff" they leave when they die + // The mob is dead, but we're still animating the "puff" they leave when they die. m_DestroyTimer += a_Dt; if (m_DestroyTimer > std::chrono::seconds(1)) { @@ -310,7 +374,7 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) m_Target = nullptr; } - // Process the undead burning in daylight + // Process the undead burning in daylight. HandleDaylightBurning(*Chunk, WouldBurnAt(GetPosition(), *Chunk)); if (TickPathFinding(*Chunk)) { @@ -1121,7 +1185,3 @@ cMonster::eFamily cMonster::GetMobFamily(void) const { return FamilyFromType(m_MobType); } - - - - diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h index c7f38c9f7..a2295777a 100644 --- a/src/Mobs/Monster.h +++ b/src/Mobs/Monster.h @@ -203,8 +203,18 @@ protected: Returns if a path is ready, and therefore if the mob should move to m_NextWayPointPosition */ bool TickPathFinding(cChunk & a_Chunk); + + /** Move in a straight line to the next waypoint in the path, will jump if needed. */ void MoveToWayPoint(cChunk & a_Chunk); + /** Ensures the destination is not buried underground or under water. Also ensures the destination is not in the air. + Only the Y coordinate of m_FinalDestination might be changed. + 1. If m_FinalDestination is the position of a water block, m_FinalDestination's Y will be modified to point to the heighest water block in the pool in the current column. + 2. If m_FinalDestination is the position of a solid, m_FinalDestination's Y will be modified to point to the first airblock above the solid in the current column. + 3. If m_FinalDestination is the position of an air block, Y will keep decreasing until hitting either a solid or water. + Now either 1 or 2 is performed. */ + bool EnsureProperDestination(cChunk & a_Chunk); + /** Resets a pathfinding task, be it due to failure or something else Resets the pathfinder. If m_IsFollowingPath is true, TickPathFinding starts a brand new path. Should only be called by the pathfinder, cMonster::Tick or StopMovingToPosition. */ diff --git a/src/Mobs/Path.cpp b/src/Mobs/Path.cpp index 84d888bf2..ebfb5b630 100644 --- a/src/Mobs/Path.cpp +++ b/src/Mobs/Path.cpp @@ -54,31 +54,6 @@ cPath::cPath( return; } - // 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 - Chunk->GetPosX() * cChunkDef::Width; - int RelZ = m_Destination.z - Chunk->GetPosZ() * cChunkDef::Width; - bool inwater = false; - for (;;) - { - 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; -- cgit v1.2.3 From 7771091099fad43025c63694ccf9362cce384aa8 Mon Sep 17 00:00:00 2001 From: worktycho Date: Wed, 6 May 2015 17:26:59 +0100 Subject: Actually empty the open list --- src/Mobs/Path.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Mobs') diff --git a/src/Mobs/Path.cpp b/src/Mobs/Path.cpp index 84d888bf2..60f88f525 100644 --- a/src/Mobs/Path.cpp +++ b/src/Mobs/Path.cpp @@ -245,7 +245,7 @@ void cPath::FinishCalculation() } m_Map.clear(); - m_OpenList.empty(); + m_OpenList = std::priority_queue, compareHeuristics>{}; } -- cgit v1.2.3 From 753dfb950a6ec880af47ac7c1b0d6d142a138eac Mon Sep 17 00:00:00 2001 From: wiseoldman95 Date: Wed, 6 May 2015 16:52:37 +0300 Subject: AI - Better shade cover --- src/Mobs/Monster.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src/Mobs') diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index df9c1f390..c799e9394 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -378,7 +378,15 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) HandleDaylightBurning(*Chunk, WouldBurnAt(GetPosition(), *Chunk)); if (TickPathFinding(*Chunk)) { - if (m_BurnsInDaylight && WouldBurnAt(m_NextWayPointPosition, *Chunk->GetNeighborChunk(FloorC(m_NextWayPointPosition.x), FloorC(m_NextWayPointPosition.z))) && !IsOnFire() && (m_TicksSinceLastDamaged == 100)) + /* If I burn in daylight, and I won't burn where I'm standing, and I'll burn in my next position, and at least one of those is true: + 1. I am idle + 2. I was not hurt by a player recently. + Then STOP. */ + if ( + m_BurnsInDaylight && ((m_TicksSinceLastDamaged == 100) || (m_EMState == IDLE)) && + WouldBurnAt(m_NextWayPointPosition, *Chunk->GetNeighborChunk(FloorC(m_NextWayPointPosition.x), FloorC(m_NextWayPointPosition.z))) && + !WouldBurnAt(GetPosition(), *Chunk->GetNeighborChunk(FloorC(GetPosition().x), FloorC(GetPosition().z))) + ) { // 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(); -- cgit v1.2.3 From 40af96b100e88faaad451028856c46b0ba15de11 Mon Sep 17 00:00:00 2001 From: wiseoldman95 Date: Wed, 6 May 2015 17:02:50 +0300 Subject: AI - Safer WouldBurnAt() --- src/Mobs/Monster.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/Mobs') diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index c799e9394..84f58ff85 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -383,9 +383,9 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) 2. I was not hurt by a player recently. Then STOP. */ if ( - m_BurnsInDaylight && ((m_TicksSinceLastDamaged == 100) || (m_EMState == IDLE)) && - WouldBurnAt(m_NextWayPointPosition, *Chunk->GetNeighborChunk(FloorC(m_NextWayPointPosition.x), FloorC(m_NextWayPointPosition.z))) && - !WouldBurnAt(GetPosition(), *Chunk->GetNeighborChunk(FloorC(GetPosition().x), FloorC(GetPosition().z))) + m_BurnsInDaylight && ((m_TicksSinceLastDamaged >= 100) || (m_EMState == IDLE)) && + WouldBurnAt(m_NextWayPointPosition, *Chunk) && + !WouldBurnAt(GetPosition(), *Chunk) ) { // 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: @@ -1170,6 +1170,11 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk, bool WouldBurn) bool cMonster::WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk) { + cChunk * Chunk = a_Chunk.GetNeighborChunk(FloorC(m_NextWayPointPosition.x), FloorC(m_NextWayPointPosition.z)); + if ((Chunk == nullptr) || (!Chunk->IsValid())) + { + return false; + } int RelX = FloorC(a_Location.x) - a_Chunk.GetPosX() * cChunkDef::Width; int RelY = FloorC(a_Location.y); int RelZ = FloorC(a_Location.z) - a_Chunk.GetPosZ() * cChunkDef::Width; -- cgit v1.2.3 From 448df85e569e85e1b4da4eac685950273f30ae1f Mon Sep 17 00:00:00 2001 From: tycho Date: Sat, 21 Mar 2015 17:17:26 +0000 Subject: Added support for additional data in the ParticleEffect Packet Also started refactoring how broadcasts are handled --- src/Mobs/Wolf.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/Mobs') diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp index c66763f17..3c2ec1520 100644 --- a/src/Mobs/Wolf.cpp +++ b/src/Mobs/Wolf.cpp @@ -5,6 +5,7 @@ #include "../World.h" #include "../Entities/Player.h" #include "../Items/ItemHandler.h" +#include "Broadcaster.h" @@ -83,13 +84,13 @@ void cWolf::OnRightClicked(cPlayer & a_Player) SetIsTame(true); SetOwner(a_Player.GetName(), a_Player.GetUUID()); m_World->BroadcastEntityStatus(*this, esWolfTamed); - m_World->BroadcastParticleEffect("heart", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5); + m_World->GetBroadcaster().BroadcastParticleEffect("heart", static_cast(GetPosition()), Vector3f{}, 0, 5); } else { // Taming failed m_World->BroadcastEntityStatus(*this, esWolfTaming); - m_World->BroadcastParticleEffect("smoke", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5); + m_World->GetBroadcaster().BroadcastParticleEffect("smoke", static_cast(GetPosition()), Vector3f{}, 0, 5); } } } -- cgit v1.2.3 From 63af47832d37de7829bb2dbfe2df9b63045cf556 Mon Sep 17 00:00:00 2001 From: Tri125 Date: Wed, 6 May 2015 23:12:17 -0400 Subject: Fixed the sound issue with the MagmaCube -Name of the sound is correctly capitalized -Get the appropriate sound depending on its size --- src/Mobs/MagmaCube.cpp | 14 ++++++++++++-- src/Mobs/MagmaCube.h | 4 ++++ 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'src/Mobs') diff --git a/src/Mobs/MagmaCube.cpp b/src/Mobs/MagmaCube.cpp index 3e9abc108..e56cfa4b8 100644 --- a/src/Mobs/MagmaCube.cpp +++ b/src/Mobs/MagmaCube.cpp @@ -7,7 +7,7 @@ cMagmaCube::cMagmaCube(int a_Size) : - super("MagmaCube", mtMagmaCube, "mob.MagmaCube.big", "mob.MagmaCube.big", 0.6 * a_Size, 0.6 * a_Size), + super("MagmaCube", mtMagmaCube, Printf("mob.magmacube.%s", GetSizeName(a_Size).c_str()), Printf("mob.magmacube.%s", GetSizeName(a_Size).c_str()), 0.6 * a_Size, 0.6 * a_Size), m_Size(a_Size) { } @@ -27,4 +27,14 @@ void cMagmaCube::GetDrops(cItems & a_Drops, cEntity * a_Killer) - +const AString cMagmaCube::GetSizeName(int a_Size) const +{ + if (a_Size > 1) + { + return "big"; + } + else + { + return "small"; + } +} diff --git a/src/Mobs/MagmaCube.h b/src/Mobs/MagmaCube.h index d66ea423a..62dd83944 100644 --- a/src/Mobs/MagmaCube.h +++ b/src/Mobs/MagmaCube.h @@ -19,6 +19,10 @@ public: virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; int GetSize(void) const { return m_Size; } + + /** Returns the text describing the slime's size, as used by the client's resource subsystem for sounds. + Returns either "big" or "small". */ + const AString GetSizeName(int a_Size) const; protected: -- cgit v1.2.3 From 9f6192687f84fc97c5f854c778f3b393965794ef Mon Sep 17 00:00:00 2001 From: Tri125 Date: Wed, 6 May 2015 23:29:36 -0400 Subject: Big Magma Cube can now spawn Following the same method as the Slime, Magma Cube can now spawn with the size of 1, 2 or 4. --- src/Mobs/MagmaCube.h | 2 +- src/Mobs/Monster.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Mobs') diff --git a/src/Mobs/MagmaCube.h b/src/Mobs/MagmaCube.h index 62dd83944..d4b3997da 100644 --- a/src/Mobs/MagmaCube.h +++ b/src/Mobs/MagmaCube.h @@ -26,7 +26,7 @@ public: protected: - /// Size of the MagmaCube, 1 .. 3, with 1 being the smallest + /// Size of the MagmaCube, 1, 2 and 4, with 1 being the smallest int m_Size; } ; diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 37774b08f..e86570c77 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -886,7 +886,7 @@ cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType) { case mtMagmaCube: { - toReturn = new cMagmaCube(Random.NextInt(2) + 1); + toReturn = new cMagmaCube(1 << Random.NextInt(3)); // Size 1, 2 or 4 break; } case mtSlime: -- cgit v1.2.3 From 290bc2e37730c14df85b9ce9acd63611ca185434 Mon Sep 17 00:00:00 2001 From: wiseoldman95 Date: Fri, 8 May 2015 17:07:36 +0300 Subject: Spaces in cPath --- src/Mobs/Path.cpp | 1 + src/Mobs/Path.h | 1 + 2 files changed, 2 insertions(+) (limited to 'src/Mobs') diff --git a/src/Mobs/Path.cpp b/src/Mobs/Path.cpp index 6fc9e06c3..8abbc4cac 100644 --- a/src/Mobs/Path.cpp +++ b/src/Mobs/Path.cpp @@ -1,3 +1,4 @@ + #include "Globals.h" #include diff --git a/src/Mobs/Path.h b/src/Mobs/Path.h index 9e893f1d7..0d903adb6 100644 --- a/src/Mobs/Path.h +++ b/src/Mobs/Path.h @@ -1,3 +1,4 @@ + #pragma once /* Wanna use the pathfinder? Put this in your header file: -- cgit v1.2.3 From 1cef39cb73f5a9130d2cb9d497ca44350fb401d8 Mon Sep 17 00:00:00 2001 From: worktycho Date: Fri, 8 May 2015 23:20:22 +0100 Subject: Move chunk position accesses after the chunk validity checks --- src/Mobs/Monster.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/Mobs') diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 84f58ff85..9df5bd930 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -264,12 +264,14 @@ bool cMonster::EnsureProperDestination(cChunk & a_Chunk) cChunk * Chunk = a_Chunk.GetNeighborChunk(m_FinalDestination.x, m_FinalDestination.z); BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - int RelX = m_FinalDestination.x - Chunk->GetPosX() * cChunkDef::Width; - int RelZ = m_FinalDestination.z - Chunk->GetPosZ() * cChunkDef::Width; + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } + + int RelX = m_FinalDestination.x - Chunk->GetPosX() * cChunkDef::Width; + int RelZ = m_FinalDestination.z - Chunk->GetPosZ() * cChunkDef::Width; // If destination in the air, go down to the lowest air block. while (m_FinalDestination.y > 0) -- cgit v1.2.3 From 218010cd96a3e887e7fbd8e18e1b74b7dc481036 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 8 May 2015 23:32:02 +0100 Subject: Fixed some Visual Studio warnings --- src/Mobs/Monster.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/Mobs') diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 84f58ff85..dc950ff7d 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -261,11 +261,11 @@ void cMonster::MoveToWayPoint(cChunk & a_Chunk) bool cMonster::EnsureProperDestination(cChunk & a_Chunk) { - cChunk * Chunk = a_Chunk.GetNeighborChunk(m_FinalDestination.x, m_FinalDestination.z); + cChunk * Chunk = a_Chunk.GetNeighborChunk(FloorC(m_FinalDestination.x), FloorC(m_FinalDestination.z)); BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - int RelX = m_FinalDestination.x - Chunk->GetPosX() * cChunkDef::Width; - int RelZ = m_FinalDestination.z - Chunk->GetPosZ() * cChunkDef::Width; + int RelX = FloorC(m_FinalDestination.x) - Chunk->GetPosX() * cChunkDef::Width; + int RelZ = FloorC(m_FinalDestination.z) - Chunk->GetPosZ() * cChunkDef::Width; if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; @@ -274,7 +274,7 @@ bool cMonster::EnsureProperDestination(cChunk & a_Chunk) // If destination in the air, go down to the lowest air block. while (m_FinalDestination.y > 0) { - Chunk->GetBlockTypeMeta(RelX, m_FinalDestination.y - 1, RelZ, BlockType, BlockMeta); + Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta); if (cBlockInfo::IsSolid(BlockType)) { break; @@ -288,7 +288,7 @@ bool cMonster::EnsureProperDestination(cChunk & a_Chunk) bool InWater = false; while (m_FinalDestination.y < cChunkDef::Height) { - Chunk->GetBlockTypeMeta(RelX, m_FinalDestination.y, RelZ, BlockType, BlockMeta); + Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y), RelZ, BlockType, BlockMeta); if (BlockType == E_BLOCK_STATIONARY_WATER) { InWater = true; -- cgit v1.2.3 From 4642a50d627e5946079068c8aa19aa1e2b27846e Mon Sep 17 00:00:00 2001 From: Tristan Date: Fri, 8 May 2015 20:50:05 -0400 Subject: GetSizeName of cSlime and cMagmaCube is now static --- src/Mobs/MagmaCube.cpp | 2 +- src/Mobs/MagmaCube.h | 2 +- src/Mobs/Slime.cpp | 2 +- src/Mobs/Slime.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/Mobs') diff --git a/src/Mobs/MagmaCube.cpp b/src/Mobs/MagmaCube.cpp index e56cfa4b8..c5dd0def0 100644 --- a/src/Mobs/MagmaCube.cpp +++ b/src/Mobs/MagmaCube.cpp @@ -27,7 +27,7 @@ void cMagmaCube::GetDrops(cItems & a_Drops, cEntity * a_Killer) -const AString cMagmaCube::GetSizeName(int a_Size) const +AString cMagmaCube::GetSizeName(int a_Size) { if (a_Size > 1) { diff --git a/src/Mobs/MagmaCube.h b/src/Mobs/MagmaCube.h index d4b3997da..b914dc867 100644 --- a/src/Mobs/MagmaCube.h +++ b/src/Mobs/MagmaCube.h @@ -22,7 +22,7 @@ public: /** Returns the text describing the slime's size, as used by the client's resource subsystem for sounds. Returns either "big" or "small". */ - const AString GetSizeName(int a_Size) const; + static AString GetSizeName(int a_Size); protected: diff --git a/src/Mobs/Slime.cpp b/src/Mobs/Slime.cpp index e42501e47..7fc4821d8 100644 --- a/src/Mobs/Slime.cpp +++ b/src/Mobs/Slime.cpp @@ -89,7 +89,7 @@ void cSlime::KilledBy(TakeDamageInfo & a_TDI) -const AString cSlime::GetSizeName(int a_Size) const +AString cSlime::GetSizeName(int a_Size) { if (a_Size > 1) { diff --git a/src/Mobs/Slime.h b/src/Mobs/Slime.h index 29605992d..40131b101 100644 --- a/src/Mobs/Slime.h +++ b/src/Mobs/Slime.h @@ -27,7 +27,7 @@ public: /** Returns the text describing the slime's size, as used by the client's resource subsystem for sounds. Returns either "big" or "small". */ - const AString GetSizeName(int a_Size) const; + static AString GetSizeName(int a_Size); protected: -- cgit v1.2.3 From c13b1931ff26a5643c9fe68ab32b1e362cfacd70 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Sat, 9 May 2015 09:25:09 +0200 Subject: More style checking. Spaces around some operators are checked. --- src/Mobs/Monster.h | 2 +- src/Mobs/Path.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Mobs') diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h index a2295777a..5d20ba810 100644 --- a/src/Mobs/Monster.h +++ b/src/Mobs/Monster.h @@ -224,7 +224,7 @@ protected: 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); virtual void HandleFalling(void); diff --git a/src/Mobs/Path.h b/src/Mobs/Path.h index 0d903adb6..adae77984 100644 --- a/src/Mobs/Path.h +++ b/src/Mobs/Path.h @@ -12,7 +12,7 @@ Put this in your .cpp: */ #ifdef COMPILING_PATHFIND_DEBUGGER - /* Note: the COMPILING_PATHFIND_DEBUGGER flag is used by Native/WiseOldMan95 to debug + /* Note: the COMPILING_PATHFIND_DEBUGGER flag is used by Native / WiseOldMan95 to debug this class outside of MCServer. This preprocessor flag is never set when compiling MCServer. */ #include "PathFinderIrrlicht_Head.h" #endif -- cgit v1.2.3 From 8a576a0a35d0db0cfe510213bfb5ec5af1323777 Mon Sep 17 00:00:00 2001 From: wiseoldman95 Date: Sun, 10 May 2015 09:08:42 +0300 Subject: PF - Less calcs per tick --- src/Mobs/Path.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Mobs') diff --git a/src/Mobs/Path.cpp b/src/Mobs/Path.cpp index 8abbc4cac..ba7d615ae 100644 --- a/src/Mobs/Path.cpp +++ b/src/Mobs/Path.cpp @@ -8,7 +8,7 @@ #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 CALCULATIONS_PER_STEP 60 // Higher means more CPU load but faster path calculations. +#define CALCULATIONS_PER_STEP 5 // Higher means more CPU load but faster path calculations. // The only version which guarantees the shortest path is 0, 0. enum class eCellStatus {OPENLIST, CLOSEDLIST, NOLIST}; -- cgit v1.2.3 From 11ef1fd24a48f8982ecf9c798047b0465ca839a2 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 9 May 2015 01:51:25 +0100 Subject: Fixed some warnings and logic errors in Monster.cpp --- src/Mobs/Monster.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src/Mobs') diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index dc950ff7d..1cc6e7391 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -1170,17 +1170,19 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk, bool WouldBurn) bool cMonster::WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk) { - cChunk * Chunk = a_Chunk.GetNeighborChunk(FloorC(m_NextWayPointPosition.x), FloorC(m_NextWayPointPosition.z)); + cChunk * Chunk = a_Chunk.GetNeighborChunk(FloorC(a_Location.x), FloorC(a_Location.z)); if ((Chunk == nullptr) || (!Chunk->IsValid())) { return false; } - int RelX = FloorC(a_Location.x) - a_Chunk.GetPosX() * cChunkDef::Width; + + int RelX = FloorC(a_Location.x) - Chunk->GetPosX() * cChunkDef::Width; int RelY = FloorC(a_Location.y); - int RelZ = FloorC(a_Location.z) - a_Chunk.GetPosZ() * cChunkDef::Width; + int RelZ = FloorC(a_Location.z) - Chunk->GetPosZ() * cChunkDef::Width; + if ( - (a_Chunk.GetSkyLight(RelX, RelY, RelZ) == 15) && // In the daylight - (a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand + (Chunk->GetSkyLight(RelX, RelY, RelZ) == 15) && // In the daylight + (Chunk->GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand (GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime GetWorld()->IsWeatherSunnyAt(POSX_TOINT, POSZ_TOINT) // Not raining ) -- cgit v1.2.3 From a8878dd2b6cee69b7cc92b19c740cc4deb7c9735 Mon Sep 17 00:00:00 2001 From: SafwatHalaby Date: Fri, 15 May 2015 20:25:44 +0300 Subject: uniquePTR --- src/Mobs/Path.cpp | 9 ++------- src/Mobs/Path.h | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) (limited to 'src/Mobs') diff --git a/src/Mobs/Path.cpp b/src/Mobs/Path.cpp index ba7d615ae..dd306af13 100644 --- a/src/Mobs/Path.cpp +++ b/src/Mobs/Path.cpp @@ -215,11 +215,6 @@ bool cPath::Step_Internal() void cPath::FinishCalculation() { - for (auto && pair : m_Map) - { - delete pair.second; - } - m_Map.clear(); m_OpenList = std::priority_queue, compareHeuristics>{}; } @@ -348,7 +343,7 @@ cPathCell * cPath::GetCell(const Vector3i & a_Location) { Cell = new cPathCell(); Cell->m_Location = a_Location; - m_Map[a_Location] = Cell; + m_Map[a_Location] = UniquePtr(Cell); Cell->m_IsSolid = IsSolid(a_Location); Cell->m_Status = eCellStatus::NOLIST; #ifdef COMPILING_PATHFIND_DEBUGGER @@ -360,6 +355,6 @@ cPathCell * cPath::GetCell(const Vector3i & a_Location) } else { - return m_Map[a_Location]; + return m_Map[a_Location].get(); } } diff --git a/src/Mobs/Path.h b/src/Mobs/Path.h index adae77984..008722d29 100644 --- a/src/Mobs/Path.h +++ b/src/Mobs/Path.h @@ -131,7 +131,7 @@ private: /* Pathfinding fields */ std::priority_queue, compareHeuristics> m_OpenList; - std::unordered_map m_Map; + std::unordered_map, VectorHasher> m_Map; Vector3i m_Destination; Vector3i m_Source; int m_StepsLeft; -- cgit v1.2.3 From 5c3a85fba10e801c6553fa943fa85605bbcd4f41 Mon Sep 17 00:00:00 2001 From: worktycho Date: Fri, 15 May 2015 18:54:45 +0100 Subject: Revert "PathFinder - smart pointers" --- src/Mobs/Path.cpp | 9 +++++++-- src/Mobs/Path.h | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'src/Mobs') diff --git a/src/Mobs/Path.cpp b/src/Mobs/Path.cpp index dd306af13..ba7d615ae 100644 --- a/src/Mobs/Path.cpp +++ b/src/Mobs/Path.cpp @@ -215,6 +215,11 @@ bool cPath::Step_Internal() void cPath::FinishCalculation() { + for (auto && pair : m_Map) + { + delete pair.second; + } + m_Map.clear(); m_OpenList = std::priority_queue, compareHeuristics>{}; } @@ -343,7 +348,7 @@ cPathCell * cPath::GetCell(const Vector3i & a_Location) { Cell = new cPathCell(); Cell->m_Location = a_Location; - m_Map[a_Location] = UniquePtr(Cell); + m_Map[a_Location] = Cell; Cell->m_IsSolid = IsSolid(a_Location); Cell->m_Status = eCellStatus::NOLIST; #ifdef COMPILING_PATHFIND_DEBUGGER @@ -355,6 +360,6 @@ cPathCell * cPath::GetCell(const Vector3i & a_Location) } else { - return m_Map[a_Location].get(); + return m_Map[a_Location]; } } diff --git a/src/Mobs/Path.h b/src/Mobs/Path.h index 008722d29..adae77984 100644 --- a/src/Mobs/Path.h +++ b/src/Mobs/Path.h @@ -131,7 +131,7 @@ private: /* Pathfinding fields */ std::priority_queue, compareHeuristics> m_OpenList; - std::unordered_map, VectorHasher> m_Map; + std::unordered_map m_Map; Vector3i m_Destination; Vector3i m_Source; int m_StepsLeft; -- cgit v1.2.3 From 4ffc6621a9ca976f95eeda80e7c073ee932af85f Mon Sep 17 00:00:00 2001 From: SafwatHalaby Date: Fri, 15 May 2015 20:25:44 +0300 Subject: PathFinder uses UniquePtr for cell map. --- src/Mobs/Path.cpp | 9 ++------- src/Mobs/Path.h | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) (limited to 'src/Mobs') diff --git a/src/Mobs/Path.cpp b/src/Mobs/Path.cpp index ba7d615ae..dd306af13 100644 --- a/src/Mobs/Path.cpp +++ b/src/Mobs/Path.cpp @@ -215,11 +215,6 @@ bool cPath::Step_Internal() void cPath::FinishCalculation() { - for (auto && pair : m_Map) - { - delete pair.second; - } - m_Map.clear(); m_OpenList = std::priority_queue, compareHeuristics>{}; } @@ -348,7 +343,7 @@ cPathCell * cPath::GetCell(const Vector3i & a_Location) { Cell = new cPathCell(); Cell->m_Location = a_Location; - m_Map[a_Location] = Cell; + m_Map[a_Location] = UniquePtr(Cell); Cell->m_IsSolid = IsSolid(a_Location); Cell->m_Status = eCellStatus::NOLIST; #ifdef COMPILING_PATHFIND_DEBUGGER @@ -360,6 +355,6 @@ cPathCell * cPath::GetCell(const Vector3i & a_Location) } else { - return m_Map[a_Location]; + return m_Map[a_Location].get(); } } diff --git a/src/Mobs/Path.h b/src/Mobs/Path.h index adae77984..008722d29 100644 --- a/src/Mobs/Path.h +++ b/src/Mobs/Path.h @@ -131,7 +131,7 @@ private: /* Pathfinding fields */ std::priority_queue, compareHeuristics> m_OpenList; - std::unordered_map m_Map; + std::unordered_map, VectorHasher> m_Map; Vector3i m_Destination; Vector3i m_Source; int m_StepsLeft; -- cgit v1.2.3 From 29e31c5be95abd6a7122a525f53d80f4576e49b2 Mon Sep 17 00:00:00 2001 From: SafwatHalaby Date: Sat, 16 May 2015 14:05:33 +0300 Subject: Pathfinder - approximated paths when original destination unreachable --- src/Mobs/AggressiveMonster.cpp | 1 - src/Mobs/Monster.cpp | 121 ++++++++++++++++++++++++++++++++--------- src/Mobs/Monster.h | 7 +++ src/Mobs/Path.cpp | 98 +++++++++++++++++++++++++-------- src/Mobs/Path.h | 21 ++++++- 5 files changed, 193 insertions(+), 55 deletions(-) (limited to 'src/Mobs') diff --git a/src/Mobs/AggressiveMonster.cpp b/src/Mobs/AggressiveMonster.cpp index d0fb79f6d..055ff47d2 100644 --- a/src/Mobs/AggressiveMonster.cpp +++ b/src/Mobs/AggressiveMonster.cpp @@ -36,7 +36,6 @@ void cAggressiveMonster::InStateChasing(std::chrono::milliseconds a_Dt) return; } } - MoveToPosition(m_Target->GetPosition()); } } diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index f3f8c6b24..a29d67d15 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -89,7 +89,7 @@ cMonster::cMonster(const AString & a_ConfigName, eMonsterType a_MobType, const A , m_SoundDeath(a_SoundDeath) , m_AttackRate(3) , m_AttackDamage(1) - , m_AttackRange(2) + , m_AttackRange(1) , m_AttackInterval(0) , m_SightDistance(25) , m_DropChanceWeapon(0.085f) @@ -147,10 +147,15 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) (Recalculate lots when close, calculate rarely when far) */ if ( ((GetPosition() - m_PathFinderDestination).Length() < 0.25) || - ((m_TicksSinceLastPathReset > 10) && (m_TicksSinceLastPathReset > (0.15 * (m_FinalDestination - GetPosition()).SqrLength()))) + ((m_TicksSinceLastPathReset > 10) && (m_TicksSinceLastPathReset > (0.4 * (m_FinalDestination - GetPosition()).SqrLength()))) ) { - ResetPathFinding(); + /* Re-calculating is expensive when there's no path to target, and it results in mobs freezing very often as a result of always recalculating. + This is a workaround till we get better path recalculation. */ + if (!m_NoPathToTarget) + { + ResetPathFinding(); + } } } @@ -161,12 +166,21 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) StopMovingToPosition(); // Invalid chunks, probably world is loading or something, cancel movement. return false; } + m_NoPathToTarget = false; + m_NoMoreWayPoints = false; m_PathFinderDestination = m_FinalDestination; m_Path = new cPath(a_Chunk, GetPosition().Floor(), m_PathFinderDestination.Floor(), 20); } switch (m_Path->Step(a_Chunk)) { + case ePathFinderStatus::NEARBY_FOUND: + { + m_NoPathToTarget = true; + m_Path->AcceptNearbyPath(); + break; + } + case ePathFinderStatus::PATH_NOT_FOUND: { StopMovingToPosition(); // Give up pathfinding to that destination. @@ -179,15 +193,22 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) } case ePathFinderStatus::PATH_FOUND: { - if (--m_GiveUpCounter == 0) + if (m_NoMoreWayPoints || (--m_GiveUpCounter == 0)) { ResetPathFinding(); // Try to calculate a path again. return false; } - else if (!m_Path->IsLastPoint() && (m_Path->IsFirstPoint() || ReachedNextWaypoint())) // Have we arrived at the next cell, as denoted by m_NextWayPointPosition? + else if (!m_Path->IsLastPoint()) // Have we arrived at the next cell, as denoted by m_NextWayPointPosition? + { + if ((m_Path->IsFirstPoint() || ReachedNextWaypoint())) + { + m_NextWayPointPosition = Vector3d(0.5, 0, 0.5) + m_Path->GetNextPoint(); + m_GiveUpCounter = 40; // Give up after 40 ticks (2 seconds) if failed to reach m_NextWayPointPosition. + } + } + else { - m_NextWayPointPosition = Vector3d(0.5, 0, 0.5) + m_Path->GetNextPoint(); - m_GiveUpCounter = 40; // Give up after 40 ticks (2 seconds) if failed to reach m_NextWayPointPosition. + m_NoMoreWayPoints = true; } return true; } @@ -269,21 +290,59 @@ bool cMonster::EnsureProperDestination(cChunk & a_Chunk) { return false; } - + int RelX = FloorC(m_FinalDestination.x) - Chunk->GetPosX() * cChunkDef::Width; int RelZ = FloorC(m_FinalDestination.z) - Chunk->GetPosZ() * cChunkDef::Width; - // If destination in the air, go down to the lowest air block. - while (m_FinalDestination.y > 0) + // If destination in the air, first try to go 1 block north, or east, or west. + // This fixes the player leaning issue. + // If that failed, we instead go down to the lowest air block. + Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta); + if (!cBlockInfo::IsSolid(BlockType)) { - Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta); - if (cBlockInfo::IsSolid(BlockType)) + bool InTheAir = true; + int x, z; + for (z = -1; z <= 1; ++z) { - break; + for (x = -1; x <= 1; ++x) + { + if ((x==0) && (z==0)) + { + continue; + } + Chunk = a_Chunk.GetNeighborChunk(FloorC(m_FinalDestination.x+x), FloorC(m_FinalDestination.z+z)); + if ((Chunk == nullptr) || !Chunk->IsValid()) + { + return false; + } + RelX = FloorC(m_FinalDestination.x+x) - Chunk->GetPosX() * cChunkDef::Width; + RelZ = FloorC(m_FinalDestination.z+z) - Chunk->GetPosZ() * cChunkDef::Width; + Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta); + if (cBlockInfo::IsSolid(BlockType)) + { + m_FinalDestination.x += x; + m_FinalDestination.z += z; + InTheAir = false; + goto breakBothLoops; + } + } } - m_FinalDestination.y -= 1; - } + breakBothLoops: + // Go down to the lowest air block. + if (InTheAir) + { + while (m_FinalDestination.y > 0) + { + Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta); + if (cBlockInfo::IsSolid(BlockType)) + { + break; + } + m_FinalDestination.y -= 1; + } + } + } // If destination in water, go up to the highest water block. // If destination in solid, go up to first air block. @@ -447,21 +506,29 @@ void cMonster::SetPitchAndYawFromDestination() } } + + + Vector3d BodyDistance = m_NextWayPointPosition - GetPosition(); + double BodyRotation, BodyPitch; + BodyDistance.Normalize(); + VectorToEuler(BodyDistance.x, BodyDistance.y, BodyDistance.z, BodyRotation, BodyPitch); + SetYaw(BodyRotation); + Vector3d Distance = FinalDestination - GetPosition(); { - double Rotation, Pitch; + double HeadRotation, HeadPitch; Distance.Normalize(); - VectorToEuler(Distance.x, Distance.y, Distance.z, Rotation, Pitch); - SetHeadYaw(Rotation); - SetPitch(-Pitch); - } - - { - Vector3d BodyDistance = m_NextWayPointPosition - GetPosition(); - double Rotation, Pitch; - BodyDistance.Normalize(); - VectorToEuler(BodyDistance.x, BodyDistance.y, BodyDistance.z, Rotation, Pitch); - SetYaw(Rotation); + VectorToEuler(Distance.x, Distance.y, Distance.z, HeadRotation, HeadPitch); + if (abs(BodyRotation - HeadRotation) < 120) + { + SetHeadYaw(HeadRotation); + SetPitch(-HeadPitch); + } + else // We're not an owl. If it's more than 120, don't look behind and instead look at where you're walking. + { + SetHeadYaw(BodyRotation); + SetPitch(-BodyPitch); + } } } diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h index 5d20ba810..c4043b0e5 100644 --- a/src/Mobs/Monster.h +++ b/src/Mobs/Monster.h @@ -180,6 +180,13 @@ protected: /** Coordinates for the ultimate, final destination last given to the pathfinder. */ Vector3d m_PathFinderDestination; + /** True if there's no path to target and we're walking to an approximated location. */ + bool m_NoPathToTarget; + + /** Whether The mob has finished their path, note that this does not imply reaching the destination, + the destination may sometimes differ from the current path. */ + bool m_NoMoreWayPoints; + /** 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 solid, goes up to find first nonsolid block, and returns that. diff --git a/src/Mobs/Path.cpp b/src/Mobs/Path.cpp index dd306af13..ba8046a2b 100644 --- a/src/Mobs/Path.cpp +++ b/src/Mobs/Path.cpp @@ -8,7 +8,7 @@ #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 CALCULATIONS_PER_STEP 5 // Higher means more CPU load but faster path calculations. +#define CALCULATIONS_PER_STEP 10 // Higher means more CPU load but faster path calculations. // The only version which guarantees the shortest path is 0, 0. enum class eCellStatus {OPENLIST, CLOSEDLIST, NOLIST}; @@ -44,7 +44,8 @@ cPath::cPath( 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) + m_Chunk(&a_Chunk), + m_BadChunkFound(false) { // TODO: if src not walkable OR dest not walkable, then abort. // Borrow a new "isWalkable" from ProcessIfWalkable, make ProcessIfWalkable also call isWalkable @@ -55,6 +56,7 @@ cPath::cPath( return; } + m_NearestPointToTarget = GetCell(m_Source); m_Status = ePathFinderStatus::CALCULATING; m_StepsLeft = a_MaxSteps; @@ -81,15 +83,20 @@ cPath::~cPath() ePathFinderStatus cPath::Step(cChunk & a_Chunk) { m_Chunk = &a_Chunk; - if (m_Status != ePathFinderStatus::CALCULATING) { return m_Status; } - if (m_StepsLeft == 0) + if (m_BadChunkFound) { FinishCalculation(ePathFinderStatus::PATH_NOT_FOUND); + return m_Status; + } + + if (m_StepsLeft == 0) + { + AttemptToFindAlternative(); } else { @@ -102,9 +109,9 @@ ePathFinderStatus cPath::Step(cChunk & a_Chunk) break; // if we're here, m_Status must have changed either to PATH_FOUND or PATH_NOT_FOUND. } } - } - m_Chunk = nullptr; + m_Chunk = nullptr; + } return m_Status; } @@ -112,6 +119,17 @@ ePathFinderStatus cPath::Step(cChunk & a_Chunk) +Vector3i cPath::AcceptNearbyPath() +{ + ASSERT(m_Status == ePathFinderStatus::NEARBY_FOUND); + m_Status = ePathFinderStatus::PATH_FOUND; + return m_Destination; +} + + + + + bool cPath::IsSolid(const Vector3i & a_Location) { ASSERT(m_Chunk != nullptr); @@ -119,6 +137,7 @@ bool cPath::IsSolid(const Vector3i & a_Location) auto Chunk = m_Chunk->GetNeighborChunk(a_Location.x, a_Location.z); if ((Chunk == nullptr) || !Chunk->IsValid()) { + m_BadChunkFound = true; return true; } m_Chunk = Chunk; @@ -149,34 +168,29 @@ bool cPath::Step_Internal() { cPathCell * CurrentCell = OpenListPop(); - // Path not reachable, open list exauhsted. + // Path not reachable. if (CurrentCell == nullptr) { - FinishCalculation(ePathFinderStatus::PATH_NOT_FOUND); - ASSERT(m_Status == ePathFinderStatus::PATH_NOT_FOUND); + AttemptToFindAlternative(); return true; } // Path found. - if ( - (CurrentCell->m_Location == m_Destination + Vector3i(0, 0, 1)) || - (CurrentCell->m_Location == m_Destination + Vector3i(1, 0, 0)) || - (CurrentCell->m_Location == m_Destination + Vector3i(-1, 0, 0)) || - (CurrentCell->m_Location == m_Destination + Vector3i(0, 0, -1)) || - (CurrentCell->m_Location == m_Destination + Vector3i(0, -1, 0)) - ) + if (CurrentCell->m_Location == m_Destination) { - do - { - m_PathPoints.push_back(CurrentCell->m_Location); // Populate the cPath with points. - CurrentCell = CurrentCell->m_Parent; - } while (CurrentCell != nullptr); - + BuildPath(); FinishCalculation(ePathFinderStatus::PATH_FOUND); return true; } - // Calculation not finished yet, process a currentCell by inspecting all neighbors. + // Calculation not finished yet. + // Check if we have a new NearestPoint. + if (CurrentCell->m_H < m_NearestPointToTarget->m_H) + { + m_NearestPointToTarget = CurrentCell; + } + + // process a currentCell by inspecting all neighbors. // Check North, South, East, West on all 3 different heights. int i; @@ -213,6 +227,38 @@ bool cPath::Step_Internal() +void cPath::AttemptToFindAlternative() +{ + if (m_NearestPointToTarget == GetCell(m_Source)) + { + FinishCalculation(ePathFinderStatus::PATH_NOT_FOUND); + } + else + { + m_Destination = m_NearestPointToTarget->m_Location; + BuildPath(); + FinishCalculation(ePathFinderStatus::NEARBY_FOUND); + } +} + + + + + +void cPath::BuildPath() +{ + cPathCell * CurrentCell = GetCell(m_Destination); + do + { + m_PathPoints.push_back(CurrentCell->m_Location); // Populate the cPath with points. + CurrentCell = CurrentCell->m_Parent; + } while (CurrentCell != nullptr); +} + + + + + void cPath::FinishCalculation() { m_Map.clear(); @@ -225,6 +271,10 @@ void cPath::FinishCalculation() void cPath::FinishCalculation(ePathFinderStatus a_NewStatus) { + if (m_BadChunkFound) + { + a_NewStatus = ePathFinderStatus::PATH_NOT_FOUND; + } m_Status = a_NewStatus; FinishCalculation(); } @@ -250,7 +300,7 @@ cPathCell * cPath::OpenListPop() // Popping from the open list also means addin { if (m_OpenList.size() == 0) { - return nullptr; // We've exhausted the search space and nothing was found, this will trigger a PATH_NOT_FOUND status. + return nullptr; // We've exhausted the search space and nothing was found, this will trigger a PATH_NOT_FOUND or NEARBY_FOUND status. } cPathCell * Ret = m_OpenList.top(); diff --git a/src/Mobs/Path.h b/src/Mobs/Path.h index 008722d29..7a4182f17 100644 --- a/src/Mobs/Path.h +++ b/src/Mobs/Path.h @@ -23,7 +23,7 @@ Put this in your .cpp: class cChunk; /* Various little structs and classes */ -enum class ePathFinderStatus {CALCULATING, PATH_FOUND, PATH_NOT_FOUND}; +enum class ePathFinderStatus {CALCULATING, PATH_FOUND, PATH_NOT_FOUND, NEARBY_FOUND}; struct cPathCell; // Defined inside Path.cpp class compareHeuristics { @@ -62,9 +62,17 @@ public: /** Destroys the path and frees its memory. */ ~cPath(); - /** Performs part of the path calculation and returns true if the path computation has finished. */ + /** Performs part of the path calculation and returns the appropriate status. + If NEARBY_FOUND is returned, it means that the destination is not reachable, but a nearby destination + is reachable. If the user likes the alternative destination, they can call AcceptNearbyPath to treat the path as found, + and to make consequent calls to step return PATH_FOUND*/ ePathFinderStatus Step(cChunk & a_Chunk); + /** Called after the PathFinder's step returns NEARBY_FOUND. + Changes the PathFinder status from NEARBY_FOUND to PATH_FOUND, returns the nearby destination that + the PathFinder found a path to. */ + Vector3i AcceptNearbyPath(); + /* Point retrieval functions, inlined for performance. */ /** Returns the next point in the path. */ inline Vector3i GetNextPoint() @@ -93,7 +101,10 @@ public: /** Returns the total number of points this path has. */ inline int GetPointCount() { - ASSERT(m_Status == ePathFinderStatus::PATH_FOUND); + if (m_Status != ePathFinderStatus::PATH_FOUND) + { + return 0; + } return m_PathPoints.size(); } @@ -119,6 +130,8 @@ private: 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(ePathFinderStatus a_NewStatus); // Clears the memory used for calculating the path and changes the status. + void AttemptToFindAlternative(); + void BuildPath(); /* Openlist and closedlist management */ void OpenListAdd(cPathCell * a_Cell); @@ -135,6 +148,7 @@ private: Vector3i m_Destination; Vector3i m_Source; int m_StepsLeft; + cPathCell * m_NearestPointToTarget; /* Control fields */ ePathFinderStatus m_Status; @@ -145,6 +159,7 @@ private: /* Interfacing with the world */ cChunk * m_Chunk; // Only valid inside Step()! + bool m_BadChunkFound; #ifdef COMPILING_PATHFIND_DEBUGGER #include "../path_irrlicht.cpp" #endif -- cgit v1.2.3 From d852209f8db9129a3d135a4f7034878d1438a57b Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Tue, 19 May 2015 09:29:27 +0100 Subject: Manual merge of #2066 --- src/Mobs/Monster.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Mobs') diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index a29d67d15..2b00f6959 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -519,7 +519,7 @@ void cMonster::SetPitchAndYawFromDestination() double HeadRotation, HeadPitch; Distance.Normalize(); VectorToEuler(Distance.x, Distance.y, Distance.z, HeadRotation, HeadPitch); - if (abs(BodyRotation - HeadRotation) < 120) + if (std::abs(BodyRotation - HeadRotation) < 120) { SetHeadYaw(HeadRotation); SetPitch(-HeadPitch); -- cgit v1.2.3