From f4e3c01a710a2cc5118807a65f8d27519a19ef37 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 4 Jul 2014 16:49:24 +0100 Subject: [PATCH] Various fixed * Fixed potential invalid pointer dereferencing, fixes #1117 * Fixed ender pearls not being loaded properly --- src/Entities/ProjectileEntity.cpp | 75 ++++++++++++++++++++++++- src/Entities/ProjectileEntity.h | 34 +++++++++-- src/Entities/ThrownEnderPearlEntity.cpp | 8 ++- src/WorldStorage/NBTChunkSerializer.cpp | 11 ++-- 4 files changed, 111 insertions(+), 17 deletions(-) diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index 76daca186..ddcc0f7fd 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -21,6 +21,7 @@ #include "FireChargeEntity.h" #include "FireworkEntity.h" #include "GhastFireballEntity.h" +#include "Player.h" @@ -215,7 +216,7 @@ protected: cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height) : super(etProjectile, a_X, a_Y, a_Z, a_Width, a_Height), m_ProjectileKind(a_Kind), - m_Creator(a_Creator), + m_CreatorData(a_Creator->GetUniqueID(), a_Creator->IsPlayer() ? ((cPlayer *)a_Creator)->GetName() : ""), m_IsInGround(false) { } @@ -227,7 +228,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height) : super(etProjectile, a_Pos.x, a_Pos.y, a_Pos.z, a_Width, a_Height), m_ProjectileKind(a_Kind), - m_Creator(a_Creator), + m_CreatorData(a_Creator->GetUniqueID(), a_Creator->IsPlayer() ? ((cPlayer *)a_Creator)->GetName() : ""), m_IsInGround(false) { SetSpeed(a_Speed); @@ -295,6 +296,74 @@ void cProjectileEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_ +cEntity * cProjectileEntity::GetCreator() +{ + if (m_CreatorData.m_Name.empty()) + { + class cProjectileCreatorCallback : public cEntityCallback + { + public: + cProjectileCreatorCallback(void) : + m_Entity(NULL) + { + } + + virtual bool Item(cEntity * a_Entity) override + { + m_Entity = a_Entity; + return true; + } + + cEntity * GetEntity(void) + { + return m_Entity; + } + + private: + + cEntity * m_Entity; + }; + + cProjectileCreatorCallback PCC; + GetWorld()->DoWithEntityByID(m_CreatorData.m_UniqueID, PCC); + return PCC.GetEntity(); + } + else + { + class cProjectileCreatorCallbackForPlayers : public cPlayerListCallback + { + public: + cProjectileCreatorCallbackForPlayers(void) : + m_Entity(NULL) + { + } + + virtual bool Item(cPlayer * a_Entity) override + { + m_Entity = a_Entity; + return true; + } + + cPlayer * GetEntity(void) + { + return m_Entity; + } + + private: + + cPlayer * m_Entity; + }; + + cProjectileCreatorCallbackForPlayers PCCFP; + GetWorld()->FindAndDoWithPlayer(m_CreatorData.m_Name, PCCFP); + return PCCFP.GetEntity(); + } +} + + + + + AString cProjectileEntity::GetMCAClassName(void) const { switch (m_ProjectileKind) @@ -304,7 +373,7 @@ AString cProjectileEntity::GetMCAClassName(void) const case pkEgg: return "Egg"; case pkGhastFireball: return "Fireball"; case pkFireCharge: return "SmallFireball"; - case pkEnderPearl: return "ThrownEnderPearl"; + case pkEnderPearl: return "ThrownEnderpearl"; case pkExpBottle: return "ThrownExpBottle"; case pkSplashPotion: return "ThrownPotion"; case pkWitherSkull: return "WitherSkull"; diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h index ae06b072f..e2ebe9f27 100644 --- a/src/Entities/ProjectileEntity.h +++ b/src/Entities/ProjectileEntity.h @@ -66,8 +66,15 @@ public: /// Returns the kind of the projectile (fast class identification) eKind GetProjectileKind(void) const { return m_ProjectileKind; } - /// Returns the entity who created this projectile; may be NULL - cEntity * GetCreator(void) { return m_Creator; } + /** Returns the entity who created this projectile through running its Unique ID through cWorld::DoWithEntityByID() + May return NULL; do not store the returned pointer outside the scope of the tick thread! + */ + cEntity * GetCreator(void); + + /** Returns the name of the player that created the projectile + Will be empty for non-player creators + */ + AString GetCreatorName(void) const { return m_CreatorData.m_Name; } /// Returns the string that is used as the entity type (class name) in MCA files AString GetMCAClassName(void) const; @@ -81,10 +88,29 @@ public: void SetIsInGround(bool a_IsInGround) { m_IsInGround = a_IsInGround; } protected: + + /** A structure that stores the Entity ID and Playername of the projectile's creator + Used to migitate invalid pointers caused by the creator being destroyed + */ + struct CreatorData + { + CreatorData(int a_UniqueID, AString & a_Name) : + m_UniqueID(a_UniqueID), + m_Name(a_Name) + { + } + + const int m_UniqueID; + AString m_Name; + }; + + /** The type of projectile I am */ eKind m_ProjectileKind; - /// The entity who has created this projectile; may be NULL (e. g. for dispensers) - cEntity * m_Creator; + /** The structure for containing the entity ID and name who has created this projectile + The ID and/or name may be NULL (e.g. for dispensers/mobs) + */ + CreatorData m_CreatorData; /// True if the projectile has hit the ground and is stuck there bool m_IsInGround; diff --git a/src/Entities/ThrownEnderPearlEntity.cpp b/src/Entities/ThrownEnderPearlEntity.cpp index a3ee23389..96dd41ee6 100644 --- a/src/Entities/ThrownEnderPearlEntity.cpp +++ b/src/Entities/ThrownEnderPearlEntity.cpp @@ -46,10 +46,12 @@ void cThrownEnderPearlEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d void cThrownEnderPearlEntity::TeleportCreator(const Vector3d & a_HitPos) { + cEntity * Creator = GetCreator(); + // Teleport the creator here, make them take 5 damage: - if (m_Creator != NULL) + if (Creator != NULL) { - m_Creator->TeleportToCoords(a_HitPos.x, a_HitPos.y + 0.2, a_HitPos.z); - m_Creator->TakeDamage(dtEnderPearl, this, 5, 0); + Creator->TeleportToCoords(a_HitPos.x, a_HitPos.y + 0.2, a_HitPos.z); + Creator->TakeDamage(dtEnderPearl, this, 5, 0); } } diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index e49042ff7..2dcae51ce 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -619,14 +619,11 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile) { ASSERT(!"Unsaved projectile entity!"); } - } // switch (ProjectileKind) - cEntity * Creator = a_Projectile->GetCreator(); - if (Creator != NULL) + } // switch (ProjectileKind) + + if (!a_Projectile->GetCreatorName().empty()) { - if (Creator->GetEntityType() == cEntity::etPlayer) - { - m_Writer.AddString("ownerName", ((cPlayer *)Creator)->GetName()); - } + m_Writer.AddString("ownerName", a_Projectile->GetCreatorName()); } m_Writer.EndCompound(); }