diff options
Diffstat (limited to 'src/Mobs')
-rw-r--r-- | src/Mobs/Monster.cpp | 32 | ||||
-rw-r--r-- | src/Mobs/Monster.h | 6 | ||||
-rw-r--r-- | src/Mobs/Path.cpp | 67 | ||||
-rw-r--r-- | src/Mobs/Path.h | 27 | ||||
-rw-r--r-- | src/Mobs/Skeleton.cpp | 20 | ||||
-rw-r--r-- | src/Mobs/Skeleton.h | 5 | ||||
-rw-r--r-- | src/Mobs/Zombie.cpp | 24 | ||||
-rw-r--r-- | src/Mobs/Zombie.h | 8 |
8 files changed, 60 insertions, 129 deletions
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index e225ff9b1..9b9bec51e 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -121,7 +121,7 @@ void cMonster::SpawnOn(cClientHandle & a_Client) -void cMonster::TickPathFinding() +void cMonster::TickPathFinding(cChunk & a_Chunk) { if (m_Path == nullptr) @@ -131,18 +131,18 @@ void cMonster::TickPathFinding() // Can someone explain why are these two NOT THE SAME??? // m_Path = new cPath(GetWorld(), GetPosition(), m_FinalDestination, 30); - m_Path = new cPath(GetWorld(), Vector3d(floor(position.x), floor(position.y), floor(position.z)), Vector3d(floor(Dest.x), floor(Dest.y), floor(Dest.z)), 20); + 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(); + m_PathStatus = m_Path->Step(&a_Chunk); switch (m_PathStatus) { case ePathFinderStatus::PATH_NOT_FOUND: { - FinishPathFinding(); + ResetPathFinding(); break; } @@ -164,7 +164,7 @@ void cMonster::TickPathFinding() } if (m_Path->IsLastPoint()) { - FinishPathFinding(); + ResetPathFinding(); } break; @@ -191,7 +191,7 @@ void cMonster::MoveToPosition(const Vector3d & a_Position) void cMonster::StopMovingToPosition() { m_bMovingToDestination = false; - FinishPathFinding(); + ResetPathFinding(); } @@ -209,7 +209,7 @@ bool cMonster::IsCoordinateInTraversedList(Vector3i a_Coords) /* 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::FinishPathFinding(void) +void cMonster::ResetPathFinding(void) { if (m_Path != nullptr) { @@ -254,6 +254,7 @@ bool cMonster::ReachedFinalDestination() void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) { super::Tick(a_Dt, a_Chunk); + GET_AND_VERIFY_CURRENT_CHUNK(Chunk, POSX_TOINT, POSZ_TOINT); if (m_Health <= 0) { @@ -276,7 +277,8 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) } // Burning in daylight - HandleDaylightBurning(a_Chunk); + bool WouldBurnRightNow = WouldBurnAt(GetPosition(), *Chunk); // cached so that we use it twice, spares some cycles. + HandleDaylightBurning(*Chunk, WouldBurnRightNow); @@ -293,14 +295,19 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) } } - TickPathFinding(); + 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) { - FinishPathFinding(); + 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 { @@ -1091,7 +1098,7 @@ void cMonster::AddRandomWeaponDropItem(cItems & a_Drops, short a_LootingLevel) -void cMonster::HandleDaylightBurning(cChunk & a_Chunk) +void cMonster::HandleDaylightBurning(cChunk & a_Chunk, bool WouldBurn) { if (!m_BurnsInDaylight) { @@ -1110,7 +1117,7 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk) return; } - if (WouldBurnAt(GetPosition(), a_Chunk)) + if (!IsOnFire() && WouldBurn) { // Burn for 100 ticks, then decide again StartBurning(100); @@ -1129,7 +1136,6 @@ bool cMonster::WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk) (a_Chunk.GetSkyLight(RelX, RelY, RelZ) == 15) && // In the daylight (a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand (GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime - !IsOnFire() && // Not already burning GetWorld()->IsWeatherSunnyAt(POSX_TOINT, POSZ_TOINT) // Not raining ) { diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h index 43861e021..9699e74ad 100644 --- a/src/Mobs/Monster.h +++ b/src/Mobs/Monster.h @@ -206,9 +206,9 @@ protected: /** Finds the next place to go This is based on the ultimate, final destination and the current position, as well as the traversed coordinates, and any environmental hazards */ - void TickPathFinding(void); + void TickPathFinding(cChunk & a_Chunk); /** Finishes a pathfinding task, be it due to failure or something else */ - void FinishPathFinding(void); + void ResetPathFinding(void); /** Sets the body yaw and head yaw/pitch based on next/ultimate destinations */ void SetPitchAndYawFromDestination(void); @@ -244,7 +244,7 @@ protected: bool m_CanPickUpLoot; int m_TicksSinceLastDamaged; // How many ticks ago we were last damaged by a player? - void HandleDaylightBurning(cChunk & a_Chunk); + void HandleDaylightBurning(cChunk & a_Chunk, bool WouldBurn); bool WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk); bool m_BurnsInDaylight; double m_RelativeWalkSpeed; diff --git a/src/Mobs/Path.cpp b/src/Mobs/Path.cpp index 0cb03c925..32eff9d2b 100644 --- a/src/Mobs/Path.cpp +++ b/src/Mobs/Path.cpp @@ -1,12 +1,9 @@ #include "Globals.h" -#ifndef COMPILING_PATHFIND_DEBUGGER - /* MCServer headers */ - #include "../World.h" - #include "../Chunk.h" -#endif #include <cmath> + #include "Path.h" +#include "../Chunk.h" #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. @@ -38,18 +35,17 @@ bool compareHeuristics::operator()(cPathCell * & a_Cell1, cPathCell * & a_Cell2) /* cPath implementation */ cPath::cPath( - cWorld * a_World, + cChunk * a_Chunk, const Vector3d & a_StartingPoint, const Vector3d & a_EndingPoint, int a_MaxSteps, double a_BoundingBoxWidth, double a_BoundingBoxHeight, int a_MaxUp, int a_MaxDown ) { + ASSERT(m_Chunk != nullptr); // TODO: if src not walkable OR dest not walkable, then abort. // Borrow a new "isWalkable" from ProcessIfWalkable, make ProcessIfWalkable also call isWalkable - m_World = a_World; - // m_World = cRoot::Get()->GetDefaultWorld(); - + m_Chunk = a_Chunk; m_Source = a_StartingPoint.Floor(); m_Destination = a_EndingPoint.Floor(); @@ -65,6 +61,7 @@ cPath::cPath( m_PointCount = 0; ProcessCell(GetCell(a_StartingPoint), nullptr, 0); + m_Chunk = nullptr; } @@ -83,8 +80,10 @@ cPath::~cPath() -ePathFinderStatus cPath::Step() +ePathFinderStatus cPath::Step(cChunk * a_Chunk) { + m_Chunk = a_Chunk; + ASSERT(m_Chunk != nullptr); if (m_Status != ePathFinderStatus::CALCULATING) { return m_Status; @@ -106,6 +105,7 @@ ePathFinderStatus cPath::Step() } } } + m_Chunk = nullptr; return m_Status; } @@ -113,15 +113,25 @@ ePathFinderStatus cPath::Step() -#ifndef COMPILING_PATHFIND_DEBUGGER bool cPath::IsSolid(const Vector3d & a_Location) { - int ChunkX, ChunkZ; - m_Item_CurrentBlock = a_Location; - cChunkDef::BlockToChunk(a_Location.x, a_Location.z, ChunkX, ChunkZ); - return !m_World->DoWithChunk(ChunkX, ChunkZ, * this); + ASSERT(m_Chunk != nullptr); + m_Chunk = m_Chunk->GetNeighborChunk(a_Location.x, a_Location.z); + if (!m_Chunk->IsValid()) + { + return true; + } + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + int RelX = a_Location.x - m_Chunk->GetPosX() * cChunkDef::Width; + int RelZ = a_Location.z - m_Chunk->GetPosZ() * cChunkDef::Width; + m_Chunk->GetBlockTypeMeta(RelX, a_Location.y, RelZ, BlockType, BlockMeta); + 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. + } + return cBlockInfo::IsSolid(BlockType); } -#endif @@ -352,28 +362,3 @@ void cPath::AddPoint(Vector3d a_Vector) m_PathPoints.push_back(a_Vector); ++m_PointCount; } - - - - - -#ifndef COMPILING_PATHFIND_DEBUGGER -bool cPath::Item(cChunk * a_Chunk) // returns FALSE if there's a solid or if we failed. -{ - int RelX = m_Item_CurrentBlock.x - a_Chunk->GetPosX() * cChunkDef::Width; - int RelZ = m_Item_CurrentBlock.z - a_Chunk->GetPosZ() * cChunkDef::Width; - - if (!a_Chunk->IsValid()) - { - return false; - } - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - a_Chunk->GetBlockTypeMeta(RelX, m_Item_CurrentBlock.y, RelZ, BlockType, BlockMeta); - return (!cBlockInfo::IsSolid(BlockType)); - - // TODO Maybe I should queue several blocks and call item() at once for all of them for better performance? - // I think Worktycho said each item() call needs 2 locks. - -} -#endif diff --git a/src/Mobs/Path.h b/src/Mobs/Path.h index 05fd59155..9927d0a34 100644 --- a/src/Mobs/Path.h +++ b/src/Mobs/Path.h @@ -18,12 +18,8 @@ Put this in your .cpp: #include <unordered_map> -/* MCServer forward declarations */ -#ifndef COMPILING_PATHFIND_DEBUGGER - -// fwd: cChunkMap.h -typedef cItemCallback<cChunk> cChunkCallback; -#endif +//fwd: ../Chunk.h +class cChunk; /* Various little structs and classes */ enum class ePathFinderStatus {CALCULATING, PATH_FOUND, PATH_NOT_FOUND}; @@ -35,9 +31,6 @@ public: }; class cPath -#ifndef COMPILING_PATHFIND_DEBUGGER -: public cChunkCallback -#endif { public: /** Creates a pathfinder instance. A Mob will probably need a single pathfinder instance for its entire life. @@ -59,7 +52,7 @@ public: @param a_EndingPoint "The block where the Zombie's knees want to be". @param a_MaxSteps The maximum steps before giving up. */ cPath( - cWorld * a_World, + cChunk * a_Chunk, const Vector3d & a_StartingPoint, const Vector3d & a_EndingPoint, int a_MaxSteps, double a_BoundingBoxWidth = 1, double a_BoundingBoxHeight = 2, int a_MaxUp = 1, int a_MaxDown = 1 @@ -69,7 +62,7 @@ public: ~cPath(); /** Performs part of the path calculation and returns true if the path computation has finished. */ - ePathFinderStatus Step(); + ePathFinderStatus Step(cChunk * a_Chunk); /* Point retrieval functions, inlined for performance. */ /** Returns the next point in the path. */ @@ -147,15 +140,9 @@ private: std::vector<Vector3d> m_PathPoints; void AddPoint(Vector3d a_Vector); - /* Interfacing with MCServer's world */ - cWorld * m_World; - #ifndef COMPILING_PATHFIND_DEBUGGER - Vector3d m_Item_CurrentBlock; // Read by Item();, it's the only way to "pass it" parameters -protected: - virtual bool Item(cChunk * a_Chunk) override; - - /* Interfacing with Irrlicht, has nothing to do with MCServer*/ - #else + /* Interfacing with the world */ + cChunk * m_Chunk; // Only valid inside Step()! + #ifdef COMPILING_PATHFIND_DEBUGGER #include "../path_irrlicht.cpp" #endif }; diff --git a/src/Mobs/Skeleton.cpp b/src/Mobs/Skeleton.cpp index ef049f8d4..f99404669 100644 --- a/src/Mobs/Skeleton.cpp +++ b/src/Mobs/Skeleton.cpp @@ -48,26 +48,6 @@ void cSkeleton::GetDrops(cItems & a_Drops, cEntity * a_Killer) -void cSkeleton::MoveToPosition(const Vector3d & a_Position) -{ - // Todo use WouldBurnAt(), not sure how to obtain a chunk though... - super::MoveToPosition(a_Position); // Look at the player and update m_Destination to hit them if they're close - - // If the destination is sufficiently skylight challenged AND the skeleton isn't on fire AND we weren't attacked recently then block the movement - if ( - !IsOnFire() && - (m_World->GetBlockSkyLight((int)floor(a_Position.x), (int)floor(a_Position.y), (int)floor(a_Position.z)) - m_World->GetSkyDarkness() > 8) && - m_TicksSinceLastDamaged == 100 - ) - { - StopMovingToPosition(); - } -} - - - - - void cSkeleton::Attack(std::chrono::milliseconds a_Dt) { m_AttackInterval += (static_cast<float>(a_Dt.count()) / 1000) * m_AttackRate; diff --git a/src/Mobs/Skeleton.h b/src/Mobs/Skeleton.h index 9c49c52fb..1b6ce4bf2 100644 --- a/src/Mobs/Skeleton.h +++ b/src/Mobs/Skeleton.h @@ -11,19 +11,18 @@ class cSkeleton : public cAggressiveMonster { typedef cAggressiveMonster super; - + public: cSkeleton(bool IsWither); CLASS_PROTODEF(cSkeleton) virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; - virtual void MoveToPosition(const Vector3d & a_Position) override; virtual void Attack(std::chrono::milliseconds a_Dt) override; virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual bool IsUndead(void) override { return true; } - + bool IsWither(void) const { return m_bIsWither; } private: diff --git a/src/Mobs/Zombie.cpp b/src/Mobs/Zombie.cpp index b2738050e..fa4ac855d 100644 --- a/src/Mobs/Zombie.cpp +++ b/src/Mobs/Zombie.cpp @@ -37,27 +37,3 @@ void cZombie::GetDrops(cItems & a_Drops, cEntity * a_Killer) AddRandomArmorDropItem(a_Drops, LootingLevel); AddRandomWeaponDropItem(a_Drops, LootingLevel); } - - - - - -void cZombie::MoveToPosition(const Vector3d & a_Position) -{ - // Todo use WouldBurnAt(), not sure how to obtain a chunk though... - super::MoveToPosition(a_Position); // Look at the player and update m_Destination to hit them if they're close - - // If the destination is sufficiently skylight challenged AND the skeleton isn't on fire AND we weren't attacked recently then block the movement - if ( - !IsOnFire() && - (m_World->GetBlockSkyLight((int)floor(a_Position.x), (int)floor(a_Position.y), (int)floor(a_Position.z)) - m_World->GetSkyDarkness() > 8) && - m_TicksSinceLastDamaged == 100 - ) - { - StopMovingToPosition(); - } -} - - - - diff --git a/src/Mobs/Zombie.h b/src/Mobs/Zombie.h index 809c2a6fe..47a9f1904 100644 --- a/src/Mobs/Zombie.h +++ b/src/Mobs/Zombie.h @@ -10,17 +10,15 @@ class cZombie : public cAggressiveMonster { typedef cAggressiveMonster super; - + public: cZombie(bool a_IsVillagerZombie); CLASS_PROTODEF(cZombie) - - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; - virtual void MoveToPosition(const Vector3d & a_Position) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual bool IsUndead(void) override { return true; } - + bool IsVillagerZombie(void) const { return m_IsVillagerZombie; } bool IsConverting (void) const { return m_IsConverting; } |