summaryrefslogtreecommitdiffstats
path: root/src/Entities
diff options
context:
space:
mode:
authorLogicParrot <LogicParrot@users.noreply.github.com>2016-02-04 08:20:08 +0100
committerLogicParrot <LogicParrot@users.noreply.github.com>2016-02-04 08:20:08 +0100
commit7767acdc4bdb4bcebcc2ae3fbf84b537d1016cd1 (patch)
treee83b2297221f3f74360304cbb4671fa8a7079722 /src/Entities
parentMerge pull request #2941 from LogicParrot/chunkBug2 (diff)
parentcMonster::m_Target safety across worlds (diff)
downloadcuberite-7767acdc4bdb4bcebcc2ae3fbf84b537d1016cd1.tar
cuberite-7767acdc4bdb4bcebcc2ae3fbf84b537d1016cd1.tar.gz
cuberite-7767acdc4bdb4bcebcc2ae3fbf84b537d1016cd1.tar.bz2
cuberite-7767acdc4bdb4bcebcc2ae3fbf84b537d1016cd1.tar.lz
cuberite-7767acdc4bdb4bcebcc2ae3fbf84b537d1016cd1.tar.xz
cuberite-7767acdc4bdb4bcebcc2ae3fbf84b537d1016cd1.tar.zst
cuberite-7767acdc4bdb4bcebcc2ae3fbf84b537d1016cd1.zip
Diffstat (limited to 'src/Entities')
-rw-r--r--src/Entities/Entity.cpp7
-rw-r--r--src/Entities/Pawn.cpp88
-rw-r--r--src/Entities/Pawn.h35
-rw-r--r--src/Entities/Player.cpp8
4 files changed, 120 insertions, 18 deletions
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 0706a1676..b207e79c9 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -1514,6 +1514,13 @@ bool cEntity::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d
SetPosition(a_NewPosition);
+ if (this->IsMob())
+ {
+ cMonster * Monster = static_cast<cMonster*>(this);
+ Monster->SetTarget(nullptr);
+ Monster->StopEveryoneFromTargetingMe();
+ }
+
// Queue add to new world
a_World->AddEntity(this);
cWorld * OldWorld = cRoot::Get()->GetWorld(GetWorld()->GetName()); // Required for the hook HOOK_ENTITY_CHANGED_WORLD
diff --git a/src/Entities/Pawn.cpp b/src/Entities/Pawn.cpp
index 2d86dfecf..c8780c326 100644
--- a/src/Entities/Pawn.cpp
+++ b/src/Entities/Pawn.cpp
@@ -8,7 +8,7 @@
#include "BoundingBox.h"
#include "../Blocks/BlockHandler.h"
#include "EffectID.h"
-
+#include "../Mobs/Monster.h"
@@ -27,6 +27,25 @@ cPawn::cPawn(eEntityType a_EntityType, double a_Width, double a_Height) :
+cPawn::~cPawn()
+{
+ ASSERT(m_TargetingMe.size() == 0);
+}
+
+
+
+
+
+void cPawn::Destroyed()
+{
+ StopEveryoneFromTargetingMe();
+ super::Destroyed();
+}
+
+
+
+
+
void cPawn::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
// Iterate through this entity's applied effects
@@ -35,18 +54,18 @@ void cPawn::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
// Copies values to prevent pesky wrong accesses and erasures
cEntityEffect::eType EffectType = iter->first;
cEntityEffect * Effect = iter->second;
-
+
Effect->OnTick(*this);
-
+
// Iterates (must be called before any possible erasure)
++iter;
-
+
// Remove effect if duration has elapsed
if (Effect->GetDuration() - Effect->GetTicks() <= 0)
{
RemoveEntityEffect(EffectType);
}
-
+
// TODO: Check for discrepancies between client and server effect values
}
@@ -126,7 +145,7 @@ void cPawn::HandleAir(void)
// Prevent the oxygen from decreasing
return;
}
-
+
super::HandleAir();
}
@@ -142,14 +161,14 @@ void cPawn::AddEntityEffect(cEntityEffect::eType a_EffectType, int a_Duration, s
// A plugin disallows the addition, bail out.
return;
}
-
+
// No need to add empty effects:
if (a_EffectType == cEntityEffect::effNoEffect)
{
return;
}
a_Duration = static_cast<int>(a_Duration * a_DistanceModifier);
-
+
m_EntityEffects[a_EffectType] = cEntityEffect::CreateEntityEffect(a_EffectType, a_Duration, a_Intensity, a_DistanceModifier);
m_World->BroadcastEntityEffect(*this, a_EffectType, a_Intensity, static_cast<short>(a_Duration));
m_EntityEffects[a_EffectType]->OnActivate(*this);
@@ -187,10 +206,10 @@ void cPawn::ClearEntityEffects()
{
// Copy values to prevent pesky wrong erasures
cEntityEffect::eType EffectType = iter->first;
-
+
// Iterates (must be called before any possible erasure)
++iter;
-
+
// Remove effect
RemoveEntityEffect(EffectType);
}
@@ -200,6 +219,38 @@ void cPawn::ClearEntityEffects()
+void cPawn::NoLongerTargetingMe(cMonster * a_Monster)
+{
+ ASSERT(!IsDestroyed()); // Our destroy override is supposed to clear all targets before we're destroyed.
+ for (auto i = m_TargetingMe.begin(); i != m_TargetingMe.end(); ++i)
+ {
+ cMonster * Monster = *i;
+ if (Monster == a_Monster)
+ {
+ ASSERT(Monster->GetTarget() != this); // The monster is notifying us it is no longer targeting us, assert if that's a lie
+ m_TargetingMe.erase(i);
+ return;
+ }
+ }
+ ASSERT(false); // If this happens, something is wrong. Perhaps the monster never called TargetingMe() or called NoLongerTargetingMe() twice.
+}
+
+
+
+
+
+void cPawn::TargetingMe(cMonster * a_Monster)
+{
+ ASSERT(!IsDestroyed());
+ ASSERT(m_TargetingMe.size() < 10000);
+ ASSERT(a_Monster->GetTarget() == this);
+ m_TargetingMe.push_back(a_Monster);
+}
+
+
+
+
+
void cPawn::HandleFalling(void)
{
/* Not pretty looking, and is more suited to wherever server-sided collision detection is implemented.
@@ -369,3 +420,20 @@ void cPawn::HandleFalling(void)
m_LastGroundHeight = GetPosY();
}
}
+
+
+
+
+
+void cPawn::StopEveryoneFromTargetingMe()
+{
+ std::vector<cMonster*>::iterator i = m_TargetingMe.begin();
+ while (i != m_TargetingMe.end())
+ {
+ cMonster * Monster = *i;
+ ASSERT(Monster->GetTarget() == this);
+ Monster->UnsafeUnsetTarget();
+ i = m_TargetingMe.erase(i);
+ }
+ ASSERT(m_TargetingMe.size() == 0);
+}
diff --git a/src/Entities/Pawn.h b/src/Entities/Pawn.h
index 0ceb1073e..05bc09e88 100644
--- a/src/Entities/Pawn.h
+++ b/src/Entities/Pawn.h
@@ -4,6 +4,9 @@
#include "Entity.h"
#include "EntityEffect.h"
+// fwd cMonster
+class cMonster;
+
@@ -14,21 +17,28 @@ class cPawn :
{
// tolua_end
typedef cEntity super;
-
+
public:
CLASS_PROTODEF(cPawn)
cPawn(eEntityType a_EntityType, double a_Width, double a_Height);
-
+ ~cPawn();
+ virtual void Destroyed() override;
+
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void KilledBy(TakeDamageInfo & a_TDI) override;
-
+
virtual bool IsFireproof(void) const override;
virtual void HandleAir(void) override;
virtual void HandleFalling(void);
+ /** Tells all pawns which are targeting us to stop targeting us. */
+ void StopEveryoneFromTargetingMe();
+
+
+
// tolua_begin
-
+
/** Applies an entity effect
Checks with plugins if they allow the addition.
@param a_EffectType The entity effect to apply
@@ -37,28 +47,39 @@ public:
@param a_DistanceModifier The scalar multiplied to the potion duration, only applies to splash potions)
*/
void AddEntityEffect(cEntityEffect::eType a_EffectType, int a_EffectDurationTicks, short a_EffectIntensity, double a_DistanceModifier = 1);
-
+
/** Removes a currently applied entity effect
@param a_EffectType The entity effect to remove
*/
void RemoveEntityEffect(cEntityEffect::eType a_EffectType);
-
+
/** Returns true, if the entity effect is currently applied
@param a_EffectType The entity effect to check
*/
bool HasEntityEffect(cEntityEffect::eType a_EffectType) const;
-
+
/** Removes all currently applied entity effects (used when drinking milk) */
void ClearEntityEffects(void);
// tolua_end
+ /** remove the monster from the list of monsters targeting this pawn. */
+ void NoLongerTargetingMe(cMonster * a_Monster);
+
+ /** Add the monster to the list of monsters targeting this pawn. (Does not check if already in list!) */
+ void TargetingMe(cMonster * a_Monster);
+
protected:
typedef std::map<cEntityEffect::eType, cEntityEffect *> tEffectMap;
tEffectMap m_EntityEffects;
double m_LastGroundHeight;
bool m_bTouchGround;
+
+private:
+
+ /** A list of all monsters that are targeting this pawn. */
+ std::vector<cMonster*> m_TargetingMe;
} ; // tolua_export
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 7ba6b2bf6..5606e9668 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -176,6 +176,7 @@ cPlayer::~cPlayer(void)
void cPlayer::Destroyed()
{
CloseWindow(false);
+ super::Destroyed();
}
@@ -1681,7 +1682,6 @@ void cPlayer::FreezeInternal(const Vector3d & a_Location, bool a_ManuallyFrozen)
bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d a_NewPosition)
{
ASSERT(a_World != nullptr);
-
if (GetWorld() == a_World)
{
// Don't move to same world
@@ -1708,6 +1708,9 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d
// Remove player from world
GetWorld()->RemovePlayer(this, false);
+ // Stop all mobs from targeting this player
+
+ StopEveryoneFromTargetingMe();
// Send the respawn packet:
if (a_ShouldSendRespawn && (m_ClientHandle != nullptr))
@@ -1720,6 +1723,9 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d
SetPosition(a_NewPosition);
+ // Stop all mobs from targeting this player
+ StopEveryoneFromTargetingMe();
+
// Queue adding player to the new world, including all the necessary adjustments to the object
a_World->AddPlayer(this);
cWorld * OldWorld = cRoot::Get()->GetWorld(GetWorld()->GetName()); // Required for the hook HOOK_ENTITY_CHANGED_WORLD